模块 Scanf

module Scanf: sig .. end

格式化输入函数。


介绍

使用格式字符串进行函数式输入

模块 Scanf 提供格式化输入函数或扫描器

格式化输入函数可以从任何类型的输入中读取,包括字符串、文件或任何可以返回字符的内容。更通用的字符源称为格式化输入通道(或扫描缓冲区),其类型为 Scanf.Scanning.in_channel。更通用的格式化输入函数从任何扫描缓冲区读取,名为 bscanf

一般来说,格式化输入函数有 3 个参数

因此,对格式化输入函数 Scanf.bscanf 的典型调用为 bscanf ic fmt f,其中

一个简单的示例

如上所述,表达式 bscanf ic "%d" f 从字符源 ic 读取一个十进制整数 n,并返回 f n

例如,

那么 bscanf Scanning.stdin "%d" f 从标准输入读取一个整数 n,并返回 f n(即 n + 1)。因此,如果我们计算 bscanf stdin "%d" f,然后在键盘上输入 41,则我们得到的结果为 42

格式化输入作为函数式特性

OCaml 的扫描功能让人联想到相应的 C 功能。但是,它也存在很大差异,更简单,但功能更强大:格式化输入函数是高阶函数,参数传递机制只是常规的函数应用,而不是命令式语言中常见的基于变量分配的机制;OCaml 格式字符串还具有有用的补充,可以轻松定义复杂的标记;正如函数式编程语言中所预期的那样,格式化输入函数还支持多态性,特别是与多态用户定义的扫描器进行任意交互。此外,OCaml 格式化输入功能在编译时完全类型检查。

未同步访问

Scanf.Scanning.in_channel 的未同步访问可能会导致 Scanf.Scanning.in_channel 状态无效。因此,对 Scanf.Scanning.in_channel 的并发访问必须同步(例如,使用 Mutex.t)。

格式化输入通道

module Scanning: sig .. end

格式化输入函数的类型

type ('a, 'b, 'c, 'd) scanner = ('a, Scanning.in_channel, 'b, 'c, 'a -> 'd, 'd) format6 -> 'c 

格式化输入扫描器的类型:('a, 'b, 'c, 'd) scanner 是从某个格式化输入通道根据某个格式字符串读取的格式化输入函数的类型;更准确地说,如果 scan 是某个格式化输入函数,那么 scan
    ic fmt f
f 应用于格式字符串 fmt 指定的所有参数,当 scanScanf.Scanning.in_channel 格式化输入通道 ic 读取这些参数时。

例如,下面的 Scanf.scanf 函数的类型为 ('a, 'b, 'c, 'd) scanner,因为它是一个从 Scanf.Scanning.stdin 读取的格式化输入函数:scanf fmt ff 应用于 fmt 指定的参数,如预期的那样,从 stdin 读取这些参数。

如果格式 fmt 包含一些 %r 指示,则必须在接收函数 f 之前提供相应的格式化输入函数。例如,如果 read_elem 是类型为 t 的值的输入函数,那么 bscanf ic "%r;" read_elem f 读取一个类型为 t 的值 v,后面跟着一个 ';' 字符,并返回 f v

type ('a, 'b, 'c, 'd) scanner_opt = ('a, Scanning.in_channel, 'b, 'c, 'a -> 'd option, 'd) format6 ->
'c
exception Scan_failure of string

当无法根据格式字符串规范读取输入时,格式化输入函数通常会引发异常 Scan_failure

通用格式化输入函数

val bscanf : Scanning.in_channel -> ('a, 'b, 'c, 'd) scanner

bscanf ic fmt r1 ... rN fScanf.Scanning.in_channel 格式化输入通道 ic 读取字符,并根据格式字符串 fmt 将它们转换为值。作为最后一步,接收函数 f 应用于读取的值,并给出 bscanf 调用的结果。

例如,如果 f 是函数 fun s i -> i + 1,那么 Scanf.sscanf "x = 1" "%s = %i" f 返回 2

参数 r1rN 是用户定义的输入函数,用于读取与格式字符串中指定的 %r 转换相对应的参数。

val bscanf_opt : Scanning.in_channel -> ('a, 'b, 'c, 'd) scanner_opt

Scanf.bscanf 相同,但在扫描失败的情况下返回 None

格式字符串描述

格式字符串是一个字符字符串,其中包含三种类型的对象

格式字符串中的空格字符

如上所述,格式字符串中的普通字符只是与输入中的下一个字符匹配;但是,有两个字符是该规则的特殊例外:空格字符 (' ' 或 ASCII 码 32) 和换行符 ('\n' 或 ASCII 码 10)。空格不匹配单个空格字符,而是匹配输入中的任何数量的“空白”。更准确地说,格式字符串中的空格匹配任何数量的制表符、空格、换行符和回车符。类似地,格式字符串中的换行符匹配单个换行符或回车符后跟换行符。

匹配任何数量的空白,格式字符串中的空格也不匹配任何空白;因此,调用 bscanf ib
    "Price = %d $" (fun p -> p)
成功并返回 1,当读取具有各种空白的输入时,例如 Price = 1 $Price  =  1    $,甚至 Price=1$

格式字符串中的转换说明

转换说明由 % 字符、可选的标志、可选的字段宽度以及一个或两个转换字符组成。

转换字符及其含义为

在引入转换的 % 字符之后,可能会有特殊标志 _:后面的转换照常进行,但结果值会被丢弃。例如,如果 f 是函数 fun i -> i + 1,而 s 是字符串 "x = 1",则 Scanf.sscanf s "%_s = %i" f 返回 2

字段宽度由一个可选的整数文字组成,该文字表示要读取的标记的最大宽度。例如,%6d 读取一个整数,最多有 6 位十进制数字;%4f 读取一个最多有 4 个字符的浮点数;而 %8[\000-\255] 返回接下来的 8 个字符(如果输入中可用字符少于 8 个,则返回所有可用字符)。

注释

格式字符串中的扫描指示

扫描指示出现在字符串转换 %s%[ range ] 之后,用于分隔标记的结束。扫描指示由一个 @ 字符开头,后面跟着一些普通字符 c。这意味着字符串标记应该在下一个匹配的 c(该字符被跳过)之前结束。如果没有遇到 c 字符,则字符串标记会尽可能地扩展。例如,"%s@\t" 读取到下一个制表符或输入结束之前的字符串。如果在格式字符串中的其他任何地方出现 @ 字符,则将其视为普通字符。

注释

扫描过程中的异常

当输入无法根据格式字符串进行读取时,扫描器可能会引发以下异常

注释

专门的格式化输入函数

val sscanf : string -> ('a, 'b, 'c, 'd) scanner

Scanf.bscanf 相同,但从给定字符串中读取。

val sscanf_opt : string -> ('a, 'b, 'c, 'd) scanner_opt

Scanf.sscanf 相同,但如果扫描失败,则返回 None

val scanf : ('a, 'b, 'c, 'd) scanner

Scanf.bscanf 相同,但从预定义的格式化输入通道 Scanf.Scanning.stdin 读取,该通道连接到 stdin

val scanf_opt : ('a, 'b, 'c, 'd) scanner_opt

Scanf.scanf 相同,但在扫描失败的情况下返回 None

val kscanf : Scanning.in_channel ->
(Scanning.in_channel -> exn -> 'd) -> ('a, 'b, 'c, 'd) scanner

Scanf.bscanf 相同,但接受一个额外的函数参数 ef,在发生错误时调用:如果扫描过程或某些转换失败,扫描函数将中止并调用错误处理函数 ef,并将格式化输入通道和中止扫描过程的异常作为参数传递。

val ksscanf : string ->
(Scanning.in_channel -> exn -> 'd) -> ('a, 'b, 'c, 'd) scanner

Scanf.kscanf 相同,但从给定的字符串读取。

从输入中读取格式字符串

val bscanf_format : Scanning.in_channel ->
('a, 'b, 'c, 'd, 'e, 'f) format6 ->
(('a, 'b, 'c, 'd, 'e, 'f) format6 -> 'g) -> 'g

bscanf_format ic fmt f 从格式化输入通道 ic 读取一个格式字符串标记,根据给定的格式字符串 fmt,并将 f 应用于生成的格式字符串值。

val sscanf_format : string ->
('a, 'b, 'c, 'd, 'e, 'f) format6 ->
(('a, 'b, 'c, 'd, 'e, 'f) format6 -> 'g) -> 'g

Scanf.bscanf_format 相同,但从给定的字符串读取。

val format_from_string : string ->
('a, 'b, 'c, 'd, 'e, 'f) format6 ->
('a, 'b, 'c, 'd, 'e, 'f) format6

format_from_string s fmt 将字符串参数转换为格式字符串,根据给定的格式字符串 fmt

val unescaped : string -> string

unescaped s 返回一个 s 的副本,其中转义序列(根据 OCaml 的词法约定)被替换为相应的特殊字符。更准确地说,Scanf.unescaped 具有以下属性:对于所有字符串 sScanf.unescaped (String.escaped s) = s

始终返回参数的副本,即使参数中没有转义序列。