【发布时间】:2014-11-21 21:35:25
【问题描述】:
我有一个 Ruby 1.8.7 脚本来解析 iOS 本地化文件:
singleline_comment = /\/\/(.*)$/
multiline_comment = /\/\*(.*?)\*\//m
string_line = /\s*"(.*?)"\s*=\s*"(.*?)"\s*\;\s*/xm
out = decoded_src.scan(/(?:#{singleline_comment}|#{multiline_comment})?\s*?#{string_line}/)
它以前可以正常工作,但今天我们用一个 800Kb 的文件对其进行了测试,并且每行末尾没有;。结果是高 CPU 负载并且 Rails 服务器没有响应。我的假设是它将整个文件作为捕获组中的单个字符串并阻塞了服务器。
解决方案是将?(正则表达式量词,0 或 1 次)添加到 ; 文字字符:
/\s*"(.*?)"\s*=\s*"(.*?)"\s*\;?\s*/xm
现在即使使用旧 iOS 格式的文件,它也能正常工作,但我现在担心的是,如果用户提交格式错误的文件,比如没有结尾的文件",该怎么办。我的服务器会再次被阻止吗?
我该如何防止这种情况发生?有什么方法可以尝试只运行五秒钟吗?我可以做些什么来避免停止我的整个 Rails 应用程序?
【问题讨论】:
-
您可以在尝试匹配正则表达式之前检查文件是否格式错误。一个简单的检查是计算
"字符的数量,看看它是偶数还是奇数。 -
关于超时,看一下Ruby的Timeout库:ruby-doc.org/stdlib-2.1.3/libdoc/timeout/rdoc/Timeout.html
-
看起来你有catastrophic backtracking 的变体(因为你有惰性量词,所以组每次都在扩大而不是变小)。很难推荐一个通用的修复方法,这取决于你的数据格式。一般来说,您最好使用正则表达式尽可能具体,在这种情况下,使用
[^"]*而不是.*?(甚至[^"]*+)在减少回溯方面会更安全。 -
计数
"不一定能说明任何有用的信息。'"1\""'.count('"') # => 3会产生误导。
标签: ruby regex ruby-1.8.7