使用 scanf 拆分非空格分隔符上的字符串

Use scanf to split a string on a non-whitespace separator

提问人:marcel fiedler 提问时间:7/2/2022 最后编辑:Maëlanmarcel fiedler 更新时间:7/5/2022 访问量:274

问:

我的目标是扫描一个包含冒号作为除法的字符串,并将其两个部分保存在一个元组中。
例如:

input: "a:b"
output: ("a", "b")

到目前为止,我的方法不断收到错误消息:“
scanf:char number 9 处的错误输入:查找 ':',找到 '\n'”。

 Scanf.bscanf Scanf.Scanning.stdin "%s:%s" (fun x y -> (x,y));;

此外,我的方法适用于整数,我很困惑为什么它不适用于字符串。

Scanf.bscanf Scanf.Scanning.stdin "%d:%d" (fun x y -> (x,y));;
4:3
- : int * int = (4, 3)
字符串 拆分 IO OCAML 扫描

评论


答:

1赞 octachron 7/2/2022 #1

默认情况下,字符串说明符是 eager 的,它将吞噬您的所有内容,直到下一个空格。您需要添加一个扫描指示 (https://ocaml.org/api/Scanf.html#indication) 来向 Scanf.sscanf 解释您希望第一个字符串在第一个字符串上结束:%s:

例如

Scanf.sscanf "a:b"
  "%s@:%s"
  (fun x y -> x,y)

返回。此处的扫描指示是紧随第一个说明符之后的说明符。通常,扫描指示是为字符编写的。"a", "b"@:%s@cc

2赞 ivg 7/2/2022 #2

说明符是贪婪的,它会将字符串读取到空格或扫描指示符。指标可以在说明符之后使用,其中是一个字符,例如,%s@<indicator>%s<indicator>

let split str = 
  Scanf.sscanf str "%s@:%s" (fun x y -> x,y)

这将指示将所有内容读入第一个字符串,删除,然后将其余部分读入第二个字符串。scanf::

6赞 kopecs 7/2/2022 #3

您看到的问题的原因是,第一个问题将继续消耗输入,直到满足以下条件之一:%s

  • 找到一个空格,
  • 遇到扫描指示,
  • 已达到输入结束。

请注意,看到冒号并不能满足其中任何一个(如果您不使用扫描指示)。这意味着第一个将消耗所有内容,直到输入缓冲区中的换行符,然后将失败。%s:

您没有同样的问题,因为不会在匹配整数时使用冒号。%d:%d%d

您可以通过改用不会使用冒号的格式字符串来解决此问题,例如 .您也可以使用扫描指示,如下所示:.%[^:]:%s%s@:%s

此外,当前方法不会在缓冲区中使用任何尾随空格,这可能会导致在后续使用 this 时将换行符添加到第一个元素中,因此您可能更愿意使用换行符。%s@:%s\n

所以,总而言之,

Scanf.bscanf Scanf.Scanning.stdin "%s@:%s\n" (fun x y -> (x,y));;