Ruby substitui string por padrão regex capturado

121

Estou tendo problemas para traduzir isso em Ruby.

Aqui está um pedaço de JavaScript que faz exatamente o que eu quero fazer:

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

Eu tentei gsub , sub e replace, mas nenhum parece fazer o que estou esperando.

Aqui estão exemplos de coisas que tentei:

"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
fonte
Você deve mostrar o código real para o que você tentou.
27612 Amber
@ Amber Coloquei amostra que eu tentei.
JD Isaacks

Respostas:

192

Tente '\1'a substituição ( aspas simples são importantes, caso contrário você precisará escapar da \):

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

Mas como você parece estar interessado apenas no grupo de captura, observe que é possível indexar uma sequência com uma expressão regular:

"foo"[/oo/]
#=> "oo"
"Z_123: foobar"[/^Z_.*(?=:)/]
#=> "Z_123"
Michael Kohl
fonte
68
Observe que isso só funciona se a sequência de substituição estiver entre aspas simples . Eu perdi 5 minutos descobrindo isso.
Vicky Chijwani
7
@ MarkThomas - muitas vezes tentamos primeiro a resposta mais aceita / aceita sem ler a totalidade das respostas. Geralmente, esse parece ser o meio mais eficiente de corrigir um problema. Dê a Vicky uma folga! :)
Josh M.
@VickyChijwani Bom comentário, mas também observe que, ao usar o Ruby inline (na linha de comando com -e), é mais provável que haja aspas duplas : printf "Punkinhead the name" | ruby -ne 'puts gsub /.*(the name)/, "Jonathans \\1"'porque a expressão fornecida -egeralmente está entre aspas simples.
22917 Jonathan Komar
Como fazer isso para todas as ocorrências de padrão na string?
Jagdeep Singh
1
@JagdeepSingh, por padrão, substitui todas as ocorrências.
Iulian Onofrei
36

\1aspas duplas precisa ser escapado. Então você quer

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

ou

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

veja os documentos no gsub em que diz "Se for uma string com aspas duplas, as duas referências anteriores deverão ser precedidas por uma barra invertida adicional".

Dito isto, se você quiser apenas o resultado da partida, poderá:

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

ou

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

Observe que o grupo (?=:)é não capturante, para que :não apareça na sua partida.

Mark Thomas
fonte
14
 "foobar".gsub(/(o+)/){|s|s+'ball'}
 #=> "fooballbar"
gaurav.singharoy
fonte
4
não sabia que eu posso fazer isso. Agradável!
vreen
5

Se você precisar usar uma regex para filtrar alguns resultados, e ENTÃO usar apenas o grupo de captura, poderá fazer o seguinte:

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
fonte
2
def get_code(str)
  str.sub(/^(Z_.*): .*/, '\1')
end
get_code('Z_foo: bar!') # => "Z_foo"
maerics
fonte
0

$ As variáveis ​​são definidas apenas para correspondências no bloco:

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

Essa também é a única maneira de chamar um método na partida. Isso não mudará a correspondência, apenas strip"\ 1" (sem alteração):

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