快速字符串索引将“ \ r \ n”组合为一个字符而不是两个字符

时间:2018-12-27 05:28:24

标签: swift string swift4

我正在使用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"

知道为什么会这样吗?

1 个答案:

答案 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