模組 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
會在 scanScanf.Scanning.in_channel 格式化輸入通道 ic 中讀取這些引數時,將 f 套用到格式字串 fmt 指定的所有引數。

例如,下面的 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)。空格不匹配單個空格字元,而是匹配輸入中的任意數量的「空白」。更準確地說,格式字串中的空格匹配任意數量的 Tab、空格、換行符和歸位字元。同樣地,格式字串中的換行符字元匹配單個換行符或後接換行符的歸位。

匹配任何數量的空白,格式字串中的空格也完全不匹配任何數量的空白;因此,當讀取包含各種空白的輸入時,例如 Price = 1 $Price  =  1    $,甚至 Price=1$,呼叫 bscanf ib
    "Price = %d $" (fun p -> p)
會成功並返回 1

格式字串中的轉換規範

轉換規範由 % 字元、後跟一個可選的標誌、一個可選的欄位寬度,以及一個或兩個轉換字元組成。

轉換字元及其含義如下:

在引入轉換的 % 字元之後,可能會出現特殊旗標 _:後續的轉換會照常發生,但產生的值會被捨棄。例如,如果 f 是函式 fun i -> i + 1,而 s 是字串 "x = 1",則 Scanf.sscanf s "%_s = %i" f 會傳回 2

欄位寬度由一個可選的整數字面值組成,表示要讀取的 Token 的最大寬度。例如,%6d 會讀取一個最多有 6 個十進位數字的整數;%4f 會讀取一個最多有 4 個字元的浮點數;而 %8[\000-\255] 會傳回接下來的 8 個字元(或如果輸入中少於 8 個字元,則會傳回所有仍可用的字元)。

附註

格式字串中的掃描指示

掃描指示出現在字串轉換 %s%[ range ] 之後,以分隔 Token 的結尾。掃描指示由 @ 字元引入,後接一些純字元 c。這表示字串 Token 應該在下一個符合的 c 之前結束(該字元會被跳過)。如果未遇到任何 c 字元,則字串 Token 會盡可能擴展。例如,"%s@\t" 會讀取一個字串,直到下一個 Tab 字元或輸入結尾。如果 @ 字元出現在格式字串中的其他任何位置,則會將其視為純字元。

附註

掃描期間的例外

當無法根據格式字串讀取輸入時,掃描器可能會引發下列例外狀況

附註

特殊的格式化輸入函式

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 根據給定的格式字串 fmt 從格式化輸入通道 ic 讀取格式字串 token,並將 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

總是返回參數的副本,即使參數中沒有逸出序列。