Подтвердить что ты не робот

Использование именованных совпадений из Go regex

Я прихожу из python, так что я, вероятно, просто не смотрю на это правильно. Я хотел бы создать довольно сложное регулярное выражение и получить доступ к совпадению полей по имени. Я не могу найти хороший пример. Самое близкое, что мне удалось получить, это следующее:

package main

import (
  "fmt"
  "regexp"
)

var myExp = regexp.MustCompile(`(?P<first>\d+)\.(\d+).(?P<second>\d+)`)

func main() {
  fmt.Printf("%+v", myExp.FindStringSubmatch("1234.5678.9"))

  match := myExp.FindStringSubmatch("1234.5678.9")
    for i, name := range myExp.SubexpNames() {
        fmt.Printf("'%s'\t %d -> %s\n", name, i, match[i])
    }
    //fmt.Printf("by name: %s %s\n", match["first"], match["second"])
}

Записанная строка - это то, как я ожидаю получить доступ к именованным полям в python. Какой эквивалентный способ сделать это? Или, если мне нужно преобразовать соответствие в карту, какой самый идиоматический способ сделать, а затем получить доступ к карте?

4b9b3361

Ответ 1

Вы можете ссылаться на свои названные группы захвата, используя следующую map:

package main

import (
    "fmt"
    "regexp"
)

var myExp = regexp.MustCompile('(?P<first>\d+)\.(\d+).(?P<second>\d+)')

func main() {
    match := myExp.FindStringSubmatch("1234.5678.9")
    result := make(map[string]string)
    for i, name := range myExp.SubexpNames() {
        if i != 0 && name != "" {
            result[name] = match[i]
        }
    }
    fmt.Printf("by name: %s %s\n", result["first"], result["second"])
}

GoPlay

Ответ 2

У меня нет репутации, чтобы прокомментировать, поэтому простите меня, если это не должно быть "ответом", но я нашел ответ выше, поэтому я включил его в функцию:

func reSubMatchMap(r *regexp.Regexp, str string) (map[string]string) {
    match := r.FindStringSubmatch(str)
    subMatchMap := make(map[string]string)
    for i, name := range r.SubexpNames() {
        if i != 0 {
            subMatchMap[name] = match[i]
        }
    }

    return subMatchMap
}

Пример использования на игровой площадке: https://play.golang.org/p/LPLND6FnTXO

Надеюсь, это поможет кому-то другому. Полюбите легкость названных групп захвата в Go.

Ответ 3

Другие подходы будут выдавать ошибку, если не найдено совпадение для "именованной группы".

Однако следующее создает map с теми именованными группами, которые были фактически найдены:

func findNamedMatches(regex *regexp.Regexp, str string) map[string]string {
    match := regex.FindStringSubmatch(str)

    results := map[string]string{}
    for i, name := range match {
        results[regex.SubexpNames()[i]] = name
    }
    return results
}

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