Regex - Как захватить "несколько" повторяющихся групп в регулярных выражениях Голанга?

У меня есть следующий текстовый файл, который я хотел бы проанализировать, чтобы получить отдельные поля:

host_group_web = ( )
host_group_lbnorth = ( lba050 lbhou002 lblon003 )

Поля, которые я хотел бы извлечь, выделены жирным шрифтом

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

host_group_web не имеет элементов между (), поэтому эта часть будет игнорироваться

Я назвал первую группу как nodegroup, а элементы между () как узлы

Я читаю файл построчно и сохраняю результаты для дальнейшей обработки.

На Голанге это фрагмент Regex, который я использую:

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])
  }
}

Я получаю следующий вывод, в котором отсутствуют остальные совпадения для узлов с именем group.

GroupName: nodegroup GroupMatch: lbnorth
GroupName: nodes GroupMatch: lba050

Сниппет на детской площадке Голанга

Мой вопрос: как мне получить Regex в Golang, который бы соответствовал группе узлов и всем узлам, которые могут быть в строке, например, lba050 lbhou002 lblon003. Количество узлов будет варьироваться, от 0 - столько же.

1 ответ

Решение

Если вы хотите захватить имя группы и все возможные имена узлов, вам следует работать с другим шаблоном регулярных выражений. Этот должен захватить их всех за один раз. Нет необходимости работать с именованными группами захвата, но вы можете, если хотите.

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])
}

Увидеть это в действии на детской площадке

Альтернатива:

Вы также можете работать так, как awk будет выполнять синтаксический анализ: используйте выражение regex p, чтобы разбить строки в токенах и распечатать нужные токены. Конечно, расположение линий должно быть таким же, как приведено в вашем примере.

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)
    }

}

Увидеть это в действии на детской площадке

Другие вопросы по тегам