pub fn format_time_ms_to_timestamp_string(time_ms: f32) -> String {
let total_ms = time_ms.max(0.0) as i32;
let minute = total_ms / 60000;
let second = (total_ms % 60000) / 1000;
let ms = total_ms % 1000;
format!("{:02}:{:02}.{:03}", minute, second, ms)
}
pub fn is_number(s: &str) -> bool {
!s.is_empty() && s.chars().all(|c| c.is_ascii_digit())
}
pub fn remove_front_back_brackets(s: &str) -> String {
let s = s.trim();
for (open, close) in [('(', ')'), ('(', ')')] {
if let Some(inner) = s.strip_prefix(open).and_then(|s| s.strip_suffix(close)) {
return inner.to_string();
}
}
s.to_string()
}
pub fn compute_text_same(text_x: &str, text_y: &str, is_case_sensitive: bool) -> f64 {
let (text_x, text_y) = if is_case_sensitive {
(text_x.to_string(), text_y.to_string())
} else {
(text_x.to_lowercase(), text_y.to_lowercase())
};
if text_x == text_y {
return 100.0;
}
let len_x = text_x.chars().count();
let len_y = text_y.chars().count();
if len_x == 0 || len_y == 0 {
return 0.0;
}
let lcs_len = lcs_length(&text_x, &text_y);
let max_len = len_x.max(len_y) as f64;
(lcs_len as f64 / max_len) * 100.0
}
pub fn lcs_length(x: &str, y: &str) -> usize {
let x_chars: Vec<char> = x.chars().collect();
let y_chars: Vec<char> = y.chars().collect();
let m = x_chars.len();
let n = y_chars.len();
if m == 0 || n == 0 {
return 0;
}
let mut prev = vec![0usize; n + 1];
let mut curr = vec![0usize; n + 1];
for i in 1..=m {
for j in 1..=n {
if x_chars[i - 1] == y_chars[j - 1] {
curr[j] = prev[j - 1] + 1;
} else {
curr[j] = prev[j].max(curr[j - 1]);
}
}
std::mem::swap(&mut prev, &mut curr);
}
prev[n]
}
pub fn is_chinese_or_japanese_character(character: char) -> bool {
matches!(character,
'\u{4E00}'..='\u{9FFF}'
| '\u{3400}'..='\u{4DBF}'
| '\u{3040}'..='\u{309F}'
| '\u{30A0}'..='\u{30FF}'
| '\u{31F0}'..='\u{31FF}')
}
pub fn has_chinese(s: &str) -> bool {
s.chars().any(|c| ('\u{4e00}'..='\u{9fff}').contains(&c))
}
pub fn collapse_whitespace(s: &str) -> String {
let mut result = String::with_capacity(s.len());
for part in s.split_whitespace() {
if !result.is_empty() {
result.push(' ');
}
result.push_str(part);
}
result
}
pub fn remove_duo_spaces(s: &str) -> String {
let mut result = String::with_capacity(s.len());
let mut last_was_space = false;
for c in s.chars() {
if c == ' ' {
if !last_was_space {
result.push(c);
}
last_was_space = true;
} else {
result.push(c);
last_was_space = false;
}
}
result
}