pub fn linguate(text: &str) -> String {
let mut result = text.to_string();
result = result.replace("--", "—");
result = result.replace("...", "…");
let mut final_text = String::with_capacity(result.len());
let mut in_double = false;
let mut escape = false;
for c in result.chars() {
if escape {
match c {
'"' | '\'' | '\\' => final_text.push(c),
_ => {
final_text.push('\\');
final_text.push(c);
}
}
escape = false;
continue;
}
match c {
'\\' => escape = true,
'"' => {
if in_double {
final_text.push('”');
} else {
final_text.push('“');
}
in_double = !in_double;
}
'\'' => final_text.push('’'),
_ => final_text.push(c),
}
}
if escape {
final_text.push('\\');
}
final_text
}
pub fn trim_lines(s: &str) -> String {
let lines: Vec<&str> = s
.lines()
.map(str::trim) .collect();
let start = lines.iter().position(|line| !line.is_empty()).unwrap_or(0);
let end = lines.iter().rposition(|line| !line.is_empty()).unwrap_or(0);
lines[start..=end].join("\n")
}
pub fn split_braced(s: &str) -> Vec<String> {
let mut result = Vec::new();
let mut buf = String::new();
let mut chars = s.chars().peekable();
let mut inside = false;
while let Some(c) = chars.next() {
if !inside && c == '[' && chars.peek() == Some(&'[') {
chars.next();
result.push(buf.clone());
buf.clear();
inside = true;
} else if inside && c == ']' && chars.peek() == Some(&']') {
chars.next();
result.push(buf.clone());
buf.clear();
inside = false;
} else {
buf.push(c);
}
}
if !buf.is_empty() {
result.push(buf);
}
result
}
#[cfg(feature = "rand")]
pub fn find_hash_match<'a, I>(strings: I, target: u64) -> Option<&'a String>
where
I: IntoIterator<Item = &'a String>,
{
strings
.into_iter()
.find(|s| const_fnv1a_hash::fnv1a_hash_str_64(s) == target)
}
#[cfg(not(feature = "rand"))]
pub fn find_hash_match<'a, I>(strings: I, target: u64) -> Option<&'a String>
where
I: IntoIterator<Item = &'a String>,
{
strings.into_iter().nth(target as usize)
}