为了账号安全,请及时绑定邮箱和手机立即绑定

匹配直到字符,但是,不要包含该字符

匹配直到字符,但是,不要包含该字符

Go
千万里不及你 2022-09-19 10:43:43
我正在尝试与以下输入进行匹配:foo=bar baz foo:1  foo:234.mds32  notfoo:baz  foo:bak foo:nospace foo:bar和输出 6 匹配:除 .匹配项应类似(即不包括尾随空格或前导空格。notfoofoo:bar一般来说,我试图匹配的规则是:查找任何 kv 对,其中键为 ,并且 kv 对由 或 分隔。foo=:对是彼此分离的字符串。kv 对之间可能有多个空格或随机字符串。作为 ^ 的结果,kv 对必须在两侧具有空格或行开始/结束。我目前对此最好的正则表达式是 ,然后提取组。'(?:\s|^)(?P<primary>foo[:=].+?)\s'primary这样做的问题是因为我们包含作为匹配的一部分,我们遇到了重叠正则表达式的问题:因为我们尝试空格字符匹配2x,并且golang正则表达式不返回重叠匹配项。\sfoo:bak foo:nospace foo:bar在其他正则表达式引擎中,我认为可以使用前瞻,但据我所知,golang正则表达式不允许这样做。有什么办法可以做到这一点吗?去游乐场链接: https://play.golang.org/p/n8gnWwpiBSR
查看完整描述

3 回答

?
慕仙森

TA贡献1827条经验 获得超7个赞

遗憾的是,Go中没有外观支持,因此,您可以通过加倍空格(例如与\s)然后与匹配来解决此问题:regexpregexp.MustCompile().ReplaceAllString(d, "$0$0")(?:\s|^)(?P<primary>foo[:=]\S+(?:\s+[^:\s]+)*)(?:\s|$)


package main


import (

    "fmt"

    "regexp"

)


func main() {

    var d = `foo=bar baz foo:1  foo:234.mds32  notfoo:baz  foo:bak foo:nospace foo:bar`

    d = regexp.MustCompile(`\s`).ReplaceAllString(d, "$0$0")

    r := regexp.MustCompile(`(?:\s|^)(?P<primary>foo[:=]\S+(?:\s+[^:\s]+)*)(?:\s|$)`)

    idx := r.SubexpIndex("primary")

    for _, m := range r.FindAllStringSubmatch(d, -1) {

        fmt.Printf("%q\n", m[idx])

    }

}

请参阅 Go 演示。输出:


"foo=bar  baz"

"foo:1"

"foo:234.mds32"

"foo:bak"

"foo:nospace"

"foo:bar"

详细信息

  • (?:\s|^)- 空格或字符串的开头

  • (?P<primary>foo[:=]\S+(?:\s+[^:\s]+)*)- 组“主要”:冒号或字符,一个或多个非空格,然后零个或多个出现一个或多个空格,然后是一个或多个字符,而不是空格或冒号foo=

  • (?:\s|$)- 白带或字符串的末端。


查看完整回答
反对 回复 2022-09-19
?
aluckdog

TA贡献1847条经验 获得超7个赞

您可以采取以下几种方法:

  1. 只需将您的模式更改为维克托·斯特里比纽在评论中提到的模式,而不是匹配。这解决了没有恶作剧的问题,但我会列出一些可能适用于类似问题的选择,这些问题不能轻易被否定。(?:\s|^)(?P<primary>foo[:=]\S+).+?\s

  2. 由于问题在于功能不允许重叠,因此不要使用它们!相反,滚动你自己的,用于获取一个匹配项的边界,通过切片字符串来提取匹配的文本,然后执行并循环直到返回零。FindAllFindStringSubmatchIndexd = d[endIndex-1:]FindStringSubmatchIndex

  3. 使用 模式将输入字符串分解为空格分隔的组件,然后丢弃不在 上的组件。您甚至可以改用。其余的将是您想要的匹配项,并且它们周围的空格将被拆分丢弃。在我看来,这个版本比试图使用匹配更清楚地传达了意图。regexp.Split()\s+regexp.Match()^foo[:=]strings.HasPrefix("foo:") || strings.HasPrefix("foo=")


查看完整回答
反对 回复 2022-09-19
?
哈士奇WWW

TA贡献1799条经验 获得超6个赞

其他人根据要求使用正则表达式给出了很好的答案。我可以大胆地建议一个非正则表达式的答案吗?


我发现正则表达式不是这种情况的最佳解决方案。最好使用拆分字符串以获取子字符串列表。对于每个字符串,根据它是否具有或两者都没有来拆分它。该函数在解析方面做得很好,类似于 中的默认拆分,它跳过了一行中的多个空格。strings.Fields(original)=:Fields()awk


工作示例:https://play.golang.org/p/xXaA9skdplz



    original := `foo=bar baz foo:1  foo:234.mds32  notfoo:baz  foo:bak foo:nospace foo:bar`


    for _, item := range strings.Fields(original) {

        if kv := strings.SplitN(item, "=", 2); len(kv) == 2 {

            fmt.Printf("key/value: %q -> %q\n", kv[0], kv[1])

        } else if kv := strings.SplitN(item, ":", 2); len(kv) == 2 {

            fmt.Printf("key/value: %q -> %q\n", kv[0], kv[1])

        } else {

            fmt.Printf("key: %q\n", item)

        }


    }

显然,您需要修改此代码以收集答案而不是打印它们。


如果您必须使用正则表达式,请使用其他答案。


查看完整回答
反对 回复 2022-09-19
  • 3 回答
  • 0 关注
  • 82 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信