use index;
pub fn expand_spaces(subject: &str, tabsize: usize) -> String {
if subject.is_empty() || tabsize == 0 {
subject.to_string()
} else {
subject.replace(&" ".repeat(tabsize), "\t")
}
}
pub fn expand_tabs(subject: &str, tabsize: usize) -> String {
if subject.is_empty() {
"".to_string()
} else {
subject.replace('\t', &" ".repeat(tabsize))
}
}
pub fn insert(subject: &str, to_insert: &str, position: usize) -> String {
let subject_len = subject.len();
if subject_len == 0 || to_insert.is_empty() {
return subject.to_string();
}
let insert_position = if position > subject_len {
subject_len
} else {
position
};
let prefix = crate::split::chars(subject)[..insert_position].join("");
let sufix = crate::split::chars(subject)[insert_position..].join("");
format!("{}{}{}", prefix, to_insert, sufix)
}
use utils::unidecode;
pub fn latinise(subject: &str) -> String {
if subject.is_empty() {
"".to_string()
} else {
unidecode(subject)
}
}
pub fn pad(subject: &str, length: usize, pad: &str) -> String {
let subject_len = crate::count::count_graphemes(subject);
match subject_len {
0 => "".to_string(),
_ => {
if subject_len >= length {
subject.to_string()
} else {
pad_left_right(subject, length, pad, PadMode::Both)
}
}
}
}
#[derive(Clone, Copy, PartialEq)]
enum PadMode {
Both,
Left,
Right,
}
fn pad_left_right(subject: &str, length: usize, pad: &str, pad_mode: PadMode) -> String {
let width = length - crate::count::count_graphemes(subject);
let to_add = if pad.is_empty() { " " } else { pad };
let times = width / to_add.len();
let str_to_add = to_add.repeat(times + 1);
let string_to_add = crate::split::chars(&str_to_add);
let padding = if pad_mode == PadMode::Left || pad_mode == PadMode::Right {
string_to_add[..width].join("")
} else {
"".to_string()
};
match pad_mode {
PadMode::Both => {
let string_to_add_len = string_to_add.len();
let middle = if string_to_add_len < width {
string_to_add_len / 2
} else {
width / 2
};
let add = usize::from(width % 2 != 0);
let prefix = string_to_add[..middle].join("");
let sufix = string_to_add[..middle + add].join("");
format!("{}{}{}", prefix, subject, sufix)
}
PadMode::Left => format!("{}{}", padding, subject),
PadMode::Right => format!("{}{}", subject, padding),
}
}
pub fn pad_left(subject: &str, length: usize, pad: &str) -> String {
let subject_len = crate::count::count_graphemes(subject);
match subject_len {
0 => "".to_string(),
_ => {
if subject_len >= length {
subject.to_string()
} else {
pad_left_right(subject, length, pad, PadMode::Left)
}
}
}
}
pub fn pad_right(subject: &str, length: usize, pad: &str) -> String {
let subject_len = crate::count::count_graphemes(subject);
match subject_len {
0 => "".to_string(),
_ => {
if subject_len >= length {
subject.to_string()
} else {
pad_left_right(subject, length, pad, PadMode::Right)
}
}
}
}
pub fn repeat(subject: &str, times: usize) -> String {
if subject.is_empty() || times == 0 {
return "".to_string();
}
subject.repeat(times)
}
pub fn replace(subject: &str, pattern: &str, replacement: &str) -> String {
if subject.is_empty() || pattern.is_empty() {
return subject.to_string();
}
match index::index_of(subject, pattern, 0) {
-1 => subject.to_string(),
x => splice(
subject,
x as isize,
crate::count::count(pattern),
replacement,
),
}
}
pub fn replace_all(subject: &str, pattern: &str, replacement: &str) -> String {
if subject.is_empty() || pattern.is_empty() {
return subject.to_string();
}
subject.replace(pattern, replacement)
}
pub fn reverse(subject: &str) -> String {
if subject.is_empty() {
return "".to_string();
}
subject.chars().rev().collect()
}
use unicode_segmentation::UnicodeSegmentation;
pub fn reverse_grapheme(subject: &str) -> String {
if subject.is_empty() {
return "".to_string();
}
UnicodeSegmentation::graphemes(subject, true)
.rev()
.collect::<Vec<&str>>()
.join("")
}
pub fn slugify(subject: &str) -> String {
if subject.is_empty() {
"".to_string()
} else {
crate::split::words(unidecode(subject).replace('\'', "").to_lowercase().trim()).join("-")
}
}
pub fn splice(subject: &str, start: isize, delete_count: usize, to_add: &str) -> String {
let subject_len = crate::count::count(subject);
fn calculate_start_position(start: isize, subject_len: usize) -> usize {
if start < 0 {
if start.unsigned_abs() > subject_len {
0
} else {
subject_len - start.unsigned_abs()
}
} else if (start as usize) >= subject_len {
subject_len
} else {
start as usize
}
}
match delete_count {
0 => match to_add.len() {
0 => subject.to_string(),
_ => {
let insert_position = calculate_start_position(start, subject_len);
if insert_position >= subject_len {
format!("{}{}", subject, to_add)
} else {
insert(subject, to_add, insert_position)
}
}
},
_ => {
let start_position = calculate_start_position(start, subject_len);
let end_position = if delete_count > subject_len - start_position {
subject_len
} else {
start_position + delete_count
};
format!(
"{}{}{}",
crate::chop::first(subject, start_position),
to_add,
crate::chop::slice(subject, end_position as isize, 0)
)
}
}
}
pub fn trim(subject: &str, whitespace: &str) -> String {
trim_left_or_right(subject, whitespace, true, true)
}
pub fn trim_left(subject: &str, whitespace: &str) -> String {
trim_left_or_right(subject, whitespace, true, false)
}
pub fn trim_right(subject: &str, whitespace: &str) -> String {
trim_left_or_right(subject, whitespace, false, true)
}
fn trim_left_or_right(subject: &str, whitespace: &str, to_left: bool, to_right: bool) -> String {
if subject.is_empty() {
return subject.to_string();
}
if whitespace.is_empty() {
if to_left && to_right {
return subject.trim().to_string();
} else if to_left {
return subject.trim_start().to_string();
} else {
return subject.trim_end().to_string();
}
}
if to_left && to_right {
subject.trim_matches(|c| whitespace.contains(c)).to_owned()
} else if to_left {
subject
.trim_start_matches(|c| whitespace.contains(c))
.to_owned()
} else {
subject
.trim_end_matches(|c| whitespace.contains(c))
.to_owned()
}
}
pub fn zfill(subject: &str, length: usize) -> String {
let subject_len = crate::count::count_graphemes(subject);
match subject_len {
0 => "".to_string(),
_ => {
if subject_len >= length {
subject.to_string()
} else {
pad_left_right(subject, length, "0", PadMode::Left)
}
}
}
}
pub fn tr(subject: &str, from: &str, to: &str) -> String {
if from.is_empty() || subject.is_empty() {
return subject.to_owned();
}
let mut result = String::from(subject);
let from_symbols = crate::split::graphemes(from);
let to_symbols = crate::split::graphemes(to);
let to_len = to_symbols.len();
for (i, c) in from_symbols.iter().enumerate() {
let new_c = if i < to_len { to_symbols[i] } else { "" };
result = result.replace(c, new_c);
}
result
}
pub fn word_wrap(subject: &str, width: usize, newline: &str, indent: &str) -> String {
let mut subject_len = crate::count::count_graphemes(subject);
if subject.is_empty() || (subject_len < width && indent.is_empty()) {
return subject.to_owned();
}
let mut result = String::new();
let mut string = String::from(subject);
let length = width + 1;
let new_line = if newline.is_empty() { "\n" } else { newline };
let indent_sym = if indent.is_empty() { "" } else { indent };
while subject_len > width {
let mut subj_part = crate::chop::prune(&string, length, "+");
subj_part = trim(&crate::chop::slice(&subj_part, 0, -1), "");
let length_to_cut = crate::count::count_graphemes(&subj_part);
string = trim(&crate::chop::slice(&string, length_to_cut as isize, 0), "");
subject_len = crate::count::count_graphemes(&string);
if subj_part == string || subj_part.is_empty() {
break;
}
let mut is_finished = false;
let mut subj_part_len = crate::count::count_graphemes(&subj_part);
while !is_finished && subj_part_len < width {
let first_char = crate::chop::first(&string, 1);
if crate::utils::PUNCTUATION.contains(&first_char) {
subj_part.push_str(&first_char);
subj_part_len = crate::count::count_graphemes(&subj_part);
string = trim(&crate::chop::slice(&string, 1, 0), "");
} else {
is_finished = true;
}
}
let str_to_insert = format!("{}{}{}", indent_sym, subj_part, new_line);
result.push_str(&str_to_insert);
}
format!("{}{}{}", result, indent_sym, string)
}
pub fn finish(subject: &str, suffix: &str) -> String {
if suffix.is_empty() || subject.ends_with(suffix) {
return subject.to_owned();
}
format!("{}{}", subject, suffix)
}
pub fn start(subject: &str, prefix: &str) -> String {
if prefix.is_empty() || subject.starts_with(prefix) {
return subject.to_owned();
}
format!("{}{}", prefix, subject)
}