ruby中字符串中所选字符替换的所有可能组合

时间:2014-02-27 11:31:03

标签: ruby string combinations substitution gsub

我想知道是否有一种简单的方法可以用简单的方式在ruby中完成所选字符替换的每个组合。

一个例子:

    string = "this is a test"
    subs = ['a'=>'@','i'=>'!','s'=>'$']
    subs.combination.each { |c|
        string.gsub c
    }

会产生

    "this is @ test"
    "th!s !s a test"
    "thi$ i$ a te$t"
    "th!s !s @ test"
    "thi$ i$ @ te$t"
    "th!$ !$ a te$t"
    "th!$ !$ @ te$t"

感谢您的帮助!

5 个答案:

答案 0 :(得分:3)

我会这样做:

string = "this is a test"
subs = {'a'=>'@','i'=>'!','s'=>'$'}

keys = subs.keys
combinations = 1.upto(subs.size).flat_map { |i| keys.combination(i).to_a }

combinations.each do |ary|
  new_string = string.dup
  ary.each { |c| new_string.gsub!(c,subs) }
  puts new_string
end

<强>输出

this is @ test
th!s !s a test
thi$ i$ a te$t
th!s !s @ test
thi$ i$ @ te$t
th!$ !$ a te$t
th!$ !$ @ te$t

答案 1 :(得分:1)

string = "this is a test"
subs = ['a'=>'@','i'=>'!','s'=>'$']

subs = subs.first.map(&:to_a)
1.upto(subs.length).each do |n|
  subs.combination(n).each do |a|
    p a.each_with_object(string.dup){|pair, s| s.gsub!(*pair)}
  end
end

答案 2 :(得分:1)

我使用String#gsub(pattern, hash)执行以下操作:

string = "this is a test"
subs = {'a'=>'@','i'=>'!','s'=>'$'} # copied from @ArupRakshit
keys = subs.keys

核心代码:

1.upto(keys.length).flat_map { |i| 
  keys.combination(i).flat_map { |c| string.gsub(/[#{c.join}]/, subs) } 
}

输出:

=> ["this is @ test",
 "th!s !s a test",
 "thi$ i$ a te$t",
 "th!s !s @ test",
 "thi$ i$ @ te$t",
 "th!$ !$ a te$t",
 "th!$ !$ @ te$t"]

答案 3 :(得分:1)

另一种方式:

string = "this is a test"
subs   = [{"a"=>"@"}, {"i"=>"!"}, {"s"=>"$"}]

subs.repeated_combination(subs.size)
    .map {|e| string.gsub(/./) {|c| (g = e.find {|h| h.key?(c)}) ? g[c] : c}}
    .uniq
  #=> ["this is @ test", "th!s !s @ test", "thi$ i$ @ te$t", "th!$ !$ @ te$t",
  #    "th!s !s a test", "th!$ !$ a te$t", thi$ i$ a te$t"]

说明:

a = subs.repeated_combination(subs.size)
  # Enumerator...
  a.to_a 
  # [[{"a"=>"@"},{"a"=>"@"},{"a"=>"@"}], [{"a"=>"@"},{"a"=>"@"},{"i"=>"!"}],
  #  [{"a"=>"@"},{"a"=>"@"},{"s"=>"$"}], [{"a"=>"@"},{"i"=>"!"},{"i"=>"!"}],
  #  [{"a"=>"@"},{"i"=>"!"},{"s"=>"$"}], [{"a"=>"@"},{"s"=>"$"},{"s"=>"$"}],
  #  [{"i"=>"!"},{"i"=>"!"},{"i"=>"!"}], [{"i"=>"!"},{"i"=>"!"},{"s"=>"$"}],
  #  [{"i"=>"!"},{"s"=>"$"},{"s"=>"$"}], [{"s"=>"$"},{"s"=>"$"},{"s"=>"$"}]]

b = a.map {|e| string.gsub(/./) {|c| (g = e.find {|h| h.key?(c)}) ? g[c] : c}}
  #=> ["this is @ test", "th!s !s @ test", "thi$ i$ @ te$t", "th!s !s @ test",
  #    "th!$ !$ @ te$t", "thi$ i$ @ te$t", "th!s !s a test", "th!$ !$ a te$t",
  #    "th!$ !$ a te$t", "thi$ i$ a te$t"]

要了解如何计算b,请考虑传递给块的a的第二个元素:

    e = [{"a"=>"@"},{"a"=>"@"},{"i"=>"!"}]

由于正则表达式,/./gsubc的每个字符string传递到块

    {|c| (g = e.find {|h| h.key?(c)}) ? g[c] : c}

搜索e以确定三个哈​​希值中的任何一个是否有c作为键。如果找到一个,即g,则将字符c替换为g[c];否则,角色保持不变。

请注意e的前两个元素是相同的。通过将第一行更改为:

可以提高效率
    subs.repeated_combination(subs.size).map(&:uniq)

但效率不是这种方法的优点之一。

回到主要计算,最后一步是:

b.uniq
  #=> ["this is @ test", "th!s !s @ test", "thi$ i$ @ te$t", "th!$ !$ @ te$t",
  #    "th!s !s a test", "th!$ !$ a te$t", "thi$ i$ a te$t"]

答案 4 :(得分:0)

单行功能解决方案

string = "this is a test"
subs = {'a'=>'@','i'=>'!','s'=>'$'}

(1..subs.size).flat_map { |n| subs.keys.combination(n).to_a }.map { |c| string.gsub(/[#{c.join}]/, subs) }
# => ["this is @ test", "th!s !s a test", "thi$ i$ a te$t", "th!s !s @ test", "thi$ i$ @ te$t", "th!$ !$ a te$t", "th!$ !$ @ te$t"]