提问人:marcel fiedler 提问时间:7/2/2022 最后编辑:Maëlanmarcel fiedler 更新时间:7/5/2022 访问量:274
使用 scanf 拆分非空格分隔符上的字符串
Use scanf to split a string on a non-whitespace separator
问:
我的目标是扫描一个包含冒号作为除法的字符串,并将其两个部分保存在一个元组中。
例如:
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)
答:
默认情况下,字符串说明符是 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
@c
c
说明符是贪婪的,它会将字符串读取到空格或扫描指示符。指标可以在说明符之后使用,其中是一个字符,例如,%s
@<indicator>
%s
<indicator>
let split str =
Scanf.sscanf str "%s@:%s" (fun x y -> x,y)
这将指示将所有内容读入第一个字符串,删除,然后将其余部分读入第二个字符串。scanf
:
:
您看到的问题的原因是,第一个问题将继续消耗输入,直到满足以下条件之一:%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));;
评论