Как сохранить разделители при разбиении строки Ruby?
У меня есть текст вроде:
content = "Do you like to code? How I love to code! I'm always coding."
Я пытаюсь разбить его на ?
или .
или !
:
content.split(/[?.!]/)
Когда я распечатываю результаты, ограничители препинания отсутствуют.
Вам нравится код
Как я люблю код
Я всегда кодирую
Как я могу сохранить пунктуацию?
Ответы
Ответ 1
Ответ
Используйте положительное выражение lookbehind (т.е. ?<=
) внутри группы захвата скобок, чтобы сохранить разделитель в конце каждой строки:
content.split(/(?<=[?.!])/)
# Returns an array with:
# ["Do you like to code?", " How I love to code!", " I'm always coding."]
Это оставляет пробел в начале второй и третьей строк. Добавьте совпадение для нуля или более пробелов (\s*
) после группы захвата, чтобы исключить его:
content.split(/(?<=[?.!])\s*/)
# Returns an array with:
# ["Do you like to code?", "How I love to code!", "I'm always coding."]
Дополнительные примечания
Хотя это не имеет смысла в вашем примере, разделитель можно смещать в начало строк, начиная со второго. Это делается с помощью позитивного регулярного выражения (т.е. ?=
). Ради кого-либо, кто ищет эту технику, вот как это сделать:
content.split(/(?=[?.!])/)
# Returns an array with:
# ["Do you like to code", "? How I love to code", "! I'm always coding", "."]
Лучшим примером для иллюстрации поведения является:
content = "- the - quick brown - fox jumps"
content.split(/(?=-)/)
# Returns an array with:
# ["- the ", "- quick brown ", "- fox jumps"]
Обратите внимание, что группа захвата квадратной скобки не нужна, поскольку существует только один разделитель. Кроме того, поскольку первое совпадение происходит с первым символом, оно заканчивается как первый элемент в массиве.
Ответ 2
Чтобы ответить на заголовок вопроса, добавление группы захвата в ваше разделенное регулярное выражение сохранит разделительные разделители:
"Do you like to code? How I love to code! I'm always coding.".split /([?!.])/
=> ["Do you like to code", "?", " How I love to code", "!", " I'm always coding", "."]
Оттуда довольно просто восстановить предложения (или сделать другое массирование, поскольку проблема вызывает его):
s.split(/([?!.])/).each_slice(2).map(&:join).map(&:strip)
=> ["Do you like to code?", "How I love to code!", "I'm always coding."]
Регулярные выражения, приведенные в других ответах, более четко выполняют тело вопроса.
Ответ 3
Используйте partition
. Пример из документации:
"hello".partition("l") #=> ["he", "l", "lo"]
Ответ 4
Я бы использовал что-то вроде:
content.scan(/.+?[?!.]/)
# => ["Do you like to code?", " How I love to code!", " I'm always coding."]
Если вы хотите избавиться от промежуточных пространств, используйте:
content.scan(/.+?[?!.]/).map(&:lstrip)
# => ["Do you like to code?", "How I love to code!", "I'm always coding."]
Ответ 5
Самый надежный способ сделать это - с библиотекой обработки естественного языка: Rails gem, чтобы разбить абзац на ряд предложений
Вы также можете разделить по группам:
@content.split(/(\?+)|(\.+)|(!+)/)
После разделения на группы вы можете присоединиться к предложению и разделителю.
@content.split(/(\?+)|(\.+)|(!+)/).each_slice(2) {|slice| puts slice.join}