pub fn escape_python(s: &str) -> String {
s.replace('\\', "\\\\")
.replace('"', "\\\"")
.replace('\n', "\\n")
.replace('\r', "\\r")
.replace('\t', "\\t")
}
pub fn escape_rust(s: &str) -> String {
s.replace('\\', "\\\\")
.replace('"', "\\\"")
.replace('\n', "\\n")
.replace('\r', "\\r")
.replace('\t', "\\t")
}
pub fn raw_string_hashes(s: &str) -> usize {
let mut max_hashes = 0;
let mut current = 0;
let mut after_quote = false;
for ch in s.chars() {
if ch == '"' {
after_quote = true;
current = 0;
} else if ch == '#' && after_quote {
current += 1;
max_hashes = max_hashes.max(current);
} else {
after_quote = false;
current = 0;
}
}
max_hashes + 1
}
pub fn rust_raw_string(s: &str) -> String {
let hashes = raw_string_hashes(s);
let h: String = "#".repeat(hashes);
format!("r{h}\"{s}\"{h}")
}
pub fn escape_js(s: &str) -> String {
s.replace('\\', "\\\\")
.replace('"', "\\\"")
.replace('\n', "\\n")
.replace('\r', "\\r")
.replace('\t', "\\t")
.replace('`', "\\`")
.replace('$', "\\$")
}
pub fn go_string_literal(s: &str) -> String {
if !s.contains('`') {
format!("`{s}`")
} else {
format!("\"{}\"", escape_go(s))
}
}
pub fn escape_go(s: &str) -> String {
s.replace('\\', "\\\\")
.replace('"', "\\\"")
.replace('\n', "\\n")
.replace('\r', "\\r")
.replace('\t', "\\t")
}
pub fn escape_java(s: &str) -> String {
s.replace('\\', "\\\\")
.replace('"', "\\\"")
.replace('\n', "\\n")
.replace('\r', "\\r")
.replace('\t', "\\t")
}
pub fn escape_csharp(s: &str) -> String {
s.replace('\\', "\\\\")
.replace('"', "\\\"")
.replace('\n', "\\n")
.replace('\r', "\\r")
.replace('\t', "\\t")
}
pub fn escape_php(s: &str) -> String {
s.replace('\\', "\\\\")
.replace('"', "\\\"")
.replace('$', "\\$")
.replace('\n', "\\n")
.replace('\r', "\\r")
.replace('\t', "\\t")
}
pub fn escape_ruby(s: &str) -> String {
s.replace('\\', "\\\\")
.replace('"', "\\\"")
.replace('#', "\\#")
.replace('\n', "\\n")
.replace('\r', "\\r")
.replace('\t', "\\t")
}
pub fn escape_ruby_single(s: &str) -> String {
s.replace('\\', "\\\\").replace('\'', "\\'")
}
pub fn ruby_needs_double_quotes(s: &str) -> bool {
s.contains('\n') || s.contains('\r') || s.contains('\t') || s.contains('\0')
}
pub fn ruby_string_literal(s: &str) -> String {
if ruby_needs_double_quotes(s) {
format!("\"{}\"", escape_ruby(s))
} else {
format!("'{}'", escape_ruby_single(s))
}
}
pub fn escape_elixir(s: &str) -> String {
s.replace('\\', "\\\\")
.replace('"', "\\\"")
.replace('#', "\\#")
.replace('\n', "\\n")
.replace('\r', "\\r")
.replace('\t', "\\t")
}
pub fn escape_r(s: &str) -> String {
s.replace('\\', "\\\\")
.replace('"', "\\\"")
.replace('\n', "\\n")
.replace('\r', "\\r")
.replace('\t', "\\t")
}
pub fn escape_c(s: &str) -> String {
s.replace('\\', "\\\\")
.replace('"', "\\\"")
.replace('\n', "\\n")
.replace('\r', "\\r")
.replace('\t', "\\t")
}
pub fn sanitize_ident(s: &str) -> String {
let mut result = String::with_capacity(s.len());
for ch in s.chars() {
if ch.is_ascii_alphanumeric() || ch == '_' {
result.push(ch);
} else {
result.push('_');
}
}
let trimmed = result.trim_start_matches(|c: char| c.is_ascii_digit());
if trimmed.is_empty() {
"_".to_string()
} else {
trimmed.to_string()
}
}
pub fn sanitize_filename(s: &str) -> String {
s.chars()
.map(|c| if c.is_ascii_alphanumeric() || c == '_' { c } else { '_' })
.collect::<String>()
.to_lowercase()
}
pub fn escape_shell(s: &str) -> String {
s.replace('\'', r"'\''")
}