2015-10-19 5 views
0

Я разрабатываю инструмент в рубине для анализа данных из файла на основе предоставленных регулярных выражений. Я разработал регулярное выражение для операторов декларации синтаксического анализа таблицы, подобные этим:Ruby Regex Evaluation работает только один раз

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

При попытке разобрать файл, содержащий эти данные, используя регулярные выражения и метод, предоставленный ниже, кажется, только для анализа данных для сотрудников таблицу, а не таблицу продаж. Кроме того, если добавить линию между сотрудниками и продаж, как это так, то застрянет на 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 

А вот метод я использую для анализа данных (калла d от 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 [email protected]_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», которая содержит массив подмассивов. Эти подмассивы представляют собой объекты данных, которые анализируются из файла, и они полны массивов кортежей, содержащих имя захваченной группы и зафиксированное значение (эти кортежи представляют атрибуты объекта).

Любое понимание очень ценится.

+0

использование двух пространств для отступы в рубиновом коде, не более/менее/вкладки и т. д. –

+1

Недопустимое подчеркивание в вашем классе символов. Поскольку в стороне использование квантификатора '{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) 
\)\; 
Смежные вопросы