如何将 gsub 应用于函数?

How do I apply gsub subject to a function?

我正在使用 Rails 5 和 Ruby 2.4。我有一个函数

my_function(str1, str2)

给定两个字符串参数,return 为真或假。我想做的是给一个更大的字符串,例如

"a   b   c d"

如果表达式

,我想用空字符串替换两个连续的 "words"(根据我的定义,一个词是一系列字符后跟一个词边界)
my_function(str1, str2)

对于这两个连续的单词计算结果为真。例如,如果

my_function("b", "c") 

计算结果为真,我希望上面的字符串变成

"a    d"

我该怎么做?

编辑: 我根据 Tom Lord 的回答添加了输出...

如果我使用

  def stuff(line)
    matches = line.scan(/\b((\S+?)\b.*?\b(\S+?))\b/)
    matches.each do |full_match, word1, word2|
      line.delete!(full_match) if word1.eql?("hello") && word2.eql?("world") 
    end
  end

行是

"hello world this is a test"

生成的字符串行是

"tisisatst"

这不是我所期望的。结果应该是

" this is a test"

编辑: 这是根据以下评论更新的答案。我把原来的答案留在了底部。

扫描 "two consecutive words" 的字符串有点棘手。您最好的选择可能是在正则表达式中使用 \b 锚点,它表示 "word boundary":

string_to_change = "a   b   c d"

matches = string_to_change.scan(/\b((\S+?)\b.*?\b(\S+?))\b/)
  # => [["a   b", "a", "b"], ["c d", "c", "d"]]

...第一个字符串是 "full match"(包括任何空格或标点符号),其他是两个单词。

分解正则表达式:

  • \b 表示 "word boundary"。我在两根弦的每一侧都放了一根。 此解决方案假定 str1str2 都是一个单词 。 (如果它们包含空格,那么我不知道您期望什么行为?)
  • \S+? 表示 "one or more non-whitespace character"。 (非贪婪匹配,所以会在first字边界处停止匹配)。

然后您可以从字符串中删除每个 "full match",如果方法 returns 对两个单词为真:

matches.each do |full_match, word1, word2|
  string_to_change.gsub!(full_match, '') if my_function(word1, word2)
end

这里没有说明的一件事(您在问题中没有详细说明...)是如何处理包含三个或更多单词的字符串。例如,考虑以下内容:

"hello world this is a test"

假设 my_function(word1, word2) returns true 仅对:"world", "this""hello", "is".

我上面的代码将 查看对:"hello", "world""this", "is""a", "test"。但也许它实际上应该:

  1. 查看所有对单词,即匹配所有单词的左手边和右手边。
  2. 重复删除单词对,即在删除初始对:"world this"后,应重新扫描字符串,然后"hello is"应也被删除?

如果需要这样的进一步增强,请在新问题中解释清楚(如果您正在努力自己解决问题)。


原回答:

str1 = "b"
str2 = "c"
string_to_change = "a   b   c d"

if my_function(str1, str2)
  string_to_change.gsub!(/\b#{str1}\b\s+\b#{str2}\b/, "")
end

分解正则表达式:

  • \b 表示 "word boundary"。我在两根弦的每一侧都放了一根。 此解决方案假定 str1str2 都是一个单词 。 (如果它们包含空格,那么我不知道您期望什么行为?)
  • \s+ 表示 "one or more whitespace character"。您可能希望对此进行调整以允许使用其他标点符号,例如逗号或句号。这个问题的一个完全通用的解决方案实际上可能是:

.

string_to_change.gsub!(/\b#{str1}\b.(\B.)*#{str2}\b/, "")

# Or equivalently:

string_to_change.gsub!(/\b#{str1}\b(.\B)*.#{str2}\b/, "")

.(\B.)* 而是收集每个字符,一次一个,始终检查它不是单词的第一个字母(即以非单词边界开头)。