假设我有一个字符串"2foo9 8bar5"
。我需要交换包裹每个单词的两个数字。结果应如下"9foo2 5bar8"
。
我可以使用以下代码完成。
def swap_num(str)
str = str.gsub(/(\d)(\D+)(\d)/, '\3\2\1')
end
但如果我有一个像"2foo9 8bar5 3+=_1"
这样的字符串,这个swap_num
方法也会交换最后一部分"3+=_1"
的数字,这不是我想要的。我只想交换包装WORDS的数字,而不是任何字符。
我尝试了以下方法,但没有奏效。
def swap_num(str)
str = str.gsub(/(\d)([a-zA-Z]+)(\d)/, '\3\2\1')
end
用简单的正则表达式做任何事情?谢谢!
更新
对不起伙计们。我犯了一个错误,str = str.gsub(/(\d)([a-zA-Z]+)(\d)/, '\3\2\1')
实际上是我的目的。但如果我使用像"\3\2\1"
这样的双引号,它就行不通。
谢谢,@ Robin指出我的原始代码确实有效。还要感谢@Cary Swoveland和@ Andie2302为我提供2个新的解决方案!真的很感激!
答案 0 :(得分:6)
你可以这样做:
R = /
\b # match a word boundary
(\d+) # match ?= 1 digits, capture in group #1
([a-z]+) # match >= 1 lower case letters, capture in group #2
(\d+) # match >= 1 digits, capture in group #3
\b # match a word boundary
/ix # case indifferent (/i) and extended mode (/x)
def flip_numbers(str)
str.gsub(R) { $3+$2+$1 }
end
flip_numbers("2foo9 8bar5")
#=> "9foo2 5bar8"
flip_numbers("233foo91 8bar5")
#=> "91foo233 5bar8"
flip_numbers("2foo9 8bar5 3+=_1")
#=> "9foo2 5bar8 3+=_1"
flip_numbers("a2foo9 8bar5 3bat7c")
#=> "a2foo9 5bar8 3bat7c"
请注意,在上一个示例中,由于字边界要求,a2foo9
和3bat7c
中的数字不会被交换。
每个匹配的字符串都传递给gsub
的块,该块计算该字符串的替换。我们可以把块写成:
{ |s| <code here> }
其中block变量等于匹配的字符串。在第一个例子中:
s = "2foo9"
我们希望将其替换为:
"9foo2"
三个捕获组的内容包含在全局变量中:
$1 #=> "9"
$2 #=> "foo"
$3 #=> "2"
因此替换字符串是:
$3+$2+$1 #=> "2foo9".
因此写了块:
{ |s| $3+$2+$1 }
但由于我们在此计算中不使用块变量s
,因此我们可以从块中省略|s|
。这是一种很好的做法,因为它减少了出错的可能性,并告诉读者不使用块变量。
表达式$3+$2+$1
可以改为gsub
的参数,但在这种情况下必须写成:
"2foo9 8bar5".gsub(R, '\3\2\1')
#=> "9foo2 5bar8"
或
"2foo9 8bar5".gsub(R, "\\3\\2\\1")
#=> "9foo2 5bar8"
这里的选择纯粹是风格。
答案 1 :(得分:4)
工作正则表达式是:
(\d)(\p{L}+)(\d)
str = str.gsub(/(\d)(\p{L}+)(\d)/, '\3\2\1')
\ p {L} ...匹配Unicode类别“字母”中的字符(任何语言的任何字母字符)