Ruby 正则表达式:多个匹配之前的文本

Ruby 正则表达式:多个匹配之前的文本,ruby,regex,Ruby,Regex,想法。给定字符串,返回所有匹配项(带重叠)以及这些匹配项之前的文本 示例。对于文本atatgcgcatat和查询atat有三个匹配项,所需的输出是atat、atatgcgcatat和atatgcgcatat 问题。我使用Ruby 2.2和String#scan方法获得多个匹配项。我尝试使用lookahead,但是regex/(?=(.*atat))/返回以atat结尾的每个子字符串。一定有一些正则表达式魔法可以解决这个问题,但我无法找出正确的拼写。鉴于正则表达式的性质和用途,没有办法做到这一点。

想法。给定字符串,返回所有匹配项(带重叠)以及这些匹配项之前的文本

示例。对于文本
atatgcgcatat
和查询
atat
有三个匹配项,所需的输出是
atat
atatgcgcatat
atatgcgcatat


问题。我使用Ruby 2.2和
String#scan
方法获得多个匹配项。我尝试使用lookahead,但是regex
/(?=(.*atat))/
返回以
atat
结尾的每个子字符串。一定有一些正则表达式魔法可以解决这个问题,但我无法找出正确的拼写。

鉴于正则表达式的性质和用途,没有办法做到这一点。当正则表达式匹配文本时,无法在另一个匹配中包含相同的文本。因此,我能想到的最佳选择是使用“向后看”来查找每场比赛的结束位置:

(?<=atat)

(?鉴于正则表达式的性质和用途,没有办法做到这一点。当正则表达式与文本匹配时,就没有办法将相同的文本包含在另一个匹配中。因此,我能想到的最佳选择是使用查找来查找每个匹配的结束位置:

(?<=atat)

(?似乎没有办法一次性解决这个问题

一种可能的解决方案是在使用
String#scan
时使用获取匹配索引,然后返回切片字符串数组:

def find_by_end text, query
    res = []
    n = query.length
    text.scan( /(?=(#{query}))/ ) do |m|
        res << text.slice(0, $~.offset(0).first + n)
    end
    res
end

find_by_end "atatgcgcatatat", "atat" #=> ["atat", "atatgcgcatat", "atatgcgcatatat"]

看来,不可能一下子解决这个问题

一种可能的解决方案是在使用
String#scan
时使用获取匹配索引,然后返回切片字符串数组:

def find_by_end text, query
    res = []
    n = query.length
    text.scan( /(?=(#{query}))/ ) do |m|
        res << text.slice(0, $~.offset(0).first + n)
    end
    res
end

find_by_end "atatgcgcatatat", "atat" #=> ["atat", "atatgcgcatat", "atatgcgcatatat"]

我相信这至少比OP的答案要好:

text = "atatgcgcatatat"
query = "atat"

res = []
text.scan(/(?=#{query})/){res.push($` + query)}                                  #`
res # => ["atat", "atatgcgcatat", "atatgcgcatatat"]

我相信这至少比OP的答案要好:

text = "atatgcgcatatat"
query = "atat"

res = []
text.scan(/(?=#{query})/){res.push($` + query)}                                  #`
res # => ["atat", "atatgcgcatat", "atatgcgcatatat"]
您可以这样做:

str = 'atatgcgcatatat'
target = 'atat'

[].tap do |a|
  str.gsub(/(?=#{target})/) { a << str[0, $~.end(0)+target.size] }
end
  #=> ["atat", "atatgcgcatat", "atatgcgcatatat"]
str='atatgcgcatat'
目标='atat'
[]点击do | a|
str.gsub(/(?={target})/{a[“atat”,“atatgcgcatat”,“atatgcgcatat”]
请注意,
gsub
返回的字符串将被丢弃。

您可以执行以下操作:

str = 'atatgcgcatatat'
target = 'atat'

[].tap do |a|
  str.gsub(/(?=#{target})/) { a << str[0, $~.end(0)+target.size] }
end
  #=> ["atat", "atatgcgcatat", "atatgcgcatatat"]
str='atatgcgcatat'
目标='atat'
[]点击do | a|
str.gsub(/(?={target})/{a[“atat”,“atatgcgcatat”,“atatgcgcatat”]


请注意,
gsub
返回的字符串已被丢弃。

但如何获得多个匹配项?
“atatgcgcatatat”。scan/*atat/#=>[“atatgcgcatatat”]
谢谢,这很有帮助!因为没有一种方法可以一次性获得输出,所以我也找到了一种方法来获得结果,它与您的建议略有不同。我将把它作为一个单独的答案发布。谢谢,@Nakilon,这很有用!但是我如何获得多个匹配?
“atatgcgcatat”。scan/*atat/#=>[“ATATGCGCATAT”]
谢谢,这很有帮助!因为没有一种方法可以一次性获得输出,所以我也找到了一种方法来获得结果,这与您的建议略有不同。我将把它作为一个单独的答案发布。谢谢,@Nakilon,这很有用!我想这不是一次就可以得到的。匹配不仅仅是重叠的,而是星形的t位于同一索引。成功后,您需要将索引移动到每个匹配开始处,以查看是否有其他匹配不等于上一个匹配。非常感谢您的评论!反转字符串,并使用相同的模式。@CasimiretHippolyte我尝试了反转字符串的想法,但对我来说似乎很难看:
“atatgcatatat”“.reverse.scan(/(?=(tata.*)/).flatte.map(&:reverse)。reverse
。我投票给sawa,选出最佳答案。@Nakilon得到了帮助(无论是否需要)。我想,只需一次就没有办法了。匹配不仅仅是重叠的,它们从同一个索引开始。成功后,您需要将索引移动到每个匹配的开始处,以查看是否有其他匹配不等于上一个匹配。非常感谢您的评论!反转字符串,并使用相同的模式。@CasimiretHippolyte我已经尝试了ide一个简单的方法是反转字符串,但对我来说似乎很难看:
“atatgcatatat”.reverse.scan(/(?=(tata.*)/).flatte.map(&:reverse)。reverse
。我对最佳答案的投票给了sawa。@Nakilon得到了帮助(无论是否需要)我想,没有必要使用中间数组:
text.to_enum(:scan,/(?你可以像我一样使用
tap
[]点击{a | text.scan(/(?={query})/{a[“atat”、“atatgcatat”、“atatgcatat”]
。确实如此!我也用Ruby实现了其他想法,并将它们添加到了我的答案中。我想,没有必要使用中间数组:
text.to_enum(:scan,/(?你可以像我一样使用
tap
[]点击{a | text.scan(/(?={query})/){a[“atat”,“atatgcatat”,“atatgcatat”,“atatgcatat”
)。