以信用卡卡號來舉例
4242424242424242
每隔四個數字插入一個空白,像是這樣:
4242 4242 4242 4242
實作
原先有嘗試過用 map 或是 reduce 等等高階函式的方式實作,
但是在建置時間和型別推論的時間都太長,再來是必須要反覆取得記憶體空間,不是很有智慧(笑)。
於是就去找了一下有沒有比較「環保」的做法。
接著就在 Stack Overflow 找到一個解法 (這裡),
這個解法簡單來說,是從 String 「內部」 來修改它的內容,這樣可以在不用額外索取記憶體空間的情形下達成。
簡化這個解答到必要的程式碼之後如下:
extension StringProtocol where Self: RangeReplaceableCollection {
mutating func insert(separator: Self, every count: Int) {
for index in indices.reversed() where index != startIndex &&
distance(from: startIndex, to: index) % count == 0 {
insert(contentsOf: separator, at: index)
}
}
}
詳細原理的解說可以參照 Swift Blog 的這篇文章
-
Strings and Characters | Swift Blog 的
Accessing and Modifying a String
章節
走訪每一個字元並以指定間隔插入指定字串
在這裡就用我自己的話說明看看。
因為 Swift 的 String 無法以單純的整數定位,所以必須要使用 String.Index
。
在這邊就是透過 Collection protocol 提供的 indices 來走訪每個位置。
(RangeReplaceableCollection 有繼承 Collection protocol)
先反轉再走訪的原因是可以避免在插入字串的過程中,長度改變造成 index 不好計算的問題
for index in indices.reversed()
觸發條件就是當前的 index 還沒抵達 startIndex :
index != startIndex
以及與第一個字元的距離的餘數為 0
distance(from: startIndex, to: index) % count == 0
符合條件之後,就可以用 RangeReplaceableCollection 提供的方法,來在指定位置插入指定字串
insert(contentsOf: separator, at: index)
-
RangeReplaceableCollection#insert(contentsOf:at:)
- 文件
使用方法
var cardNumber = "4242424242424242"
cardNumber.insert(separator: " ", every: 4)
print(cardNumber) // output: 4242 4242 4242 4242
當然也可以拿來插入複數字元:
var content = "鯛魚燒"
content.insert(separator: " 🐟 ", every: 1)
print(content) // output: 鯛 🐟 魚 🐟 燒
以上!
參考資料
- How add separator to string at every N characters in swift? | Stack Overflow
- Strings and Characters | Swift Blog
- Collection#indices
- RangeReplaceableCollection#insert(contentsOf: at:)
環境
- Xcode 10.3 (10G8)
- Swift 5
最後
如果內文需要更新、有錯誤或容易誤解的地方,歡迎發修改或是留言告訴我!