我正在使用Swift 4.2处理包含\r\n
的字符串。我遇到了Swift索引的一种奇怪行为,看来\r\n
将被Swift索引方法视为一个字符而不是两个字符。我编写了一段代码来演示这种行为:
var text = "ABC\r\n\r\nDEF"
func printChar(_ lower: Int, _ upper: Int) {
let start = text.index(text.startIndex, offsetBy: lower)
let end = text.index(text.startIndex, offsetBy: upper)
print("\"" + text[start..<end] + "\"")
}
printChar(0, 1) // "A"
printChar(1, 2) // "B"
printChar(2, 3) // "C"
printChar(3, 4) // new line
printChar(4, 5) // new line (okay, what's going on here?)
printChar(5, 6) // "D"
printChar(6, 7) // "E"
printChar(7, 8) // "F"
打印结果将是
"A"
"B"
"C"
"
"
"
"
"D"
"E"
"F"
知道为什么会这样吗?
答案 0 :(得分:8)
TLDR:\r\n
是一个字素簇,由于Unicode,在Swift中被视为单个Character
。
Swift将\r\n
视为一个Character
。
Objective-C NSString
将其视为两个字符(根据length
的结果)。
https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html有人写道:
–“ \ r \ n”是单个
Character
。这是正确的行为吗?–是的,
Character
对应于Unicode字素簇,而“ \ r \ n”被视为单个字素簇。
随后的回复中发布了Unicode文档的链接,请查看On the swift-users forum,该文档正式声明CRLF是一个字素簇。
看看this table。
通常将字符串视为字符序列,但是在使用NSString对象或通常使用Unicode字符串的情况下,在大多数情况下,处理子字符串比处理单个字符更好。其原因是,在许多情况下,用户认为文本中的字符可能由字符串中的多个字符表示。
Apple documentation on Characters and Grapheme Clusters上的Swift文档也值得一读。
这个Strings and Characters也很有趣。
NSString
代表UTF-16编码的文本。长度,索引和范围均基于UTF-16代码单位。
这的另一个示例是类似的表情符号。这个单个字符实际上是%uD83D%uDC4D%uD83C%uDFFB,这是四个不同的unicode标量。但是,如果您在仅带有表情符号的字符串上调用count
,您(正确)会得到1
。
如果要查看标量,可以按以下步骤对其进行迭代:
for scalar in text.unicodeScalars {
print("\(scalar.value) ", terminator: "")
}
"\r\n"
可以给您13 10
overview from objc.io,您会发现NSString
与众不同的原因:
count属性返回的字符数并不总是与包含相同字符的NSString的length属性相同。 NSString的长度取决于字符串的UTF-16表示形式中16位代码单元的数量,而不是字符串中的Unicode扩展字素簇的数量。
因此,这并不是Swift字符串索引的真正“奇怪”行为,而是Unicode如何对待这些字符以及Swift如何设计String
的结果。快速字符串索引使用Character
,而\r\n
是单个Character
。