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



假设我有一个字符串"2foo9 8bar5" .我需要交换两个数字来包装每个单词。结果应如下所示"9foo2 5bar8"

我可以用以下代码做到这一点。

def swap_num(str)
  str = str.gsub(/(d)(D+)(d)/, '321')
end

但是如果我有这样的字符串"2foo9 8bar5 3+=_1",这个swap_num方法也会交换最后一部分的数字"3+=_1",这不是我想要的。我只想交换包装单词的数字,而不是任何字符。

我尝试了以下方法,但没有奏效。

def swap_num(str)
  str = str.gsub(/(d)([a-zA-Z]+)(d)/, '321')
end

有什么方法可以用简单的正则表达式做到这一点吗?谢谢!

更新:

对不起,伙计们。我犯了一个错误,str = str.gsub(/(d)([a-zA-Z]+)(d)/, '321')实际上达到了我的目的。但是如果我像这样使用双引号"321"就行不通了.

谢谢,@Robin指出我的原始代码确实有效。还要感谢@Cary Swoveland 和 @Andie2302 为我提供了 2 个新的解决方案!真的很感激!

你可以

这样做:

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"

请注意,在上一个示例中,由于单词边界要求,a2foo93bat7c中的数字不会交换。

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

{ |s| <code here> }

其中块变量等于匹配的字符串。在第一个示例中,这将是:

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, '321')
  #=> "9foo2 5bar8" 

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

这里的选择纯粹是风格上的。

工作正则表达式是:

(d)(p{L}+)(d)
str = str.gsub(/(d)(p{L}+)(d)/, '321')

\p{L} ...匹配 Unicode 类别"字母"中的字符(任何语言的任何字母字符)

最新更新