nom/character/
mod.rs

1//! Character specific parsers and combinators
2//!
3//! Functions recognizing specific characters
4
5use core::marker::PhantomData;
6
7use crate::error::ErrorKind;
8use crate::FindToken;
9use crate::IsStreaming;
10use crate::Mode;
11use crate::{error::ParseError, AsChar, Err, IResult, Input, Needed, Parser};
12
13#[cfg(test)]
14mod tests;
15
16pub mod complete;
17pub mod streaming;
18
19#[inline]
20#[doc(hidden)]
21#[deprecated(since = "8.0.0", note = "Replaced with `AsChar::is_alpha`")]
22pub fn is_alphabetic(chr: u8) -> bool {
23  matches!(chr, 0x41..=0x5A | 0x61..=0x7A)
24}
25
26#[inline]
27#[doc(hidden)]
28#[deprecated(since = "8.0.0", note = "Replaced with `AsChar::is_dec_digit`")]
29pub fn is_digit(chr: u8) -> bool {
30  matches!(chr, 0x30..=0x39)
31}
32
33#[inline]
34#[doc(hidden)]
35#[deprecated(since = "8.0.0", note = "Replaced with `AsChar::is_hex_digit`")]
36pub fn is_hex_digit(chr: u8) -> bool {
37  matches!(chr, 0x30..=0x39 | 0x41..=0x46 | 0x61..=0x66)
38}
39
40#[inline]
41#[doc(hidden)]
42#[deprecated(since = "8.0.0", note = "Replaced with `AsChar::is_oct_digit`")]
43pub fn is_oct_digit(chr: u8) -> bool {
44  matches!(chr, 0x30..=0x37)
45}
46
47/// Tests if byte is ASCII binary digit: 0-1
48///
49/// # Example
50///
51/// ```
52/// # use nom::character::is_bin_digit;
53/// assert_eq!(is_bin_digit(b'a'), false);
54/// assert_eq!(is_bin_digit(b'2'), false);
55/// assert_eq!(is_bin_digit(b'0'), true);
56/// assert_eq!(is_bin_digit(b'1'), true);
57/// ```
58#[inline]
59pub fn is_bin_digit(chr: u8) -> bool {
60  matches!(chr, 0x30..=0x31)
61}
62
63#[inline]
64#[doc(hidden)]
65#[deprecated(since = "8.0.0", note = "Replaced with `AsChar::is_alphanum`")]
66pub fn is_alphanumeric(chr: u8) -> bool {
67  AsChar::is_alphanum(chr)
68}
69
70#[inline]
71#[doc(hidden)]
72#[deprecated(since = "8.0.0", note = "Replaced with `AsChar::is_space`")]
73pub fn is_space(chr: u8) -> bool {
74  chr == b' ' || chr == b'\t'
75}
76
77#[inline]
78#[doc(hidden)]
79#[deprecated(since = "8.0.0", note = "Replaced with `AsChar::is_newline`")]
80pub fn is_newline(chr: u8) -> bool {
81  chr == b'\n'
82}
83
84/// Recognizes one character.
85///
86/// # Example
87///
88/// ```
89/// # use nom::{Err, error::{ErrorKind, Error}, Needed, IResult};
90/// # use nom::character::streaming::char;
91/// fn parser(i: &str) -> IResult<&str, char> {
92///     char('a')(i)
93/// }
94/// assert_eq!(parser("abc"), Ok(("bc", 'a')));
95/// assert_eq!(parser("bc"), Err(Err::Error(Error::new("bc", ErrorKind::Char))));
96/// assert_eq!(parser(""), Err(Err::Incomplete(Needed::new(1))));
97/// ```
98pub fn char<I, Error: ParseError<I>>(c: char) -> impl Parser<I, Output = char, Error = Error>
99where
100  I: Input,
101  <I as Input>::Item: AsChar,
102{
103  Char { c, e: PhantomData }
104}
105
106/// Parser implementation for [char()]
107pub struct Char<E> {
108  c: char,
109  e: PhantomData<E>,
110}
111
112impl<I, Error: ParseError<I>> Parser<I> for Char<Error>
113where
114  I: Input,
115  <I as Input>::Item: AsChar,
116{
117  type Output = char;
118  type Error = Error;
119  #[inline(always)]
120  fn process<OM: crate::OutputMode>(
121    &mut self,
122    i: I,
123  ) -> crate::PResult<OM, I, Self::Output, Self::Error> {
124    match (i).iter_elements().next().map(|t| {
125      let b = t.as_char() == self.c;
126      (&self.c, b)
127    }) {
128      None => {
129        if OM::Incomplete::is_streaming() {
130          Err(Err::Incomplete(Needed::new(self.c.len() - i.input_len())))
131        } else {
132          Err(Err::Error(OM::Error::bind(|| Error::from_char(i, self.c))))
133        }
134      }
135      Some((_, false)) => Err(Err::Error(OM::Error::bind(|| Error::from_char(i, self.c)))),
136      Some((c, true)) => Ok((i.take_from(c.len()), OM::Output::bind(|| c.as_char()))),
137    }
138  }
139}
140
141/// Recognizes one character and checks that it satisfies a predicate
142///
143/// # Example
144///
145/// ```
146/// # use nom::{Err, error::{ErrorKind, Error}, Needed, IResult};
147/// # use nom::character::complete::satisfy;
148/// fn parser(i: &str) -> IResult<&str, char> {
149///     satisfy(|c| c == 'a' || c == 'b')(i)
150/// }
151/// assert_eq!(parser("abc"), Ok(("bc", 'a')));
152/// assert_eq!(parser("cd"), Err(Err::Error(Error::new("cd", ErrorKind::Satisfy))));
153/// assert_eq!(parser(""), Err(Err::Error(Error::new("", ErrorKind::Satisfy))));
154/// ```
155pub fn satisfy<F, I, Error: ParseError<I>>(
156  predicate: F,
157) -> impl Parser<I, Output = char, Error = Error>
158where
159  I: Input,
160  <I as Input>::Item: AsChar,
161  F: Fn(char) -> bool,
162{
163  Satisfy {
164    predicate,
165    make_error: |i: I| Error::from_error_kind(i, ErrorKind::Satisfy),
166  }
167}
168
169/// Parser implementation for [satisfy]
170pub struct Satisfy<F, MakeError> {
171  predicate: F,
172  make_error: MakeError,
173}
174
175impl<I, Error: ParseError<I>, F, MakeError> Parser<I> for Satisfy<F, MakeError>
176where
177  I: Input,
178  <I as Input>::Item: AsChar,
179  F: Fn(char) -> bool,
180  MakeError: Fn(I) -> Error,
181{
182  type Output = char;
183  type Error = Error;
184
185  #[inline(always)]
186  fn process<OM: crate::OutputMode>(
187    &mut self,
188    i: I,
189  ) -> crate::PResult<OM, I, Self::Output, Self::Error> {
190    match (i).iter_elements().next().map(|t| {
191      let c = t.as_char();
192      let b = (self.predicate)(c);
193      (c, b)
194    }) {
195      None => {
196        if OM::Incomplete::is_streaming() {
197          Err(Err::Incomplete(Needed::Unknown))
198        } else {
199          Err(Err::Error(OM::Error::bind(|| (self.make_error)(i))))
200        }
201      }
202      Some((_, false)) => Err(Err::Error(OM::Error::bind(|| (self.make_error)(i)))),
203      Some((c, true)) => Ok((i.take_from(c.len()), OM::Output::bind(|| c.as_char()))),
204    }
205  }
206}
207
208/// Recognizes one of the provided characters.
209///
210/// # Example
211///
212/// ```
213/// # use nom::{Err, error::ErrorKind};
214/// # use nom::character::complete::one_of;
215/// assert_eq!(one_of::<_, _, (&str, ErrorKind)>("abc")("b"), Ok(("", 'b')));
216/// assert_eq!(one_of::<_, _, (&str, ErrorKind)>("a")("bc"), Err(Err::Error(("bc", ErrorKind::OneOf))));
217/// assert_eq!(one_of::<_, _, (&str, ErrorKind)>("a")(""), Err(Err::Error(("", ErrorKind::OneOf))));
218/// ```
219pub fn one_of<I, T, Error: ParseError<I>>(list: T) -> impl Parser<I, Output = char, Error = Error>
220where
221  I: Input,
222  <I as Input>::Item: AsChar,
223  T: FindToken<char>,
224{
225  Satisfy {
226    predicate: move |c: char| list.find_token(c),
227    make_error: move |i| Error::from_error_kind(i, ErrorKind::OneOf),
228  }
229}
230
231//. Recognizes a character that is not in the provided characters.
232///
233/// # Example
234///
235/// ```
236/// # use nom::{Err, error::ErrorKind, Needed};
237/// # use nom::character::streaming::none_of;
238/// assert_eq!(none_of::<_, _, (_, ErrorKind)>("abc")("z"), Ok(("", 'z')));
239/// assert_eq!(none_of::<_, _, (_, ErrorKind)>("ab")("a"), Err(Err::Error(("a", ErrorKind::NoneOf))));
240/// assert_eq!(none_of::<_, _, (_, ErrorKind)>("a")(""), Err(Err::Incomplete(Needed::Unknown)));
241/// ```
242pub fn none_of<I, T, Error: ParseError<I>>(list: T) -> impl Parser<I, Output = char, Error = Error>
243where
244  I: Input,
245  <I as Input>::Item: AsChar,
246  T: FindToken<char>,
247{
248  Satisfy {
249    predicate: move |c: char| !list.find_token(c),
250    make_error: move |i| Error::from_error_kind(i, ErrorKind::NoneOf),
251  }
252}
253
254// Matches one byte as a character. Note that the input type will
255/// accept a `str`, but not a `&[u8]`, unlike many other nom parsers.
256///
257/// # Example
258///
259/// ```
260/// # use nom::{character::complete::anychar, Err, error::{Error, ErrorKind}, IResult};
261/// fn parser(input: &str) -> IResult<&str, char> {
262///     anychar(input)
263/// }
264///
265/// assert_eq!(parser("abc"), Ok(("bc",'a')));
266/// assert_eq!(parser(""), Err(Err::Error(Error::new("", ErrorKind::Eof))));
267/// ```
268pub fn anychar<T, E: ParseError<T>>(input: T) -> IResult<T, char, E>
269where
270  T: Input,
271  <T as Input>::Item: AsChar,
272{
273  let mut it = input.iter_elements();
274  match it.next() {
275    None => Err(Err::Error(E::from_error_kind(input, ErrorKind::Eof))),
276    Some(c) => Ok((input.take_from(c.len()), c.as_char())),
277  }
278}
279
280/// Parser implementation for char
281pub struct AnyChar<E> {
282  e: PhantomData<E>,
283}
284
285impl<I, Error: ParseError<I>> Parser<I> for AnyChar<Error>
286where
287  I: Input,
288  <I as Input>::Item: AsChar,
289{
290  type Output = char;
291  type Error = Error;
292
293  fn process<OM: crate::OutputMode>(
294    &mut self,
295    i: I,
296  ) -> crate::PResult<OM, I, Self::Output, Self::Error> {
297    match (i).iter_elements().next() {
298      None => {
299        if OM::Incomplete::is_streaming() {
300          Err(Err::Incomplete(Needed::new(1)))
301        } else {
302          Err(Err::Error(OM::Error::bind(|| {
303            Error::from_error_kind(i, ErrorKind::Eof)
304          })))
305        }
306      }
307      Some(c) => Ok((i.take_from(c.len()), OM::Output::bind(|| c.as_char()))),
308    }
309  }
310}
311
312/// Recognizes one or more ASCII numerical characters: 0-9
313///
314/// *Streaming version*: Will return `Err(nom::Err::Incomplete(_))` if there's not enough input data,
315/// or if no terminating token is found (a non digit character).
316/// # Example
317///
318/// ```
319/// # use nom::{Err, error::ErrorKind, IResult, Needed};
320/// # use nom::character::streaming::digit1;
321/// assert_eq!(digit1::<_, (_, ErrorKind)>("21c"), Ok(("c", "21")));
322/// assert_eq!(digit1::<_, (_, ErrorKind)>("c1"), Err(Err::Error(("c1", ErrorKind::Digit))));
323/// assert_eq!(digit1::<_, (_, ErrorKind)>(""), Err(Err::Incomplete(Needed::new(1))));
324/// ```
325pub fn digit1<T, E: ParseError<T>>() -> impl Parser<T, Output = T, Error = E>
326where
327  T: Input,
328  <T as Input>::Item: AsChar,
329{
330  Digit1 { e: PhantomData }
331}
332
333/// Parser implementation for [digit1]
334pub struct Digit1<E> {
335  e: PhantomData<E>,
336}
337
338impl<I: Input, E: ParseError<I>> Parser<I> for Digit1<E>
339where
340  <I as Input>::Item: AsChar,
341{
342  type Output = I;
343
344  type Error = E;
345
346  #[inline]
347  fn process<OM: crate::OutputMode>(
348    &mut self,
349    input: I,
350  ) -> crate::PResult<OM, I, Self::Output, Self::Error> {
351    input.split_at_position_mode1::<OM, _, _>(|item| !item.is_dec_digit(), ErrorKind::Digit)
352  }
353}
354
355/// Recognizes zero or more spaces, tabs, carriage returns and line feeds.
356///
357/// *Streaming version*: Will return `Err(nom::Err::Incomplete(_))` if there's not enough input data,
358/// or if no terminating token is found (a non space character).
359/// # Example
360///
361/// ```
362/// # use nom::{Err, error::ErrorKind, IResult, Needed};
363/// # use nom::character::streaming::multispace0;
364/// assert_eq!(multispace0::<_, (_, ErrorKind)>(" \t\n\r21c"), Ok(("21c", " \t\n\r")));
365/// assert_eq!(multispace0::<_, (_, ErrorKind)>("Z21c"), Ok(("Z21c", "")));
366/// assert_eq!(multispace0::<_, (_, ErrorKind)>(""), Err(Err::Incomplete(Needed::new(1))));
367/// ```
368pub fn multispace0<T, E: ParseError<T>>() -> impl Parser<T, Output = T, Error = E>
369where
370  T: Input,
371  <T as Input>::Item: AsChar,
372{
373  MultiSpace0 { e: PhantomData }
374  /*input.split_at_position(|item| {
375    let c = item.as_char();
376    !(c == ' ' || c == '\t' || c == '\r' || c == '\n')
377  })*/
378}
379
380/// Parser implementation for [multispace0()]
381pub struct MultiSpace0<E> {
382  e: PhantomData<E>,
383}
384
385impl<I, Error: ParseError<I>> Parser<I> for MultiSpace0<Error>
386where
387  I: Input,
388  <I as Input>::Item: AsChar,
389{
390  type Output = I;
391  type Error = Error;
392
393  fn process<OM: crate::OutputMode>(
394    &mut self,
395    i: I,
396  ) -> crate::PResult<OM, I, Self::Output, Self::Error> {
397    i.split_at_position_mode::<OM, _, _>(|item| {
398      let c = item.as_char();
399      !(c == ' ' || c == '\t' || c == '\r' || c == '\n')
400    })
401  }
402}