如何使用正则表达式在ruby中交换字符串中的数字位置?

Edm*_*Lee 2 ruby regex

假设我有一个字符串"2foo9 8bar5".我需要交换包裹每个单词的两个数字.结果应该是这样的"9foo2 5bar8".

我可以用以下代码完成.

def swap_num(str)
  str = str.gsub(/(\d)(\D+)(\d)/, '\3\2\1')
end
Run Code Online (Sandbox Code Playgroud)

但是如果我有这样的字符串"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
Run Code Online (Sandbox Code Playgroud)

用简单的正则表达式做任何事情?谢谢!

更新:

对不起大家.我犯了一个错误,str = str.gsub(/(\d)([a-zA-Z]+)(\d)/, '\3\2\1')实际上是我的目的.但是如果我使用这样的双引号就行不通"\3\2\1".

谢谢,@ Robin指出我的原始代码实际工作.还要感谢@Cary Swoveland和@ Andie2302为我提供2个新的解决方案!真的很感激!

Car*_*and 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"
Run Code Online (Sandbox Code Playgroud)

请注意,在最后一个示例中,由于单词边界要求,数字中a2foo93bat7c不进行交换.

每个匹配的字符串都传递给gsub块,该块计算该字符串的替换.我们可以把块写成:

{ |s| <code here> }
Run Code Online (Sandbox Code Playgroud)

其中block变量等于匹配的字符串.在第一个示例中,它将是:

s = "2foo9"
Run Code Online (Sandbox Code Playgroud)

我们希望将其替换为:

"9foo2"
Run Code Online (Sandbox Code Playgroud)

三个捕获组的内容包含在全局变量中:

$1 #=> "9"
$2 #=> "foo"
$3 #=> "2"
Run Code Online (Sandbox Code Playgroud)

因此,替换字符串是:

$3+$2+$1 #=> "2foo9".
Run Code Online (Sandbox Code Playgroud)

因此该块被写入:

{ |s| $3+$2+$1 }
Run Code Online (Sandbox Code Playgroud)

但由于我们s在此计算中不使用块变量,因此我们可以|s|从块中省略.这是一种很好的做法,因为它减少了出错的可能性,并告诉读者不使用块变量.

该表达式$3+$2+$1可以作为参数gsub,但在这种情况下必须写入:

"2foo9 8bar5".gsub(R, '\3\2\1')
  #=> "9foo2 5bar8" 
Run Code Online (Sandbox Code Playgroud)

要么

"2foo9 8bar5".gsub(R, "\\3\\2\\1")
  #=> "9foo2 5bar8" 
Run Code Online (Sandbox Code Playgroud)

这里的选择纯粹是风格.