如何在单个gsub
中执行以下操作regex
以获得所需的输出?
string = "Make all the changes within a single pass"
string.gsub(/[^aeiou|\s]/, '*').gsub(/\s/, '&')
#=> "*a*e&a**&**e&**a**e*&*i**i*&a&*i***e&*a**"
gsub
如果不是元音或空间,请将其替换
*
gsub
如果是空格,请将其替换为&
我问的原因是因为我觉得链接gsub
不是正确的方式来做到这一点。如果您认为这是一个好方法,请告诉我。
答案 0 :(得分:1)
好的,所以我发现我可以像这样传递block
:
string.gsub(/[^aeiou]/) {|g| g =~ /\s/ ? "&" : "*"}
#=> "*a*e&a**&**e&**a**e*&*i**i*&a&*i***e&*a**"
我更喜欢上面的解决方案,但这也有效:
string.gsub(/[^aeiou|\s]/, '*').gsub(/\s/, '&')
#=> "*a*e&a**&**e&**a**e*&*i**i*&a&*i***e&*a**"
基准测试结果(已更正):使用Benchmark
类(900k长字符串样本大小)
Benchmark.measure { string.gsub(/[^aeiou]/) {|g| g =~ /\s/ ? "&" : "*"} }
#=> 0.800000 0.010000 0.810000 ( 0.801419 )
Benchmark.measure { string.gsub(/[^aeiou|\s]/, '*').gsub(/\s/, '&') }
#=> 0.230000 0.000000 0.230000 ( 0.231482 )
看起来第二个选项的速度要快很多倍,并且速度明显高,并且似乎具有首选的可读性。
<强>更新强>
基于@Matt的回答,我也能够使用:string#tr
这个解决方案非常快(所有测试中最快的)字符串@ 900k字符大小。
string.tr(' ', '&').tr('^[aeiou|&]', '*')
Benchmark.measure { string.tr(' ', '&').tr('^[aeiou|&]', '*') }
#=> 0.000000 0.000000 0.000000 ( 0.015000 )
答案 1 :(得分:1)
这使用String#tr
在一次传递中进行替换。这假设字符串由可打印的ASCII字符组成。
string.tr " \t\nB-DF-HJ-NP-TV-Zb-df-hj-np-tv-z!-@[-`{-~", '&&&*'
# => "*a*e&a**&**e&**a**e*&*i**i*&a&*i***e&*a**"
对于tr
,-
是范围运算符。因此,对于字母B
,C
,D
,由于它们是连续的,因此可以写为B-D
。所以B-DF-HJ-NP-TV-Z
基本上都是大写字母减去元音。与小写相同,后跟ASCII图表上的所有可打印标点符号。这些都被*
取代。与\s
匹配的唯一3个空白字符是空格,制表符和换行符,这些字符在字符串的前面显式列出,并且每个字符都替换为&
。
如果允许2次传递,则可以更简洁地写为
string.tr(' ','&').tr('^AEIOUaeiou&','*')
答案 2 :(得分:0)
string.gsub(/(\s)|([^aeiou])/){$1 ? "&" : "*"}
# => "*a*e&a**&**e&**a**e*&*i**i*&a&*i***e&*a**"