Ruby Regex评估仅适用一次

时间:2015-10-19 15:10:02

标签: ruby regex

我正在使用ruby设计一个工具来根据提供的正则表达式映射解析文件中的数据。我设计了一个用于解析表声明语句的正则表达式,如下所示:

 Employees(INTEGER ID UNIQUE AUTOINCREMENT, TEXT NAME, TEXT POSITION);
 Sales(INTEGER ID, INTEGER EMP_ID, REAL MONEY, TEXT DATE);

当我尝试使用正则表达式和下面提供的方法解析包含此数据的文件时,它似乎只解析Employees表的数据,而不是Sales表。此外,如果我在Employees和Sales之间添加一行,那么它将停留在 matchdata = regex.match行 行:

Employees(INTEGER ID UNIQUE AUTOINCREMENT, TEXT NAME, TEXT POSITION);
Customers(INTEGER ID UNIQUE AUTOINCREMENT, TEXT NAME, TEXT DATA, TEXT PURCHASE_ID);
Sales(INTEGER ID, INTEGER EMP_ID, REAL MONEY, TEXT DATE);

这是正在使用的正则表达式:

(?<name>[a-zA-Z0-9_]+)\((?<parameters>(?:[\s,]*[a-zA-Z]+\s*)+)(?:\);)

这是我的测试程序:

require_relative '../main/regex_data_parser.rb'

parser = RegexParser.new
parser.add_regex('Sqlite_Table', /(?<name>[a-zA-Z0-9_]+)\((?<parameters>(?:[\s,]*[a-zA-Z]+\s*)+)(?:\);)/)
ddl_file = ARGV[0]
if ddl_file.length < 1 then
  puts 'No Input File provided.'
else
  parser.parse_file ddl_file
  parser.print_debug
end

这是我用来解析数据的方法(从RegexParser调用):

#Parses file for data based on the provided regex.
def parse_file(file)
  #Exit the method with an error code of -1 if the regex is null
  if @regex_mappings.nil? || @regex_mappings.empty? then
    return -1
  end

  #Traverses the file, scanning for data
  @data_mappings = {}
  File.foreach(file) do |line|
    puts 'Scanning: ' + line
    #Assembles matchdata
    @regex_mappings.each do |obj_name, regex|
      puts 'Assembling matchdata for ' + obj_name
      matchdata = regex.match line  
      puts 'Matchdata assembled'
      if !matchdata.nil? then
        puts 'Found match data. Finding names of captured groups.'
        #Retrieves names of matched capture groups
        keys = matchdata.names
         if !keys.nil? then
           puts 'Found matched groups. Finding attributes'
           #Initializes mappings for this key
           if !@data_mappings.key? obj_name then
             puts 'Initialize object array: ' + obj_name
             @data_mappings[obj_name] = []
           end

           #Initializes the line data array
           line_data = []
           keys.each do |key|
             #Finds the value of each matched capture group on this line.
             value = matchdata[key]
             #Adds the mapping to the line data array
             line_data << [key, value]
           end

           #Maps the line data to the name of the regex being used
           @data_mappings[obj_name] << line_data
        end
      end
    end
  end

  return 0
end

我希望能够根据提供的带有命名捕获组的正则表达解析每一行,并存储相对于正则表达式的指定名称的数据。对于此示例,应该有一个哈希表,其中包含键“Sqlite_Table”的条目,该键包含一个子数组数组。这些子数组表示从文件中解析的数据对象,它们包含元组数组,包含捕获组的名称和捕获的值(这些元组表示对象属性)。

非常感谢任何见解。

1 个答案:

答案 0 :(得分:0)

问题源于这个表达式(?:[\s,]*[a-zA-Z]+\s*)+
对于引擎来说太复杂了。回溯路径太多了。

如果将其更改为(?:[\s,]*[a-zA-Z]\s*)+,则可以使用。

但是,唯一要做的就是确保至少有一个 字母字符,它不会使用逗号强制执行任何形式。

如果您不关心字母或逗号,可以使用它。

 # (?<name>[a-zA-Z0-9_]+)\((?<parameters>[a-zA-Z\s,]+)\)\;

 (?<name> [a-zA-Z0-9_]+ )      # (1)
 \(
 (?<parameters>                # (2 start)
      [a-zA-Z\s,]+ 
 )                             # (2 end)
 \)\;

但是,如果你关心表格,你至少想要一个阿尔法 在逗号之间,您可以使用修改后的展开循环方法,如此

 # (?<name>[a-zA-Z0-9_]+)\((?<parameters>(?:\s*[a-zA-Z])+(?:,(?:\s*[a-zA-Z])+)*\s*)\)\;

 (?<name> [a-zA-Z0-9_]+ )      # (1)
 \(
 (?<parameters>                # (2 start)
      (?:
           \s* 
           [a-zA-Z] 
      )+
      (?:
           ,
           (?:
                \s* 
                [a-zA-Z] 
           )+
      )*
      \s* 
 )                             # (2 end)
 \)\;