Ruby remplace la chaîne par le modèle de regex capturé

121

J'ai du mal à traduire cela en Ruby.

Voici un morceau de JavaScript qui fait exactement ce que je veux faire:

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

J'ai essayé gsub , sub et replace mais aucun ne semble faire ce que j'attends.

Voici des exemples de choses que j'ai essayées:

"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
la source
Vous devez afficher le code réel de ce que vous avez essayé.
Ambre
@Amber j'ai mis l'échantillon que j'ai essayé.
JD Isaacks

Réponses:

192

Essayez '\1'le remplacement ( les guillemets simples sont importants, sinon vous devez échapper à \):

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

Mais comme vous ne semblez être intéressé que par le groupe de capture, notez que vous pouvez indexer une chaîne avec une expression régulière:

"foo"[/oo/]
#=> "oo"
"Z_123: foobar"[/^Z_.*(?=:)/]
#=> "Z_123"
Michael Kohl
la source
68
Notez que cela ne fonctionne que si la chaîne de remplacement est entre guillemets simples . J'ai perdu 5 minutes à comprendre cela.
Vicky Chijwani
7
@MarkThomas - souvent, nous essayons d'abord la réponse supérieure / acceptée sans lire l'intégralité des réponses. Cela semble généralement être le moyen le plus efficace de résoudre un problème. Donnez une pause à Vicky! :)
Josh M.
@VickyChijwani Bon commentaire, mais notez également que lors de l'utilisation de Ruby en ligne (sur la ligne de commande avec -e), il est plus probable de voir des guillemets doubles : printf "Punkinhead the name" | ruby -ne 'puts gsub /.*(the name)/, "Jonathans \\1"'parce que l'expression fournie à -eest généralement entourée de guillemets simples.
Jonathan Komar
Comment faire cela pour toutes les occurrences de motif dans la chaîne?
Jagdeep Singh
1
@JagdeepSingh, It, par défaut, remplace toutes les occurrences.
Iulian Onofrei
36

\1entre guillemets doit être échappé. Alors tu veux non plus

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

ou

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

voir la documentation sur gsub où il est dit "S'il s'agit d'une chaîne entre guillemets, les deux références arrière doivent être précédées d'une barre oblique inverse supplémentaire."

Cela étant dit, si vous voulez juste le résultat du match, vous pouvez faire:

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

ou

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

Notez que le (?=:)est un groupe non capturant afin que le :n'apparaisse pas dans votre correspondance.

Mark Thomas
la source
14
 "foobar".gsub(/(o+)/){|s|s+'ball'}
 #=> "fooballbar"
gaurav.singharoy
la source
4
Je ne savais pas que je pouvais faire ça. Agréable!
vreen
5

Si vous devez utiliser une expression régulière pour filtrer certains résultats, et ALORS utiliser uniquement le groupe de capture, vous pouvez effectuer les opérations suivantes:

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

$ les variables ne sont définies que pour les correspondances dans le bloc:

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

C'est également la seule façon d'appeler une méthode sur la correspondance. Cela ne changera pas la correspondance, seulement strip"\ 1" (en le laissant inchangé):

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