有时,我需要使用依赖于后台的NSString / NSRange的API,但是我的大部分代码都在Swift中。
当我需要提供索引(或范围)时,应该使用哪个Swift字符计数?
例如,给定此功能:
func replace(_ string: String, characterAtIndex characterIndex: Int) -> String {
let regex = try! NSRegularExpression(pattern: ".", options: [])
let range = NSRange(location: characterIndex, length: 1)
let mutableString = NSMutableString(string: string)
regex.replaceMatches(in: mutableString, options: [], range: range, withTemplate: "!")
return mutableString as String
}
我应该使用6种不同的方式来获取字符串中的字符计数吗?
答案 0 :(得分:0)
documentation for NSString.length指定:
接收器中UTF-16代码单元的数量。
因此,如果要在String和NSString之间互操作:
string.utf16.count
,它将与(string as NSString).length
完美匹配。如果要计算可见字符数:
您应该使用string.count
,它将匹配您需要键盘上的→(向右)键的相同次数,直到结束为止的字符串(假设您从头开始)。
注意:这并不总是100%准确,但苹果似乎正在不断改进其实现,以使其越来越准确。
这里是一个Swift 4.0游乐场,用于测试一堆字符串和函数:
let header = "NSString .utf16❔ encodedOffset❔ NSRange❔ .count❔ .characters❔ distance❔ .unicodeScalars❔ .utf8❔ Description"
var format = " %3d %3d ❓ %3d ❓ %3d ❓ %3d ❓ %3d ❓ %3d ❓ %3d ❓ %3d ❓ %@"
format = format.replacingOccurrences(of: "❓", with: "%@") // "❓" acts as a placeholder for "%@" to align the text perfectly
print(header)
test("")
test("abc")
test("❌")
test("")
test("☾test")
test("")
test("\u{200d}\u{200d}\u{200d}")
test("")
test("\u{1F468}")
test("♀️♂️")
test("你好吗")
test("مرحبا", "Arabic word")
test("م", "Arabic letter")
test("שלום", "Hebrew word")
test("ם", "Hebrew letter")
func test(_ s: String, _ description: String? = nil) {
func icon(for length: Int) -> String {
return length == (s as NSString).length ? "✅" : "❌"
}
let description = description ?? "'" + s + "'"
let string = String(
format: format,
(s as NSString).length,
s.utf16.count, icon(for: s.utf16.count),
s.endIndex.encodedOffset, icon(for: s.endIndex.encodedOffset),
NSRange(s.startIndex..<s.endIndex, in: s).upperBound, icon(for: NSRange(s.startIndex..<s.endIndex, in: s).upperBound),
s.count, icon(for: s.count),
s.characters.count, icon(for: s.characters.count),
s.distance(from: s.startIndex, to: s.endIndex), icon(for: s.distance(from: s.startIndex, to: s.endIndex)),
s.unicodeScalars.count, icon(for: s.unicodeScalars.count),
s.utf8.count, icon(for: s.utf8.count),
description)
print(string)
}
这是输出:
NSString .utf16❔ encodedOffset❔ NSRange❔ .count❔ .characters❔ distance❔ .unicodeScalars❔ .utf8❔ Description
0 0 ✅ 0 ✅ 0 ✅ 0 ✅ 0 ✅ 0 ✅ 0 ✅ 0 ✅ ''
3 3 ✅ 3 ✅ 3 ✅ 3 ✅ 3 ✅ 3 ✅ 3 ✅ 3 ✅ 'abc'
1 1 ✅ 1 ✅ 1 ✅ 1 ✅ 1 ✅ 1 ✅ 1 ✅ 3 ❌ '❌'
4 4 ✅ 4 ✅ 4 ✅ 1 ❌ 1 ❌ 1 ❌ 2 ❌ 8 ❌ ''
5 5 ✅ 5 ✅ 5 ✅ 5 ✅ 5 ✅ 5 ✅ 5 ✅ 7 ❌ '☾test'
11 11 ✅ 11 ✅ 11 ✅ 1 ❌ 1 ❌ 1 ❌ 7 ❌ 25 ❌ ''
11 11 ✅ 11 ✅ 11 ✅ 1 ❌ 1 ❌ 1 ❌ 7 ❌ 25 ❌ ''
8 8 ✅ 8 ✅ 8 ✅ 4 ❌ 4 ❌ 4 ❌ 4 ❌ 16 ❌ ''
2 2 ✅ 2 ✅ 2 ✅ 1 ❌ 1 ❌ 1 ❌ 1 ❌ 4 ❌ ''
58 58 ✅ 58 ✅ 58 ✅ 13 ❌ 13 ❌ 13 ❌ 32 ❌ 122 ❌ '♀️♂️'
3 3 ✅ 3 ✅ 3 ✅ 3 ✅ 3 ✅ 3 ✅ 3 ✅ 9 ❌ '你好吗'
5 5 ✅ 5 ✅ 5 ✅ 5 ✅ 5 ✅ 5 ✅ 5 ✅ 10 ❌ Arabic word
1 1 ✅ 1 ✅ 1 ✅ 1 ✅ 1 ✅ 1 ✅ 1 ✅ 2 ❌ Arabic letter
4 4 ✅ 4 ✅ 4 ✅ 4 ✅ 4 ✅ 4 ✅ 4 ✅ 8 ❌ Hebrew word
1 1 ✅ 1 ✅ 1 ✅ 1 ✅ 1 ✅ 1 ✅ 1 ✅ 2 ❌ Hebrew letter
结论:
(s as NSString).length
,s.utf16.count
(首选),s.endIndex.encodedOffset
或NSRange(s.startIndex..<s.endIndex, in: s)
。s.count
(首选),s.characters.count
(不推荐使用)或s.distance(from: s.startIndex, to: s.endIndex)
一个有用的扩展,可以获取完整的字符串:
public extension String {
var nsrange: NSRange {
return NSRange(startIndex..<endIndex, in: self)
}
}
因此,您可以像这样调用原始方法:
replace("", characterAtIndex: "".utf16.count - 1) // �!