web-dev-qa-db-fra.com

Utiliser des correspondances nommées de Go regex

Je viens de python, donc je ne regarde probablement pas ça de la bonne façon. Je voudrais créer une expression rationnelle assez compliquée et pouvoir accéder aux champs correspondants par nom. Je n'arrive pas à trouver un bon exemple. Le plus proche que j'ai réussi à obtenir est la suivante:

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

La ligne commentée est la façon dont je m'attendrais à accéder aux champs nommés en python. Quelle est la façon équivalente de le faire en aller? Ou si j'ai besoin de convertir le match en carte, quelle est la manière la plus idiomatique de créer et d’accéder ensuite à la carte?

29
Kurt Schwehr

Вы можете ссылаться на свои именованные группы захвата, используя 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

41
hwnd

Je n'ai pas la réputation de commenter, alors pardonnez-moi si cela ne devrait pas être une "réponse", mais j'ai trouvé la réponse ci-dessus utile, je l'ai donc intégrée à une fonction:

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
}

Exemple d'utilisation sur le terrain de jeu: https://play.golang.org/p/LPLND6FnTXO

J'espère que cela sera utile à quelqu'un d'autre. Aimez la facilité des groupes de capture nommés dans Go. 

6
gpanda

Les autres approches génèrent une erreur lorsqu'aucune correspondance n'a été trouvée pour un "groupe nommé". Cependant, ce qui suit crée une map avec tous les groupes nommés réellement trouvés:

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

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

Cette approche va seulement renvoyer la carte avec les correspondances du groupe nommé. S'il n'y a pas de correspondance, cela retournera simplement nil. J'ai trouvé que c'était beaucoup plus facile à gérer que les erreurs commises si aucune correspondance n'était trouvée.

0
russt