【问题标题】:How to remove substring matching to any element of array如何删除与数组的任何元素匹配的子字符串
【发布时间】:2014-07-05 05:33:26
【问题描述】:

我有:

str ="this is the string "

我有一个字符串数组:

array =["this is" ,"second element", "third element"]

我想处理字符串,以便删除与数组中任何元素匹配的子字符串,并返回字符串的其余部分。我想要以下输出:

output: "the string "

我该怎么做?

【问题讨论】:

  • 我认为您应该研究 Regex(正则表达式)。他们准确地解决了您正在寻找的问题。
  • 定义“sub string matching”。您的意思是真正的子字符串,还是您的意思是要尊重单词边界以便只匹配完整的单词?

标签: ruby-on-rails ruby arrays string


【解决方案1】:

这是一种方法-

array =["this is" ,"second element", "third element"]
str = "this is the string "
str.gsub(Regexp.union(array),'') # => " the string "

允许不区分大小写 - str.gsub(/#{array.join('|')}/i,'')

【讨论】:

    【解决方案2】:

    你没有说你是想要真正的子字符串匹配,还是在单词边界处进行子字符串匹配。有区别。以下是尊重单词边界的方法:

    str = "this is the string "
    array = ["this is" ,"second element", "third element"]
    pattern = /\b(?:#{ Regexp.union(array).source })\b/ # => /\b(?:this\ is|second\ element|third\ element)\b/
    
    str[pattern] # => "this is"
    str.gsub(pattern, '').squeeze(' ').strip # => "the string"
    

    下面是 unionunion.source 的情况:

    Regexp.union(array) # => /this\ is|second\ element|third\ element/
    Regexp.union(array).source # => "this\\ is|second\\ element|third\\ element"
    

    source 在创建模式时以正则表达式更容易使用的形式返回连接的数组,而不会在模式中注入漏洞。考虑这些差异以及它们在模式匹配中可以做什么:

    /#{ Regexp.union(%w[a . b]) }/ # => /(?-mix:a|\.|b)/
    /#{ Regexp.union(%w[a . b]).source }/ # => /a|\.|b/
    

    第一个创建一个单独的模式,具有自己的大小写、多行和空格尊重标志,将嵌入外部模式中。这可能是一个很难追踪和修复的错误,因此只有在您打算拥有子模式时才这样做。

    另外,请注意如果您尝试使用会发生什么:

    /#{ %w[a . b].join('|') }/ # => /a|.|b/
    

    生成的模式中嵌入了一个通配符.,它会破坏你的模式,使其匹配任何东西。不要去那里。

    如果我们不告诉正则表达式引擎遵守单词边界,那么可能会发生意外/不受欢迎/可怕的事情:

    str = "this isn't the string "
    array = ["this is" ,"second element", "third element"]
    pattern = /(?:#{ Regexp.union(array).source })/ # => /(?:this\ is|second\ element|third\ element)/
    
    str[pattern] # => "this is"
    str.gsub(pattern, '').squeeze(' ').strip # => "n't the string"
    

    在处理包含完整单词的子字符串时,从单词的角度来思考是很重要的。引擎不知道区别,所以你必须告诉它该做什么。不需要进行文本处理的人经常错过这种情况。

    【讨论】:

      【解决方案3】:

      我看到了两种解决方案,起初我更喜欢 Brad 的解决方案。但是我认为这两种方法是如此不同,以至于必须存在性能差异,所以我在下面创建了文件并运行它。

      require 'benchmark/ips'
      
      str = 'this is the string '
      array =['this is' ,'second element', 'third element']
      
      def by_loop(str, array)
        array.inject(str) { |result , substring| result.gsub substring, ''  }
      end
      
      def by_regex(str, array)
        str.gsub(Regexp.union(array),'')
      end
      
      def by_loop_large(str, array)
        array = array * 100
        by_loop(str, array)
      end
      
      def by_regex_large(str, array)
        array = array * 100
        by_regex(str, array)
      end
      
      Benchmark.ips do |x|
        x.report("loop")  { by_loop(str, array) }
        x.report("regex") { by_regex(str, array) }
        x.report("loop large")  { by_loop_large(str, array) }
        x.report("regex large") { by_regex_large(str, array) }
      end
      

      结果:

      -------------------------------------------------
                  loop    16719.0 (±10.4%) i/s -      83888 in   5.073791s
                 regex    18701.5 (±4.2%) i/s -      94554 in   5.063600s
            loop large      182.6 (±0.5%) i/s -        918 in   5.027865s
           regex large      330.9 (±0.6%) i/s -       1680 in   5.076771s
      

      结论:

      当数组变大时,Arup 的方法效率更高。

      关于 Tin Man 对文本单引号的关注,我认为这很重要,但这将是 OP 的责任,而不是当前的算法。这两种方法在该字符串上产生相同的结果。

      【讨论】:

        猜你喜欢
        • 2022-01-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-05
        • 1970-01-01
        • 2018-05-05
        • 2011-01-23
        • 2015-03-21
        相关资源
        最近更新 更多