Swift 中的格式化字元串
在 Swift 中,因為 String 實作了 ExpressibleByStringLiteral 這個協定,是以正常情況下直接使用 let str = "This is a string." 這樣的字面量表達配合字元串插值即可建立我們想要的執行個體。
但是如果涉及數字的輸出,往往還是需要使用格式化字元串的方式來初始化字元串,格式化字元串也就是類似于 Java 和 C 語言那樣的構造方式,調用 init(format: String, _ arguments: CVarArg...) 這個方法就可以使用格式化字元串。舉個例子,使用下面的代碼就可以實作以四舍五入規則輸出兩位小數。
1
2
3var double = 0.12345
print(String(format: "%.2f", double))
// 0.12
以上這些知識都是已經滾瓜爛熟的了,不用再強調。主要是我在使用 iOS 13中新推出的 CryptoKit 對字元串進行 SHA256 加密,标準的寫法是這樣的:
1
2
3
4
5
6extension String{
func sha256(using encoding: String.Encoding = .utf8) -> String {
let data = self.data(using: encoding)!
return SHA256.hash(data: data).compactMap { String(format: "%0.2x", $0)}.joined()
}
}
對字元串構成的 Data 對象進行哈希,得到32個8位資料,每個資料取值範圍為0~255,要得到 SHA256 字元串,需要将每個資料轉換為一個兩位的十六進制數,然後将十六進制的資料拼接到一起,得到的64位字元串就是我們需要的 SHA256 加密字元串。
我對第4行的 “%0.2x” 比較好奇,是以專門去查了一下關于格式化字元串的資料。
格式化字元串,format string,是一些程式設計語言中用于指定輸出格式與輸出位置的字元串參數,其中格式化占位符用于對應參數清單并按指定的格式對參數進行轉換。對于上面的代碼段,“%0.2x” 就是格式化字元串,其中 %0.2x 是格式化占位符,$0 是參數清單。這裡面最重要的就是格式化占位符。
格式化占位符的格式如下:
%[parameter][flags][field width][.precision][length]type
對于每一種類型的參數,都有不同的可選項,下面挨個介紹一下。
parameter
parameter 是可選的,預設預設,parameter 的作用是指定參數清單的輸出順序,預設沒有值的情況下,參數清單中的值按順序填入占位符所在的位置。可以使用形如 n$ 的格式填入 parameter,說明這個占位符使用參數清單中的第 n 個參數進行填充。
1
2print(String(format: "This is %2$d, and that is %1$d", 1, 2))
// This is 2, and that is 1
flags
flags 标示一些輸出格式的設定,有以下幾個可選配置:
+:預設預設 ,如果為 + 表示總是顯示正數的符号
1
2print(String(format: "%+d", 1))
// +1
空格:預設預設,有符号數在忽略正号或者輸出0個字元的時候,字首一個空格
1
2print(String(format: "% d", 1))
// 1(注意1左邊有一個空格)
-:預設預設,預設時字元串右對齊,否則左對齊
1
2
3
4print(String(format: "%5d", 1))
// 1(注意1左邊有4個空格)
print(String(format: "%-5d", 1))
// 1 (注意1右邊有4個空格)
#:預設預設,對于’g‘與’G’,不删除尾部0以表示精度。對于’f’, ‘F’, ‘e’, ‘E’, ‘g’, ‘G’, 總是輸出小數點。對于’o’, ‘x’, ‘X’, 在非0數值前分别輸出字首0, 0x, and 0X表示數制。
1
2print(String(format: "%#x", 255))
// 0xff
field width
指定字元串最小寬度,可選,寬度不足的話按照之前設定的左右對齊方式對齊,并在另一端補空格,寬度超過的話不做截斷。如果寬度值的字首為0,代表用0補齊寬度不足的字元串。
1
2print(String(format: "%03d", 1))
// 001
.precision
指定精度,可選,對于不同類型的數值有不同的作用。對于整型(d,i,u,x,o),位數不足在左側用0補齊,精度超出的不做處理。對于浮點(a,e,f),指小數點右側的位數,不足的話在右側用0補齊,超出的部分四舍五入進行截斷。對于浮點(g),指有效數字最大位數。
1
2
3
4print(String(format: "%.3d", 1))
// 001
print(String(format: "%.3f", 1.23456))
// 1.235
length
指定浮點或整型的長度,可選。
修飾符
描述
h
可用于将 d, o, u, x, X 轉換為 short 或 unsigned short
hh
可用于将 d, o, u, x, X 轉換為 char 或 unsigned char
l
可用于将 d, o, u, x, X 轉換為 long 或 unsigned long
ll, q
可用于将 d, o, u, x, X 轉換為 long long 或 unsigned long long
L
可用于将 a, A, e, E, f, F, g, G 轉換為 long double
z
可用于将 d, o, u, x, X 轉換為 size_t.
t
可用于将 d, o, u, x, X 轉換為 ptrdiff_t.
j
可用于将 d, o, u, x, X 轉換為 intmax_t 或 uintmax_t
1
2
3var short = Int(Int16.max) + 1 // 32768
print(String(format: "%hd", short))
// -32768
type
這個是最重要的,也是必選的,用于指定我們的參數類型。
我從蘋果開發者官方文檔中找到了這個表格,這個表格基于 Objective-C,但是大部分内容對 Swift 依然适用。
修飾符
描述
%@
對象描述,輸出對象方法 descriptionWithLocale: 或 description 傳回的字元串。
%%
'%' 輸出%字元。
%d, %D
有符号32位整型 (int)。
%u, %U
無符号32位整型 (unsigned int)。
%x
無符号32位整型 (unsigned int),以小寫十六進制輸出。
%X
無符号32位整型 (unsigned int),以大寫十六進制輸出。
%o, %O
無符号32位整型 (unsigned int),以八進制輸出。
%f
64位浮點數 (double).
%e
64位浮點數 (double),以小寫科學計數法輸出。
%E
64位浮點數 (double),以大寫科學計數法輸出。
%g
64位浮點數 (double),當指數部分在閉區間 [-4,5] 内,輸出為定點形式;否則輸出為指數浮點形式。
%G
64位浮點數 (double),當指數部分在閉區間 [-4,5] 内,輸出為定點形式;否則輸出為指數浮點形式。
%c
8位無符号字元 (unsigned char).
%C
16位UTF-16字元 (unichar).
%s
8位無符号字元數組。
%S
16位UTF-16字元數組。
%p
指針。
%a
64位浮點數 (double),使用小寫科學計數法與十六進制進行輸出。
%A
64位浮點數 (double),使用大寫科學計數法與十六進制進行輸出。
%F
64位浮點數,以十進制輸出。
至此我們就介紹完了,舉一個綜合性例子:
1print(String(format: "%-#.8X", 54321))
結合上面說的參數,這個格式化字元串的意思就是,以左對齊(-),表示數制(#),最少8位(.8)的格式輸出一個大寫十六進制數(X),最終輸出“0X0000D431”。
此時再回到開頭我看到的 SHA256 算法中的那個格式化字元串”%0.2x“,意思也就明白了,輸出一個0補齊寬度不足的(0),最少2位(.2)的小寫十六進制數(x),也可以省略為“%.2x"。
參考資料