module Format: Format
您可以將此模組視為提供 printf
功能的擴展,以提供自動換行。在您常規的 printf
格式字串中加入美觀列印註解,可以讓您獲得精美的縮排和換行。美觀列印註解在函式 Format.fprintf
的說明文件中介紹如下。
您也可以使用此模組提供的顯式美觀列印框管理和列印函式。這種風格比簡潔的 fprintf
格式字串更基本,但更冗長。
例如,序列 open_box 0; print_string "x ="; print_space ();
在美觀列印框中列印
print_int 1; close_box (); print_newline ()x = 1
,可以簡寫為 printf "@[%s@ %i@]@." "x =" 1
,甚至更短的 printf "@[x =@ %i@]@." 1
。
此函式庫一般使用者的經驗法則
open_box 0
獲得的);print_cut ()
輸出的簡單換行提示,或 print_space ()
輸出的空格表示換行提示;print_int
和 print_string
)顯示其內容;close_box ()
以關閉該框;print_newline ()
。如果沒有開啟美觀列印框,則美觀列印命令的行為未指定。下面 open_
函式開啟的每個框都必須使用 close_box
關閉,才能正確格式化。否則,框中列印的某些內容可能不會輸出,或格式不正確。
在互動式使用的情況下,每個語句都在標準美觀列印器的初始狀態中執行:在每個語句執行後,互動式系統會關閉所有開啟的美觀列印框、刷新所有待處理文字,並重置標準美觀列印器。
警告:將此模組的美觀列印函式呼叫與 Stdlib
低階輸出函式呼叫混合使用是容易出錯的。
美觀列印函式輸出的是在美觀列印器佇列中延遲並堆疊的內容,以便計算正確的換行。相反,基本 I/O 輸出函式直接寫入其輸出裝置。因此,基本 I/O 函式的輸出可能會在之前呼叫的美觀列印函式的輸出之前顯示。例如,
會導致輸出
Stdlib.print_string "<";
Format.print_string "PRETTY";
Stdlib.print_string ">";
Format.print_string "TEXT";
<>PRETTYTEXT
。
type
formatter
與美觀列印器(也稱為格式化器)及其所有機制相對應的抽象資料。另請參閱 定義格式化器。
美觀列印引擎使用美觀列印框和換行提示的概念來驅動美觀列印器的縮排和換行行為。
每種不同的美觀列印框種類都會引入特定的換行策略
請注意,換行策略是框特定的:框的策略不會支配內部框的策略。例如,如果垂直框巢狀在水平框中,則垂直框內的所有換行提示都會換行。
此外,在 最大縮排限制 之後開啟框會換行,無論該框最終是否適合該行。
val pp_open_box : formatter -> int -> unit
val open_box : int -> unit
pp_open_box ppf d
在格式化器 ppf
中開啟一個新的帶有偏移量 d
的壓縮美觀列印框。
在此框內,美觀列印器會在每一行上盡可能多地列印內容。
如果該行沒有更多空間來列印框的其餘部分,則換行提示會換行。
在此框內,美觀列印器會強調框結構:如果結構框不完全適合單行,則如果換行「向左移動」(即新行的縮排小於目前行的縮排),則換行提示也會換行。
此框是通用的美觀列印框。
如果美觀列印器在框中換行,則偏移量 d
會加到目前的縮排中。
val pp_close_box : formatter -> unit -> unit
val close_box : unit -> unit
關閉最近開啟的美觀列印框。
val pp_open_hbox : formatter -> unit -> unit
val open_hbox : unit -> unit
pp_open_hbox ppf ()
開啟一個新的「水平」美觀列印框。
此框在一行上列印內容。
水平框中的換行提示永遠不會換行。(換行仍可能發生在更深層次巢狀的框內)。
val pp_open_vbox : formatter -> int -> unit
val open_vbox : int -> unit
pp_open_vbox ppf d
開啟一個新的帶有偏移量 d
的「垂直」美觀列印框。
此框會在框中盡可能多的行上列印內容。
垂直框中的每個換行提示都會換行。
如果美觀列印器在框中換行,則 d
會加到目前的縮排中。
val pp_open_hvbox : formatter -> int -> unit
val open_hvbox : int -> unit
pp_open_hvbox ppf d
開啟一個新的帶有偏移量 d
的「水平/垂直」美觀列印框。
如果此框適合單行,則其行為與水平框相同,否則其行為與垂直框相同。
如果美觀列印器在框中換行,則 d
會加到目前的縮排中。
val pp_open_hovbox : formatter -> int -> unit
val open_hovbox : int -> unit
pp_open_hovbox ppf d
開啟一個新的帶有偏移量 d
的「水平或垂直」美觀列印框。
此框盡可能在每一行上列印內容。
如果該行沒有更多空間來列印框的其餘部分,則換行提示會換行。
如果美觀列印器在框中換行,則 d
會加到目前的縮排中。
val pp_print_string : formatter -> string -> unit
val print_string : string -> unit
pp_print_string ppf s
在目前的美觀列印框中列印 s
。
val pp_print_bytes : formatter -> bytes -> unit
val print_bytes : bytes -> unit
pp_print_bytes ppf b
在目前的美觀列印框中列印 b
。
val pp_print_as : formatter -> int -> string -> unit
val print_as : int -> string -> unit
pp_print_as ppf len s
在目前的美觀列印框中列印 s
。美觀列印器會將 s
的格式設定為其長度為 len
。
val pp_print_int : formatter -> int -> unit
val print_int : int -> unit
在目前的美觀列印框中列印一個整數。
val pp_print_float : formatter -> float -> unit
val print_float : float -> unit
在目前的美觀列印框中列印一個浮點數。
val pp_print_char : formatter -> char -> unit
val print_char : char -> unit
在目前的美觀列印框中列印一個字元。
val pp_print_bool : formatter -> bool -> unit
val print_bool : bool -> unit
在目前的美觀列印框中列印一個布林值。
val pp_print_nothing : formatter -> unit -> unit
不列印任何內容。
「換行提示」會告知美觀列印器輸出一些空格或換行,無論哪種方式更適合目前的美觀列印框換行規則。
換行提示用於分隔列印項目,並且對於讓美觀列印器正確換行和縮排項目是強制性的。
簡單的換行提示是
注意:對於美觀列印引擎而言,空格和換行的概念是抽象的,因為程式設計師可以完全重新定義這些概念。但是,在美觀列印器的預設設定中,「輸出空格」僅表示列印空格字元 (ASCII 碼 32),而「換行」表示列印換行字元 (ASCII 碼 10)。
val pp_print_space : formatter -> unit -> unit
val print_space : unit -> unit
pp_print_space ppf ()
發出一個「空格」換行提示:美觀列印器可以在此點換行,否則會列印一個空格。
pp_print_space ppf ()
等效於 pp_print_break ppf 1 0
。
val pp_print_cut : formatter -> unit -> unit
val print_cut : unit -> unit
pp_print_cut ppf ()
發出一個「剪切」換行提示:美觀列印器可以在此點換行,否則不列印任何內容。
pp_print_cut ppf ()
等效於 pp_print_break ppf 0 0
。
val pp_print_break : formatter -> int -> int -> unit
val print_break : int -> int -> unit
pp_print_break ppf nspaces offset
發出一個「完整」換行提示:美觀列印器可以在此點換行,否則會列印 nspaces
個空格。
如果美觀列印器換行,則 offset
會加到目前的縮排中。
val pp_print_custom_break : formatter ->
fits:string * int * string -> breaks:string * int * string -> unit
pp_print_custom_break ppf ~fits:(s1, n, s2) ~breaks:(s3, m, s4)
發出一個自訂換行提示:美觀列印器可以在此點換行。
如果不換行,則會發出 s1
,然後是 n
個空格,然後是 s2
。
如果換行,則會發出 s3
字串,然後是縮排(根據框規則),然後是 m
個空格的偏移量,然後是 s4
字串。
雖然 n
和 m
由 formatter_out_functions.out_indent
處理,字串將由 formatter_out_functions.out_string
處理。這允許自訂格式化器以不同方式處理縮排,例如,輸出 <br/>
標籤或
實體。
如果您想在換行或不換行時變更列印的(非空白)可見字元,則自訂換行符號很有用。例如,在列印列表 [a; b; c]
時,您可能希望在垂直列印時新增尾隨分號
[
a;
b;
c;
]
您可以按如下方式操作
printf "@[<v 0>[@;<0 2>@[<v 0>a;@,b;@,c@]%t]@]@\n"
(pp_print_custom_break ~fits:("", 0, "") ~breaks:(";", 0, ""))
val pp_force_newline : formatter -> unit -> unit
val force_newline : unit -> unit
在目前的精美列印框中強制換行。
精美列印器必須在此處分割行,
這不是精美列印的常規方式,因為命令式行分割可能會干擾目前的行計數器和方塊大小計算。在封閉的垂直方塊中使用換行提示是更好的選擇。
val pp_print_if_newline : formatter -> unit -> unit
val print_if_newline : unit -> unit
如果前一行剛被分割,則執行下一個格式化命令。否則,忽略下一個格式化命令。
val pp_print_flush : formatter -> unit -> unit
val print_flush : unit -> unit
精美列印結束:將精美列印器重置為初始狀態。
所有開啟的精美列印框都會關閉,所有待處理的文字都會列印出來。此外,精美列印器的底層輸出裝置會被清除,以確保所有待處理的文字都確實顯示。
注意:在精美列印常式的一般過程中,永遠不要使用 print_flush
,因為精美列印器使用複雜的緩衝機制來正確縮排輸出;隨機手動清除這些緩衝區會與精美列印器的策略衝突,並導致呈現效果不佳。
只有在顯示所有待處理的資料是強制性的(例如在您希望使用者閱讀某些文字的互動式使用情況下),並且重設精美列印器狀態不會干擾進一步的精美列印時,才考慮使用 print_flush
。
警告:如果精美列印器的輸出裝置是輸出通道,則重複呼叫 print_flush
表示重複呼叫 flush
以清除輸出通道;這些明確的清除呼叫可能會破壞輸出通道的緩衝策略,並可能嚴重影響效率。
val pp_print_newline : formatter -> unit -> unit
val print_newline : unit -> unit
精美列印結束:將精美列印器重置為初始狀態。
所有開啟的精美列印框都會關閉,所有待處理的文字都會列印出來。
等同於 Format.print_flush
,在清除裝置之前,在精美列印器的底層輸出裝置上發出新的一行。請參閱 Format.print_flush
的相關警告詞。
注意:這不是輸出新行的常規方式;首選方法是在垂直精美列印框內使用換行提示。
val pp_infinity : int
pp_infinity
是邊界的最大大小。它的確切值取決於實作,但保證大於 109。
val pp_set_margin : formatter -> int -> unit
val set_margin : int -> unit
pp_set_margin ppf d
將右邊界設定為 d
(以字元為單位):精美列印器會根據給定的換行提示分割超出右邊界的行。將邊界設定為 d
表示格式化引擎旨在每行最多列印 d-1
個字元。如果 d
小於 2,則不會發生任何事情。如果 d >=
Format.pp_infinity
,則右邊界會設定為 Format.pp_infinity
- 1
。如果 d
小於目前的最大縮排限制,則會降低最大縮排限制,同時嘗試保持最小比例 max_indent/margin>=50%
,如果可能,則保持目前的差值 margin - max_indent
。
另請參閱 Format.pp_set_geometry
。
val pp_get_margin : formatter -> unit -> int
val get_margin : unit -> int
傳回右邊界的位置。
val pp_set_max_indent : formatter -> int -> unit
val set_max_indent : int -> unit
pp_set_max_indent ppf d
將行的最大縮排限制設定為 d
(以字元為單位):一旦達到此限制,新的精美列印框將會被拒絕到左邊,除非封閉的方塊完全適合目前的行。舉例來說,
set_margin 10; set_max_indent 5; printf "@[123456@[7@]89A@]@."
產生
123456
789A
因為巢狀方塊 "@[7@]"
在最大縮排限制 (7>5
) 之後開啟,且其父方塊不適合目前的行。無論是縮短父方塊的長度以使其適合一行
printf "@[123456@[7@]89@]@."
還是開啟一個介於最大縮排限制之前且適合目前行的中間方塊
printf "@[123@[456@[7@]89@]A@]@."
都可以避免將內部方塊拒絕到左邊,並分別列印 "123456789"
和 "123456789A"
。另請注意,垂直方塊永遠不適合一行,而水平方塊永遠完全適合目前的行。開啟方塊可能會分割一行,而內容可能適合。如果此行為有問題,可以透過將最大縮排限制設定為 margin - 1
來縮減此行為。請注意,將最大縮排限制設定為 margin
是無效的。
如果 d
小於 2,則不會發生任何事情。
如果 d
大於目前的邊界,則會忽略它,並保留目前的最大縮排限制。
另請參閱 Format.pp_set_geometry
。
val pp_get_max_indent : formatter -> unit -> int
val get_max_indent : unit -> int
傳回最大縮排限制(以字元為單位)。
幾何函式可用於同時操作耦合變數、邊界和最大縮排限制。
type
geometry = {
|
max_indent : |
|
margin : |
}
val check_geometry : geometry -> bool
檢查格式化器幾何是否有效:1 < max_indent < margin <
Format.pp_infinity
val pp_set_geometry : formatter -> max_indent:int -> margin:int -> unit
val set_geometry : max_indent:int -> margin:int -> unit
val pp_safe_set_geometry : formatter -> max_indent:int -> margin:int -> unit
val safe_set_geometry : max_indent:int -> margin:int -> unit
pp_set_geometry ppf ~max_indent ~margin
設定 ppf
的邊界和最大縮排限制。
當 1 < max_indent < margin <
Format.pp_infinity
時,pp_set_geometry ppf ~max_indent ~margin
等同於 pp_set_margin ppf margin; pp_set_max_indent ppf max_indent
;並避免了細微不正確的 pp_set_max_indent ppf max_indent; pp_set_margin ppf margin
;
在此網域之外,pp_set_geometry
會引發無效的引數例外狀況,而 pp_safe_set_geometry
不會執行任何動作。
val pp_update_geometry : formatter -> (geometry -> geometry) -> unit
pp_update_geometry ppf (fun geo -> { geo with ... })
讓您以一種能夠穩健處理以新欄位擴充的 geometry
記錄的方式來更新格式化器的幾何。
如果傳回的幾何不滿足 Format.check_geometry
,則會引發無效的引數例外狀況。
val update_geometry : (geometry -> geometry) -> unit
val pp_get_geometry : formatter -> unit -> geometry
val get_geometry : unit -> geometry
傳回格式化器的目前幾何
最大格式化深度是同時開啟的精美列印框的最大數目。
巢狀深度較深的方塊內的資料會列印為省略符號(更準確地說,會列印為 Format.get_ellipsis_text
()
傳回的文字)。
val pp_set_max_boxes : formatter -> int -> unit
val set_max_boxes : int -> unit
pp_set_max_boxes ppf max
設定同時開啟的精美列印框的最大數目。
巢狀深度較深的方塊內的資料會列印為省略符號(更準確地說,會列印為 Format.get_ellipsis_text
()
傳回的文字)。
如果 max
小於 2,則不會發生任何事情。
val pp_get_max_boxes : formatter -> unit -> int
val get_max_boxes : unit -> int
傳回允許在省略符號之前使用的最大精美列印框數目。
val pp_over_max_boxes : formatter -> unit -> bool
val over_max_boxes : unit -> bool
測試是否已開啟允許的最大精美列印框數目。
製表框會在分割成固定長度儲存格的行上列印資料。製表框提供一種簡單的方式來顯示左對齊文字的垂直欄。
此方塊具有命令 set_tab
來定義儲存格邊界,以及命令 print_tab
來在儲存格之間移動,並在行上沒有更多要列印的儲存格時分割該行。
注意:在製表框內列印是以行導向的,因此在製表框內任意分割行會導致呈現效果不佳。然而,在 Format
模組內控制使用製表框允許簡單地列印欄。
val pp_open_tbox : formatter -> unit -> unit
val open_tbox : unit -> unit
open_tbox ()
開啟新的製表框。
此方塊會列印分隔成固定寬度儲存格的行。
在製表框內,特殊的製表標記會在行上定義關注點(例如,劃分儲存格邊界)。函式 Format.set_tab
會在插入點設定製表標記。
製表框具有特定的製表換行符號,以移至下一個製表標記或分割行。函式 Format.print_tbreak
會列印製表換行符號。
val pp_close_tbox : formatter -> unit -> unit
val close_tbox : unit -> unit
關閉最近開啟的製表框。
val pp_set_tab : formatter -> unit -> unit
val set_tab : unit -> unit
在目前的插入點設定製表標記。
val pp_print_tab : formatter -> unit -> unit
val print_tab : unit -> unit
print_tab ()
會發出「下一個」製表換行提示:如果尚未設定在製表標記上,插入點會移至右邊的第一個製表標記,或者精美列印器會分割行,且插入點會移至最左邊的製表標記。
它等同於 print_tbreak 0 0
。
val pp_print_tbreak : formatter -> int -> int -> unit
val print_tbreak : int -> int -> unit
print_tbreak nspaces offset
會發出「完整」製表換行提示。
如果尚未設定在製表標記上,插入點會移至右邊的第一個製表標記,且精美列印器會列印 nspaces
個空格。
如果右邊沒有下一個製表標記,則精美列印器會在此處分割行,然後插入點會移至方塊最左邊的製表標記。
如果美觀列印器換行,則 offset
會加到目前的縮排中。
val pp_set_ellipsis_text : formatter -> string -> unit
val set_ellipsis_text : string -> unit
設定開啟過多精美列印框時列印的省略符號文字(預設為單個點,.
)。
val pp_get_ellipsis_text : formatter -> unit -> string
val get_ellipsis_text : unit -> string
傳回省略符號的文字。
type
stag = ..
語意標籤(或簡稱為標籤)是使用者定義的註解,用於將使用者的特定操作與列印的實體關聯。
語意標籤的常見用法是文字裝飾,以便為顯示裝置取得特定的字體或文字大小渲染,或標記實體的分界(例如 HTML 或 TeX 元素或終端跳脫序列)。更精細的語意標籤用法可以處理美化列印器行為的動態修改,以便正確列印某些特定標籤內的內容。例如,我們可以定義一個 RGB 標籤如下:
type stag += RGB of {r:int;g:int;b:int}
為了正確劃分列印的實體,語意標籤必須在實體之前開啟,並在實體之後關閉。語意標籤必須像括號一樣正確巢狀,使用 Format.pp_open_stag
和 Format.pp_close_stag
。
當標籤開啟或關閉時,會發生標籤特定的操作。在每次發生時,會執行兩種操作:標籤標記和標籤列印。
粗略地說,標籤標記通常用於在渲染裝置中獲得更好的文字渲染,而標籤列印則允許微調列印例程,以便根據語意標籤以不同方式列印相同的實體(即列印額外的內容,甚至省略部分輸出)。
更精確地說:當語意標籤開啟或關閉時,會依序發生「標籤列印」和「標籤標記」操作。
print_open_stag
(或 print_close_stag
):該標籤列印函數隨後可以將任何常規內容列印到格式器(因此,此內容會像往常一樣在格式器佇列中排隊,以進行進一步的換行計算)。mark_open_stag
(或 mark_close_stag
):該標籤標記函數隨後可以傳回「標籤開啟標記」(或「標籤關閉標記」),以便直接輸出到格式器的輸出裝置。由於直接寫入格式器的輸出裝置,語意標籤標記字串不會被視為驅動換行的列印內容的一部分(換句話說,與標籤標記對應的字串長度在換行時會被視為零)。
因此,語意標籤處理在某種意義上對列印美化是透明的,並且不會干擾通常的縮排。因此,單個列印美化例程可以輸出簡單的「逐字」內容,或更豐富的裝飾輸出,具體取決於標籤的處理方式。預設情況下,標籤不會啟用,因此輸出不會使用標籤資訊裝飾。一旦將 set_tags
設定為 true
,列印美化引擎就會遵守標籤,並相應地裝飾輸出。
預設的標籤標記函數的行為方式與 HTML 相同:字串標籤會用 "<" 和 ">" 包圍,而其他標籤則會被忽略;因此,標籤字串 "t"
的開啟標記是 "<t>"
,而關閉標記是 "</t>"
。
預設的標籤列印函數不執行任何動作。
標籤標記和標籤列印函數是使用者可定義的,並且可以透過呼叫 Format.set_formatter_stag_functions
來設定。
可以使用 Format.set_tags
開啟或關閉語意標籤操作。可以使用 Format.set_mark_tags
開啟或關閉標籤標記操作。可以使用 Format.set_print_tags
開啟或關閉標籤列印操作。
typetag =
string
type
Format.stag +=
| |
String_tag of |
(* |
| *) |
val pp_open_stag : formatter -> stag -> unit
val open_stag : stag -> unit
pp_open_stag ppf t
開啟名為 t
的語意標籤。
格式器的 print_open_stag
標籤列印函數會使用 t
作為引數呼叫;然後,會將 t
的開啟標籤標記(由 mark_open_stag t
提供)寫入格式器的輸出裝置。
val pp_close_stag : formatter -> unit -> unit
val close_stag : unit -> unit
pp_close_stag ppf ()
關閉最近開啟的語意標籤 t
。
會將關閉標籤標記(由 mark_close_stag t
提供)寫入格式器的輸出裝置;然後,會使用 t
作為引數呼叫格式器的 print_close_stag
標籤列印函數。
formatter -> bool -> unit
: bool -> unit
: pp_set_tags ppf b
開啟或關閉語意標籤的處理(預設為關閉)。
formatter -> bool -> unit
: bool -> unit
: pp_set_print_tags ppf b
開啟或關閉標籤列印操作。
formatter -> bool -> unit
: bool -> unit
: pp_set_mark_tags ppf b
開啟或關閉標籤標記操作。
formatter -> unit -> bool
: unit -> bool
: 傳回標籤列印操作的目前狀態。
formatter -> unit -> bool
: unit -> bool
: 傳回標籤標記操作的目前狀態。
val pp_set_formatter_out_channel : formatter -> out_channel -> unit
val set_formatter_out_channel : out_channel -> unit
將標準美化列印器的輸出重新導向至指定的通道。(標準格式器的所有輸出函數都設定為列印至指定通道的預設輸出函數。)
set_formatter_out_channel
等同於 Format.pp_set_formatter_out_channel
std_formatter
。
val pp_set_formatter_output_functions : formatter -> (string -> int -> int -> unit) -> (unit -> unit) -> unit
val set_formatter_output_functions : (string -> int -> int -> unit) -> (unit -> unit) -> unit
pp_set_formatter_output_functions ppf out flush
將標準美化列印器的輸出函數重新導向至函數 out
和 flush
。
out
函數執行所有美化列印器字串輸出。它會使用字串 s
、起始位置 p
和字元數 n
呼叫;它應該輸出 s
的字元 p
到 p + n - 1
。
flush
函數會在美化列印器排清時呼叫(透過轉換 %!
、或美化列印指示 @?
或 @.
,或使用低階函數 print_flush
或 print_newline
)。
val pp_get_formatter_output_functions : formatter -> unit -> (string -> int -> int -> unit) * (unit -> unit)
val get_formatter_output_functions : unit -> (string -> int -> int -> unit) * (unit -> unit)
傳回標準美化列印器的目前輸出函數。
Format
模組功能非常全面,可讓您完全重新定義美化列印輸出的含義:您可以提供自己的函數來定義如何處理縮排、換行,甚至列印所有必須列印的字元!
type
formatter_out_functions = {
|
out_string : |
|||
|
out_flush : |
|||
|
out_newline : |
|||
|
out_spaces : |
|||
|
out_indent : |
(* |
| *) |
}
特定於格式器的輸出函數集
out_string
函數執行所有美化列印器字串輸出。它會使用字串 s
、起始位置 p
和字元數 n
呼叫;它應該輸出 s
的字元 p
到 p + n - 1
。out_flush
函數會排清美化列印器的輸出裝置。out_newline
來開啟新的一行。out_spaces
函數會輸出空格。它會使用要輸出的空格數呼叫。out_indent
函數會執行新行縮排。它會使用新行的縮排值呼叫。預設情況下
out_string
和 out_flush
是特定於輸出裝置的;(例如,output_string
和 flush
用於 out_channel
裝置,或 Buffer.add_substring
和 ignore
用於 Buffer.t
輸出裝置),out_newline
等同於 out_string "\n" 0 1
;out_spaces
和 out_indent
等同於 out_string (String.make n ' ') 0 n
。val pp_set_formatter_out_functions : formatter -> formatter_out_functions -> unit
val set_formatter_out_functions : formatter_out_functions -> unit
pp_set_formatter_out_functions ppf out_funs
將 ppf
的所有美化列印器輸出函數設定為引數 out_funs
的函數,
透過這種方式,您可以變更縮排的含義(縮排可以是除了只列印空格字元以外的其他內容)和開啟新行的含義(可以連接到應用程式本身所需的任何其他動作)。
函數 out_spaces
和 out_newline
的合理預設值分別為 out_funs.out_string (String.make n ' ') 0 n
和 out_funs.out_string "\n" 0 1
。
val pp_get_formatter_out_functions : formatter -> unit -> formatter_out_functions
val get_formatter_out_functions : unit -> formatter_out_functions
傳回美化列印器的目前輸出函數,包括換行和縮排函數。適用於記錄目前的設定,並在之後還原它。
type
formatter_stag_functions = {
|
mark_open_stag : |
|
mark_close_stag : |
|
print_open_stag : |
|
print_close_stag : |
}
特定於格式器的語意標籤處理函數:mark
版本是「標籤標記」函數,將字串標記與標籤關聯,以便美化列印引擎將這些標記作為 0 長度的符號寫入格式器的輸出裝置。print
版本是「標籤列印」函數,可以在標籤關閉或開啟時執行常規列印。
val pp_set_formatter_stag_functions : formatter -> formatter_stag_functions -> unit
val set_formatter_stag_functions : formatter_stag_functions -> unit
pp_set_formatter_stag_functions ppf tag_funs
更改開啟和關閉語義標籤操作的含義,以便在 ppf
上列印時使用 tag_funs
中的函式。
當使用名稱 t
開啟語義標籤時,字串 t
會傳遞給開啟標籤標記函式(記錄 tag_funs
的 mark_open_stag
欄位),該函式必須傳回該名稱的開啟標籤標記。當下一次呼叫 close_stag ()
時,語義標籤名稱 t
會傳回給關閉標籤標記函式(記錄 tag_funs
的 mark_close_stag
欄位),該函式必須傳回該名稱的關閉標籤標記。
記錄的 print_
欄位包含在標籤開啟和關閉時呼叫的標籤列印函式,以在美觀列印佇列中輸出常規內容。
val pp_get_formatter_stag_functions : formatter -> unit -> formatter_stag_functions
val get_formatter_stag_functions : unit -> formatter_stag_functions
傳回標準美觀列印器的目前語義標籤操作函式。
定義新的格式化器允許在多個輸出裝置上平行輸出無關的內容。格式化器的所有參數都是格式化器本機的:右邊界、最大縮排限制、同時開啟的最大美觀列印方塊數量、省略符號等等,每個格式化器都是特定的,並且可以獨立設定。
例如,給定一個 Buffer.t
緩衝區 b
,Format.formatter_of_buffer
b
會傳回一個新的格式化器,使用緩衝區 b
作為其輸出裝置。同樣地,給定一個 out_channel
輸出通道 oc
,Format.formatter_of_out_channel
oc
會傳回一個新的格式化器,使用通道 oc
作為其輸出裝置。
或者,給定 out_funs
,一組完整的格式化器輸出函式,則 Format.formatter_of_out_functions
out_funs
會計算一個新的格式化器,使用這些函式進行輸出。
val formatter_of_out_channel : out_channel -> formatter
formatter_of_out_channel oc
會傳回一個新的格式化器,寫入對應的輸出通道 oc
。
val synchronized_formatter_of_out_channel : out_channel -> formatter Domain.DLS.key
synchronized_formatter_of_out_channel oc
會傳回網域本機狀態的索引鍵,該狀態保存用於寫入對應輸出通道 oc
的網域本機格式化器。
當格式化器與多個網域一起使用時,來自網域的輸出將在格式化器被清除的位置(例如使用 Format.print_flush
時)彼此交錯。
val std_formatter : formatter
初始網域的標準格式化器,用於寫入標準輸出。
val get_std_formatter : unit -> formatter
get_std_formatter ()
會傳回目前網域用於寫入標準輸出的標準格式化器。
val err_formatter : formatter
初始網域的格式化器,用於寫入標準錯誤。
val get_err_formatter : unit -> formatter
get_err_formatter ()
會傳回目前網域用於寫入標準錯誤的格式化器。
val formatter_of_buffer : Buffer.t -> formatter
formatter_of_buffer b
會傳回一個新的格式化器,寫入緩衝區 b
。在美觀列印結束時,必須使用 Format.pp_print_flush
或 Format.pp_print_newline
清除格式化器,以便將所有待處理的內容列印到緩衝區中。
val stdbuf : Buffer.t
初始網域的字串緩衝區,str_formatter
在其中寫入。
val get_stdbuf : unit -> Buffer.t
get_stdbuf ()
會傳回目前網域的字串緩衝區,目前網域的字串格式化器在其中寫入。
val str_formatter : formatter
初始網域的格式化器,用於輸出到 Format.stdbuf
字串緩衝區。
str_formatter
被定義為 Format.formatter_of_buffer
Format.stdbuf
。
val get_str_formatter : unit -> formatter
目前網域的格式化器,用於輸出到目前網域的字串緩衝區。
val flush_str_formatter : unit -> string
傳回使用目前網域的 str_formatter
列印的內容,清除格式化器並重設對應的緩衝區。
val make_formatter : (string -> int -> int -> unit) -> (unit -> unit) -> formatter
make_formatter out flush
會傳回一個新的格式化器,該格式化器使用函式 out
進行輸出,並使用函式 flush
進行清除。
例如,
make_formatter
(Stdlib.output_substring oc)
(fun () -> Stdlib.flush oc)
會傳回一個 out_channel
oc
的格式化器。
val make_synchronized_formatter : (string -> int -> int -> unit) ->
(unit -> unit) -> formatter Domain.DLS.key
make_synchronized_formatter out flush
會傳回網域本機狀態的索引鍵,該狀態保存網域本機格式化器,該格式化器使用函式 out
進行輸出,並使用函式 flush
進行清除。
當格式化器與多個網域一起使用時,來自網域的輸出將在格式化器被清除的位置(例如使用 Format.print_flush
時)彼此交錯。
val formatter_of_out_functions : formatter_out_functions -> formatter
formatter_of_out_functions out_funs
會傳回一個新的格式化器,該格式化器使用輸出函式集 out_funs
進行寫入。
有關引數 out_funs
的含義,請參閱 Format.formatter_out_functions
類型的定義。
符號美觀列印是使用符號格式化器的美觀列印,也就是說,格式化器會輸出符號美觀列印項目。
當使用符號格式化器時,會發生所有常規的美觀列印活動,但輸出內容是符號的,並且儲存在輸出項目的緩衝區中。在美觀列印結束時,清除輸出緩衝區允許在執行低階輸出操作之前對符號輸出進行後處理。
實際上,首先使用以下命令定義符號輸出緩衝區 b
let sob = make_symbolic_output_buffer ()
。然後使用以下命令定義符號格式化器let ppf = formatter_of_symbolic_output_buffer sob
像往常一樣使用符號格式化器 ppf
,並在美觀列印結束時,透過使用以下命令清除符號輸出緩衝區 sob
來擷取符號項目
flush_symbolic_output_buffer sob
.type
symbolic_output_item =
| |
Output_flush |
(* | 符號清除命令 | *) |
| |
Output_newline |
(* | 符號換行命令 | *) |
| |
Output_string of |
(* |
| *) |
| |
Output_spaces of |
(* |
| *) |
| |
Output_indent of |
(* |
| *) |
符號美觀列印器產生的項目
type
symbolic_output_buffer
符號美觀列印器的輸出緩衝區。
val make_symbolic_output_buffer : unit -> symbolic_output_buffer
make_symbolic_output_buffer ()
會傳回一個新的符號輸出緩衝區。
val clear_symbolic_output_buffer : symbolic_output_buffer -> unit
clear_symbolic_output_buffer sob
會重設緩衝區 sob
。
val get_symbolic_output_buffer : symbolic_output_buffer -> symbolic_output_item list
get_symbolic_output_buffer sob
會傳回緩衝區 sob
的內容。
val flush_symbolic_output_buffer : symbolic_output_buffer -> symbolic_output_item list
flush_symbolic_output_buffer sob
會傳回緩衝區 sob
的內容,並重設緩衝區 sob
。flush_symbolic_output_buffer sob
等效於 let items = get_symbolic_output_buffer sob in
clear_symbolic_output_buffer sob; items
val add_symbolic_output_item : symbolic_output_buffer -> symbolic_output_item -> unit
add_symbolic_output_item sob itm
會將項目 itm
新增至緩衝區 sob
。
val formatter_of_symbolic_output_buffer : symbolic_output_buffer -> formatter
formatter_of_symbolic_output_buffer sob
會傳回一個符號格式化器,該格式化器會輸出到 symbolic_output_buffer
sob
。
val pp_print_iter : ?pp_sep:(formatter -> unit -> unit) ->
(('a -> unit) -> 'b -> unit) ->
(formatter -> 'a -> unit) -> formatter -> 'b -> unit
pp_print_iter ~pp_sep iter pp_v ppf v
會使用 pp_v
在 ppf
上格式化 iter
對值的集合 v
的迭代。迭代之間以 pp_sep
分隔(預設為 Format.pp_print_cut
)。
val pp_print_list : ?pp_sep:(formatter -> unit -> unit) ->
(formatter -> 'a -> unit) -> formatter -> 'a list -> unit
pp_print_list ?pp_sep pp_v ppf l
會列印清單 l
的項目,使用 pp_v
來列印每個項目,並在項目之間呼叫 pp_sep
(pp_sep
預設為 Format.pp_print_cut
)。在空清單上不會執行任何動作。
val pp_print_array : ?pp_sep:(formatter -> unit -> unit) ->
(formatter -> 'a -> unit) -> formatter -> 'a array -> unit
pp_print_array ?pp_sep pp_v ppf a
會列印陣列 a
的項目,使用 pp_v
來列印每個項目,並在項目之間呼叫 pp_sep
(pp_sep
預設為 Format.pp_print_cut
)。在空陣列上不會執行任何動作。
如果在呼叫 pp_print_array
後修改了 a
,則列印的值可能與預期的不同,因為 Format
可以延遲列印。這可以透過清除 ppf
來避免。
val pp_print_seq : ?pp_sep:(formatter -> unit -> unit) ->
(formatter -> 'a -> unit) ->
formatter -> 'a Seq.t -> unit
pp_print_seq ?pp_sep pp_v ppf s
會列印序列 s
的項目,使用 pp_v
來列印每個項目,並在項目之間呼叫 pp_sep
(pp_sep
預設為 Format.pp_print_cut
。在空序列上不會執行任何動作。
此函式不會在無限序列上終止。
val pp_print_text : formatter -> string -> unit
pp_print_text ppf s
會列印 s
,並分別使用 Format.pp_print_space
和 Format.pp_force_newline
列印空格和換行符號。
val pp_print_option : ?none:(formatter -> unit -> unit) ->
(formatter -> 'a -> unit) -> formatter -> 'a option -> unit
pp_print_option ?none pp_v ppf o
會在 ppf
上使用 pp_v
列印 o
(如果 o
是 Some v
),如果它是 None
,則列印 none
。none
預設不會列印任何內容。
val pp_print_result : ok:(formatter -> 'a -> unit) ->
error:(formatter -> 'e -> unit) ->
formatter -> ('a, 'e) result -> unit
pp_print_result ~ok ~error ppf r
會在 ppf
上使用 ok
(如果 r
是 Ok _
)和 error
(如果 r
是 Error _
)來列印 r
。
val pp_print_either : left:(formatter -> 'a -> unit) ->
right:(formatter -> 'b -> unit) ->
formatter -> ('a, 'b) Either.t -> unit
pp_print_either ~left ~right ppf e
會在 ppf
上使用 left
(如果 e
是 Either.Left _
)和 right
(如果 e
是 Either.Right _
)來列印 e
。
模組 Format
提供了一整套類似 printf
的函式,用於使用格式字串規格進行美觀列印。
可以在格式字串中新增特定的註解,以便向美觀列印引擎提供美觀列印命令。
這些註解是透過使用 @
字元在格式字串中引入的。例如,@
表示空格分行符號,@,
表示切割,@[
開啟新的方塊,而 @]
關閉最後一個開啟的方塊。
val fprintf : formatter -> ('a, formatter, unit) format -> 'a
fprintf ff fmt arg1 ... argN
會根據格式字串 fmt
格式化引數 arg1
到 argN
,並將產生的字串輸出到格式化器 ff
上。
格式字串 fmt
是一個字元字串,其中包含三種類型的物件:如 Printf
模組中所指定的純字元和轉換規格,以及 Format
模組特定的美觀列印指示。
美化列印指示字元以 @
字元引入,其含義如下:
@[
:開啟一個美化列印框。可以使用以下語法選擇性地指定框的類型和偏移量: <
字元,後跟一個可選的框類型指示,然後是一個可選的整數偏移量,以及結束的 >
字元。美化列印框類型為 h
、v
、hv
、b
或 hov
中的其中一個。 'h
' 代表「水平」美化列印框,'v
' 代表「垂直」美化列印框,'hv
' 代表「水平/垂直」美化列印框,'b
' 代表展示縮排的「水平或垂直」美化列印框,'hov
' 代表簡單的「水平或垂直」美化列印框。例如, @[<hov 2>
開啟一個縮排為 2 的「水平或垂直」美化列印框,如同使用 open_hovbox 2
所獲得的結果。有關美化列印框的更多詳細資訊,請參閱各種框開啟函式 open_*box
。@]
:關閉最近開啟的美化列印框。@,
:輸出「剪切」換行提示,如同 print_cut ()
。@
:輸出「空格」換行提示,如同 print_space ()
。@;
:輸出「完整」換行提示,如同 print_break
。換行提示的 nspaces
和 offset
參數可以使用以下語法選擇性地指定: <
字元,後跟一個整數 nspaces
值,然後是一個整數 offset
,以及結束的 >
字元。如果未提供任何參數,則完整換行會預設為「空格」換行提示。@.
:刷新美化列印器並分割行,如同 print_newline ()
。@<n>
:將以下項目列印為長度為 n
。因此, printf "@<0>%s" arg
會將 arg
列印為零長度字串。如果 @<n>
後面沒有跟著轉換規範,則格式的下一個字元會列印為長度 n
。@{
:開啟一個語義標籤。可以使用以下語法選擇性地指定標籤的名稱: <
字元,後跟一個可選的字串規範,以及結束的 >
字元。字串規範是任何不包含結束字元 '>'
的字元字串。如果省略,則標籤名稱預設為空字串。有關語義標籤的更多詳細資訊,請參閱函式 Format.open_stag
和 Format.close_stag
。@}
:關閉最近開啟的語義標籤。@?
:刷新美化列印器,如同 print_flush ()
。這等同於轉換 %!
。@\n
:強制換行,如同 force_newline ()
,這不是美化列印的正常方式,您應該偏好在垂直美化列印框內使用換行提示。注意:為了防止將 @
字元解釋為美化列印指示,請使用 %
字元將其逸出。舊的引號模式 @@
已棄用,因為它與字元 '@'
的格式化輸入解釋不相容。
範例: printf "@[%s@ %d@]@." "x =" 1
等同於 open_box (); print_string "x ="; print_space ();
。它在美化列印的「水平或垂直」框內列印
print_int 1; close_box (); print_newline ()x = 1
。
val printf : ('a, formatter, unit) format -> 'a
與上述 fprintf
相同,但輸出至 get_std_formatter ()
。
它的定義類似於 fun fmt -> fprintf (get_std_formatter ()) fmt
,但會延遲呼叫 get_std_formatter
,直到收到 format
所需的最後一個引數。當與多個網域一起使用時,網域的輸出將在刷新格式器的點交錯,例如使用 Format.print_flush
。
val eprintf : ('a, formatter, unit) format -> 'a
與上述 fprintf
相同,但輸出至 get_err_formatter ()
。
它的定義類似於 fun fmt -> fprintf (get_err_formatter ()) fmt
,但會延遲呼叫 get_err_formatter
,直到收到 format
所需的最後一個引數。當與多個網域一起使用時,網域的輸出將在刷新格式器的點交錯,例如使用 Format.print_flush
。
val sprintf : ('a, unit, string) format -> 'a
與上述 printf
相同,但不是在格式器上列印,而是傳回一個字串,其中包含格式化引數的結果。請注意,美化列印器佇列會在每次呼叫 sprintf
結束時刷新。請注意,如果您的格式字串包含 %a
,則應使用 asprintf
。
如果多次且相關地呼叫 sprintf
以在單一字串上輸出資料,則應考慮將 fprintf
與預先定義的格式器 str_formatter
一起使用,並呼叫 flush_str_formatter ()
以取得最終結果。
或者,您可以使用 Format.fprintf
以及寫入您自己的緩衝區的格式器:在美化列印結束時刷新格式器和緩衝區會傳回所需的字串。
val asprintf : ('a, formatter, unit, string) format4 -> 'a
與上述 printf
相同,但不是在格式器上列印,而是傳回一個字串,其中包含格式化引數的結果。 asprintf
的類型非常通用,可以與 %a
轉換良好地互動。
val dprintf : ('a, formatter, unit, formatter -> unit) format4 -> 'a
與 Format.fprintf
相同,只是格式器是最後一個引數。 dprintf "..." a b c
是一個 formatter -> unit
類型的函式,可以提供給格式規範 %t
。
這可以用作 Format.asprintf
的替代品,以延遲格式化決策。在格式化內容中使用 Format.asprintf
傳回的字串會強制隔離地執行格式化決策,並且可能會過早建立最終字串。 Format.dprintf
允許延遲格式化決策,直到知道最終的格式化內容。例如
let t = Format.dprintf "%i@ %i@ %i" 1 2 3 in
...
Format.printf "@[<v>%t@]" t
val ifprintf : formatter -> ('a, formatter, unit) format -> 'a
與上述 fprintf
相同,但不列印任何內容。在有條件列印時忽略某些資料很有用。
使用連續性的格式化美化列印。
val kfprintf : (formatter -> 'a) ->
formatter -> ('b, formatter, unit, 'a) format4 -> 'b
與上述 fprintf
相同,但不是立即傳回,而是在列印結束時將格式器傳遞給其第一個引數。
val kdprintf : ((formatter -> unit) -> 'a) ->
('b, formatter, unit, 'a) format4 -> 'b
與上述 Format.dprintf
相同,但不是立即傳回,而是在列印結束時將暫停的列印器傳遞給其第一個引數。
val ikfprintf : (formatter -> 'a) ->
formatter -> ('b, formatter, unit, 'a) format4 -> 'b
與上述 kfprintf
相同,但不列印任何內容。在有條件列印時忽略某些資料很有用。
val ksprintf : (string -> 'a) -> ('b, unit, string, 'a) format4 -> 'b
與上述 sprintf
相同,但不是傳回字串,而是將其傳遞給第一個引數。
val kasprintf : (string -> 'a) -> ('b, formatter, unit, 'a) format4 -> 'b
與上述 asprintf
相同,但不是傳回字串,而是將其傳遞給第一個引數。
一些熱身範例,讓您了解如何使用 Format。
我們有一個配對 (int * bool)
的清單 l
,最上層會為我們列印它
# let l = List.init 20 (fun n -> n, n mod 2 = 0)
val l : (int * bool) list =
[(0, true); (1, false); (2, true); (3, false); (4, true); (5, false);
(6, true); (7, false); (8, true); (9, false); (10, true); (11, false);
(12, true); (13, false); (14, true); (15, false); (16, true); (17, false);
(18, true); (19, false)]
如果我們想要在沒有最上層魔術的情況下自己列印它,我們可以嘗試這樣
# let pp_pair out (x,y) = Format.fprintf out "(%d, %b)" x y
val pp_pair : Format.formatter -> int * bool -> unit = <fun>
# Format.printf "l: [@[<hov>%a@]]@."
Format.(pp_print_list ~pp_sep:(fun out () -> fprintf out ";@ ") pp_pair) l
l: [(0, true); (1, false); (2, true); (3, false); (4, true); (5, false);
(6, true); (7, false); (8, true); (9, false); (10, true); (11, false);
(12, true); (13, false); (14, true); (15, false); (16, true);
(17, false); (18, true); (19, false)]
簡而言之,它的作用是
pp_pair
列印一個以 "(" ")" 包圍的配對 bool*int
。它會取得一個格式器(格式化發生之處)和配對本身。列印完成後,它會傳回 ()
。Format.printf "l = [@[<hov>%a@]]@." ... l
類似於 printf
,但帶有額外的格式化指示(以 "@" 表示)。配對 "@[<hov>
" 和 "@]
" 是一個「水平或垂直框」。Format.formatter
的狀態。請勿將 "\n" 與 Format
一起使用。printf
的 "%d" 或 "%s"。但是,"%d" 列印一個整數,而 "%s" 列印一個字串,"%a" 取得一個列印器(類型為 Format.formatter -> 'a -> unit
)和一個值(類型為 'a
),並將列印器套用至該值。這是列印器可組合性的關鍵。Format.pp_print_list ~pp_sep:(...) pp_pair
來建立清單列印器。 pp_print_list
取得一個元素列印器並傳回一個清單列印器。如果提供了可選引數 ?pp_sep
,則會在每個元素之間呼叫它以列印分隔符號。(fun out () -> Format.fprintf out ";@ ")
。它會列印 ";",然後是 "@ ",這是一個換行空格(如果框即將溢位,則會列印「 」,否則會列印換行符號)。此 "@ " 負責將清單列印分成幾行。如果我們省略 "@ ",我們會得到一個醜陋的單行列印
# Format.printf "l: [@[<hov>%a@]]@."
Format.(pp_print_list ~pp_sep:(fun out () -> fprintf out "; ") pp_pair) l
l: [(0, true); (1, false); (2, true); (* ... *); (18, true); (19, false)]
- : unit = ()
一般來說,為程式中的重要類型定義自訂列印器是一個很好的做法。例如,如果您要像這樣定義基本的幾何類型
type point = {
x: float;
y: float;
}
type rectangle = {
ll: point; (* lower left *)
ur: point; (* upper right *)
}
為了除錯目的,或在記錄檔中或在主控台上顯示資訊,為這些類型定義列印器會很方便。以下是如何執行此操作的範例。請注意,"%.3f" 是一個 float
列印器,在小數點後具有 3 位數的精確度;"%f" 會列印所需的位數,這有點冗長;"%h" 是一個十六進制浮點列印器。
let pp_point out (p:point) =
Format.fprintf out "{ @[x=%.3f;@ y=%.3f@] }" p.x p.y
let pp_rectangle out (r:rectangle) =
Format.fprintf out "{ @[ll=%a;@ ur=%a@] }"
pp_point r.ll pp_point r.ur
在 .mli
檔案中,我們可以有
val pp_point : Format.formatter -> point -> unit
val pp_rectangle : Format.formatter -> rectangle -> unit
這些列印器現在可以在其他列印器中使用 "%a"。
# Format.printf "some rectangle: %a@."
(Format.pp_print_option pp_rectangle)
(Some {ll={x=1.; y=2.}; ur={x=42.; y=500.12345}})
some rectangle: { l={ x=1.000; y=2.000 }; ur={ x=42.000; y=500.123 } }
# Format.printf "no rectangle: %a@."
(Format.pp_option pp_rectangle)
None
no rectangle:
請參閱我們如何將 pp_print_option
(選項列印器)與我們新定義的矩形列印器結合使用,就像我們之前對 pp_print_list
所做的一樣。
如需更廣泛的教學課程,請參閱 「使用 Format 模組」。
最後一個注意事項: Format
模組是一個起點。OCaml 生態系統具有使格式化更容易和更具表現力的程式庫,具有更多的組合器、更簡潔的名稱等。此類程式庫的一個範例是 Fmt。
也可以使用 https://github.com/ocaml-ppx/ppx_deriving 或類似的 ppx 衍生器,從類型定義自動衍生美化列印器。