Ruby заменяет только первое вхождение нескольких регулярных выражений, передаваемых как хэш
У меня есть абзац текста и я хочу только Руби sub
первое регулярное соответствие слова. Это было бы прекрасно, если бы я только должен был соответствовать одной строке, но я передаю несколько регулярных выражений в мой sub:
regex = Regexp.new(["Lebron James", "Chris Paul"].join("|"))
names_hash = {"Lebron James" => "**Lebron James**", "Chris Paul" => "**Chris Paul**"}
str = "of the best players left in the playoffs, Lebron James is the most experienced player left in the field and probably in all of the league. Chris Paul has played in many playoff games but has never been to a conference final. Lebron James on the other hand, has been to seven straight NBA finals."
Если я запускаю str.gsub(regex, names_hash)
, все экземпляры Леброна Джеймса и Криса Пола заменяются на:
" из лучших игроков, оставшихся в плей-офф, Леброн Джеймс является самым опытный игрок вышел на поле и, наверное, во всех лига. Крис Пол имеет играл во многих играх плей-офф, но никогда был на финале конференции. Леброн Джеймс с другой стороны, был до семи финалов НБА подряд."
И если я запускаю str.sub(regex, names_hash)
(sub вместо gsub), я получаю только первое появление Леброна Джеймса, но не Криса Пола:
" из лучших игроков, оставшихся в плей-офф, Леброн Джеймс является самым опытный игрок вышел на поле и, наверное, во всех лига. Крис Пол играл во многих фильмах. плей-офф игры, но никогда не было к финалу конференции. Леброн Джеймс, с другой стороны, побывал в семь финалов подряд в НБА."
Мой вопрос:
Как мне настроить то, что у меня есть, чтобы я мог заменить как первый экземпляр Леброна Джеймса, так и Криса Пола, но не вторую ссылку Леброна Джеймса? Мой ожидаемый результат:
" из лучших игроков, оставшихся в плей-офф, Леброн Джеймс является самым опытный игрок вышел на поле и наверняка во всех лига. Крис Пол играл во многих играх плей-офф, но никогда не был к финалу конференции. Леброн Джеймс, с другой стороны, побывал в семь финалов подряд в НБА."
3 ответа:
Как насчет:
regex = Regexp.new(["Lebron James", "Chris Paul"].join("|")) names_hash = {"Lebron James" => "**Lebron James**", "Chris Paul" => "**Chris Paul**"} str = "of the best players left in the playoffs, Lebron James is the most experienced player left in the field and probably in all of the league. Chris Paul has played in many playoff games but has never been to a conference final. Lebron James on the other hand, has been to seven straight NBA finals." str.gsub(regex) { |name| names_hash.delete(name) || name }
Это будет считываться из
Обратите внимание, что этот подход мутирует исходныйnames_hash
только для первой замены; после этогоgsub
будет "по умолчанию" не вносить никаких изменений.names_hash
- так что вам может понадобитьсяdup
заранее, если переменная понадобится позже.
Одним из вариантов было бы вызывать
sub
отдельно для каждого имени в последовательности.Кроме того, вы можете использовать форму блока
gsub
, чтобы отслеживать, какие имена вы уже выделили:names_seen = [] regex = Regexp.union(["Lebron James", "Chris Paul"]) str = .. str.gsub(regex) do |name| if names_seen.include?(name) name # not the first; replace with itself else names_seen << name # remember "**#{name}**" # or use `names_hash[name]` if needed end end
Хотя ответ Тома Лордса хорош, я хочу показать вам другой способ решения вашей проблемы. Мое решение включает в себя вызов строка#sub столько раз, сколько у вас есть имен.
str = 'of the best players left in the playoffs, Lebron James is the most experienced player left in the field and probably in all of the league. Chris Paul has played in many playoff games but has never been to a conference final. Lebron James on the other hand, has been to seven straight NBA finals.' names = ['Lebron James', 'Chris Paul']
Оригинальный ответ
replacements = names.map { |name| "**#{name}**" } replacements = names.zip(replacements) replacements.inject(str) { |str, args| str.sub(*args) }
Как мудасобва указал в комментариях , Карта # / #zip может быть излишним. Вместо этого вы можете просто запустить следующее:
names.inject(str) { |str, name| str.sub(name, "**#{name}**") }
Возвращает
" из лучших игроки, оставшиеся в плей-офф, Леброн Джеймс - самый опытный игрок, оставшийся на поле и, вероятно, во всей лиге. Крис Пол участвовал во многих играх плей-офф, но никогда не был в финале конференции. Леброн Джеймс, с другой стороны, был в семи подряд НБА финалы."
Ссылки