#parser-combinator #parser #combinator #file-format #input #data #compose

parser-compose

用于编写和组合任意文件或数据格式的解析器的库

18个重大版本

0.19.0 2023年12月17日
0.17.0 2023年12月9日
0.16.0 2023年10月7日

#607 in 解析器实现

Download history 2/week @ 2024-03-27 5/week @ 2024-04-03

每月213次下载

MIT 许可证

48KB
788

Parser Compose

已弃用。请参阅 bparse

⚠️ 警告 ☣️
下面是自制的、手工编写的代码。实验性的。可能无法按广告那样工作。

文档

示例

是什么?

parser-compose 是一个用于编写任意数据格式解析器的crate。您可以使用它来解析字符串切片和元素实现 Cloneslice

类似项目

这是如何不同的?

parser-compose 不提供错误处理或报告功能。如果解析成功,您将获得一个包含值的 Some(..)。如果解析失败,您将获得一个 None。许多解析任务不需要知道解析失败的原因,只需要知道它失败了。例如,当解析HTTP消息头时,您只需要知道它是否有效。这个crate专注于这种用例,并通过这样做摒弃了支持解析器错误处理的所有仪式。

示例

解析IMF http日期

use parser_compose::{Parser,utf8_scalar};

struct ImfDate {
  day_name: String,
  day: u8,
  month: String,
  year: u16,
  hour: u8,
  minute: u8,
  second: u8,
}

fn imfdate(input: &str) -> Option<(ImfDate, &str)> {
  let digit = utf8_scalar(0x30..=0x39);
  let twodigits = digit
    .repeats(2)
    .input()
    .map(|s| u8::from_str_radix(s, 10).unwrap());


  // day-name     = %s"Mon" / %s"Tue" / %s"Wed"
  //              / %s"Thu" / %s"Fri" / %s"Sat" / %s"Sun"
  let day_name = "Mon".or("Tue").or("Wed")
    .or("Thu").or("Fri").or("Sat").or("Sun")
    .map(str::to_string);

  let day = twodigits;

  // month        = %s"Jan" / %s"Feb" / %s"Mar" / %s"Apr"
  //               / %s"May" / %s"Jun" / %s"Jul" / %s"Aug"
  //               / %s"Sep" / %s"Oct" / %s"Nov" / %s"Dec"
  let month = "Jan".or("Feb").or("Mar").or("Apr")
    .or("May").or("Jun").or("Jul").or("Aug")
    .or("Sep").or("Oct").or("Nov").or("Dec")
    .map(str::to_string);

  let year = digit
    .repeats(4)
    .input()
    .map(|s| u16::from_str_radix(s, 10).unwrap());

  // date1        = day SP month SP year
  let date1 = (day, " ", month, " ", year)
    .map(|(d, _, m, _, y)| (d, m, y));

  let gmt = "GMT";

  let hour = twodigits;
  let minute = twodigits;
  let second = twodigits;

  // time-of-day  = hour ":" minute ":" second
  let time_of_day = (hour, ":", minute, ":", second)
    .map(|(h,_,m,_,s)| (h, m, s));

  // IMF-fixdate  = day-name "," SP date1 SP time-of-day SP GMT
  (day_name, ", ", date1, " ", time_of_day, " ", gmt)
    .map(|res| ImfDate {
      day_name: res.0,
      day: res.2.0,
      month: res.2.1,
      year: res.2.2,
      hour: res.4.0,
      minute: res.4.1,
      second: res.4.2,
    }).try_parse(input)
}

let input = "Sun, 06 Nov 1994 08:49:37 GMT";

let (date, rest) = imfdate(input).unwrap();

assert_eq!(date.day_name, "Sun");
assert_eq!(date.day, 6);
assert_eq!(date.month, "Nov");
assert_eq!(date.year, 1994);
assert_eq!(date.hour, 8);
assert_eq!(date.minute, 49);
assert_eq!(date.second, 37);

// missing comma after day name
assert!(
  imfdate("Sun 06 Nov 1994 08:49:37 GMT").is_none(),
);

验证http引号字符串

use parser_compose::{Parser,byte};

/// Tries to parse a quoted string out of `input`.
/// If it succeeds, the returned tuple contains the quoted string (without
/// quotes) along with the rest of the input
fn quoted_string(input: &[u8]) -> Option<(&[u8], &[u8])> {
  let htab = byte(b'\t');
  let sp = byte(b' ');
  let dquote = byte(b'"');
  let obs_text = byte(0x80..=0xFF); 
  let vchar = byte(0x21..=0x7E);

  // qdtext = HTAB / SP / %x21 / %x23-5B / %x5D-7E / obs-text
  let qdtext = htab
    .or(sp)
    .or(byte(0x21))
    .or(byte(0x23..=0x5B))
    .or(byte(0x5D..=0x7E))
    .or(obs_text);

  // quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
  let quoted_pair = (
    byte(b'\\'),
    htab.or(sp).or(vchar).or(obs_text)
  ).input();


  // quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE
  (dquote, qdtext.or(quoted_pair).repeats(0..).input(), dquote)
    .map(|(_, r, _)| r)
    .try_parse(input)
}

// 3 quoted strings one after the other "1", "a" and "\""
let input = r##""1""a""\"""##.as_bytes(); 

let (first, rest) = quoted_string(input).unwrap();

assert_eq!(
  b"1",
  first
);

// Notice that because of its signature, `quoted_string` can be treated as a parser
let (remaining, _) = quoted_string.accumulate(2).try_parse(rest).unwrap();

assert_eq!(remaining.len(), 2);
assert_eq!(remaining[0], b"a");
assert_eq!(remaining[1], b"\\\"");

感谢

如果没有以下内容,这个crate将无法实现:

无运行时依赖