Ruby相当于grep -v

时间:2010-11-12 15:08:39

标签: ruby regex grep

这就是我一直在做的事情:

my_array.reject { |elem| elem =~ /regex/ }.each { ... }

我觉得这有点笨拙,但我没有找到任何可以让我将其更改为my_array.grepv /regex/ { ... }

的内容

有这样的功能吗?

9 个答案:

答案 0 :(得分:7)

你知道Symbol#to_proc如何帮助链接?你可以用正则表达式做同样的事情:

class Regexp
  def to_proc
    Proc.new {|string| string =~ self}
  end
end

["Ruby", "perl", "Perl", "PERL"].reject(&/perl/i)
=> ["Ruby"]

但你可能不应该这样做。 Grep不仅适用于正则表达式 - 您可以像以下一样使用它

[1,2, "three", 4].grep(Fixnum)

如果你想grep -v,你必须实现Class#to_proc,这听起来不对。

答案 1 :(得分:4)

这个怎么样?

arr = ["abc", "def", "aaa", "def"]
arr - arr.grep(/a/)  #=> ["def", "def"]

我故意包含一个复制品,以确保所有这些都被退回。

答案 2 :(得分:4)

如何反转正则表达式?

["ab", "ac", "bd"].grep(/^[^a]/) # => ["bd"]

答案 3 :(得分:3)

我不相信有这样的内置内容,但它很简单,可以添加:

class Array
  def grepv(regex, &block)
    self.reject { |elem| elem =~ regex }.each(&block)
  end
end

请注意,调用此函数时需要在正则表达式周围使用parens,否则会出现语法错误:

myarray.grepv(/regex/) { ... }

答案 4 :(得分:1)

你可以这样做:

my_array.reject{|e| e[/regex/]}.each { ... }

但实际上很难更简洁和自我记录。它可以使用grep(/.../)使用一些负面前瞻模式编写,但后来我认为理解整体操作变得更难,因为模式本身更难理解。

答案 5 :(得分:0)

尝试使用Array#collect!

my_array.collect! do |elem|
  if elem =~ /regex/
    # do stuff
    elem
  end
end

编辑:抱歉,您之后必须致电Array#compact。至少那将消除第二块。但它更多的是物理代码。这取决于你做了多少“东西”。

答案 6 :(得分:0)

您只需要否定正则表达式匹配的结果。

Enumerable.module_eval do
  def grepv regexp
    if block_given?
      self.each do |item|
        yield item if item !~ regexp
      end
    else
      self.find_all do |item|
        item !~ regexp
      end
    end
  end
end

答案 7 :(得分:0)

谢谢大家的意见。最后,我这样做了:

module Enumerable
    def grepv(condition)

        non_matches = []

        self.each do |item|
            unless condition === item or condition === item.to_s
                non_matches.push(item)
                yield item if block_given?
            end
        end

        return non_matches
    end
end

不确定这是否是最佳方式,因为我刚开始使用Ruby。它比其他人的解决方案要长一些,但是我喜欢它,因为它与Enumerable的grep选项非常类似 - 它可以处理任何可以处理===的东西,就像grep一样,它会产生它找到的项目,如果一个块是给定,并且两种方式都返回一个不匹配的数组。

我添加了or to_s部分,以便例如穿插在数组中的任何整数都可以与相同的正则表达式匹配,不过我可以想象这有时可能会有所帮助。

答案 8 :(得分:0)

这是另一个镜头,有bltxdHsiu的答案,并希望保留尽可能多的精神尽可能原始的grep(即使它是罗嗦的):

module Enumerable
  def grepv(condition)
    if block_given?
      each do |item|
        yield item if not condition === item
      end
    else
      inject([]) do |memo, item|
        memo << item if not condition === item
        memo
      end
    end
  end
end

如果你提供一个街区,那么一切都像你期望的那样是懒惰的。如果您不提供块,则会有一些重复的代码。我真的希望Andrew Grimm的答案适用于一般情况。

>> (%w(1 2 3) + [4]).cycle(3).grepv(Fixnum)
=> ["1", "2", "3", "1", "2", "3", "1", "2", "3"]

>> (%w(1 2 3) + [4]).cycle(3).grepv(/[12]/)
=> ["3", 4, "3", 4, "3", 4]

在这两种情况下,你都不会为项目比较支付O(n^2),就像你在最坏的情况下进行数组减法一样。