如何使用正则表达式捕获“多个”重复组

6

我有一个文本文件,希望能将其中的各个字段解析出来:

host_group_web = ( )
host_group_lbnorth = ( lba050 lbhou002 lblon003 )

我想要提取的字段已用粗体标出。

  • host_group_web = ( )
  • host_group_lbnorth = (lba505 lbhou002 lblon003)

host_group_web( )之间没有任何项,因此该部分将被忽略。

我将第一组命名为nodegroup,括号中间的项目称为nodes

我正在逐行读取文件,并将结果存储以进行进一步处理。

在Golang中,这是我使用的正则表达式片段:

hostGroupLine := "host_group_lbnorth = ( lba050 lbhou002 lblon003 )"
hostGroupExp := regexp.MustCompile(`host_group_(?P<nodegroup>[[:alnum:]]+)\s*=\s*\(\s*(?P<nodes>[[:alnum:]]+\s*)`)
hostGroupMatch := hostGroupExp.FindStringSubmatch(hostGroupLine)

for i, name := range hostGroupExp.SubexpNames() {
  if i != 0 {
    fmt.Println("GroupName:", name, "GroupMatch:", hostGroupMatch[i])
  }
}

我得到了以下输出,其中缺少名为nodes的组的其余匹配项。
GroupName: nodegroup GroupMatch: lbnorth
GroupName: nodes GroupMatch: lba050

Golang Playground中的代码片段

我的问题是,如何在Golang中使用正则表达式来匹配nodegroup和可能在同一行中的所有nodes,例如lba050 lbhou002 lblon003。节点数量将会有所变化,从0个到很多个不等。


1
你可以重复匹配一个捕获组,但它只会存储该组的最后一次匹配。我认为没有办法绕过先在一轮中捕获所有节点,然后在第二轮中拆分它们。 - Sebastian Proske
谢谢。我猜这会节省我一些头脑的劳动。干杯! - mindrunner
1个回答

5

如果您想捕获组名和所有可能的节点名称,您应该使用不同的正则表达式模式。这个模式应该可以一次性捕获它们所有。不需要使用命名捕获组,但如果您愿意,可以使用。

hostGroupExp := regexp.MustCompile(`host_group_([[:alnum:]]+)|([[:alnum:]]+) `)

hostGroupLine := "host_group_lbnorth = ( lba050 lbhou002 lblon003 )"
hostGroupMatch := hostGroupExp.FindAllStringSubmatch(hostGroupLine, -1)

fmt.Printf("GroupName: %s\n", hostGroupMatch[0][1])
for i := 1; i < len(hostGroupMatch); i++ {
    fmt.Printf("  Node: %s\n", hostGroupMatch[i][2])
}

playground中查看它的运作。

替代方案:

您还可以像awk一样工作来解析:使用正则表达式将行拆分为令牌,并打印所需的令牌。当然,行布局应与您的示例中给出的相同。

package main

import (
    "fmt"
    "regexp"
)

func printGroupName(tokens []string) {
    fmt.Printf("GroupName: %s\n", tokens[2])
    for i := 5; i < len(tokens)-1; i++ {
        fmt.Printf("  Node: %s\n", tokens[i])
    }
}

func main() {

    // regexp line splitter (either _ or space)
    r := regexp.MustCompile(`_| `)

    // lines to parse
    hostGroupLines := []string{
        "host_group_lbnorth = ( lba050 lbhou002 lblon003 )",
        "host_group_web = ( web44 web125 )",
        "host_group_web = ( web44 )",
        "host_group_lbnorth = ( )",
    }

    // split lines on regexp splitter and print result
    for _, line := range hostGroupLines {
        hostGroupMatch := r.Split(line, -1)
        printGroupName(hostGroupMatch)
    }

}

playground中看它的实际运行效果。


你是正确的。改变正则表达式确实是更好的解决方案。感谢您提供这段代码。我一定会保存下来以备将来参考。 - mindrunner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接