【问题标题】:Replace all words which don't match a RegExp pattern in Ruby替换所有与 Ruby 中的 RegExp 模式不匹配的单词
【发布时间】:2020-10-25 17:09:43
【问题描述】:

我有一个 ruby​​ 字符串,比如说
"hello, I am a string, I am surrounded by quotes"
我想替换所有不匹配正则表达式模式的单词(用空格分隔),比如说/.+?s/"foo"。 所以结果将是
"foo foo foo foo string, foo foo surrounded foo quotes"

因为单词有分隔符我可以做

str = "hello, I am a string, I am surrounded by quotes"
str = str.split
str.each{
  |e|
  x = e.match(/(.+)?s/)
  if x.to_s.empty? then e.replace "foo" end
}
str = str.join(" ")
puts str # -> foo foo foo foo string, foo foo surrounded foo quotes

但是有没有更好的方法呢?因为对于一个相对简单的操作来说,这是相当多的代码。

【问题讨论】:

标签: ruby


【解决方案1】:

从您的示例看来,您想用'foo' 替换所有单词,但包含's' 的单词除外;即'string''surrounded''quotes'。为此,您可以将/(.+)?s/ 简化为/s/(例如'beeswax'.match?(/s/) #=> true)。

最好在整个字符串上使用String#gsub,因为它会保留单词之间的额外空格。如果将字符串拆分为空格,替换结果数组中的每个单词,然后joins 这些元素形成一个新字符串,则将删除多余的空格。例如,如果一个是老式的并且在句子之间插入两个空格,我们可能会有以下内容。

str = "Hello, I use a string of words, surrounded by quotes.  So there."
                                                             

并希望保留结果字符串中句点后面的两个空格。此外,在空格上分割然后加入修改过的单词会创建一个不必要的数组。

假设我们希望将包含匹配's''S' 的单词替换为'foo'。包含's''S'的单词匹配正则表达式

r = /s/i

我们可以这样写:

str.gsub(/\w+/) { |s| s.match?(r) ? s : 'foo' }
  #=> "foo, foo use foo string foo words, surrounded foo quotes.  So foo."

gsub 的参数是一个匹配单词的正则表达式。

考虑第二个例子。假设我们用'foo' 替换所有既不以's''S' 开头也不以结尾的单词;也就是不符合正则表达式的词

r = /\As|s\z/i

我们可以这样做:

str.gsub(/\w+/) { |s| s.match?(r) ? s : 'foo' }
  #=> "foo, foo foo foo string foo words, surrounded foo quotes.  So foo."

【讨论】:

  • 谢谢,如果你只给它一个参数,我不知道 gsub 会返回一些东西。
【解决方案2】:

我不确定这样的事情是否更适合你,这取决于你喜欢什么。

base_string = "hello, i am a string, i am surrounded by quotes"
array_from_string = base_string.split.each do |e|
  e.replace('foo') if e.match(/(.+)?s/).nil?
end

puts array_from_string.join(' ')

【讨论】:

    【解决方案3】:

    替换任何不以s开头或结尾的单词

    假设您的真正规则是排除以字符s 开头或结尾的单词,您可以拆分单词,然后将String#gsub 映射到每个元素上。例如,使用 Ruby 2.7.2+(我实际使用的是 3.0.0-preview1):

    str = "hello, i am a string, i am surrounded by quotes"
    str.split.map { _1.gsub(/\b[^s]+\b/) { "foo" } }.join ?\s
    #=> "foo, foo foo foo string, foo foo surrounded foo quotes"
    

    这也适用于早期的 Ruby 版本。只需将位置块参数(例如 _1)替换为像 word 这样的命名变量,并且(如果您愿意)将速记 ?\s 替换为 "\s"。例如,使用 Ruby 2.5.8:

    str = 'hello, i am a string, i am surrounded by quotes'
    str.split.map do |word|
      word.gsub(/\b[^s]+\b/) { 'foo' }
    end.join "\s"
    #=> "foo, foo foo foo string, foo foo surrounded foo quotes"
    

    结果应该是一样的。

    【讨论】:

      猜你喜欢
      • 2015-03-11
      • 1970-01-01
      • 1970-01-01
      • 2011-09-30
      • 2012-05-18
      • 1970-01-01
      • 1970-01-01
      • 2012-03-07
      • 1970-01-01
      相关资源
      最近更新 更多