Swift 和正则表达式,cpu 对某些字符串失控
Swift and regex, cpu goes haywire for some strings
我想用正则表达式匹配本地化行。一切正常,除非尝试匹配此字符串。您可以将代码放在 playground 中以查看它不会停止,或者将代码放在空白项目中以查看 cpu 100% 并停留在 'let match' 行。现在有趣的是,如果你删除最后一个词它会起作用。我不知道是否适用于中文或其他奇怪的字符,这是希腊语。
let lineContent = "\"key\" = \" Χρήση παλιάς συνόμευση\";"
if let r = try? NSRegularExpression(pattern: "\"(.*)+\"(^|[ ]*)=(^|[ ]*)\"(.*)+\";", options: NSRegularExpressionOptions()) {
let match = r.matchesInString(lineContent, options: NSMatchingOptions(), range: NSMakeRange(0, lineContent.characters.count))
match.count
}
稍后编辑:实际上字符类型并不重要,而是字数。这个放在右边的字符串也不起作用:'jhg jhgjklkhjkh hhhhh hhh'
正如评论中已经提到的那样,.*+
导致了灾难性的回溯,导致 CPU 的高使用率(通常无法匹配)。
而不是使用像
这样的模式
\"(.*)+\"
因为您要匹配双引号之间的所有内容,请使用否定字符集:
\"([^\"]+)\"
根据上面的评论 - 用惰性版本替换嵌套的 (.*)+
- (.*?)
.
您在 (.*)+
中嵌套了量词,这将导致 catastrophic backtracking(我建议阅读那篇文章)。问题是当子表达式失败时,正则表达式引擎回溯以测试另一个替代方案。嵌套量词意味着主题字符串中每个字符的尝试次数将呈指数级增长:它将测试 (.*)+
的所有重复,并且对于每个字符,还将测试 .*
.[=23 的所有重复=]
为避免这种情况,请使用尽可能具体定义的模式:
"\"([^\"]+)\"[ ]*=[ ]*\"([^\"]*)\";"
\"([^\"]+)\"
匹配
- 开场
"
[^\"]+
除引号外的任意数量的字符。将 +
更改为 *
以允许空字符串。
- 收盘
"
代码
let lineContent = "\"key\" = \" Χρήση παλιάς συνόμευση\";"
if let r = try? NSRegularExpression(pattern: "\"([^\"]+)\"[ ]*=[ ]*\"([^\"]*)\";", options: NSRegularExpressionOptions()) {
let match = r.matchesInString(
lineContent,
options: NSMatchingOptions(),
range: NSMakeRange(0, lineContent.characters.count)
)
for index in 1..<match[0].numberOfRanges {
print((lineContent as NSString).substringWithRange(match[0].rangeAtIndex(index)))
}
}
我想用正则表达式匹配本地化行。一切正常,除非尝试匹配此字符串。您可以将代码放在 playground 中以查看它不会停止,或者将代码放在空白项目中以查看 cpu 100% 并停留在 'let match' 行。现在有趣的是,如果你删除最后一个词它会起作用。我不知道是否适用于中文或其他奇怪的字符,这是希腊语。
let lineContent = "\"key\" = \" Χρήση παλιάς συνόμευση\";"
if let r = try? NSRegularExpression(pattern: "\"(.*)+\"(^|[ ]*)=(^|[ ]*)\"(.*)+\";", options: NSRegularExpressionOptions()) {
let match = r.matchesInString(lineContent, options: NSMatchingOptions(), range: NSMakeRange(0, lineContent.characters.count))
match.count
}
稍后编辑:实际上字符类型并不重要,而是字数。这个放在右边的字符串也不起作用:'jhg jhgjklkhjkh hhhhh hhh'
正如评论中已经提到的那样,.*+
导致了灾难性的回溯,导致 CPU 的高使用率(通常无法匹配)。
而不是使用像
这样的模式\"(.*)+\"
因为您要匹配双引号之间的所有内容,请使用否定字符集:
\"([^\"]+)\"
根据上面的评论 - 用惰性版本替换嵌套的 (.*)+
- (.*?)
.
您在 (.*)+
中嵌套了量词,这将导致 catastrophic backtracking(我建议阅读那篇文章)。问题是当子表达式失败时,正则表达式引擎回溯以测试另一个替代方案。嵌套量词意味着主题字符串中每个字符的尝试次数将呈指数级增长:它将测试 (.*)+
的所有重复,并且对于每个字符,还将测试 .*
.[=23 的所有重复=]
为避免这种情况,请使用尽可能具体定义的模式:
"\"([^\"]+)\"[ ]*=[ ]*\"([^\"]*)\";"
\"([^\"]+)\"
匹配- 开场
"
[^\"]+
除引号外的任意数量的字符。将+
更改为*
以允许空字符串。- 收盘
"
- 开场
代码
let lineContent = "\"key\" = \" Χρήση παλιάς συνόμευση\";"
if let r = try? NSRegularExpression(pattern: "\"([^\"]+)\"[ ]*=[ ]*\"([^\"]*)\";", options: NSRegularExpressionOptions()) {
let match = r.matchesInString(
lineContent,
options: NSMatchingOptions(),
range: NSMakeRange(0, lineContent.characters.count)
)
for index in 1..<match[0].numberOfRanges {
print((lineContent as NSString).substringWithRange(match[0].rangeAtIndex(index)))
}
}