如何覆盖String.scan和FindAllString中的匹配行为?

时间:2016-04-27 04:08:29

标签: ruby regex go

我想确定是否可以通过连接任何一个子字符串来创建给定的字符串。作为一个具体示例,我想根据匹配的正则表达式"sgene"的哪一部分拆分字符串sg|ge|ne|n|s。答案是"s""ge""ne",因为这三个部分是如何将字符串从正则表达式(即所需的子字符串集)中分解为多个部分。

Go有regexp.(*Regexp).FindAllString,Ruby有Regexp.scan来执行此操作。在我的代码中,无论我是否在超弦之前或之后对子串进行排序都会丢失一个匹配,因为我的正则表达式重叠。

这是一个在Go中重现问题的程序:

package main

import (
    "fmt"
    "regexp"
)

func main() {
    str := "sgene"
    superBeforeSub := regexp.MustCompile("sg|ge|ne|n|s")
    subBeforeSuper := regexp.MustCompile("n|s|sg|ge|ne")
    regexes := []*regexp.Regexp{superBeforeSub, subBeforeSuper}
    for _, rgx := range regexes {
        fmt.Println(rgx.MatchString(str), rgx.FindAllString(str, -1))
    }
}

该程序输出:

true [sg ne]
true [s ge n]

这是Ruby中的相同程序(Ruby的问题也见here):

str = "sgene"
regexes = [/sg|ge|ne|n|s/, /n|s|sg|ge|ne/] 
regexes.each do |regex|
  puts "%s %s" % [(regex === str).to_s, str.scan(regex).inspect]
end

输出:

true ["sg", "ne"]
true ["s", "ge", "n"]

正则表达式引擎知道字符串可以由正则表达式匹配,但FindAllStringscan与布尔匹配的方式不匹配。他们似乎使用了一个贪婪的最长匹配搜索,忽略了至少一个e。如何使用正则表达式将字符串拆分为[s ge ne]两种语言?

2 个答案:

答案 0 :(得分:0)

这个答案仅涉及Ruby。

我们获得正则表达式

r = /sg|ge|ne|n|s/

对于这个正则表达式,

"sgene".scan r
  #=> ["sg", "ne"]

据我了解,您希望找到正则表达式r_new元素顺序的重新排列,以便

"sgene".scan(r_new).join == "sgene"

以不同的方式查看,但等效地,您将获得一个数组和一个字符串

arr = ["sg", "ge", "ne", "n", "s"]
target = "sgene"

并想确定是否存在arrperm的部分或全部元素的排列,以便

target == perm.join

并且询问是否可以使用正则表达式完成此操作。我不相信它可以,但我无法证明这一点。此外,有几条评论对此表示怀疑。

然而,可以这样做。

(1..arr.size).each_with_object([]) { |n, perms|
  arr.permutation(n).each  { |p| perms << p if p.join==target } }
  #=> [["s", "ge", "ne"]]

我使用select而非any?,以便识别所有有效的排列。例如:

arr = ["sg", "ge", "ne", "n", "s", "e"]
(1..arr.size).each_with_object([]) { |n, perms|
  arr.permutation(n).each  { |p| perms << p if p.join==target } }
  #=> [["sg", "e", "ne"], ["s", "ge", "ne"], ["s", "ge", "n", "e"]]

答案 1 :(得分:0)

也许我不理解你实际上想要做什么,但只是改变正则表达式中符号的顺序。 这不是一个贪婪与非贪婪的事情,因为你没有使用通配符。

这只是正则表达式问题的匹配。

这是修改后的版本on Play。唯一不同的是改变正则表达式本身以提供所需的输出。

我所做的就是将“n”移动到模式的末尾,就像在s|sg|ge|ne|n

中一样
package main

import (
    "fmt"
    "regexp"
)

func main() {
    str := "sgene"
    superBeforeSub := regexp.MustCompile("sg|ge|ne|n|s")
    subBeforeSuper := regexp.MustCompile("n|s|sg|ge|ne")
    orderIActuallyWant := regexp.MustCompile("s|sg|ge|ne|n")
    regexes := []*regexp.Regexp{superBeforeSub, subBeforeSuper, orderIActuallyWant}
    for _, rgx := range regexes {
        fmt.Println(rgx.MatchString(str), rgx.FindAllString(str, -1))
    }
}