一次通过多个字符串操作的正则表达式?

时间:2014-03-17 20:36:56

标签: ruby regex

如何在单个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不是正确的方式来做到这一点。如果您认为这是一个好方法,请告诉我。

3 个答案:

答案 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-是范围运算符。因此,对于字母BCD,由于它们是连续的,因此可以写为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**"