Ruby заменяет только первое вхождение нескольких регулярных выражений, переданных как хеш - PullRequest
0 голосов
/ 23 мая 2018

У меня есть абзац текста и я хочу только Ruby 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), все экземпляры Lebron James и Chris Paul заменяются

"лучших игроков, оставшихся в плей-офф, Леброн Джеймс - самый опытный игрок, оставшийся на поле и, вероятно, во всей лиге. КрисПол играл во многих играх плей-офф, но никогда не был в финале конференции. Леброн Джеймс , с другой стороны, был в семи финалах NBA подряд. "

И если я запускаю str.sub(regex, names_hash) (sub вместо gsub), я получаю только первое появление Леброна Джеймса, но не Криса Пола:

"из лучших игроков, оставшихся в плей-офф, Леброн Джеймс - самый опытный игрок, оставшийся на поле и, вероятно, во всей лиге. Крис Пол играл во многих играх плей-офф, но никогда не был в финале конференции. С другой стороны, Леброн Джеймс был всемь подряд NBФинал. "

Мой вопрос:

Как мне настроить то, что у меня есть, чтобы я мог заменить как первый экземпляр Леброна Джеймса и Криса Пола, но не второйупоминание о Леброне Джеймсе?Мой ожидаемый результат:

"из лучших игроков, оставшихся в плей-офф, Lebron James - самый опытный игрок, оставшийся на поле и, вероятно, во всей лиге. Крис Пол играл во многих играх плей-офф, но никогда не был в финале конференции. С другой стороны, Леброн Джеймс был в семи финалах NBA подряд. "

Ответы [ 3 ]

0 голосов
/ 23 мая 2018

Как насчет:

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, если переменная потребуется позже.

0 голосов
/ 23 мая 2018

Хотя Том Лордс отвечает хорошо, я хочу показать вам другой способ решения вашей проблемы.Мое решение заключается в том, чтобы звонить String # 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) }

Как указал мудасобва в комментариях , # map / # zip может быть излишним.Вместо этого вы можете запустить следующее:

names.inject(str) { |str, name| str.sub(name, "**#{name}**") }

возвращает

"лучших игроков, оставшихся в плей-офф, Леброн Джеймс самый опытный игрок, оставшийся на поле и, вероятно, во всей лиге. Крис Пол играл во многих играх плей-офф, но никогда не был в финале конференции. С другой стороны, Леброн Джеймс былдо семи прямых финалов NBA. "

ссылки

0 голосов
/ 23 мая 2018

Один из вариантов будет вызывать 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
...