我有一个数组:arr=[x1, x2, x3...]和一个函数,它根据arr中的第一个x返回一个值,表明该函数为真.

本质上:

# my_x is the return of func() 
# with the first x in arr that func(x) is true
# and the entire arr array is not processed.

my_x=arr.ruby_magic{|x| func(x) } 

my_x should be equal to first true value return of func(x)

假设arr中的每个X都是正则表达式模式.不必运行每个正则表达式,我希望从第一场比赛中返回捕获组.

在Python语言中,我会用next编写一个生成器.它将运行每个谓词,直到真返回,然后将该值传递给m.如果没有真返回,则使用None作为缺省值,但缺省值可以是任何值:

import re 

patterns=[r"no match", r": (Value.*?pref)", r": (Value.*)", r"etc..."]

s=""" 
This is the input txt
This is a match if the other is not found: Value 1

This is the match I am looking for first: Value 1 pref

Last line.
"""

val_I_want=next(
        (m.group(1) for p in patterns 
            if (m:=re.search(rf'{p}', s))), None)

我还没有在Ruby中找到对应的代码.

我可以做一个显式循环:

# s in the same multiline string as above...

patterns=[/no match/, /: (Value.*?pref)/, /: (Value.*)/,/etc.../]

val_I_want=nil 
patterns.each{|p| 
    m=p.match(s)
    if m then
        val_I_want=m[1]
        break 
    end     
}
# val_I_want is either nil or 
# the first match capture group that is true

这就是我想要的功能,但与Python生成器相比,这似乎有点冗长.

我已经try 了grep,第一个值是谓词.但这里的问题是,entire结果数组是在使用next之前生成的:

patterns.grep(proc {|p| p.match(s)}) {|m| m.match(s)[1]}.to_enum
# can then use .next on that.
#BUT it runs though the entire array when all I want is the first

#<Enumerator: ["Value 1 pref", "Value 1"]:each>

我try 了find,但返回的第一个模式为真,而不是捕获组:

> e=patterns.find{|p| p.match(s) }
=> /: (Value.*?pref)/

# Now I would have to rerun match with the pattern found to get the text

pip ?

推荐答案

而@Dogbert的答案可能是优先的和更惯用的ruby.

您还可以将您演示的each循环和您try 的Enumerable#find的使用组合成以下内容:

val_I_want = patterns.find {|p| m = p.match(s) and break m[1] }
# Or more esoterically and about as golfish as I can get it 
#(modification inspired by @CarySwoveland's use of the ruby global $1)
val_I_want = patterns.find{s[_1]and break$1}

这之所以有效,是因为:

  1. 如果不存在匹配项,String#match将返回nil
  2. and的优先级低于赋值(因此m的赋值发生在右手条件被判断之前)
  3. 在本例中,break使用返回值m[1]退出循环
  4. 如果不存在真值,find将返回nil

或者,更接近于您的原始实现(尽管没有上面的那么吸引人)

val_I_want = patterns.find {|p| if m = p.match(s) then break m[1] end }

Ruby相关问答推荐

类似于模块的 attr_accessor 和 attr_reader 的东西?

字符串长度多显示一个字符 - ruby

如何判断一个对象在 Ruby 中是否可迭代?

如何在 Ruby 中生成一个包含 n 个唯一随机数的列表?

如何使用 Ruby 删除字符串中某个字符后的子字符串?

在 gem 中放置/访问配置文件的位置?

对具有相同键的 2 个哈希属性求和

如何在 VIM 中导航 Ruby 方法?

在 Ubuntu 上安装 Ruby 1.9.1?

如何用 Ruby 覆盖 shell 中的打印行?

在包含任意数量的嵌套散列和数组的散列中查找键/值对

如何在Ruby中获取终端窗口的宽度

如何使用 Ruby 2.3 中引入的 Array#dig 和 Hash#dig?

迭代一个数组,一次 n 项

在不同的换行符上拆分

比较两个数组忽略Ruby中的元素顺序

如何获取当前 rake 任务的 PID?

区分一个Ruby字符串或数组

如何使用 RVM 更新 Ruby 解释器?

判断ruby中的字符长度