除了某些字符串之外如何替换字符串中的所有字符(在Ruby中)

时间:2015-05-18 17:44:02

标签: ruby regex string

我在尝试找到适当的字符串替换方法时遇到了一些麻烦。我想替换字符串中的每个字符除了'用于选择单词或字符串集(在数组中提供)。我知道那里有gsub方法,但我想我想要实现的是它的反面。例如......

我的字符串:"Part of this string needs to be substituted"

关键字:["this string", "substituted"]

所需的输出:"**** ** this string ***** ** ** substituted"

PS。这是我的第一个问题,所以非常感谢您的帮助!

6 个答案:

答案 0 :(得分:1)

这是一种不同的方法。首先,与你最终想要的相反:编辑你想要保留的内容。然后将这个编辑后的字符串与原始字符逐个字符进行比较,如果字符相同,则编辑,如果不是,则保留原始字符。

class String
  # Returns a string with all words except those passed in as keepers
  # redacted.
  #
  #      "Part of this string needs to be substituted".gsub_except(["this string", "substituted"], '*')
  #      # => "**** ** this string ***** ** ** substituted"
  def gsub_except keep, mark
    reverse_keep = self.dup
    keep.each_with_object(Hash.new(0)) { |e, a| a[e] = mark * e.length }
             .each { |word, redacted| reverse_keep.gsub! word, redacted }
    reverse_keep.chars.zip(self.chars).map do |redacted, original|
      redacted == original && original != ' ' ?  mark : original
    end.join
  end
end

答案 1 :(得分:0)

您可以使用以下内容:

str="Part of this string needs to be substituted"
keep = ["this","string", "substituted"]

str.split(" ").map{|word| keep.include?(word) ? word : word.split("").map{|w| "*"}.join}.join(" ")

但这只会保留单词,而不是短语。

答案 2 :(得分:0)

这可能比我上一个答案更容易理解:

s = "Part of this string needs to be substituted"
k = ["this string", "substituted"]

tmp = s
for(key in k) {
    tmp = tmp.replace(k[key], function(x){ return "*".repeat(x.length)})
}

res = s.split("")
for(charIdx in s) {
    if(tmp[charIdx] != "*" && tmp[charIdx] != " ") {
        res[charIdx] = "*"
    } else {
        res[charIdx] = s.charAt(charIdx)
    }
}
var finalResult = res.join("")

说明:

这取决于我之前关于使用关键字的位置的想法,以便用星号替换字符串的部分。首先:

对于每个关键字,我们将其替换为与其长度相同的星号。所以:

s.replace("this string", function(x){
    return "*".repeat(x.length)
}

替换匹配"此字符串"的s部分。使用x.length *' s

我们为每个密钥执行此操作,为了完整性,您应该确保替换是全局的,而不仅仅是找到的第一个匹配项。 /this string/g,我在答案中没有这样做,但我认为你应该能够弄清楚如何自己使用new RegExp

接下来,我们将原始字符串的副本拆分为数组。如果你是一个视觉形象的人,那么认为这是一种奇怪的角色添加应该是有道理的:

"Part of this string needs to be substituted"
"Part of *********** needs to be substituted" +
---------------------------------------------
 **** ** this string ***** ** ** ***********

是我们的目标。因此,如果我们的tmp变量有星号,那么我们想要带来原始字符串,否则我们想用*替换字符

使用if语句可以轻松完成。为了使它成为问题中的榜样,如果它是一个空间,我们也会带来原始角色。最后,我们通过.join("")将数组连接回一个字符串,以便您可以再次使用字符串。

有道理吗?

答案 3 :(得分:0)

您可以使用以下方法:收集需要变成星号的子字符串,然后执行此替换:

str="Part of this string needs to be substituted"
arr = ["this string", "substituted"]

arr_to_remove = str.split(Regexp.new("\\b(?:" + arr.map { |x| Regexp.escape(x) }.join('|') + ")\\b|\\s+")).reject { |s| s.empty? }

arr_to_remove.each do |s|
    str = str.gsub(s, "*" * s.length)
end
puts str

demo program的输出:

**** ** this string ***** ** ** substituted

答案 4 :(得分:0)

您可以使用String#split的形式使用带有捕获组的正则表达式。

<强>代码

def sub_some(str, keywords)
  str.split(/(#{keywords.join('|')})/)
     .map {|s| keywords.include?(s) ? s : s.gsub(/./) {|c| (c==' ') ? c : '*'}}
     .join
end

示例

str = "Part of this string needs to be substituted"
keywords = ["this string", "substituted"]
sub_some(str, keywords)
  #=> "**** ** this string ***** ** ** substituted" 

<强>解释

r = /(#{keywords.join('|')})/
  #=> /(this string|substituted)/ 
a = str.split(r)
  #=> ["Part of ", "this string", " needs to be ", "substituted"] 
e = a.map
  #=> #<Enumerator: ["Part of ", "this string", " needs to be ",
  #     "substituted"]:map> 

s = e.next
  #=> "Part of " 
keywords.include?(s) ? s : s.gsub(/./) { |c| (c==' ') ? c : '*' }
  #=> s.gsub(/./) { |c| (c==' ') ? c : '*' }
  #=> "Part of "gsub(/./) { |c| (c==' ') ? c : '*' }
  #=> "**** ** " 

s = e.next
keywords.include?(s) ? s : s.gsub(/./) { |c| (c==' ') ? c : '*' }
  #=> "this string" 
keywords.include?(s) ? s : s.gsub(/./) { |c| (c==' ') ? c : '*' }
  #=> s
  #=> "this string" 

依旧......最后,

["**** ** ", "this string", " ***** ** ** ", "substituted"].join('|') 
  #=> "**** ** this string ***** ** ** substituted" 

请注意,在v.1.9.3之前,Enumerable#map在没有给出块时没有返回枚举器。然而,计算是相同的。

答案 5 :(得分:0)

str = "Part of this string needs to be substituted"
keywords = ["this string", "substituted"]

pattern = /(#{keywords.join('|')})/

str.split(pattern).map {|i| keywords.include?(i) ? i : i.gsub(/\S/,"*")}.join
#=> "**** ** this string ***** ** ** substituted"

相同代码的更易读的版本

str = "Part of this string needs to be substituted"
keywords = ["this string", "substituted"]

#Use regexp pattern to split string around keywords.
pattern = /(#{keywords.join('|')})/ #pattern => /(this string|substituted)/
str = str.split(pattern) #=> ["Part of ", "this string", " needs to be ", "substituted"]

redacted = str.map do |i|
    if keywords.include?(i)
        i
    else
        i.gsub(/\S/,"*") # replace all non-whitespace characters with "*"
    end
end      
# redacted => ["**** **", "this string", "***** ** **", "substituted"]
redacted.join