Разбор строк отдельных слов и групп слов внутри кавычек с использованием регулярных выражений в Ruby - PullRequest
0 голосов
/ 13 октября 2010

Я пытаюсь выяснить, как лучше разобрать строки текста, значения которых выглядят следующим образом:

line1  
'Line two' fudgy whale 'rolly polly'  
fudgy 'line three' whale  
fudgy whale 'line four'  
'line five' 'fish heads' 
line six  

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

Желаемый вывод :

["line1"]
["Line two", "fudgy", "whale", "rolly polly"]
["fudgy", "line three", "whale"]
["fudgy", "whale", "line four"]
["line five", "fish heads"]
["line", "six"]

Чтение строк уже обрабатывается для меня через Cucumber.Каждая строка читается как одно строковое значение, и я хочу разобрать отдельные слова и любое количество слов, содержащихся в одинарных кавычках.Я почти ничего не знаю о регулярных выражениях, но я собрал воедино регулярное выражение, используя регулярное выражение "или" оператор ("|"), которое сблизило меня.

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

text_line.split(/(\w+)|'(.*?)'/)

В результате были получены следующие, менее приемлемые массивы:

["", "line1"]
["", "Line two", " ", "fudgy", " ", "whale", " ", "rolly polly"]
["", "fudgy", " ", "line three", " ", "whale"]
["", "fudgy", " ", "whale", " ", "line four"]
["", "line five", " ", "fish heads"]
["", "line", "", "six"]

Затем я попытался использовать сканирование вместо разбиения и увидел следующее:

text_line.scan(/(\w+)|'(.*?)'/)
[["line1", nil]]
[[nil, "Line two"], ["fudgy", nil], ["whale", nil], [nil, "rolly polly"]]
[["fudgy", nil], [nil, "line three"], ["whale", nil]]
[["fudgy", nil,], ["whale", nil], [nil, "line four"]]
[[nil, "line five"], [nil, "fish heads"]]
[["line", nil], [nil, "six",]]

Таким образом, я мог видеть, что оператор регулярного выражения "или" производил значение для каждой возможной "или" позиции, которая имела смысл.Зная, что я понял, я могу использовать сканирование, выравнивание и сжатие, чтобы очистить его, давая мне желаемый вывод :

text_line.scan(/(\w+)|'(.*?)'/).flatten.compact
["line1"]
["Line two", "fudgy", "whale", "rolly polly"]
["fudgy", "line three", "whale"]
["fudgy", "whale", "line four"]
["line five", "fish heads"]
["line", "six"]

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

Итак, можно ли использовать одно регулярное выражение для анализавыше линий и получить желаемый результат ?Возможно, я с самого начала отстранен от регулярных выражений, но я думаю, мог бы я просто как-то сгруппировать или, чтобы они возвращали только одно значение на группу, которое, вероятно, было бы тем, что я ищу.

Пожалуйстане стесняйтесь предлагать альтернативные решения, но Я ищу элегантные решения, сделанные Ruby , так как я пытаюсь научить себя, как использовать язык.

Заранее спасибо за ваше время

отредактировано для включения более точного регулярного выражения тининфи

Ответы [ 3 ]

1 голос
/ 13 октября 2010

Если вы хотите получить массив массивов разного размера, вы можете сделать это в два этапа: .split и .scan. В вашем случае .scan имеет () с двух сторон от |, поэтому у вас проблемы с nil (что должно быть полезно, но не в вашем случае). Таким образом, вы должны либо использовать .flatten.compact, либо добавить третий шаг .delete.

text.split("\n").map{|i|p i.scan(/'([^']+)'|(\w+)/).flatten.compact}
text.split("\n").map{|i|p i.scan(/'[^']+'|\w+/).map{|i|i.delete "'"}}
0 голосов
/ 20 августа 2013

У меня есть чувство, что вам все еще не нравится это, но это самое близкое к "единственному регулярному выражению", которое я мог бы придумать:

text_line.scan(/(?<=')(?:[^\s][^']*)(?=')|(?:\w+)/)

Это ломается, если вводимый текстсодержит слово в кавычках, начинающееся с пробела.

0 голосов
/ 14 октября 2010

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

'(.*?)'|(\w+)

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

'quote one' 'quote two'

Ниже было отклонено как менее элегантное, чем оригинальное решение.
Вы можете попробовать:

regex = %r((\w+)|(?:')([^"\r\n]*)(?:'))
text.split(regex).delete_if { |x| x.strip.empty? }

...