string_utils.rs (1482B)
1 use std::ops::{Bound, RangeBounds}; 2 3 pub trait StringUtils { 4 fn substring(&self, start: usize, len: usize) -> &str; 5 fn slice(&self, range: impl RangeBounds<usize>) -> &str; 6 } 7 8 impl StringUtils for str { 9 fn substring(&self, start: usize, len: usize) -> &str { 10 let mut char_pos = 0; 11 let mut byte_start = 0; 12 let mut it = self.chars(); 13 loop { 14 if char_pos == start { 15 break; 16 } 17 if let Some(c) = it.next() { 18 char_pos += 1; 19 byte_start += c.len_utf8(); 20 } else { 21 break; 22 } 23 } 24 char_pos = 0; 25 let mut byte_end = byte_start; 26 loop { 27 if char_pos == len { 28 break; 29 } 30 if let Some(c) = it.next() { 31 char_pos += 1; 32 byte_end += c.len_utf8(); 33 } else { 34 break; 35 } 36 } 37 &self[byte_start..byte_end] 38 } 39 fn slice(&self, range: impl RangeBounds<usize>) -> &str { 40 let start = match range.start_bound() { 41 Bound::Included(bound) | Bound::Excluded(bound) => *bound, 42 Bound::Unbounded => 0, 43 }; 44 let len = match range.end_bound() { 45 Bound::Included(bound) => *bound + 1, 46 Bound::Excluded(bound) => *bound, 47 Bound::Unbounded => self.len(), 48 } - start; 49 self.substring(start, len) 50 } 51 }