Skip to main content

scanner_rust/
scanner_str.rs

1use std::str::FromStr;
2
3use utf8_width::*;
4
5use crate::{ScannerError, whitespaces::*};
6
7/// A simple text scanner which can in-memory-ly parse primitive types and strings using UTF-8 from a string slice.
8#[derive(Debug)]
9pub struct ScannerStr<'a> {
10    text:        &'a str,
11    text_length: usize,
12    position:    usize,
13}
14
15impl<'a> ScannerStr<'a> {
16    /// Create a scanner from a string.
17    ///
18    /// ```rust
19    /// use std::io;
20    ///
21    /// use scanner_rust::ScannerStr;
22    ///
23    /// let mut sc = ScannerStr::new("123 456");
24    /// ```
25    #[inline]
26    pub fn new<S: ?Sized + AsRef<str>>(text: &S) -> ScannerStr<'_> {
27        let text = text.as_ref();
28
29        ScannerStr {
30            text,
31            text_length: text.len(),
32            position: 0,
33        }
34    }
35}
36
37impl<'a> ScannerStr<'a> {
38    /// Read the next char. If the data is not a correct char, it will return a `Ok(Some(REPLACEMENT_CHARACTER))` which is �. If there is nothing to read, it will return `Ok(None)`.
39    ///
40    /// ```rust
41    /// use scanner_rust::ScannerStr;
42    ///
43    /// let mut sc = ScannerStr::new("5 c 中文");
44    ///
45    /// assert_eq!(Some('5'), sc.next_char().unwrap());
46    /// assert_eq!(Some(' '), sc.next_char().unwrap());
47    /// assert_eq!(Some('c'), sc.next_char().unwrap());
48    /// assert_eq!(Some(' '), sc.next_char().unwrap());
49    /// assert_eq!(Some('中'), sc.next_char().unwrap());
50    /// assert_eq!(Some('文'), sc.next_char().unwrap());
51    /// assert_eq!(None, sc.next_char().unwrap());
52    /// ```
53    pub fn next_char(&mut self) -> Result<Option<char>, ScannerError> {
54        if self.position == self.text_length {
55            return Ok(None);
56        }
57
58        let data = self.text.as_bytes();
59
60        let e = data[self.position];
61
62        let width = unsafe { get_width_assume_valid(e) };
63
64        match width {
65            1 => {
66                self.position += 1;
67
68                Ok(Some(e as char))
69            },
70            _ => {
71                let char_str = &self.text[self.position..(self.position + width)];
72
73                self.position += width;
74
75                Ok(char_str.chars().next())
76            },
77        }
78    }
79
80    /// Read the next line but not include the trailing line character (or line characters like `CrLf`(`\r\n`)). If there is nothing to read, it will return `Ok(None)`.
81    ///
82    /// ```rust
83    /// use scanner_rust::ScannerStr;
84    ///
85    /// let mut sc = ScannerStr::new("123 456\r\n789 \n\n 中文 ");
86    ///
87    /// assert_eq!(Some("123 456"), sc.next_line().unwrap());
88    /// assert_eq!(Some("789 "), sc.next_line().unwrap());
89    /// assert_eq!(Some(""), sc.next_line().unwrap());
90    /// assert_eq!(Some(" 中文 "), sc.next_line().unwrap());
91    /// ```
92    pub fn next_line(&mut self) -> Result<Option<&'a str>, ScannerError> {
93        if self.position == self.text_length {
94            return Ok(None);
95        }
96
97        let data = self.text.as_bytes();
98
99        let mut p = self.position;
100
101        loop {
102            let e = data[p];
103
104            let width = unsafe { get_width_assume_valid(e) };
105
106            match width {
107                1 => {
108                    match e {
109                        b'\n' => {
110                            let text = &self.text[self.position..p];
111
112                            if p + 1 < self.text_length && data[p + 1] == b'\r' {
113                                self.position = p + 2;
114                            } else {
115                                self.position = p + 1;
116                            }
117
118                            return Ok(Some(text));
119                        },
120                        b'\r' => {
121                            let text = &self.text[self.position..p];
122
123                            if p + 1 < self.text_length && data[p + 1] == b'\n' {
124                                self.position = p + 2;
125                            } else {
126                                self.position = p + 1;
127                            }
128
129                            return Ok(Some(text));
130                        },
131                        _ => (),
132                    }
133
134                    p += 1;
135                },
136                _ => {
137                    p += width;
138                },
139            }
140
141            if p == self.text_length {
142                break;
143            }
144        }
145
146        let text = &self.text[self.position..p];
147
148        self.position = p;
149
150        Ok(Some(text))
151    }
152}
153
154impl<'a> ScannerStr<'a> {
155    /// Skip the next whitespaces (`javaWhitespace`). If there is nothing to read, it will return `Ok(false)`.
156    ///
157    /// ```rust
158    /// use scanner_rust::ScannerStr;
159    ///
160    /// let mut sc = ScannerStr::new("1 2   c");
161    ///
162    /// assert_eq!(Some('1'), sc.next_char().unwrap());
163    /// assert_eq!(Some(' '), sc.next_char().unwrap());
164    /// assert_eq!(Some('2'), sc.next_char().unwrap());
165    /// assert_eq!(true, sc.skip_whitespaces().unwrap());
166    /// assert_eq!(Some('c'), sc.next_char().unwrap());
167    /// assert_eq!(false, sc.skip_whitespaces().unwrap());
168    /// ```
169    pub fn skip_whitespaces(&mut self) -> Result<bool, ScannerError> {
170        if self.position == self.text_length {
171            return Ok(false);
172        }
173
174        let data = self.text.as_bytes();
175
176        loop {
177            let e = data[self.position];
178
179            let width = unsafe { get_width_assume_valid(e) };
180
181            match width {
182                1 => {
183                    if !is_whitespace_1(e) {
184                        break;
185                    }
186
187                    self.position += 1;
188                },
189                3 => {
190                    if !is_whitespace_3(
191                        data[self.position],
192                        data[self.position + 1],
193                        data[self.position + 2],
194                    ) {
195                        break;
196                    }
197
198                    self.position += 3;
199                },
200                _ => {
201                    break;
202                },
203            }
204
205            if self.position == self.text_length {
206                break;
207            }
208        }
209
210        Ok(true)
211    }
212
213    /// Read the next token separated by whitespaces. If there is nothing to read, it will return `Ok(None)`.
214    ///
215    /// ```rust
216    /// use scanner_rust::ScannerStr;
217    ///
218    /// let mut sc = ScannerStr::new("123 456\r\n789 \n\n 中文 ");
219    ///
220    /// assert_eq!(Some("123"), sc.next().unwrap());
221    /// assert_eq!(Some("456"), sc.next().unwrap());
222    /// assert_eq!(Some("789"), sc.next().unwrap());
223    /// assert_eq!(Some("中文"), sc.next().unwrap());
224    /// assert_eq!(None, sc.next().unwrap());
225    /// ```
226    #[allow(clippy::should_implement_trait)]
227    pub fn next(&mut self) -> Result<Option<&'a str>, ScannerError> {
228        if !self.skip_whitespaces()? {
229            return Ok(None);
230        }
231
232        if self.position == self.text_length {
233            return Ok(None);
234        }
235
236        let data = self.text.as_bytes();
237
238        let mut p = self.position;
239
240        loop {
241            let e = data[p];
242
243            let width = unsafe { get_width_assume_valid(e) };
244
245            match width {
246                1 => {
247                    if is_whitespace_1(e) {
248                        let text = &self.text[self.position..p];
249
250                        self.position = p;
251
252                        return Ok(Some(text));
253                    }
254
255                    p += 1;
256                },
257                3 => {
258                    if is_whitespace_3(data[p], data[p + 1], data[p + 2]) {
259                        let text = &self.text[self.position..p];
260
261                        self.position = p;
262
263                        return Ok(Some(text));
264                    } else {
265                        p += 3;
266                    }
267                },
268                _ => {
269                    p += width;
270                },
271            }
272
273            if p == self.text_length {
274                break;
275            }
276        }
277
278        let text = &self.text[self.position..p];
279
280        self.position = p;
281
282        Ok(Some(text))
283    }
284}
285
286impl<'a> ScannerStr<'a> {
287    /// Read the next text (as a string slice) with a specific max number of characters. If there is nothing to read, it will return `Ok(None)`.
288    ///
289    /// ```rust
290    /// use scanner_rust::ScannerStr;
291    ///
292    /// let mut sc = ScannerStr::new("123 456\r\n789 \n\n 中文 ");
293    ///
294    /// assert_eq!(Some("123"), sc.next_str(3).unwrap());
295    /// assert_eq!(Some(" 456"), sc.next_str(4).unwrap());
296    /// assert_eq!(Some("\r\n789 "), sc.next_str(6).unwrap());
297    /// assert_eq!(Some("\n\n 中"), sc.next_str(4).unwrap());
298    /// assert_eq!(Some("文"), sc.next().unwrap());
299    /// assert_eq!(Some(" "), sc.next_str(2).unwrap());
300    /// assert_eq!(None, sc.next_str(2).unwrap());
301    /// ```
302    pub fn next_str(
303        &mut self,
304        max_number_of_characters: usize,
305    ) -> Result<Option<&'a str>, ScannerError> {
306        if self.position == self.text_length {
307            return Ok(None);
308        }
309
310        let data = self.text.as_bytes();
311
312        let mut p = self.position;
313        let mut c = 0;
314
315        while c < max_number_of_characters {
316            let width = unsafe { get_width_assume_valid(data[p]) };
317
318            p += width;
319
320            c += 1;
321
322            if p == self.text_length {
323                break;
324            }
325        }
326
327        let text = &self.text[self.position..p];
328
329        self.position = p;
330
331        Ok(Some(text))
332    }
333}
334
335impl<'a> ScannerStr<'a> {
336    /// Read the next text until it reaches a specific boundary. If there is nothing to read, it will return `Ok(None)`.
337    ///
338    /// ```rust
339    /// use scanner_rust::ScannerStr;
340    ///
341    /// let mut sc = ScannerStr::new("123 456\r\n789 \n\n 中文 ");
342    ///
343    /// assert_eq!(Some("123"), sc.next_until(" ").unwrap());
344    /// assert_eq!(Some("456\r"), sc.next_until("\n").unwrap());
345    /// assert_eq!(Some("78"), sc.next_until("9 ").unwrap());
346    /// assert_eq!(Some("\n\n 中文 "), sc.next_until("kk").unwrap());
347    /// assert_eq!(None, sc.next().unwrap());
348    /// ```
349    pub fn next_until<S: AsRef<str>>(
350        &mut self,
351        boundary: S,
352    ) -> Result<Option<&'a str>, ScannerError> {
353        if self.position == self.text_length {
354            return Ok(None);
355        }
356
357        let boundary = boundary.as_ref().as_bytes();
358        let boundary_length = boundary.len();
359
360        if boundary_length == 0 || boundary_length > self.text_length - self.position {
361            let text = &self.text[self.position..];
362
363            self.position = self.text_length;
364
365            return Ok(Some(text));
366        }
367
368        let data = self.text.as_bytes();
369
370        for i in self.position..=(self.text_length - boundary_length) {
371            let e = i + boundary_length;
372
373            if &data[i..e] == boundary {
374                let text = &self.text[self.position..i];
375
376                self.position = e;
377
378                return Ok(Some(text));
379            }
380        }
381
382        let text = &self.text[self.position..];
383
384        self.position = self.text_length;
385
386        Ok(Some(text))
387    }
388}
389
390impl<'a> ScannerStr<'a> {
391    #[inline]
392    fn next_parse<T: FromStr>(&mut self) -> Result<Option<T>, ScannerError>
393    where
394        ScannerError: From<<T as FromStr>::Err>, {
395        let result = self.next()?;
396
397        match result {
398            Some(s) => Ok(Some(s.parse()?)),
399            None => Ok(None),
400        }
401    }
402}
403
404impl<'a> ScannerStr<'a> {
405    #[inline]
406    fn next_raw_parse<T: FromStr, S: AsRef<str>>(
407        &mut self,
408        boundary: S,
409    ) -> Result<Option<T>, ScannerError>
410    where
411        ScannerError: From<<T as FromStr>::Err>, {
412        let result = self.next_until(boundary)?;
413
414        match result {
415            Some(s) => Ok(Some(s.parse()?)),
416            None => Ok(None),
417        }
418    }
419}
420
421macro_rules! scanner_str_number_methods {
422    ($(($t:ty, $next:ident, $next_until:ident, $sample:literal, $v1:literal, $v2:literal)),+ $(,)?) => {
423        impl<'a> ScannerStr<'a> {
424            $(
425                #[doc = concat!(
426                    "Read the next token separated by whitespaces and parse it to a `", stringify!($t), "` value. If there is nothing to read, it will return `Ok(None)`.\n\n```rust\nuse scanner_rust::ScannerStr;\n\nlet mut sc = ScannerStr::new(", stringify!($sample), ");\n\nassert_eq!(Some(", stringify!($v1), "), sc.", stringify!($next), "().unwrap());\nassert_eq!(Some(", stringify!($v2), "), sc.", stringify!($next), "().unwrap());\n```"
427                )]
428                #[inline]
429                pub fn $next(&mut self) -> Result<Option<$t>, ScannerError> {
430                    self.next_parse()
431                }
432            )+
433        }
434
435        impl<'a> ScannerStr<'a> {
436            $(
437                #[doc = concat!(
438                    "Read the next text until it reaches a specific boundary and parse it to a `", stringify!($t), "` value. If there is nothing to read, it will return `Ok(None)`.\n\n```rust\nuse scanner_rust::ScannerStr;\n\nlet mut sc = ScannerStr::new(", stringify!($sample), ");\n\nassert_eq!(Some(", stringify!($v1), "), sc.", stringify!($next_until), "(\" \").unwrap());\nassert_eq!(Some(", stringify!($v2), "), sc.", stringify!($next_until), "(\" \").unwrap());\n```"
439                )]
440                #[inline]
441                pub fn $next_until<S: AsRef<str>>(
442                    &mut self,
443                    boundary: S,
444                ) -> Result<Option<$t>, ScannerError> {
445                    self.next_raw_parse(boundary)
446                }
447            )+
448        }
449    };
450}
451
452scanner_str_number_methods! {
453    (u8, next_u8, next_u8_until, "1 2", 1, 2),
454    (u16, next_u16, next_u16_until, "1 2", 1, 2),
455    (u32, next_u32, next_u32_until, "1 2", 1, 2),
456    (u64, next_u64, next_u64_until, "1 2", 1, 2),
457    (u128, next_u128, next_u128_until, "1 2", 1, 2),
458    (usize, next_usize, next_usize_until, "1 2", 1, 2),
459    (i8, next_i8, next_i8_until, "1 2", 1, 2),
460    (i16, next_i16, next_i16_until, "1 2", 1, 2),
461    (i32, next_i32, next_i32_until, "1 2", 1, 2),
462    (i64, next_i64, next_i64_until, "1 2", 1, 2),
463    (i128, next_i128, next_i128_until, "1 2", 1, 2),
464    (isize, next_isize, next_isize_until, "1 2", 1, 2),
465    (f32, next_f32, next_f32_until, "1 2.5", 1.0, 2.5),
466    (f64, next_f64, next_f64_until, "1 2.5", 1.0, 2.5),
467}
468
469impl<'a> ScannerStr<'a> {
470    /// Drop the next line but not include the trailing line character (or line characters like `CrLf`(`\r\n`)). If there is nothing to read, it will return `Ok(None)`. If there is something to read, it will return `Ok(Some(i))`. The `i` is the length (in bytes) of the dropped line.
471    ///
472    /// ```rust
473    /// use scanner_rust::ScannerStr;
474    ///
475    /// let mut sc = ScannerStr::new("123 456\r\n789 \n\n 中文 ");
476    ///
477    /// assert_eq!(Some(7), sc.drop_next_line().unwrap());
478    /// assert_eq!(Some("789 "), sc.next_line().unwrap());
479    /// assert_eq!(Some(0), sc.drop_next_line().unwrap());
480    /// assert_eq!(Some(" 中文 "), sc.next_line().unwrap());
481    /// assert_eq!(None, sc.drop_next_line().unwrap());
482    /// ```
483    #[inline]
484    pub fn drop_next_line(&mut self) -> Result<Option<usize>, ScannerError> {
485        Ok(self.next_line()?.map(str::len))
486    }
487
488    /// Drop the next token separated by whitespaces. If there is nothing to read, it will return `Ok(None)`. If there is something to read, it will return `Ok(Some(i))`. The `i` is the length (in bytes) of the dropped token.
489    ///
490    /// ```rust
491    /// use scanner_rust::ScannerStr;
492    ///
493    /// let mut sc = ScannerStr::new("123 456\r\n789 \n\n 中文 ");
494    ///
495    /// assert_eq!(Some(3), sc.drop_next().unwrap());
496    /// assert_eq!(Some("456"), sc.next().unwrap());
497    /// assert_eq!(Some(3), sc.drop_next().unwrap());
498    /// assert_eq!(Some("中文"), sc.next().unwrap());
499    /// assert_eq!(None, sc.drop_next().unwrap());
500    /// ```
501    #[inline]
502    pub fn drop_next(&mut self) -> Result<Option<usize>, ScannerError> {
503        Ok(self.next()?.map(str::len))
504    }
505
506    /// Drop the next text until it reaches a specific boundary. If there is nothing to read, it will return `Ok(None)`. If there is something to read, it will return `Ok(Some(i))`. The `i` is the length (in bytes) of the dropped text, excluding the boundary.
507    ///
508    /// ```rust
509    /// use scanner_rust::ScannerStr;
510    ///
511    /// let mut sc = ScannerStr::new("123 456\r\n789 \n\n 中文 ");
512    ///
513    /// assert_eq!(Some(7), sc.drop_next_until("\r\n").unwrap());
514    /// assert_eq!(Some("789 "), sc.next_line().unwrap());
515    /// assert_eq!(Some(0), sc.drop_next_until("\n").unwrap());
516    /// assert_eq!(Some(" 中文 "), sc.next_line().unwrap());
517    /// assert_eq!(None, sc.drop_next_until("").unwrap());
518    /// ```
519    #[inline]
520    pub fn drop_next_until<S: AsRef<str>>(
521        &mut self,
522        boundary: S,
523    ) -> Result<Option<usize>, ScannerError> {
524        Ok(self.next_until(boundary)?.map(str::len))
525    }
526}
527
528impl<'a> Iterator for ScannerStr<'a> {
529    type Item = &'a str;
530
531    #[inline]
532    fn next(&mut self) -> Option<Self::Item> {
533        self.next().unwrap_or(None)
534    }
535}