Swift 当源包含 unicode 字符时正则表达式匹配失败
Swift Regex matching fails when source contains unicode characters
我正在尝试使用 NSRegularExpression 进行简单的正则表达式匹配,但是当源包含多字节字符时,我在匹配字符串时遇到了一些问题:
let string = "D 9"
// The following matches (any characters)(SPACE)(numbers)(any characters)
let pattern = "([\s\S]*) ([0-9]*)(.*)"
let slen : Int = string.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)
var error: NSError? = nil
var regex = NSRegularExpression(pattern: pattern, options: NSRegularExpressionOptions.DotMatchesLineSeparators, error: &error)
var result = regex?.stringByReplacingMatchesInString(string, options: nil, range: NSRange(location:0,
length:slen), withTemplate: "First \"\" Second: \"\"")
上面的代码 returns "D" 和预期的“9”
如果我现在更改第一行以包含英国 'Pound' 货币符号,如下所示:
let string = "£ 9"
然后匹配不起作用,即使表达式的 ([\s\S]*)
部分仍应匹配 any 前导字符。
我知道 £
符号需要两个字节,但是通配符前导匹配应该忽略那些不应该吗?
谁能解释一下这是怎么回事?
这可能会造成混淆。 stringByReplacingMatchesInString()
的第一个参数映射自NSString
中的
Objective-C 到 Swift 中的 String
,但 range:
参数仍然是
一个 NSRange
。因此,您必须以单位指定范围
NSString
使用(UTF-16 代码点数):
var result = regex?.stringByReplacingMatchesInString(string,
options: nil,
range: NSRange(location:0, length:(string as NSString).length),
withTemplate: "First \"\" Second: \"\"")
或者您可以使用 count(string.utf16)
而不是 (string as NSString).length
.
完整示例:
let string = "£ 9"
let pattern = "([\s\S]*) ([0-9]*)(.*)"
var error: NSError? = nil
let regex = NSRegularExpression(pattern: pattern,
options: NSRegularExpressionOptions.DotMatchesLineSeparators,
error: &error)!
let result = regex.stringByReplacingMatchesInString(string,
options: nil,
range: NSRange(location:0, length:(string as NSString).length),
withTemplate: "First \"\" Second: \"\"")
println(result)
// First "£" Second: "9"
我已经 运行 讨论过几次,Martin 的回答帮助我理解了这个问题。这是对我有用的解决方案的快速版本。
如果您的正则表达式函数包含这样构建的范围参数:
NSRange(location: 0, length: yourString.count)
你可以改成这样:
NSRange(location: 0, length: yourString.utf16.count)
我正在尝试使用 NSRegularExpression 进行简单的正则表达式匹配,但是当源包含多字节字符时,我在匹配字符串时遇到了一些问题:
let string = "D 9"
// The following matches (any characters)(SPACE)(numbers)(any characters)
let pattern = "([\s\S]*) ([0-9]*)(.*)"
let slen : Int = string.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)
var error: NSError? = nil
var regex = NSRegularExpression(pattern: pattern, options: NSRegularExpressionOptions.DotMatchesLineSeparators, error: &error)
var result = regex?.stringByReplacingMatchesInString(string, options: nil, range: NSRange(location:0,
length:slen), withTemplate: "First \"\" Second: \"\"")
上面的代码 returns "D" 和预期的“9”
如果我现在更改第一行以包含英国 'Pound' 货币符号,如下所示:
let string = "£ 9"
然后匹配不起作用,即使表达式的 ([\s\S]*)
部分仍应匹配 any 前导字符。
我知道 £
符号需要两个字节,但是通配符前导匹配应该忽略那些不应该吗?
谁能解释一下这是怎么回事?
这可能会造成混淆。 stringByReplacingMatchesInString()
的第一个参数映射自NSString
中的
Objective-C 到 Swift 中的 String
,但 range:
参数仍然是
一个 NSRange
。因此,您必须以单位指定范围
NSString
使用(UTF-16 代码点数):
var result = regex?.stringByReplacingMatchesInString(string,
options: nil,
range: NSRange(location:0, length:(string as NSString).length),
withTemplate: "First \"\" Second: \"\"")
或者您可以使用 count(string.utf16)
而不是 (string as NSString).length
.
完整示例:
let string = "£ 9"
let pattern = "([\s\S]*) ([0-9]*)(.*)"
var error: NSError? = nil
let regex = NSRegularExpression(pattern: pattern,
options: NSRegularExpressionOptions.DotMatchesLineSeparators,
error: &error)!
let result = regex.stringByReplacingMatchesInString(string,
options: nil,
range: NSRange(location:0, length:(string as NSString).length),
withTemplate: "First \"\" Second: \"\"")
println(result)
// First "£" Second: "9"
我已经 运行 讨论过几次,Martin 的回答帮助我理解了这个问题。这是对我有用的解决方案的快速版本。
如果您的正则表达式函数包含这样构建的范围参数:
NSRange(location: 0, length: yourString.count)
你可以改成这样:
NSRange(location: 0, length: yourString.utf16.count)