用正则表达式缓慢解析

Ede*_*der 0 ruby regex parsing jruby token

我有以下正则表达式用于数据验证:

lexer = /(?:
      (.{18}|(?:.*)(?=\s\S{2,})|(?:[^\s+]\s){1,})\s*
      (.{18}|(?:.*)(?=\s\S{2,})|(?:[^\s+]\s){1,})\s*
      (?:\s+([A-Za-z][A-Za-z0-9]{2}(?=\s))|(\s+))\s*
      (Z(?:RO[A-DHJ]|EQ[A-C]|HIB|PRO|PRP|RMA)|H(?:IB[2E]|ALB)|F(?:ER[2T]|LUP2|ST4Q))\s*
      (\S+)\s*
      (\S+)\s*
      (\S+)\s*
      (\S+)\s*
      (\S+)\s*
      (\S+)\s*
      (\S+)\s*
      (\S+)\s*
      (\S+)\s*
      (\S+)\s*
      (\S+)\s*
      (\S+)\s*
      (\S+)\s*
      (\S+)\s*
      (\S+)\s*
      (\s+\d{10}|\s+)\s*
      (\d{6})\s*
      (.*)(?=((?:\d{2}\/){2}\d{4}))\s*
      ((?:\d{2}\/){2}\d{4})\s*
      (\S+)
    )/x
Run Code Online (Sandbox Code Playgroud)

问题是我必须遍历10000行(平均值)的文件,使用正则表达式执行验证,从而导致解析缓慢的应用程序.

  filename = File.new(@file, "r")
  filename.each_line.with_index do |line, index|
    next if index < INFO_AT + 1

    lexer = /(?:
      (.{18}|(?:.*)(?=\s\S{2,})|(?:[^\s+]\s){1,})\s*
      (.{18}|(?:.*)(?=\s\S{2,})|(?:[^\s+]\s){1,})\s*
      (?:\s+([A-Za-z][A-Za-z0-9]{2}(?=\s))|(\s+))\s*
      (Z(?:RO[A-DHJ]|EQ[A-C]|HIB|PRO|PRP|RMA)|H(?:IB[2E]|ALB)|F(?:ER[2T]|LUP2|ST4Q))\s*
      (\S+)\s*
      (\S+)\s*
      (\S+)\s*
      (\S+)\s*
      (\S+)\s*
      (\S+)\s*
      (\S+)\s*
      (\S+)\s*
      (\S+)\s*
      (\S+)\s*
      (\S+)\s*
      (\S+)\s*
      (\S+)\s*
      (\S+)\s*
      (\S+)\s*
      (\s+\d{10}|\s+)\s*
      (\d{6})\s*
      (.*)(?=((?:\d{2}\/){2}\d{4}))\s*
      ((?:\d{2}\/){2}\d{4})\s*
      (\S+)
    )/x

    m = lexer.match(line)
    begin
      if (m) then ...
Run Code Online (Sandbox Code Playgroud)

编辑 在这里,您可以找到我需要解析的一些行:文件

编辑II @Mike R.

我正在解析每行包含25列的文件,每列可能有自己的验证方式.它可以是空格或完整的字符集.

  • 验证是必需的,因为我必须删除与那种部分不匹配的行.
  • 可能没有必要
  • 这是必要的

我不相信它的构造很糟糕,它使用的前瞻,可能在我重复代码的部分(我只是不记得捕获组索引\ 1 ... \n,如果这是你的意思意思是!)我也相信灾难性的回溯正在这里发生.

如果你看到这个文件,也许你会明白为什么我这样做!我们以第一列为例.我必须匹配"部件号",我没有任何关于如何执行此操作的规则,示例:

  • 123456789
  • 1 555 989
  • 0123456789123456789

简单的\ S +或(\ S +\s){1,}都不能解决这个问题,因为我不会保证数据的完整性.

泰!

任何改进,建议?

~EderQuiñones

Dig*_*oss 5

  1. 正则表达式在循环中不会改变,因此将lexer =分配拉出循环.("循环不变代码运动.")

  2. 我不确定这会更快还是更慢,但重复的子表达式可能只是一个外部重复组.

  3. 所以这很明显,我敢肯定,但编写一个真正的解析器可能是有意义的.Ruby有一个名为Treetop的高级PEG解析器生成器.传统方法是Lex + Yacc(例如flex + bison)或者只是实现扫描程序和递归下降解析器的C程序.旧学校,是的,但很容易写,从另一个CRUD程序有点变化.

  4. 我同意其他响应者的观点,表达式是不必要的多余,复杂,应该分解为至少两个单独的和更小的表达式.两个表达式可能很有趣,因为它们都可以相反地锚定.