Ruby заменяет строку захваченным шаблоном регулярного выражения

121

У меня проблемы с переводом этого на Ruby.

Вот фрагмент JavaScript, который делает именно то, что я хочу:

function get_code(str){
    return str.replace(/^(Z_.*): .*/,"$1")​​​​​​​​​​​​​​​​​​​​​​​​​​​;
}

Я пробовал gsub , sub и replace, но, похоже, ни один из них не сделал того, чего я ожидал.

Вот примеры того, что я пробовал:

"Z_sdsd: sdsd".gsub(/^(Z_.*): .*/) { |capture| capture }
"Z_sdsd: sdsd".gsub(/^(Z_.*): .*/, "$1")
"Z_sdsd: sdsd".gsub(/^(Z_.*): .*/, "#{$1}")
"Z_sdsd: sdsd".gsub(/^(Z_.*): .*/, "\1")
"Z_sdsd: sdsd".gsub(/(.).*/) { |capture| capture }
Джей Ди Айзекс
источник
Вы должны показать реальный код того, что вы пробовали.
Эмбер,
@ Янтарь Я положил образец, который пробовал.
JD Isaacks

Ответы:

192

Попробуйте '\1'заменить ( одинарные кавычки важны, иначе вам нужно избежать \):

"foo".gsub(/(o+)/, '\1\1\1')
#=> "foooooo"

Но поскольку вам кажется, что вас интересует только группа захвата, обратите внимание, что вы можете индексировать строку с помощью регулярного выражения:

"foo"[/oo/]
#=> "oo"
"Z_123: foobar"[/^Z_.*(?=:)/]
#=> "Z_123"
Майкл Коль
источник
68
Обратите внимание, что это работает, только если строка замены заключена в одинарные кавычки . Я потратил 5 минут, чтобы понять это.
Вики Чижвани
7
@MarkThomas - часто мы сначала пробуем самый популярный / принятый ответ, не читая всех ответов. Как правило, это наиболее эффективный способ решения проблемы. Дайте Вики передохнуть! :)
Джош М.
@VickyChijwani Хороший комментарий, но также обратите внимание, что при использовании Ruby inline (в командной строке с помощью -e) более вероятно увидеть двойные кавычки : printf "Punkinhead the name" | ruby -ne 'puts gsub /.*(the name)/, "Jonathans \\1"'потому что выражение, предоставленное для -e, обычно заключено в одинарные кавычки.
Джонатан Комар
Как это сделать для всех вхождений шаблона в строку?
Jagdeep Singh
1
@JagdeepSingh, Он по умолчанию заменяет все вхождения.
Юлиан
36

\1в двойных кавычках нужно экранировать. Так ты хочешь

"Z_sdsd: sdsd".gsub(/^(Z_.*): .*/, "\\1")

или

"Z_sdsd: sdsd".gsub(/^(Z_.*): .*/, '\1')

см. документацию на gsub, где говорится: «Если это строка в двойных кавычках, обеим обратным ссылкам должна предшествовать дополнительная обратная косая черта».

При этом, если вам просто нужен результат матча, вы можете:

"Z_sdsd: sdsd".scan(/^Z_.*(?=:)/)

или

"Z_sdsd: sdsd"[/^Z_.*(?=:)/]

Обратите внимание, что (?=:)это не захватывающая группа, поэтому :не отображается в вашем матче.

Марк Томас
источник
14
 "foobar".gsub(/(o+)/){|s|s+'ball'}
 #=> "fooballbar"
gaurav.singharoy
источник
4
не знал, что могу это сделать. Ницца!
vreen 07
5

Если вам нужно использовать регулярное выражение для фильтрации некоторых результатов, а ЗАТЕМ использовать только группу захвата, вы можете сделать следующее:

str = "Leesburg, Virginia  20176"
state_regex = Regexp.new(/,\s*([A-Za-z]{2,})\s*\d{5,}/)
# looks for the comma, possible whitespace, captures alpha,
# looks for possible whitespace, looks for zip

> str[state_regex]
=> ", Virginia  20176"

> str[state_regex, 1] # use the capture group
=> "Virginia"
grumpit
источник
2
def get_code(str)
  str.sub(/^(Z_.*): .*/, '\1')
end
get_code('Z_foo: bar!') # => "Z_foo"
maerics
источник
0

$ переменные устанавливаются только на совпадения в блоке:

"Z_sdsd: sdsd".gsub(/^(Z_.*): .*/) { "#{ $1.strip }" }

Это также единственный способ вызвать метод для соответствия. Это не изменит совпадение, только strip"\ 1" (оставив его без изменений):

"Z_sdsd: sdsd".gsub(/^(Z_.*): .*/, "\\1".strip)
Lisapple
источник