gpt4 book ai didi

ruby - 从 ruby​​ 返回替换数组

转载 作者:数据小太阳 更新时间:2023-10-29 08:02:44 26 4
gpt4 key购买 nike

我想获取字符串 foofoofoo,将 foo 映射到 bar,并将所有单独的替换作为数组返回 - [ 'barfoofoo', 'foobarfoo', 'foofoobar']

这是我最好的:

require 'pp'
def replace(string, pattern, replacement)
results = []
string.length.times do |idx|
match_index = (Regexp.new(pattern) =~ string[idx..-1])
next unless match_index
match_index = idx + match_index
prefix = ''
if match_index > 0
prefix = string[0..match_index - 1]
end

suffix = ''
if match_index < string.length - pattern.length - 1
suffix = string[match_index + pattern.length..-1]
end

results << prefix + replacement + suffix
end
results.uniq
end

pp replace("foofoofoo", 'foo', 'bar')

这有效(至少对于这个测试用例),但似乎太冗长和老套。我可以做得更好吗,也许可以通过将 string#gsub 与 block 或类似的 block 一起使用?

最佳答案

使用 pre_match ($`) 和 post_match ($') 很容易做到:

    def replace_matches(str, re, repl)
return enum_for(:replace_matches, str, re, repl) unless block_given?
str.scan(re) do
yield "#$`#{repl}#$'"
end
end

str = "foofoofoo"

# block usage
replace_matches(str, /foo/, "bar") { |x| puts x }

# enum usage
puts replace_matches(str, /foo/, "bar").to_a

编辑:如果你有重叠匹配,那么它会变得更难,因为正则表达式并不能真正处理它。所以你可以这样做:

def replace_matches(str, re, repl)
return enum_for(:replace_matches, str, re, repl) unless block_given?
re = /(?=(?<pattern>#{re}))/
str.scan(re) do
pattern_start = $~.begin(0)
pattern_end = pattern_start + $~[:pattern].length
yield str[0 ... pattern_start] + repl + str[pattern_end .. -1]
end
end

str = "oooo"
replace_matches(str, /oo/, "x") { |x| puts x }

这里我们滥用了 0 宽度的积极前瞻,所以我们可以获得重叠匹配。然而,我们还需要知道我们匹配了多少个字符,我们不能像以前那样做,因为匹配是 0 宽度,所以我们将重新捕获 lookahead 的内容,并计算新的宽度那个。

(免责声明:它仍然只匹配每个字符一次;如果您想考虑每个字符的多种可能性,例如在您的 /f|o|fo/ 情况下,它会使事情变得更加复杂.)

编辑:稍微调整一下,我们甚至可以支持适当的类似 gsub 的行为:

def replace_matches(str, re, repl)
return enum_for(:replace_matches, str, re, repl) unless block_given?
new_re = /(?=(?<pattern>#{re}))/
str.scan(new_re) do
pattern_start = $~.begin(0)
pattern_end = pattern_start + $~[:pattern].length
new_repl = str[pattern_start ... pattern_end].gsub(re, repl)
yield str[0 ... pattern_start] + new_repl + str[pattern_end .. -1]
end
end

str = "abcd"
replace_matches(str, /(?<first>\w)(?<second>\w)/, '\k<second>\k<first>').to_a
# => ["bacd", "acbd", "abdc"]

(免责声明:最后一个片段无法处理模式使用后视或先行检查匹配区域之外的情况。)

关于ruby - 从 ruby​​ 返回替换数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41817907/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com