Ruby zamienia łańcuch na przechwycony wzorzec wyrażenia regularnego

121

Mam problem z przetłumaczeniem tego na język Ruby.

Oto fragment JavaScript, który robi dokładnie to, co chcę:

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

Próbowałem gsub , sub i replace, ale żaden nie wydaje się robić tego, czego oczekuję.

Oto przykłady rzeczy, których próbowałem:

"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
źródło
Powinieneś pokazać rzeczywisty kod tego, co próbowałeś.
Amber
@Amber Położyłem próbkę, którą próbowałem.
JD Isaacks

Odpowiedzi:

192

Spróbuj '\1'zamiany ( pojedyncze cudzysłowy są ważne, w przeciwnym razie musisz uciec \):

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

Ale ponieważ wydaje się, że interesuje Cię tylko grupa przechwytywania, zwróć uwagę, że możesz zindeksować ciąg za pomocą wyrażenia regularnego:

"foo"[/oo/]
#=> "oo"
"Z_123: foobar"[/^Z_.*(?=:)/]
#=> "Z_123"
Michael Kohl
źródło
68
Zauważ, że działa to tylko wtedy, gdy zastępujący ciąg znajduje się w apostrofach . Zmarnowałem 5 minut, zastanawiając się nad tym.
Vicky Chijwani
7
@MarkThomas - często staramy się najpierw sprawdzić najlepszą / zaakceptowaną odpowiedź bez czytania całości odpowiedzi. Wydaje się, że jest to najskuteczniejszy sposób rozwiązania problemu. Daj Vicky spokój! :)
Josh M.
@VickyChijwani Dobry komentarz, ale pamiętaj również, że gdy używasz Ruby inline (w wierszu poleceń z -e), jest bardziej prawdopodobne, że zobaczysz podwójne cudzysłowy : printf "Punkinhead the name" | ruby -ne 'puts gsub /.*(the name)/, "Jonathans \\1"'ponieważ wyrażenie dostarczane do -ejest zwykle zawijane w pojedyncze cudzysłowy.
Jonathan Komar
Jak to zrobić dla wszystkich wystąpień wzorca w ciągu?
Jagdeep Singh
1
@JagdeepSingh, domyślnie zastępuje wszystkie wystąpienia.
Iulian Onofrei,
36

\1w cudzysłowie muszą zostać zmienione. Więc ty też chcesz

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

lub

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

zobacz dokumentację na gsub, gdzie jest napisane: "Jeśli jest to ciąg znaków w podwójnych cudzysłowach, oba odniesienia wsteczne muszą być poprzedzone dodatkowym ukośnikiem odwrotnym."

Biorąc to pod uwagę, jeśli chcesz tylko wyniku meczu, możesz zrobić:

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

lub

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

Zwróć uwagę, że nie (?=:)jest to grupa do przechwytywania, więc :nie pojawia się ona w Twoim meczu.

Mark Thomas
źródło
14
 "foobar".gsub(/(o+)/){|s|s+'ball'}
 #=> "fooballbar"
gaurav.singharoy
źródło
4
nie wiedziałem, że mogę to zrobić. Miły!
vreen
5

Jeśli potrzebujesz użyć wyrażenia regularnego do odfiltrowania niektórych wyników, a WTEDY użyj tylko grupy przechwytywania, możesz wykonać następujące czynności:

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"
zrzęda
źródło
2
def get_code(str)
  str.sub(/^(Z_.*): .*/, '\1')
end
get_code('Z_foo: bar!') # => "Z_foo"
maerics
źródło
0

$ zmienne są ustawiane tylko tak, aby pasowały do ​​bloku:

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

Jest to również jedyny sposób na wywołanie metody w dopasowaniu. Nie zmieni to dopasowania, tylko strip„\ 1” (pozostawiając bez zmian):

"Z_sdsd: sdsd".gsub(/^(Z_.*): .*/, "\\1".strip)
Lisapple
źródło