Skip to content

Instantly share code, notes, and snippets.

@victor-iyi
Created August 20, 2022 18:55
Show Gist options
  • Save victor-iyi/90d2bfcb383147e002a3c1ce57fc626f to your computer and use it in GitHub Desktop.
Save victor-iyi/90d2bfcb383147e002a3c1ce57fc626f to your computer and use it in GitHub Desktop.
String split in Rust
#[derive(Debug)]
pub struct StrSplit<'haystack, D> {
remainder: Option<&'haystack str>,
delimiter: D,
}
impl<'haystack, D> StrSplit<'haystack, D> {
pub fn new(haystack: &'haystack str, delimiter: D) -> Self {
Self {
remainder: Some(haystack),
delimiter,
}
}
}
pub trait Delimiter {
fn find_next(&self, s: &str) -> Option<(usize, usize)>;
}
impl Delimiter for &str {
fn find_next(&self, s: &str) -> Option<(usize, usize)> {
s.find(self).map(|start| (start, start + self.len()))
}
}
impl Delimiter for char {
fn find_next(&self, s: &str) -> Option<(usize, usize)> {
s.char_indices()
.find(|(_, c)| c == self)
.map(|(start, _)| (start, start + self.len_utf8()))
}
}
impl<'haystack, D> Iterator for StrSplit<'haystack, D>
where
D: Delimiter,
{
type Item = &'haystack str;
fn next(&mut self) -> Option<Self::Item> {
let remainder = self.remainder.as_mut()?;
if let Some((del_start, del_end)) = self.delimiter.find_next(remainder) {
let until_delimiter = &remainder[..del_start];
*remainder = &remainder[del_end..];
Some(until_delimiter)
} else {
self.remainder.take()
}
}
}
pub fn until_delimiter(s: &str, c: char) -> &str {
StrSplit::new(s, c)
.next()
.expect("StrSplit always return at least one result")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let letters: Vec<_> = StrSplit::new("a b c d e", " ").collect();
assert_eq!(letters, vec!["a", "b", "c", "d", "e"]);
}
#[test]
fn tail() {
let letters: Vec<_> = StrSplit::new("a b c d ", " ").collect();
assert_eq!(letters, vec!["a", "b", "c", "d", ""]);
}
#[test]
fn empty_tail() {
let letters: Vec<_> = StrSplit::new("a b c d ", " ").collect();
assert_eq!(letters, vec!["a", "b", "c", "d", ""]);
}
#[test]
fn test_until_delimiter() {
assert_eq!(until_delimiter("hello world", 'o'), "hell");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment