Как получить неопределенное количество захватов в регулярном выражении?

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

Вот регулярное выражение, которое я сейчас использую:

(?<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 regex.

1 ответ

Решение

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

Вам нужно разделить второй захват с , как шаг после процесса.

Смотрите демо Ruby:

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("+")              # => {"+"=>""}
Другие вопросы по тегам