Skip to main content

nekolib/utils/
scanner.rs

1//! スキャナ。
2
3use std::io::{stdin, Error, Read};
4
5/// スキャナ。
6///
7/// 文字列スライスを読み、所望の型に変換する。
8///
9/// # Examples
10/// ```
11/// use std::num::ParseIntError;
12///
13/// use nekolib::utils::Scanner;
14///
15/// let mut p: Scanner = "1 2  a\nb 3".to_string().into();
16///
17/// assert_eq!(p.next::<i32>(), Ok(1));
18/// assert_eq!(p.next::<i32>(), Ok(2));
19/// // `"a"` => `ParseIntError { kind: InvalidDigit }`
20/// assert!(p.next::<i32>().is_err());
21///
22/// assert_eq!(p.next::<char>(), Ok('b'));
23/// assert_eq!(p.next::<String>(), Ok("3".to_string()));
24/// assert_eq!(p.next::<String>(), Ok("".to_string()));
25///
26/// // `""` => `ParseIntError { kind: Empty }`
27/// assert!(p.next::<i32>().is_err());
28/// // `""` => `ParseCharError { kind: EmptyString }`
29/// assert!(p.next::<char>().is_err());
30/// // ok again, as `&str` => `String` never fails
31/// assert_eq!(p.next::<String>(), Ok("".to_string()));
32/// ```
33pub struct Scanner {
34    buf: String,
35    pos: usize,
36}
37
38impl From<String> for Scanner {
39    fn from(buf: String) -> Self { Self { buf, pos: 0 } }
40}
41
42impl Scanner {
43    pub fn from_stdin() -> Result<Self, Error> {
44        let mut s = String::new();
45        stdin().read_to_string(&mut s)?;
46        Ok(Self::from(s))
47    }
48    pub fn next<T: Scan>(&mut self) -> Result<T, <T as Scan>::Err> {
49        let (x, endpos) = T::scan(&self.buf[self.pos..]);
50        self.pos += endpos;
51        x
52    }
53    pub fn next_m1<T>(&mut self) -> Result<T, <T as Scan>::Err>
54    where
55        T: Scan + std::ops::Sub<Output = T> + std::convert::From<u8>,
56    {
57        self.next::<T>().map(|x| x - 1_u8.into())
58    }
59    pub fn next_n<T>(&mut self, n: usize) -> Result<Vec<T>, <T as Scan>::Err>
60    where
61        T: Scan + Clone,
62    {
63        let mut res = vec![];
64        for _ in 0..n {
65            res.push(self.next::<T>()?);
66        }
67        Ok(res)
68    }
69    pub fn get_while<P>(&mut self, pat: P) -> &str
70    where
71        P: Fn(char) -> bool,
72    {
73        let s = &self.buf[self.pos..];
74        let len = s.find(|c| pat(c)).unwrap_or(s.len());
75        let s = &s[..len];
76        self.pos += len;
77        s
78    }
79    pub fn get_line(&mut self) -> &str {
80        let s = &self.buf[self.pos..];
81        let len = s.find('\n').map(|i| i + 1).unwrap_or(s.len());
82        let s = &s[..len];
83        self.pos += len;
84        s
85    }
86    pub fn ignore(&mut self) { self.ignore_while(char::is_whitespace); }
87    pub fn ignore_while<P>(&mut self, pat: P)
88    where
89        P: Fn(char) -> bool,
90    {
91        self.get_while(|c| !pat(c));
92    }
93}
94
95pub trait Scan: Sized {
96    type Err: std::error::Error;
97    fn scan(buf: &str) -> (Result<Self, Self::Err>, usize);
98}
99
100macro_rules! impl_scan_int {
101    ($t:ty) => {
102        impl Scan for $t {
103            type Err = std::num::ParseIntError;
104            fn scan(buf: &str) -> (Result<Self, Self::Err>, usize) {
105                let start = buf.find(|c| !char::is_whitespace(c)).unwrap_or(buf.len());
106                let buf = &buf[start..];
107                let len = buf.find(char::is_whitespace).unwrap_or(buf.len());
108                let buf = &buf[..len];
109                (buf.parse(), start + len)
110            }
111        }
112    };
113    ( $( $t:ty, )* ) => { $( impl_scan_int!($t); )* }
114}
115
116impl_scan_int! {
117    i8, i16, i32, i64, i128, isize,
118    u8, u16, u32, u64, u128, usize,
119}
120
121macro_rules! impl_scan_float {
122    ($t:ty) => {
123        impl Scan for $t {
124            type Err = std::num::ParseFloatError;
125            fn scan(buf: &str) -> (Result<Self, Self::Err>, usize) {
126                let start = buf.find(|c| !char::is_whitespace(c)).unwrap_or(buf.len());
127                let buf = &buf[start..];
128                let len = buf.find(char::is_whitespace).unwrap_or(buf.len());
129                let buf = &buf[..len];
130                (buf.parse(), start + len)
131            }
132        }
133    };
134    ( $( $t:ty, )* ) => { $( impl_scan_float!($t); )* }
135}
136
137impl_scan_float! { f32, f64, }
138
139impl Scan for String {
140    type Err = std::convert::Infallible;
141    fn scan(buf: &str) -> (Result<Self, Self::Err>, usize) {
142        let start = buf.find(|c| !char::is_whitespace(c)).unwrap_or(buf.len());
143        let buf = &buf[start..];
144        let len = buf.find(char::is_whitespace).unwrap_or(buf.len());
145        let buf = &buf[..len];
146        (Ok(buf.to_string()), start + len)
147    }
148}
149
150impl Scan for char {
151    type Err = std::char::ParseCharError;
152    fn scan(buf: &str) -> (Result<Self, Self::Err>, usize) {
153        let start = buf.find(|c| !char::is_whitespace(c)).unwrap_or(buf.len());
154        let buf = &buf[start..];
155        let len =
156            buf.char_indices().nth(1).map(|(i, _)| i).unwrap_or(buf.len());
157        (buf[..len].parse(), start + len)
158    }
159}
160
161#[derive(std::fmt::Debug, Eq, PartialEq)]
162pub struct ScanTupleError();
163
164impl std::fmt::Display for ScanTupleError {
165    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
166        write!(f, "error: while parsing tuple")
167    }
168}
169
170impl std::error::Error for ScanTupleError {}
171
172macro_rules! impl_scan_tuple {
173    (
174        ( $( ($i:ident: $t:tt) ),+ )
175    ) => {
176        impl< $( $t ),+> Scan for ( $( $t ),+ )
177        where
178            $( $t: Scan, )+
179        {
180            type Err = ScanTupleError;
181            fn scan(buf: &str) -> (Result<Self, ScanTupleError>, usize) {
182                let mut len = 0;
183                $(
184                    let (x, i) = $t::scan(&buf[len..]);
185                    len += i;
186                    let $i = match x {
187                        Ok(x) => x,
188                        Err(_) => return (Err(ScanTupleError()), len),
189                    }
190                );* ;
191                (Ok(( $( $i ),+ )), len)
192            }
193        }
194    };
195}
196
197impl_scan_tuple! { ((a: A), (b: B)) }
198impl_scan_tuple! { ((a: A), (b: B), (c: C)) }
199impl_scan_tuple! { ((a: A), (b: B), (c: C), (d: D)) }
200impl_scan_tuple! { ((a: A), (b: B), (c: C), (d: D), (e: E)) }
201impl_scan_tuple! { ((a: A), (b: B), (c: C), (d: D), (e: E), (f: F)) }
202impl_scan_tuple! { ((a: A), (b: B), (c: C), (d: D), (e: E), (f: F), (g: G))}
203impl_scan_tuple! {(
204    (a: A), (b: B), (c: C), (d: D), (e: E), (f: F), (g: G), (h: H)
205)}
206impl_scan_tuple! {(
207    (a: A), (b: B), (c: C), (d: D), (e: E), (f: F), (g: G), (h: H), (i: I)
208)}
209impl_scan_tuple! {(
210    (a: A), (b: B), (c: C), (d: D), (e: E), (f: F), (g: G), (h: H), (i: I),
211    (j: J)
212)}
213impl_scan_tuple! {(
214    (a: A), (b: B), (c: C), (d: D), (e: E), (f: F), (g: G), (h: H), (i: I),
215    (j: J), (k: K)
216)}
217impl_scan_tuple! {(
218    (a: A), (b: B), (c: C), (d: D), (e: E), (f: F), (g: G), (h: H), (i: I),
219    (j: J), (k: K), (l: L)
220)}
221
222// 結局、input! が使いやすくない? また考える