Given an input string, finds the next "token" which is normally delimited by whitespace, but "quoted strings" are also supported. Returns that token and the remainder. If there are no more tokens, this returns None. Yes this is a lot of manual parsing and there's a ton of crates we could use, like winnow, but this problem domain is *just* simple enough that I decided not to learn that yet.
(s: &str)
| 125 | /// like winnow, but this problem domain is *just* simple enough that I decided |
| 126 | /// not to learn that yet. |
| 127 | fn next_token(s: &str) -> Option<(&str, &str)> { |
| 128 | let s = s.trim_start(); |
| 129 | let (first, rest) = match s.strip_prefix('"') { |
| 130 | None => match s.find(|c: char| c.is_whitespace()) { |
| 131 | Some(idx) => s.split_at(idx), |
| 132 | None => (s, ""), |
| 133 | }, |
| 134 | Some(rest) => { |
| 135 | let end = rest.find('"')?; |
| 136 | (&rest[..end], &rest[end + 1..]) |
| 137 | } |
| 138 | }; |
| 139 | if first.is_empty() { |
| 140 | None |
| 141 | } else { |
| 142 | Some((first, rest)) |
| 143 | } |
| 144 | } |
| 145 | |
| 146 | fn next_token_owned(s: &str) -> Option<(String, &str)> { |
| 147 | Self::next_token(s).map(|(a, b)| (a.to_owned(), b)) |