如何在Go

时间:2015-11-04 06:18:45

标签: regex go

我试图编写一个可以提取命令的正则表达式,这是我到目前为止使用负面的后观断言所得到的:

\b(?<![@#\/])\w.*

所以输入:

/msg @nickname #channel foo bar baz
/foo #channel @nickname foo bar baz 
foo bar baz
每次都会提取

foo bar baz。见工作示例 https://regex101.com/r/lF9aG7/3

在Go中,这不会编译http://play.golang.org/p/gkkVZgScS_

它抛出:

panic: regexp: Compile(`\b(?<![@#\/])\w.*`): error parsing regexp: invalid or unsupported Perl syntax: `(?<`

我做了一些研究,并且在语言中不支持负面的外观,以保证O(n)时间。

我怎样才能重写这个正则表达式,以便在没有负面背后的情况下做同样的事情?

2 个答案:

答案 0 :(得分:2)

因为在你否定的背后,你只使用一个简单的字符集;你可以用一个否定的字符集替换它:

\b[^@#/]\w.*

如果在字符串的开头允许,则使用^锚:

(?:^|[^@#\/])\b\w.*

根据您问题中的Go playground链接中的示例,我认为您希望过滤掉以[#@/]中的字符开头的所有字词。您可以使用filter功能:

func Filter(vs []string, f func(string) bool) []string {
    vsf := make([]string, 0)
    for _, v := range vs {
        if f(v) {
            vsf = append(vsf, v)
        }
    }
    return vsf
}

Process函数,它使用上面的过滤器:

func Process(inp string) string {
    t := strings.Split(inp, " ")
    t = Filter(t, func(x string) bool {
        return strings.Index(x, "#") != 0 &&
            strings.Index(x, "@") != 0 &&
            strings.Index(x, "/") != 0
    })
    return strings.Join(t, " ")
}

可以在playground http://play.golang.org/p/ntJRNxJTxo的行动中看到它

答案 1 :(得分:1)

您实际上可以匹配前面的字符(或行的开头)并使用组在子表达式中获取所需的文本。

<强>正则表达式

(?:^|[^@#/])\b(\w+)
  • (?:^|[^@#/])匹配^行的开头或[^@#/]@#/以外的任何字符
  • \b用于断言单词开头的单词边界
  • (\w+)生成子表达式
    • 并匹配\w+任意数量的字符

<强>代码

cmds := []string{
    `/msg @nickname #channel foo bar baz`,
    `#channel @nickname foo bar baz /foo`,
    `foo bar baz @nickname #channel`,
    `foo bar baz#channel`}

regex := regexp.MustCompile(`(?:^|[^@#/])\b(\w+)`)


// Loop all cmds
for _, cmd := range cmds{
    // Find all matches and subexpressions
    matches := regex.FindAllStringSubmatch(cmd, -1)

    fmt.Printf("`%v` \t==>\n", cmd)

    // Loop all matches
    for n, match := range matches {
        // match[1] holds the text matched by the first subexpression (1st set of parentheses)
        fmt.Printf("\t%v. `%v`\n", n, match[1])
    }
}

<强>输出

`/msg @nickname #channel foo bar baz`   ==>
    0. `foo`
    1. `bar`
    2. `baz`
`#channel @nickname foo bar baz /foo`   ==>
    0. `foo`
    1. `bar`
    2. `baz`
`foo bar baz @nickname #channel`    ==>
    0. `foo`
    1. `bar`
    2. `baz`
`foo bar baz#channel`   ==>
    0. `foo`
    1. `bar`
    2. `baz`

<强>游乐场
http://play.golang.org/p/AaX9Cg-7Vx