use std::cmp::Ordering;
pub trait CharString {
fn indexof(&self, searchstring: &str, start_index: usize) -> Option<usize>;
fn substr(&self, start_index: isize, length: isize) -> String;
fn substru(&self, start_index: usize, length: usize) -> String;
fn substr_end(&self, start_index: isize) -> String;
fn substring(&self, start_index: isize, end_index: isize) -> String;
fn str_remove(&self, start_index: usize, length: usize) -> String;
}
impl CharString for str {
fn indexof(&self, searchstring: &str, start_index: usize) -> Option<usize> {
indexof(&self, searchstring, start_index)
}
fn substr(&self, start_index: isize, length: isize) -> String {
substr(&self, start_index, length)
}
fn substru(&self, start_index: usize, length: usize) -> String {
substru(&self, start_index, length)
}
fn substr_end(&self, start_index: isize) -> String {
substr_end(&self, start_index)
}
fn substring(&self, start_index: isize, end_index: isize) -> String {
substring(&self, start_index, end_index)
}
fn str_remove(&self, start_index: usize, length: usize) -> String {
str_remove(&self, start_index, length)
}
}
impl CharString for String {
fn indexof(&self, searchstring: &str, start_index: usize) -> Option<usize> {
indexof(&self, searchstring, start_index)
}
fn str_remove(&self, start_index: usize, length: usize) -> String {
str_remove(&self, start_index, length)
}
fn substr(&self, start_index: isize, length: isize) -> String {
substr(&self, start_index, length)
}
fn substru(&self, start_index: usize, length: usize) -> String {
substru(&self, start_index, length)
}
fn substr_end(&self, start_index: isize) -> String {
substr_end(&self, start_index)
}
fn substring(&self, start_index: isize, end_index: isize) -> String {
substring(&self, start_index, end_index)
}
}
#[macro_export]
macro_rules! str_concat {
($($arg:expr),+) => {
{
let mut len = 0;
$(
len += $arg.len();
)*
let mut result = String::with_capacity(len);
$(
result.push_str($arg);
)*
result
}
};
}
#[inline]
fn calc_start_end(total_length: usize, start_index: isize, length: isize) -> (usize, usize) {
let start: isize;
let last: isize;
let total_length: isize = total_length as isize;
if total_length == 0 || length == 0 || start_index < -total_length || start_index >= total_length {
return (0, 0);
}
let length: isize = length.clamp(-total_length, total_length);
if start_index >= 0 {
start = start_index
} else {
start = total_length + start_index
}
if length > 0 {
last = (start + length - 1).clamp(0, total_length - 1) } else {
last = (start + length + 1).clamp(0, total_length + 1)
}
if start > last {
(last as usize, (start + 1) as usize)
} else {
(start as usize, (last + 1) as usize)
}
}
pub fn indexof(s: &str, searchstring: &str, start_index: usize) -> Option<usize> {
if searchstring.is_empty() {
return None;
}
let mut char_index: usize = start_index;
let search_len: usize = searchstring.chars().count();
let total_len: usize = s.len();
let mut match_count: usize;
let mut next_index: usize;
let mut self_tmp: std::iter::Skip<std::str::Chars<'_>>;
for c in s.chars().skip(start_index) {
if c == searchstring.chars().next().unwrap() {
match_count = 1;
self_tmp = s.chars().skip(char_index + 1);
for sc in searchstring.chars().skip(1) {
next_index = char_index + match_count;
if next_index >= total_len || self_tmp.next().unwrap() != sc {
break;
}
match_count += 1;
}
if match_count == search_len {
return Some(char_index);
}
}
char_index += 1;
}
None
}
pub fn str_remove(s: &str, start_index: usize, length: usize) -> String {
let mut chars: std::str::Chars = s.chars();
let mut s: String = s.to_owned();
if length == 0 {
return s;
}
let len_byte: usize = s.len(); let mut start_byte: usize = 0; let mut start_byte_found: bool = false; let end_byte: usize; let mut pos_byte: usize = 0;
let end_index: usize = start_index + length;
let mut c: char;
let mut pos: usize = 0;
loop {
c = chars.next().unwrap();
if pos == start_index {
start_byte = pos_byte;
start_byte_found = true;
} else if pos == end_index {
end_byte = pos_byte;
break;
}
pos += 1;
pos_byte += c.len_utf8();
if pos_byte == len_byte {
if start_byte_found {
end_byte = pos_byte;
break;
}
return s;
}
}
s.replace_range(start_byte..end_byte, ""); s
}
pub fn substr(s: &str, start_index: isize, length: isize) -> String {
let total_length: usize = s.chars().count();
let (start, end) = calc_start_end(total_length, start_index, length);
s.chars().skip(start).take(end - start).collect::<String>()
}
#[inline]
pub fn substru(s: &str, start_index: usize, length: usize) -> String {
s.chars().skip(start_index).take(length).collect::<String>()
}
pub fn substr_end(s: &str, start_index: isize) -> String {
let total_length: isize = s.chars().count() as isize;
if (start_index < -total_length) || (start_index > total_length) {
return String::new();
}
let start: isize = if start_index >= 0 {
start_index
} else {
total_length + start_index
};
s.chars()
.skip(start as usize)
.take((total_length - start) as usize)
.collect::<String>()
}
pub fn substring(s: &str, start_index: isize, end_index: isize) -> String {
let mut start: isize;
let mut end: isize;
match start_index.cmp(&end_index) {
Ordering::Less => {
start = start_index;
end = end_index;
}
Ordering::Greater => {
start = end_index;
end = start_index;
}
Ordering::Equal => {
return String::new();
}
}
let total_length: usize = s.chars().count();
start = isize::max(0, start);
end = isize::min(end, total_length as isize);
s.chars()
.skip(start as usize)
.take((end - start) as usize)
.collect::<String>()
}