如何在 Go 中模拟负向后视

我正在尝试编写一个可以提取命令的正则表达式,这是到目前为止我使用否定的lookbehind断言所得到的:


\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) 时间。


我怎样才能重写这个正则表达式,让它在没有负面回顾的情况下做同样的事情?


慕村9548890
浏览 161回答 2
2回答

幕布斯6054654

由于在否定的回顾中,您只使用了一个简单的字符集;您可以用否定字符集替换它:\b[^@#/]\w.*如果在字符串的开头允许,则使用^锚点:(?:^|[^@#\/])\b\w.*根据您问题中 Go 游乐场链接中的示例,我认为您希望过滤掉所有以[#@/]. 您可以使用一个filter函数:func Filter(vs []string, f func(string) bool) []string {&nbsp; &nbsp; vsf := make([]string, 0)&nbsp; &nbsp; for _, v := range vs {&nbsp; &nbsp; &nbsp; &nbsp; if f(v) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; vsf = append(vsf, v)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; return vsf}和一个Process函数,它利用了上面的过滤器:func Process(inp string) string {&nbsp; &nbsp; t := strings.Split(inp, " ")&nbsp; &nbsp; t = Filter(t, func(x string) bool {&nbsp; &nbsp; &nbsp; &nbsp; return strings.Index(x, "#") != 0 &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; strings.Index(x, "@") != 0 &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; strings.Index(x, "/") != 0&nbsp; &nbsp; })&nbsp; &nbsp; return strings.Join(t, " ")}它可以在操场上看到http://play.golang.org/p/ntJRNxJTxo

慕的地10843

您实际上可以匹配前面的字符(或行的开头)并使用组在子表达式中获取所需的文本。正则表达式(?:^|[^@#/])\b(\w+)(?:^|[^@#/])匹配^行首或[^@#/]任何字符,除了@#/\b&nbsp;断言单词开头的单词边界(\w+)&nbsp;生成子表达式并匹配\w+任意数量的单词字符代码cmds := []string{&nbsp; &nbsp; `/msg @nickname #channel foo bar baz`,&nbsp; &nbsp; `#channel @nickname foo bar baz /foo`,&nbsp; &nbsp; `foo bar baz @nickname #channel`,&nbsp; &nbsp; `foo bar baz#channel`}regex := regexp.MustCompile(`(?:^|[^@#/])\b(\w+)`)// Loop all cmdsfor _, cmd := range cmds{&nbsp; &nbsp; // Find all matches and subexpressions&nbsp; &nbsp; matches := regex.FindAllStringSubmatch(cmd, -1)&nbsp; &nbsp; fmt.Printf("`%v` \t==>\n", cmd)&nbsp; &nbsp; // Loop all matches&nbsp; &nbsp; for n, match := range matches {&nbsp; &nbsp; &nbsp; &nbsp; // match[1] holds the text matched by the first subexpression (1st set of parentheses)&nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("\t%v. `%v`\n", n, match[1])&nbsp; &nbsp; }}输出`/msg @nickname #channel foo bar baz`&nbsp; &nbsp;==>&nbsp; &nbsp; 0. `foo`&nbsp; &nbsp; 1. `bar`&nbsp; &nbsp; 2. `baz``#channel @nickname foo bar baz /foo`&nbsp; &nbsp;==>&nbsp; &nbsp; 0. `foo`&nbsp; &nbsp; 1. `bar`&nbsp; &nbsp; 2. `baz``foo bar baz @nickname #channel`&nbsp; &nbsp; ==>&nbsp; &nbsp; 0. `foo`&nbsp; &nbsp; 1. `bar`&nbsp; &nbsp; 2. `baz``foo bar baz#channel`&nbsp; &nbsp;==>&nbsp; &nbsp; 0. `foo`&nbsp; &nbsp; 1. `bar`&nbsp; &nbsp; 2. `baz`游乐场http://play.golang.org/p/AaX9Cg-7Vx
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go