15

假设我有一个字符串:“hEY”

我想把它转换成“嘿”

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

这就是我的想法,但是当我在 gsub 方法中使用 upcase 方法时,它似乎什么也没做。这是为什么?

编辑:我想出了这个方法:

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

有没有办法在正则表达式中做到这一点?我真的不明白 '\1' '\2' 的事情。那是反向引用吗?这是如何运作的

4

3 回答 3

15

@sawa 有一个简单的答案,你已经用另一种机制编辑了你的问题。但是,要回答您的两个问题:

有没有办法在正则表达式中做到这一点?

不,Ruby 的正则表达式不像其他一些正则表达式风格那样支持大小写更改功能。您可以通过查看 1.9 和 2.0 的官方 Ruby 正则表达式文档并搜索“case”一词来“证明”这一点:

我真的不明白 '\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"

现在,您必须了解代码何时运行。在您的原始代码中……</p>

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等,您可以使用它们来构造替换字符串。

于 2013-03-26T02:25:24.027 回答
10

我不知道您为什么要尝试以复杂的方式进行操作,但是通常的方法是:

"hEY".capitalize # => "Hey"

如果您坚持使用正则表达式 and upcase,那么您还需要downcase

"hEY".downcase.sub(/\w/){$&.upcase} # => "Hey"
于 2013-03-26T00:48:08.453 回答
7

如果您真的只想交换字符串中每个字母的大小写,则可以完全避免正则表达式的复杂性,因为 There's A Method For That™。

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

也有swapcase!破坏性的做法。

于 2013-03-26T08:04:54.253 回答