2016-11-08 13 views
1

Я делаю простой стековый язык, который использует команды для управления стеком. Когда я нахожу команду в источнике, я использую это регулярное выражение для выделения фактического имени команды, например sum, и аргументов команды. Аргументы окружены треугольными скобками и разделяются запятыми.Как получить неопределенное количество захватов в регулярном выражении?

Вот регулярное выражение настоящее время я использую:

(?<command>[^<>\s]+)(\<(?<args>(\d+)+(?>,\s*\d+)*)\>)? 

Теперь это работает отлично, а вот некоторые примеры его работы:

+    => command: '+', args: nil 
sum<5>   => command: 'sum', args: '5' 
print<1, 2, 3> => command: 'print', args: '1, 2, 3' 

Это работает точно так, как я хочу для каждого из них но последнее. Мой вопрос в том, есть ли способ захватить каждый аргумент отдельно? Я имею в виду вот так:

print<1, 2, 3> => command: 'print', args: ['1', '2', '3'] 

Кстати, я использую последний механизм регулярных выражений Ruby.

+1

Нет, с помощью простого регулярного выражения с повторяющимися группами захвата не будет работать таким образом. Вам нужно разделить второй захват с помощью ',' как шаг после процесса. Ruby regex engine не сохраняет стек захвата. –

+0

Это позор - спасибо, в любом случае – Zac

+1

Очень немного ароматов регулярных выражений имеют поддержку стека группы захвата, только по умолчанию поддерживают модуль регулярных выражений .NET и Python PyPi. Близким рисунком будет ['/ (?: \ G (?! \ A), \ s * | (? [^ <> \ s] +) <)(? \ d +) /'] (http: // rubular. com/r/BDocFayOkZ), но он использует множественное сопоставление, и если на входе имеется более одного ввода, возможно, возникнут проблемы с их разграничением. –

ответ

1

Невозможно получить такой вывод с использованием простого регулярного выражения с повторяющимися группами захвата в регулярном выражении Ruby, так как движок не сохраняет стек захвата.

Вам необходимо разделить второй захват с помощью , в качестве этапа после обработки.

См Ruby demo:

def cmd_split(s) 
    rx = /(?<command>[^<>\s]+)(<(?<args>(\d+)+(?:,\s*\d+)*)>)?/ 
    res = [] 
    s.scan(rx) { 
     res << ($~[:args] != nil ? 
      Hash["command", $~[:command], "args", $~[:args].split(/,\s*/)] : 
      Hash[$~[:command], ""]) } 
    return res 
end 

puts cmd_split("print<1, 2, 3>") # => {"command"=>"print", "args"=>["1", "2", "3"]} 
puts cmd_split("disp<1>")  # => {"command"=>"disp", "args"=>["1"]} 
puts cmd_split("+")    # => {"+"=>""}