2013-03-26 9 views
10

że mam wyrażenie: „Hey”Jak zmienić wielkość liter w ciągu znaków przy użyciu regex w Ruby

Chcę konwertować do „Hey”

string.gsub!(/([a-z])([A-Z]+)/, '\1'.upcase) 

To jest pomysł mam , ale wygląda na to, że metoda upcase nic nie robi, gdy używam jej w ramach metody gsub. Dlaczego?

EDIT: wymyśliłem tej metody:

string.gsub!(/([a-z])([A-Z]+)/) { |str| str.downcase!.capitalize! } 

Czy istnieje sposób, aby to zrobić w regex chociaż? Naprawdę nie rozumiem rzeczy '\ 1' '\ 2'. Czy to jest backreferencing? Jak to działa

Odpowiedz

8

@sawa Posiada prostą odpowiedź, a ty edytować swoje pytanie z innego mechanizmu. Jednak, aby odpowiedzieć na dwa z twoich pytań:

Czy jest jakiś sposób zrobienia tego w regex chociaż?

Nie, regex Ruby nie obsługuje funkcję przypadku zmieniających się jak some other regex flavors do. można "udowodnić" to do siebie, przeglądając oficjalne Ruby docs regex dla 1,9 i 2,0 oraz poszukiwanie słowo "przypadek":

I don Naprawdę rozumiemy sprawę \ "\ 1". Czy to jest backreferencing? Jak to działa?

Twoje wykorzystanie numeru \1 jest rodzajem backreferencji. Odniesienie zwrotne może być, gdy używasz \1 i takich w wzorcu wyszukiwania. Na przykład wyrażenie regularne /f(.)\1/ znajdzie literę f, po której następuje dowolny znak, po którym następuje ta sama postać (na przykład "foo" lub "f !!").

W tym przypadku w ciągu zastępującym przekazywany do metody takiej jak String#gsub, odwołanie zwrotne odnosi się do poprzedniego przechwytywania. Od docs:

„Jeśli wymiana jest String zostanie on zastąpiony dopasowanego tekstu może zawierać powrotem odniesień do grup przechwytujących wzorca za formularza \d, gdzie d jest numer grupy lub \k<n>. , gdzie n jest nazwą grupy.Jeśli jest to łańcuch podwójnie cytowany, oba odniesienia wstecz muszą być poprzedzone dodatkowym ukośnikiem odwrotnym."

W praktyce oznacza to:.

"hello world".gsub(/([aeiou])/, '_\1_') #=> "h_e_ll_o_ w_o_rld" 
"hello world".gsub(/([aeiou])/, "_\1_") #=> "h_\u0001_ll_\u0001_ w_\u0001_rld" 
"hello world".gsub(/([aeiou])/, "_\\1_") #=> "h_e_ll_o_ w_o_rld" 

Teraz trzeba zrozumieć, gdy kod jest uruchamiany w oryginalnym kodzie ...

string.gsub!(/([a-z])([A-Z]+)/, '\1'.upcase) 

... co robisz dzwoni upcase na łańcuchu '\1' (bez efektu) i , następnie, wywołując metodę gsub!, przekazując wyrażenie i ciąg znaków jako p arametry.

Wreszcie kolejny sposób, aby osiągnąć ten sam cel jest w postaci bloku tak:

# Take your pick of which you prefer: 
string.gsub!(/([a-z])([A-Z]+)/){ $1.upcase << $2.downcase } 
string.gsub!(/([a-z])([A-Z]+)/){ [$1.upcase,$2.downcase].join } 
string.gsub!(/([a-z])([A-Z]+)/){ "#{$1.upcase}#{$2.downcase}" } 

W postaci bloku gsub złapanych wzory są do zmiennych globalnych $1, $2, itd. I możesz ich użyć do skonstruowania zastępczego ciągu znaków.

+0

, więc znaki dolara są tym, w jaki sposób się wycofujesz w formularzu blokowym? – ordinary

+0

. Po dopasowaniu wyrażenia regularnego Ruby aktualizuje zmienne globalne "$ 1" i inne. Po prostu są dostępne w formie bloku oprócz innych lokalizacji. – Phrogz

10

nie wiem dlaczego starasz się zrobić to w sposób skomplikowany, ale zwykle sposobem jest:

"hEY".capitalize # => "Hey" 

Jeśli upierasz się przy użyciu regex i upcase, wtedy musiałaby również downcase:

"hEY".downcase.sub(/\w/){$&.upcase} # => "Hey" 
7

Jeśli naprawdę chcesz po prostu zamienić wielkość liter każdej litery w łańcuchu, możesz całkowicie uniknąć złożoności wyrażenia regularnego, ponieważ There's A Method For That ™.

"hEY".swapcase # => "Hey" 
"HellO thERe".swapcase # => "hELLo THerE" 

Jest też swapcase! zrobić to destrukcyjnie.

Powiązane problemy