webentwicklung-frage-antwort-db.com.de

So erhalten Sie die Funktion zum Erfassen von Gruppen in regulären Ausdrücken von Go

Ich portiere eine Bibliothek von Ruby nach Go und habe gerade festgestellt, dass reguläre Ausdrücke in Ruby nicht mit Go (google RE2) kompatibel sind Ich habe darauf hingewiesen, dass Ruby & Java (und andere Sprachen verwenden reguläre PCRE-Ausdrücke (Perl-kompatibel, die das Erfassen von Gruppen unterstützen))) Schreiben Sie meine Ausdrücke so, dass sie in Go korrekt kompiliert werden.

Zum Beispiel habe ich den folgenden regulären Ausdruck:

`(?<Year>\d{4})-(?<Month>\d{2})-(?<Day>\d{2})`

Dies sollte Eingaben akzeptieren wie:

2001-01-20

Mit den Erfassungsgruppen können Jahr, Monat und Tag in Variablen erfasst werden. Es ist sehr einfach, den Wert jeder Gruppe zu ermitteln. Indizieren Sie einfach die zurückgegebenen übereinstimmenden Daten mit dem Gruppennamen und Sie erhalten den Wert zurück. So, um zum Beispiel das Jahr zu bekommen, so etwas wie diesen Pseudocode:

m=expression.Match("2001-01-20")
year = m["Year"]

Dies ist ein Muster, das ich häufig in meinen Ausdrücken verwende, daher muss ich viel umschreiben.

Gibt es eine Möglichkeit, diese Art von Funktionalität in Go regexp zu erhalten? Wie soll ich diese Ausdrücke umschreiben?

40
Plastikfan

wie soll ich diese Ausdrücke umschreiben?

Füge ein paar Ps hinzu, wie definiert hier :

(?P<Year>\d{4})-(?P<Month>\d{2})-(?P<Day>\d{2})

Verweisen Sie auf die Namen der Erfassungsgruppen mit re.SubexpNames().

Und benutze wie folgt :

package main

import (
    "fmt"
    "regexp"
)

func main() {
    r := regexp.MustCompile(`(?P<Year>\d{4})-(?P<Month>\d{2})-(?P<Day>\d{2})`)
    fmt.Printf("%#v\n", r.FindStringSubmatch(`2015-05-27`))
    fmt.Printf("%#v\n", r.SubexpNames())
}
56
thwd

Ich habe eine Funktion für den Umgang mit URL-Ausdrücken erstellt, die aber auch Ihren Anforderungen entspricht. Sie können this Snippet überprüfen, aber es funktioniert einfach so:

/**
 * Parses url with the given regular expression and returns the 
 * group values defined in the expression.
 *
 */
func getParams(regEx, url string) (paramsMap map[string]string) {

    var compRegEx = regexp.MustCompile(regEx)
    match := compRegEx.FindStringSubmatch(url)

    paramsMap = make(map[string]string)
    for i, name := range compRegEx.SubexpNames() {
        if i > 0 && i <= len(match) {
            paramsMap[name] = match[i]
        }
    }
    return
}

Sie können diese Funktion wie folgt verwenden:

params := getParams(`(?P<Year>\d{4})-(?P<Month>\d{2})-(?P<Day>\d{2})`, `2015-05-27`)
fmt.Println(params)

und die Ausgabe wird sein:

map[Year:2015 Month:05 Day:27]
18
eluleci

Um RAM und die CPU-Auslastung zu verbessern, ohne anonyme Funktionen in der Schleife aufzurufen und ohne Arrays in den Speicher der Schleife mit der Funktion "Anhängen" zu kopieren, siehe folgendes Beispiel:

Sie können mehr als eine Untergruppe mit mehrzeiligem Text speichern, ohne Zeichenfolge mit '+' anzufügen und ohne for-Schleife innerhalb von for-Schleife zu verwenden (wie in anderen hier veröffentlichten Beispielen).

txt := `2001-01-20
2009-03-22
2018-02-25
2018-06-07`

regex := *regexp.MustCompile(`(?s)(\d{4})-(\d{2})-(\d{2})`)
res := regex.FindAllStringSubmatch(txt, -1)
for i := range res {
    //like Java: match.group(1), match.gropu(2), etc
    fmt.Printf("year: %s, month: %s, day: %s\n", res[i][1], res[i][2], res[i][3])
}

Ausgabe:

year: 2001, month: 01, day: 20
year: 2009, month: 03, day: 22
year: 2018, month: 02, day: 25
year: 2018, month: 06, day: 07

Anmerkung: res [i] [0] = ~ match.group (0) Java

Wenn Sie diese Informationen speichern möchten, verwenden Sie einen Strukturtyp:

type date struct {
  y,m,d int
}
...
func main() {
   ...
   dates := make([]date, 0, len(res))
   for ... {
      dates[index] = date{y: res[index][1], m: res[index][2], d: res[index][3]}
   }
}

Es ist besser, anonyme Gruppen zu verwenden (Leistungsverbesserung)

Die Verwendung von "ReplaceAllGroupFunc" auf Github ist aus folgenden Gründen eine schlechte Idee:

  1. verwendet Schleife in Schleife
  2. verwendet einen anonymen Funktionsaufruf in der Schleife
  3. hat viel Code
  4. verwendet die Funktion "Anhängen" in der Schleife und das ist schlecht. Bei jedem Aufruf der Funktion "Anhängen" wird das Array an eine neue Speicherposition kopiert
9
VasileM

Wenn Sie beim Erfassen von Gruppen basierend auf einer Funktion ersetzen müssen, können Sie dies verwenden:

import "regexp"

func ReplaceAllGroupFunc(re *regexp.Regexp, str string, repl func([]string) string) string {
    result := ""
    lastIndex := 0

    for _, v := range re.FindAllSubmatchIndex([]byte(str), -1) {
        groups := []string{}
        for i := 0; i < len(v); i += 2 {
            groups = append(groups, str[v[i]:v[i+1]])
        }

        result += str[lastIndex:v[0]] + repl(groups)
        lastIndex = v[1]
    }

    return result + str[lastIndex:]
}

Beispiel:

str := "abc foo:bar def baz:qux ghi"
re := regexp.MustCompile("([a-z]+):([a-z]+)")
result := ReplaceAllGroupFunc(re, str, func(groups []string) string {
    return groups[1] + "." + groups[2]
})
fmt.Printf("'%s'\n", result)

https://Gist.github.com/elliotchance/d419395aa776d632d897

1
Elliot Chance

Einfache Methode zur Ermittlung von Gruppennamen basierend auf der @ VasileM-Antwort.

Haftungsausschluss: Es geht nicht um Speicher-/CPU-/Zeitoptimierung

package main

import (
    "fmt"
    "regexp"
)

func main() {
    r := regexp.MustCompile(`^(?P<Year>\d{4})-(?P<Month>\d{2})-(?P<Day>\d{2})$`)

    res := r.FindStringSubmatch(`2015-05-27`)
    names := r.SubexpNames()
    for i, _ := range res {
        if i != 0 {
            fmt.Println(names[i], res[i])
        }
    }
}

https://play.golang.org/p/Y9cIVhMa2p

0
spiil