模組 Stdlib.Scanf

module Scanf: Scanf

簡介

使用格式字串的功能輸入

模組 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 格式字串還具有有用的附加功能,可以輕鬆定義複雜的 token;正如函數式程式語言中所預期的那樣,格式化輸入函式也支援多型,特別是與多型使用者定義的掃描器之間的任意互動。此外,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 f 會將 f 套用至 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 f 會從 Scanf.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、空格、換行和歸位字元。同樣地,格式字串中的換行字元會比對單一換行字元,或歸位字元後接一個換行字元。

比對任何數量的空白時,格式字串中的空格也會比對完全沒有空白;因此,當讀取輸入中具有各種空白時,呼叫 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%[ 範圍 ] 之後,以分隔標記的結尾。掃描指示由 @ 字元引入,後跟某些純字元 c。這表示字串標記應在下一個符合的 c 之前結束 (且會跳過該 c)。如果未遇到 c 字元,則字串標記會盡可能擴展。例如,"%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

即使參數中沒有跳脫序列,也總是回傳參數的副本。