希腊字母的字符串范围不一致
Inconsistent ranges of strings with greek letter
我将展示代码和输出,因为它更容易解释问题。
注释行中的代码和输出:
let greekLetter = "β"
let string1 = greekLetter
/// string2 is the same as string1 but converted to NSString then back to String
let string2 = String(NSString(string: greekLetter))
print(string1.range(of: greekLetter)!)
/// prints: Index(_rawBits: 0)..<Index(_rawBits: 131072)
print(string2.range(of: greekLetter)!)
/// prints: Index(_rawBits: 0)..<Index(_rawBits: 65536)
问题:一个包含希腊字母的字符串 returns 一个范围不同于具有相同希腊字母的相同字符串,该字符串已转换为 NSString 然后再次返回到 String。
知道为什么吗?
为什么提出这个问题:
我正在做一些解析,我需要找到特定字符串的范围,然后插入其他内容来代替它。由于错误的范围返回错误的位置插入字符串由于错误 lower/upper 绑定位置。
更新 2:
假设我有一个任务:在给定的字符串“β-1”中将“1”更改为“2”。这个字符串来自服务器。
请查看此代码示例:
let wordWithGreekLetter = "β-1"
var string1 = wordWithGreekLetter
let data = """
{ "name" : "\(wordWithGreekLetter)" }
""".data(using: String.Encoding.utf8)
struct User: Decodable {
let name: String
}
let user = try! JSONDecoder().decode(User.self, from: data!)
/// string2 is the same as string1 but decoded from the data
var string2 = user.name
let rangeOfNumberOne1 = string1.range(of: "1")!
string1.removeSubrange(rangeOfNumberOne1)
string1.insert("2", at: rangeOfNumberOne1.lowerBound)
/// RESULT: string1 = "β-2"
let rangeOfNumberOne2 = string2.range(of: "1")!
string2.removeSubrange(rangeOfNumberOne2)
string2.insert("2", at: rangeOfNumberOne2.lowerBound)
/// RESULT: string2 = "β2-"
正如 Rob 在 中解释的那样,索引的原始位是一个实现细节,您不应该关心该值。
实际问题是(引自Collection):
Saved indices may become invalid as a result of mutating operations.
这样 rangeOfNumberOne1/2
可能在您对字符串调用 removeSubrange()
后不再有效。
在这种特殊情况下,可能 发生在 string2
(从 NSString
桥接),因为删除字符 可能 重组内部存储。但这纯粹是猜测:唯一重要的是当前代码表现出未定义的行为。
如果替换
let rangeOfNumberOne1 = string1.range(of: "1")!
string1.removeSubrange(rangeOfNumberOne1)
string1.insert("2", at: rangeOfNumberOne1.lowerBound)
来自
let rangeOfNumberOne1 = string1.range(of: "1")!
string1.replaceSubrange(rangeOfNumberOne1, with: "2")
(和 string2
类似)然后你会得到相同的结果 "β-2" 对于两个字符串。
我将展示代码和输出,因为它更容易解释问题。
注释行中的代码和输出:
let greekLetter = "β"
let string1 = greekLetter
/// string2 is the same as string1 but converted to NSString then back to String
let string2 = String(NSString(string: greekLetter))
print(string1.range(of: greekLetter)!)
/// prints: Index(_rawBits: 0)..<Index(_rawBits: 131072)
print(string2.range(of: greekLetter)!)
/// prints: Index(_rawBits: 0)..<Index(_rawBits: 65536)
问题:一个包含希腊字母的字符串 returns 一个范围不同于具有相同希腊字母的相同字符串,该字符串已转换为 NSString 然后再次返回到 String。
知道为什么吗?
为什么提出这个问题: 我正在做一些解析,我需要找到特定字符串的范围,然后插入其他内容来代替它。由于错误的范围返回错误的位置插入字符串由于错误 lower/upper 绑定位置。
更新 2:
假设我有一个任务:在给定的字符串“β-1”中将“1”更改为“2”。这个字符串来自服务器。 请查看此代码示例:
let wordWithGreekLetter = "β-1"
var string1 = wordWithGreekLetter
let data = """
{ "name" : "\(wordWithGreekLetter)" }
""".data(using: String.Encoding.utf8)
struct User: Decodable {
let name: String
}
let user = try! JSONDecoder().decode(User.self, from: data!)
/// string2 is the same as string1 but decoded from the data
var string2 = user.name
let rangeOfNumberOne1 = string1.range(of: "1")!
string1.removeSubrange(rangeOfNumberOne1)
string1.insert("2", at: rangeOfNumberOne1.lowerBound)
/// RESULT: string1 = "β-2"
let rangeOfNumberOne2 = string2.range(of: "1")!
string2.removeSubrange(rangeOfNumberOne2)
string2.insert("2", at: rangeOfNumberOne2.lowerBound)
/// RESULT: string2 = "β2-"
正如 Rob 在
实际问题是(引自Collection):
Saved indices may become invalid as a result of mutating operations.
这样 rangeOfNumberOne1/2
可能在您对字符串调用 removeSubrange()
后不再有效。
在这种特殊情况下,可能 发生在 string2
(从 NSString
桥接),因为删除字符 可能 重组内部存储。但这纯粹是猜测:唯一重要的是当前代码表现出未定义的行为。
如果替换
let rangeOfNumberOne1 = string1.range(of: "1")!
string1.removeSubrange(rangeOfNumberOne1)
string1.insert("2", at: rangeOfNumberOne1.lowerBound)
来自
let rangeOfNumberOne1 = string1.range(of: "1")!
string1.replaceSubrange(rangeOfNumberOne1, with: "2")
(和 string2
类似)然后你会得到相同的结果 "β-2" 对于两个字符串。