Вопрос по regex, ruby – Как разделить строку, содержащую и разделитель и экранированный разделитель?

4

Мой разделитель строк;, Разделитель экранируется в строке как\;, Например.,

irb(main):018:0> s = "a;b;;d\\;e"
=> "a;b;;d\\;e"
irb(main):019:0> s.split(';')
=> ["a", "b", "", "d\\", "e"]

Может ли кто-нибудь предложить мне регулярное выражение, чтобы вывод split["a", "b", "", "d\\;e"]? Я использую Ruby 1.8.7

Я думаю, что вы можете сделать это с помощью регулярных выражений. Смотрите этот вопросstackoverflow.com/questions/2164211/… Ismael Abreu

Ваш Ответ

2   ответа
6

1.8.7 не имеет отрицательного взгляда без Oniguruma (который может быть скомпилирован).

1.9.3; ура:

> s = "a;b;c\\;d"
=> "a;b;c\\;d"
> s.split /(?<!\\);/
=> ["a", "b", "c\\;d"]

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

> require 'oniguruma'
> re = Oniguruma::ORegexp.new "(?<!\\\\);"
> s = "hello;there\\;nope;yestho"
> re.match_all s
=> [#<MatchData ";">, #<MatchData ";">]
> mds = re.match_all s
=> [#<MatchData ";">, #<MatchData ";">]
> mds.collect {|md| md.offset}
=> [[5, 6], [17, 18]]

Другие варианты включают в себя:

  • Splitting on ; and post-processing the results looking for trailing \\, or
  • Do a char-by-char loop and maintain some simple state and just split manually.
Я реализовал свой собственный сплит с помощью цикла char-by-char (ваше второе предложение). Это работает, даже когда есть пустые поля. sv.
Дэйв, спасибо за ваши предложения. К сожалению, мы не используем самоцвет Oniguruma с Ruby 1.8.7. Я собирался попробовать другие предложенные вами варианты, но решение dbenhur'а работает для меня прямо сейчас. sv.
@svhyd Я не уверенscan не могу справиться и с этим сценарием, хотя я недостаточно знаком с ним, чтобы знать, как это сделать. Однако это один из тех случаев, когда, если у вас нет надлежащей поддержки регулярных выражений, сделайте это «вручную». ИМО приемлемо, потому что ваши потребности довольно узки. Я не уверен, что будет быстрее; зависит от того, как движок регулярных выражений реализован в 1.8.7 - если это Ruby, то сканирование вручную, вероятно, будет быстрее. Рад, что ты получил это работает!
2

Как ответил @ dave-newton, вы можете использовать отрицательный взгляд назад, но это не поддерживается в 1.8. Альтернативой, которая будет работать как в 1.8, так и в 1.9, является использованиеСтрока # сканирования вместо разделения, с шаблоном, не принимающим (точка с запятой или обратная косая черта) или anychar с префиксом обратной реакции:

$ irb
>> RUBY_VERSION
=> "1.8.7"
>> s = "a;b;c\\;d"
=> "a;b;c\\;d"
s.scan /(?:[^;\\]|\\.)+/
=> ["a", "b", "c\\;d"]
Я изменил вопрос, добавив в него пустое поле (то есть точку с запятой). sv.
На самом деле, если есть пустой; сам по себе для поляscan  не возвращает пустую строку, поэтому я теряю информацию о положении поля. Например, если исходная строкаa;;c\\;d, ваше решение возвращается["a", "c\\;d"], Есть ли способ разбить / отсканировать, где результат будет["a", "", "c\\;d"]? sv.
Спасибо, это сработало для меня. sv.

Похожие вопросы