Использование именованных совпадений из 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. Какой эквивалентный способ сделать это? Или, если мне нужно преобразовать соответствие в карту, какой самый идиоматический способ сделать, а затем получить доступ к карте?
Ответы
Ответ 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
. Я обнаружил, что гораздо легче иметь дело с ошибками, если не найдено совпадение.