Ocaml中字符串的简单解析

Ocaml中字符串的简单解析,ocaml,Ocaml,我不确定最好的方法是什么,所以我想我应该问问。我有这样一句话: NAME="/dev/sda" TYPE="disk" MODEL="KINGSTON SV300S3" (从lsblk获得,有几个选项),我希望尽可能简单地提取每个字段。是的,我知道lsblk有一个非常好的--json,但不幸的是,这是我不能使用的最近添加的一个,我们有一些非常旧的服务器仍在生产中 也许用Str和一些正则表达式?谷歌似乎说了很多menhir,我从来没有用过它,但我担心,仅仅对于像这样的几个变量来说,这可能有点沉重

我不确定最好的方法是什么,所以我想我应该问问。我有这样一句话:

NAME="/dev/sda" TYPE="disk" MODEL="KINGSTON SV300S3"
(从lsblk获得,有几个选项),我希望尽可能简单地提取每个字段。是的,我知道lsblk有一个非常好的--json,但不幸的是,这是我不能使用的最近添加的一个,我们有一些非常旧的服务器仍在生产中

也许用Str和一些正则表达式?谷歌似乎说了很多menhir,我从来没有用过它,但我担心,仅仅对于像这样的几个变量来说,这可能有点沉重?
我曾尝试在字符和字符串上使用String.split\u,但当模型包含空格时,它开始变得复杂,字符上的String.split\u当然不会忽略双引号之间的空格。

Str
可能会做到这一点,标准库中鲜为人知的代码可以非常方便地进行不太繁重的字符串操作,至少对于或多或少遵守OCaml词汇约定的格式是如此。基本上,它会将您的
char
流转换为令牌流,您可以更轻松地解析这些令牌流。我想,
lsblk
的完整输出格式可能需要一些改进,但对于您的示例,以下内容就足够了:

let lexer = Genlex.make_lexer [ "=" ]

let test = "NAME=\"/dev/sda\" TYPE=\"disk\" MODEL=\"KINGSTON SV300S3\""
let test_stream = Stream.of_string test
let test_stream_token = lexer test_stream

let info =
  let l = ref [] in
  try
    while true do
      let kw = Stream.next test_stream_token in
      let eq = Stream.next test_stream_token in
      let v = Stream.next test_stream_token in
      let kw =
        match kw with Ident s -> s | _ -> failwith "Unrecognized pattern"
      in
      let () = match eq with Kwd "=" -> () | _ -> failwith "Expected '='" in
      let v = match v with String s -> s | _ -> failwith "Expected string" in
      l:=(kw,v)::!l
    done;
    assert false
  with Stream.Failure -> List.rev !l
基本上,主循环认为输入中包含的信息是一系列项目,其形式为
=”
,由
Genlex
生成的lexer分解为三个标记


它的结果是:
[(“NAME”,“dev/sda”);(“TYPE”,“disk”);(“MODEL”,“KINGSTON SV300S3”)]
虽然
Str
可能会起作用,但标准库中鲜为人知的方法对于不太繁重的字符串操作非常方便,至少对于或多或少遵守OCaml词汇约定的格式是如此。基本上,它会将您的
char
流转换为令牌流,您可以更轻松地解析这些令牌流。我想,
lsblk
的完整输出格式可能需要一些改进,但对于您的示例,以下内容就足够了:

let lexer = Genlex.make_lexer [ "=" ]

let test = "NAME=\"/dev/sda\" TYPE=\"disk\" MODEL=\"KINGSTON SV300S3\""
let test_stream = Stream.of_string test
let test_stream_token = lexer test_stream

let info =
  let l = ref [] in
  try
    while true do
      let kw = Stream.next test_stream_token in
      let eq = Stream.next test_stream_token in
      let v = Stream.next test_stream_token in
      let kw =
        match kw with Ident s -> s | _ -> failwith "Unrecognized pattern"
      in
      let () = match eq with Kwd "=" -> () | _ -> failwith "Expected '='" in
      let v = match v with String s -> s | _ -> failwith "Expected string" in
      l:=(kw,v)::!l
    done;
    assert false
  with Stream.Failure -> List.rev !l
基本上,主循环认为输入中包含的信息是一系列项目,其形式为
=”
,由
Genlex
生成的lexer分解为三个标记

它的结果是:
[(“名称”、“/dev/sda”);(“类型”、“磁盘”);(“型号”、“金斯敦SV300S3”)]
明白了:

let re = Str.regexp "NAME=\"\\(.*\\)\" TYPE=\"\\(.*\\)\" MODEL=\"\\(.*\\)\"" in
  match Str.string_match re line 0 with
  | false -> [`Null]
  | true  ->
     let name = Str.matched_group 1 line in
     let typ = Str.matched_group 2 line in
     let model = Str.matched_group 3 line in
     Printf.printf "%s, %s, %s\n" name typ model
明白了:

let re = Str.regexp "NAME=\"\\(.*\\)\" TYPE=\"\\(.*\\)\" MODEL=\"\\(.*\\)\"" in
  match Str.string_match re line 0 with
  | false -> [`Null]
  | true  ->
     let name = Str.matched_group 1 line in
     let typ = Str.matched_group 2 line in
     let model = Str.matched_group 3 line in
     Printf.printf "%s, %s, %s\n" name typ model

对于这样的简单格式,Scanf模块可能是一个可行的替代方案:

let extract s = Scanf.sscanf s "NAME=%S TYPE=%S MODEL=%S" (fun x y z -> x, y ,z);;
;; extract {|NAME="/dev/sda" TYPE="disk" MODEL="KINGSTON SV300S3"|}
屈服

(“/dev/sda”、“disk”、“KINGSTON SV300S3”)


正如所料。

对于这样的简单格式,Scanf模块可能是一个可行的替代方案:

let extract s = Scanf.sscanf s "NAME=%S TYPE=%S MODEL=%S" (fun x y z -> x, y ,z);;
;; extract {|NAME="/dev/sda" TYPE="disk" MODEL="KINGSTON SV300S3"|}
屈服

(“/dev/sda”、“disk”、“KINGSTON SV300S3”)


正如所料。

Menhir在这方面做得太过火了。正则表达式似乎是很自然的方法。你有没有一个例子来说明如何做到这一点?我找到了大量的检查,但我找不到任何子字符串提取。Menhir在这方面做得太过分了。正则表达式似乎是很自然的方法。你有没有一个例子来说明如何做到这一点?我找到了大量的检查,但我找不到任何子字符串提取。我从未听说过genlex,但这里的函数基本上完全符合我的需要!即使我决定某一天需要新专栏,它也会开箱即用,这太完美了。谢谢!现在试着理解一下:)我从来没有听说过genlex,但这里的函数基本上就是我所需要的!即使我决定某一天需要新专栏,它也会开箱即用,这太完美了。谢谢!现在试着去理解:)Scanf总是让我畏缩,但它显然是适合这里工作的工具。Scanf总是让我畏缩,但它显然是适合这里工作的工具。