Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- fn main() {
- let inputs = &["foo; bar; baz", "foo;", ";foo"];
- for input in inputs {
- println!("qas: {:?}", quote_aware_split(input, ";").collect::<Vec<_>>());
- println!("std: {:?}", input.split(';').collect::<Vec<_>>());
- }
- }
- fn quote_aware_split<'a>(input: &'a str, split: &'a str) -> QuoteAwareSplit<'a> {
- QuoteAwareSplit { haystack: input, needle: split, fused: false }
- }
- pub struct QuoteAwareSplit<'a> {
- haystack: &'a str, // the text being searched
- needle: &'a str, // the text being searched for
- fused: bool // if we've consumed the haystack and no more results should be returned
- }
- impl<'a> QuoteAwareSplit<'a> {
- pub fn remainder(&mut self) -> &str {
- let haystack = self.haystack;
- self.haystack = "";
- self.fused = true;
- haystack
- }
- }
- impl<'a> Iterator for QuoteAwareSplit<'a> {
- type Item = &'a str;
- fn next(&mut self) -> Option<Self::Item> {
- let (l, r, o) = self.next_idx()?;
- if l == 0 && r == 0 && o == 0 {
- self.fused = true;
- return Some("");
- }
- let ret = &self.haystack[l..r];
- self.haystack = &self.haystack[r+o..];
- return Some(ret);
- }
- }
- impl<'a> QuoteAwareSplit<'a> {
- // (left_ptr, right_ptr, right_advance_offset)
- fn next_idx(&self) -> Option<(usize, usize, usize)> {
- let mut in_escape = false;
- let mut in_quote = false;
- if self.fused {
- return None;
- }
- if self.haystack.is_empty() {
- return Some((0, 0, 0));
- }
- if self.needle.is_empty() {
- return Some((0, self.haystack.len(), 0));
- }
- let needle_first = self.needle.chars().next().unwrap();
- for (i, c) in self.haystack.chars().enumerate() {
- // if we're in an unescaped quote/string, don't look for needle
- if c == '"' { // double-quote character
- if in_escape {
- in_escape = false;
- } else {
- in_quote = !in_quote;
- }
- } else if c == '\\' {
- in_escape = !in_escape;
- } else if in_escape {
- in_escape = false;
- }
- if !in_quote && c == needle_first {
- let needle_len = self.needle.len();
- if needle_len + i > self.haystack.len() {
- break;
- }
- if &self.haystack[i..i+needle_len] == self.needle {
- return Some((0, i, needle_len));
- }
- }
- }
- return Some((0, self.haystack.len(), 0));
- }
- pub fn peek(&self) -> Option<&str> {
- self.next_idx().map(|(l, r, _)| &self.haystack[l..r])
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement