Как изменить регистр букв в строке с помощью RegEx в Ruby

Скажем, у меня есть строка: "hEY"

Я хочу преобразовать его в "Привет"

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

Это та идея, которая у меня есть, но кажется, что метод upcase ничего не делает, когда я использую его в методе gsub. Почему это?

EDIT: я придумал этот метод:

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

Есть ли способ сделать это в регулярном выражении? Я действительно не понимаю вещь \\ ''\2 '. Это обратная связь? Как это работает

Ответ 1

@sawa Простой ответ, и вы отредактировали свой вопрос другим механизмом. Однако, чтобы ответить на два из ваших вопросов:

Есть ли способ сделать это в регулярном выражении?

Нет, Ruby regex не поддерживает функцию изменения регистра, как некоторые другие варианты regex. Вы можете "доказать" это себе, просмотрев официальные документы регулярного выражения Ruby для 1.9 и 2.0 и поиская слово "случай":

Я действительно не понимаю вещь '\ 1' '\ 2'. Это обратная связь? Как это работает?

Ваше использование \1 - это своего рода обратная связь. Если вы используете \1 и т.д. В шаблоне поиска, может быть обратная ссылка. Например, регулярное выражение /f(.)\1/ найдет букву f, за которой следует любой символ, за которым следует тот же самый символ (например, "foo" или "f!!" ).

В этом случае в заменяющей строке, переданной методу типа String#gsub, обратная ссылка относится к предыдущему захвату. Из документов:

"Если замена является строкой, она будет заменена совпадающим текстом. Она может содержать обратные ссылки на группы захвата шаблонов формы \d, где d - номер группы или \k<n>, где n - это имя группы. Если это строка с двумя кавычками, обе обратные ссылки должны предшествовать дополнительной обратной косой чертой."

На практике это означает:

"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"

Теперь вам нужно понять, когда выполняется код. В вашем исходном коде...

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

... то, что вы делаете, вызывает upcase в строке '\1' (которая не имеет никакого эффекта), а затем вызывает метод gsub!, передавая в регулярное выражение и строку в качестве параметров.

Наконец, еще один способ достижения этой же цели состоит в том, что блочная форма выглядит так:

# 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}" }

В блочной форме gsub захваченные шаблоны устанавливаются на глобальные переменные $1, $2 и т.д., и вы можете использовать их для построения строки замены.

Ответ 2

Я не знаю, почему вы пытаетесь сделать это сложным способом, но обычный способ:

"hEY".capitalize # => "Hey"

Если вы настаиваете на использовании регулярных выражений и upcase, вам также понадобится downcase:

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

Ответ 3

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

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

Там также swapcase! сделать это разрушительно.