#[must_use]
pub fn unescape_json_strings(content: &str) -> String {
if content.contains("\\n") || content.contains("\\t") || content.contains("\\r") {
content
.replace("\\n", "\n")
.replace("\\t", "\t")
.replace("\\r", "\r")
} else {
content.to_string()
}
}
#[must_use]
pub fn unescape_json_strings_aggressive(content: &str) -> String {
std::iter::successors(Some(content.to_string()), |prev| {
let next = prev
.replace("\\\\n", "\n")
.replace("\\\\t", "\t")
.replace("\\\\r", "\r")
.replace("\\n", "\n")
.replace("\\t", "\t")
.replace("\\r", "\r");
(next != *prev).then_some(next)
})
.last()
.unwrap_or_default()
}
#[must_use]
pub fn contains_literal_escape_sequences(content: &str) -> bool {
content.lines().enumerate().any(|(i, line)| {
let trimmed = line.trim();
if i == 1 && (trimmed == "\\n" || trimmed == "\\n\\n" || trimmed.starts_with("\\n\\n")) {
return true;
}
trimmed.contains("\\n\\n\\n") || trimmed.contains("\\n\\n\\n\\n")
})
}
#[must_use]
pub fn final_escape_sequence_cleanup(message: &str) -> String {
if contains_literal_escape_sequences(message) {
unescape_json_strings_aggressive(message)
} else {
unescape_json_strings(message)
}
}
#[must_use]
pub fn preprocess_raw_content(content: &str) -> String {
std::iter::successors(Some(content.to_string()), |prev| {
let next = prev
.replace("\\\\n", "\x00NEWLINE\x00")
.replace("\\n", "\n")
.replace("\x00NEWLINE\x00", "\n")
.replace("\\\\t", "\x00TAB\x00")
.replace("\\t", "\t")
.replace("\x00TAB\x00", "\t")
.replace("\\\\r", "\x00CR\x00")
.replace("\\r", "\r")
.replace("\x00CR\x00", "\r");
(next != *prev).then_some(next)
})
.last()
.unwrap_or_default()
}
#[cfg(test)]
include!("cleaning/test_helpers_thought_stripping.rs");
#[cfg(test)]
include!("cleaning/test_helpers_formatting.rs");
#[cfg(test)]
mod cleaning_tests;