В настоящее время я разделяю строку по шаблону, например:
outcome_array=the_text.split(pattern_to_split_by)
Проблема заключается в том, что сам шаблон, который я разделял, всегда опускается.
Как мне заставить его включить сам шаблон разделения?
В настоящее время я разделяю строку по шаблону, например:
outcome_array=the_text.split(pattern_to_split_by)
Проблема заключается в том, что сам шаблон, который я разделял, всегда опускается.
Как мне заставить его включить сам шаблон разделения?
Спасибо Марку Уилкинсу за глупость, но здесь более короткий код для этого:
irb(main):015:0> s = "split on the word on okay?"
=> "split on the word on okay?"
irb(main):016:0> b=[]; s.split(/(on)/).each_slice(2) { |s| b << s.join }; b
=> ["split on", " the word on", " okay?"]
или
s.split(/(on)/).each_slice(2).map(&:join)
См. ниже справку для объяснения.
Вот как это работает. Сначала мы разделим на "on", но завершим его в круглые скобки, чтобы сделать его в группу соответствия. Когда в регулярном выражении передается группа соответствия в split
, Ruby будет включать эту группу в вывод:
s.split(/(on)/)
# => ["split", "on", "the word", "on", "okay?"
Теперь мы хотим присоединиться к каждому экземпляру "on" с предыдущей строкой. each_slice(2)
помогает, передавая два элемента за раз до своего блока. Позвольте просто вызвать each_slice(2)
, чтобы увидеть, какие результаты. Поскольку each_slice
, при вызове без блока, вернет перечислитель, мы применим to_a
к Enumerator, чтобы мы могли видеть, что Enumerator перечислил:
s.split(/(on)/).each_slice(2).to_a
# => [["split", "on"], ["the word", "on"], ["okay?"]]
Мы приближаемся. Теперь нам нужно только присоединиться к словам. И это подводит нас к полному решению выше. Я развожу его в отдельные строки, чтобы было легче следовать:
b = []
s.split(/(on)/).each_slice(2) do |s|
b << s.join
end
b
# => ["split on", "the word on" "okay?"]
Но есть отличный способ устранить временный b
и значительно сократить код:
s.split(/(on)/).each_slice(2).map do |a|
a.join
end
map
передает каждый элемент своего входного массива в блок; результат блока становится новым элементом в этой позиции в выходном массиве. В МРТ >= 1,8,7 вы можете сократить его еще больше, до эквивалента:
s.split(/(on)/).each_slice(2).map(&:join)
Вы можете использовать утверждение регулярного выражения для определения точки разделения без использования какого-либо входа. Ниже приведено положительное утверждение для разделения сразу после 'on':
s = "split on the word on okay?"
s.split(/(?<=on)/)
=> ["split on", " the word on", " okay?"]
Или положительный прогноз перед разбиением непосредственно перед 'on':
s = "split on the word on okay?"
s.split(/(?=on)/)
=> ["split ", "on the word ", "on okay?"]
С чем-то подобным, вы можете захотеть убедиться, что 'on' не является частью более крупного слова (например, "утверждение" ), а также удаляет пустое пространство в расколе:
"don't split on assertion".split(/(?<=\bon\b)\s*/)
=> ["don't split on", "assertion"]
Если вы используете шаблон с группами, он также вернет шаблон в результаты:
irb(main):007:0> "split it here and here okay".split(/ (here) /)
=> ["split it", "here", "and", "here", "okay"]
Изменить. Дополнительная информация указала, что целью является включение элемента, на котором он был разделен, с одной из половин разделенных элементов. Я думаю, что есть простой способ сделать это, но я этого не знаю и сегодня не успел поиграть с ним. Таким образом, в отсутствие умного решения, это один из способов грубой силы. Используйте метод split
, как описано выше, чтобы включить разделенные элементы в массиве. Затем выполните итерацию по массиву и объедините каждую вторую запись (которая по определению является значением разделения) с предыдущей записью.
s = "split on the word on and include on with previous"
a = s.split(/(on)/)
# iterate through and combine adjacent items together and store
# results in a second array
b = []
a.each_index{ |i|
b << a[i] if i.even?
b[b.length - 1] += a[i] if i.odd?
}
print b
Результаты в этом:
["split on", " the word on", " and include on", " with previous"]