pub const I18N: &[u8] = b"I18N.";
#[derive(Debug, Clone)]
pub struct RangeStr<'a> {
pub str: Vec<&'a str>,
pub range: Vec<std::ops::Range<usize>>,
}
pub fn replace<S: AsRef<str>>(s: &str, li: &[std::ops::Range<usize>], to_li: &[S]) -> String {
let mut result = s.to_string();
for (range, replacement) in li.iter().zip(to_li).rev() {
result.replace_range(range.clone(), replacement.as_ref());
}
result
}
pub fn extract(input: &str) -> RangeStr<'_> {
let bytes = input.as_bytes();
let mut range_li = Vec::new();
let mut str_li = Vec::new();
let mut i = 0;
while i < bytes.len() {
if let Some(start) = find_subsequence(&bytes[i..], b"${") {
let start_pos = i + start + 2;
let mut j = start_pos;
j = skip_whitespace(bytes, j);
let word_begin = j + I18N.len();
if bytes[j..].starts_with(I18N) {
j += I18N.len(); if let Some(end) = find_subsequence(&bytes[j..], b"}") {
let end_pos = j + end;
let mut word_end = end_pos - 1;
while word_end > j {
if b" \t".contains(&bytes[word_end]) {
word_end -= 1;
} else {
break;
}
}
range_li.push(start_pos..end_pos);
str_li.push(&input[word_begin..=word_end]);
i = end_pos + 1;
} else {
break;
}
} else {
i = start_pos + 2;
}
} else {
break;
}
}
RangeStr {
range: range_li,
str: str_li,
}
}
fn find_subsequence(haystack: &[u8], needle: &[u8]) -> Option<usize> {
haystack
.windows(needle.len())
.position(|window| window == needle)
}
fn skip_whitespace(bytes: &[u8], mut pos: usize) -> usize {
while pos < bytes.len()
&& (bytes[pos] == b' ' || bytes[pos] == b'\t' || bytes[pos] == b'\n' || bytes[pos] == b'\r')
{
pos += 1;
}
pos
}