为什么用重音符号分割字符串会崩溃?
Why does splitting a string with accents crash?
这应该很简单……
import Foundation
let str:String = "Beyonce\u{301} and Tay"
print(str)
print(str.components(separatedBy: CharacterSet(charactersIn: "e")))
编译正常,直到我 运行 可执行文件:
// Beyoncé and Tay
// Illegal instruction (core dumped)
我怀疑 Swift 很难处理组合 '\u{65}'
重音标记,但考虑到该语言对基于字素的字符串模型的强调程度,我认为很明显在 'e'
上拆分 "Beyonce\u{301} and Tay"
应该只给出 ["B", "yonce\u{301} and Tay"]
,因为 'e\u{301}'
应该被解释为单个字素而不是 'e'
加上组合锐音符。
在单个字符上拆分不会崩溃:
print(str.components(separatedBy: "e"))
// ["B", "yoncé and Tay"]
我的swift版本是
swiftc -version
Swift version 3.0-dev (LLVM 3e3d712024, Clang 09ad59b006, Swift fdf6ee20e4)
Target: x86_64-unknown-linux-gnu
Swift 的 Linux 端口似乎有错误。我不会在我的回答中解决这个问题。下面的代码在 Mac OS X.
上进行了测试
您 运行 遇到了 Unicode 规范化问题。字母 é
可以用两种方式表示,Swift 认为相同:
let s1 = "e\u{301}" // letter e + combining acute accent
let s2 = "\u{0e9}" // small letter e with acute
s1.characters.count // 1
s2.characters.count // 1
s1 == s2 // true
那是因为 Swift 的 String
和它的前身 NSString
一样对 Unicode 有很好的支持。但是如果你深入研究,你会开始看到一些不同之处:
s1.utf16.count // 2
s2.utf16.count // 1
因此,即使 s1
和 s2
相等,它们的存储方式也不同:使用 2 或 1 个代码点。 components(seperatedBy: )
对这个事实视而不见。它遍历字符串中的所有代码点并在找到字母 e
时拆分。在一种形式到另一种形式之间的转换称为 规范化 并影响函数的工作方式:
let str1 = "Beyonce\u{301} and Tay"
let str2 = str1.precomposedStringWithCanonicalMapping // normalize the string to Form C
let charset = CharacterSet(charactersIn: "e")
str1.components(separatedBy: charset) // ["B", "yonc", "́ and Tay"]
str2.components(separatedBy: charset) // ["B", "yoncé and Tay"]
参考文献:
这应该很简单……
import Foundation
let str:String = "Beyonce\u{301} and Tay"
print(str)
print(str.components(separatedBy: CharacterSet(charactersIn: "e")))
编译正常,直到我 运行 可执行文件:
// Beyoncé and Tay
// Illegal instruction (core dumped)
我怀疑 Swift 很难处理组合 '\u{65}'
重音标记,但考虑到该语言对基于字素的字符串模型的强调程度,我认为很明显在 'e'
上拆分 "Beyonce\u{301} and Tay"
应该只给出 ["B", "yonce\u{301} and Tay"]
,因为 'e\u{301}'
应该被解释为单个字素而不是 'e'
加上组合锐音符。
在单个字符上拆分不会崩溃:
print(str.components(separatedBy: "e"))
// ["B", "yoncé and Tay"]
我的swift版本是
swiftc -version
Swift version 3.0-dev (LLVM 3e3d712024, Clang 09ad59b006, Swift fdf6ee20e4)
Target: x86_64-unknown-linux-gnu
Swift 的 Linux 端口似乎有错误。我不会在我的回答中解决这个问题。下面的代码在 Mac OS X.
上进行了测试您 运行 遇到了 Unicode 规范化问题。字母 é
可以用两种方式表示,Swift 认为相同:
let s1 = "e\u{301}" // letter e + combining acute accent
let s2 = "\u{0e9}" // small letter e with acute
s1.characters.count // 1
s2.characters.count // 1
s1 == s2 // true
那是因为 Swift 的 String
和它的前身 NSString
一样对 Unicode 有很好的支持。但是如果你深入研究,你会开始看到一些不同之处:
s1.utf16.count // 2
s2.utf16.count // 1
因此,即使 s1
和 s2
相等,它们的存储方式也不同:使用 2 或 1 个代码点。 components(seperatedBy: )
对这个事实视而不见。它遍历字符串中的所有代码点并在找到字母 e
时拆分。在一种形式到另一种形式之间的转换称为 规范化 并影响函数的工作方式:
let str1 = "Beyonce\u{301} and Tay"
let str2 = str1.precomposedStringWithCanonicalMapping // normalize the string to Form C
let charset = CharacterSet(charactersIn: "e")
str1.components(separatedBy: charset) // ["B", "yonc", "́ and Tay"]
str2.components(separatedBy: charset) // ["B", "yoncé and Tay"]
参考文献: