【问题标题】:Regex named groups in Golang not capturing correctlyGolang 中的正则表达式命名组未正确捕获
【发布时间】:2015-08-07 11:35:43
【问题描述】:

我有以下字符串,它是来自我们网络上的投影仪的发现数据包:

AMXB<-SDKClass=VideoProjector><-UUID=ABCDEFG><-Make=DELL><-Model=S300w><-Revision=0.2.0>

我正在尝试编写一些将其转换为地图的 Golang 代码,因此我可以调用 details["UUID"] 并让它返回 ABCDEFG。我写了一个看起来像这样的正则表达式:

(?:UUID=)(?P<UUID>(.*?))>|(?:Make=)(?P<Make>(.*?))>|(?:Model=)(?P<Model>(.*?))>|(?:SDKClass=)(?P<SDKClass>(.*?))>

当我使用regex 101 在线测试它时,它似乎与所有内容都匹配得很好,除了编号的组,但我可以很容易地忽略那些:

第 1 场

SDKClass [15-29] VideoProjector

  1. [15-29] 视频投影仪

第 2 场

UUID [37-49] B8AC6FDFE1E2

  1. [37-49] B8AC6FDFE1E2

第 3 场

制造 [57-61] 戴尔

  1. [57-61] 戴尔

第 4 场

型号 [70-75] S300w

  1. [70-75] S300w

但是当我在 Golang 中尝试时,我得到了different results(注意:这些结果是使用 go-spew 整理的,以便于阅读):

([][]string) (len=4 cap=10) {
 ([]string) (len=9 cap=9) {
  (string) (len=24) "SDKClass=VideoProjector>",
  (string) "",
  (string) "",
  (string) "",
  (string) "",
  (string) "",
  (string) "",
  (string) (len=14) "VideoProjector",
  (string) (len=14) "VideoProjector"
 },
 ([]string) (len=9 cap=9) {
  (string) (len=18) "UUID=B8AC6FDFE1E2>",
  (string) (len=12) "B8AC6FDFE1E2",
  (string) (len=12) "B8AC6FDFE1E2",
  (string) "",
  (string) "",
  (string) "",
  (string) "",
  (string) "",
  (string) ""
 },
 ([]string) (len=9 cap=9) {
  (string) (len=10) "Make=DELL>",
  (string) "",
  (string) "",
  (string) (len=4) "DELL",
  (string) (len=4) "DELL",
  (string) "",
  (string) "",
  (string) "",
  (string) ""
 },
 ([]string) (len=9 cap=9) {
  (string) (len=12) "Model=S300w>",
  (string) "",
  (string) "",
  (string) "",
  (string) "",
  (string) (len=5) "S300w",
  (string) (len=5) "S300w",
  (string) "",
  (string) ""
 }
}

我的正则表达式有什么问题,我该如何解决?我已经尝试了几乎所有的表达式组合(我现在几乎是一个正则表达式大师:\)

【问题讨论】:

    标签: regex go


    【解决方案1】:

    据我所知,它的工作原理与您编写的完全一样,并且在 regex101 和 Go 中同样出色。您观察到的差异只是因为结果呈现方式的不同。

    让我们仔细看看 regex101 返回的结果。比如这个:

    MATCH 1
    SDKClass    [15-29]  `VideoProjector`
    8.          [15-29]  `VideoProjector`
    

    它基本上说它找到了两个子匹配,其中一个被命名,另一个在索引 8 上。然后让我们看一下 Go:

    ([]string) (len=9 cap=9) {
      (string) (len=24) "SDKClass=VideoProjector>",
      (string) "",
      (string) "",
      (string) "",
      (string) "",
      (string) "",
      (string) "",
      (string) (len=14) "VideoProjector",
      (string) (len=14) "VideoProjector"
     },
    

    它表示它为第 7 组和第 8 组找到了两个子匹配项。为了获得第 7 组的名称,您应该调用r.SubexpNames(),这将为r.SubexpNames()[7] 返回SDKClass

    所以两者都返回相同的结果。

    【讨论】:

    • 谢谢。我看了看,这可以让我得到匹配名称,但仍然不是值,没有大量循环和删除空值。最后,我用 FindAllString 换掉了 FindAllStringSubmatch,现在我得到了一组更好的结果。不完美,但没有什么是 Split() 解决不了的:play.golang.org/p/uHKGiFG-5s
    • 我觉得只要找<-([^=]+)=([^>]+)>play.golang.org/p/KEK5EtqM_5就可以改进
    【解决方案2】:

    因此,在 AlexAtNet 的帮助下,我得到了答案——足以让我继续前进。这是我的最终代码:

    r, _ := regexp.Compile("<-([^=]+)=([^>]+)>")
    
    match := r.FindAllString(string(msg), -1)
    result := make(map[string]string)
    
    for _, p := range match {
        split := strings.Split(p, "=")
        result[split[0]] = split[1]
    }
    

    结果如下:

    ([]string) (len=4 cap=10) {
     (string) (len=23) "SDKClass=VideoProjector",
     (string) (len=17) "UUID=B8AC6FDFE1E2",
     (string) (len=9) "Make=DELL",
     (string) (len=11) "Model=S300w"
     (string) (len=14) "Revision=0.2.0"
    }
    

    但我可以通过= 简单地Split() 字符串并获取属性名称和值。

    我仍在寻找对我的正则表达式和/或代码的改进,以便我可以看到如何正确地做到这一点,而无需额外的拆分或过多的代码。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-05-23
      • 2019-03-17
      • 2011-03-03
      • 1970-01-01
      • 1970-01-01
      • 2019-05-19
      • 2018-02-13
      • 2014-10-27
      相关资源
      最近更新 更多