如何在ruby中使用正则表达式交换字符串中的数字位置?
假设我有一个字符串如何在ruby中使用正则表达式交换字符串中的数字位置?,ruby,regex,Ruby,Regex,假设我有一个字符串“2foo9 8bar5”。我需要交换包裹每个单词的两个数字。结果应该是这样的“9foo2 5bar8” 我可以用下面的代码来完成 def swap_num(str) str = str.gsub(/(\d)(\D+)(\d)/, '\3\2\1') end 但是如果我有一个像这样的字符串,这个方法也会交换最后一部分的数字,这不是我想要的。我只想交换包含单词的数字,而不是任何字符 我尝试了以下方法,但没有成功 def swap_num(str) str = str.g
“2foo9 8bar5”
。我需要交换包裹每个单词的两个数字。结果应该是这样的“9foo2 5bar8”
我可以用下面的代码来完成
def swap_num(str)
str = str.gsub(/(\d)(\D+)(\d)/, '\3\2\1')
end
但是如果我有一个像这样的字符串,这个方法也会交换最后一部分的数字,这不是我想要的。我只想交换包含单词的数字,而不是任何字符
我尝试了以下方法,但没有成功
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为我提供了两个新的解决方案!真的很感激 工作正则表达式是:
(\d)(\p{L}+)(\d)
str = str.gsub(/(\d)(\p{L}+)(\d)/, '\3\2\1')
\p{L}。。。匹配Unicode类别“字母”(任何语言的任何字母字符)中的字符。您可以执行以下操作:
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> }
我们希望用以下内容取代:
"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"
或
这里的选择纯粹是风格上的。您的尝试怎么会失败?它根本不会改变任何东西,并且输出与我输入的字符串完全相同的字符串。对我来说,这似乎没什么问题:您能显示更多代码吗?我的错。实际上,这项工作。当我使用双引号
“\3\2\1”
时,它不起作用。然后它输出这个结果“\u0003\u0002\u0001\u0003\u0002\u0001 3+=\u1”
。但是,当我使用单引号时,它是有效的。这是为什么?实际上我刚刚找到了我的原始代码str=str.gsub(/(\d)([a-zA-Z]+)(\d/,“\3\2\1”)
将实现我所期望的,这只是在包装[a-zA-Z]+
时交换数字。我没有得到正确的输出,因为我使用了双引号,比如“\3\2\1”
,而不是单引号。你能解释一下\p{L}
的作用吗?埃德蒙,假设你试着匹配单词str=“Passé”
的字母。让我们先试试r=/[a-zA-Z]+/
,str[r]#=>“Pass”
。不太好。我们需要一个能处理Unicode字符的正则表达式。我们可以使用/\p{L}+/
,/\p{alpha}+/
或/[:alpha:]+/
。这些都返回“Passé”。然而,当匹配预期仅为ASCII字符时,有些人更喜欢其中任何一个字符的简洁性/灵活性,而不是/[a-zA-Z]+/
(或/[a-Z]+//i
)。请参阅已接受的答案进行更全面的讨论。\p{L}
在本例中只是混淆了问题。这个问题与unicode无关,所以没有理由这样做。@pguardiario unicode从来没有错过。它符合交换号码包装文字的要求。谢谢@Cary Swoveland。但是你能解释一下块{$3+$2+$1}
是如何工作的吗?我是新来的,以前从未使用过美元符号。我提供了一个解释。
"2foo9 8bar5".gsub(R, '\3\2\1')
#=> "9foo2 5bar8"
"2foo9 8bar5".gsub(R, "\\3\\2\\1")
#=> "9foo2 5bar8"