ライブラリをRuby=からGoにポーティングしていますが、RubyがGo(google RE2)と互換性がないことを発見しました。 Ruby&Java(他の言語はPCRE正規表現(Perl互換、グループのキャプチャをサポート)を使用))、 Goで問題なくコンパイルできるように式を書きます。
たとえば、次の正規表現があります。
`(?<Year>\d{4})-(?<Month>\d{2})-(?<Day>\d{2})`
これは次のような入力を受け入れる必要があります。
2001-01-20
キャプチャグループにより、年、月、日を変数にキャプチャできます。各グループの価値を取得するには、非常に簡単です。返された一致したデータにグループ名でインデックスを付けるだけで、値を取得できます。そのため、たとえば年を取得するには、次のような擬似コードを使用します。
m=expression.Match("2001-01-20")
year = m["Year"]
これは表現でよく使うパターンなので、多くの書き直しが必要です。
だから、Go正規表現でこの種の機能を取得する方法はありますか?これらの式をどのように書き直す必要がありますか?
これらの式をどのように書き直す必要がありますか?
定義されているように、いくつかのPを追加します here :
_(?P<Year>\d{4})-(?P<Month>\d{2})-(?P<Day>\d{2})
_
re.SubexpNames()
を使用したキャプチャグループ名の相互参照。
次のように を使用します。
_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())
}
_
私はURL表現を処理するための関数を作成しましたが、それもあなたのニーズに合っています。 this スニペットを確認できますが、次のように機能します。
/**
* 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
}
この関数は次のように使用できます。
params := getParams(`(?P<Year>\d{4})-(?P<Month>\d{2})-(?P<Day>\d{2})`, `2015-05-27`)
fmt.Println(params)
出力は次のようになります。
map[Year:2015 Month:05 Day:27]
RAMおよびCPU使用率を改善するには、ループ内で匿名関数を呼び出さず、ループ内のメモリ内の配列を「追加」関数でコピーせずに、次の例を参照してください。
「+」で文字列を追加せずに、forループ内でforループを使用せずに、複数行のテキストで複数のサブグループを保存できます(他の例と同様)。
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])
}
出力:
year: 2001, month: 01, day: 20
year: 2009, month: 03, day: 22
year: 2018, month: 02, day: 25
year: 2018, month: 06, day: 07
注:res [i] [0] =〜match.group(0)Java
この情報を保存する場合は、構造体タイプを使用します。
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]}
}
}
匿名グループを使用することをお勧めします(パフォーマンスの向上)
Githubに投稿された "ReplaceAllGroupFunc"を使用するのは、次の理由から悪い考えです。
グループのキャプチャ中に機能に基づいて置き換える必要がある場合は、これを使用できます。
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:]
}
例:
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)
@VasileMの回答に基づいてグループ名を決定する簡単な方法。
免責事項:メモリ/ CPU /時間の最適化ではありません
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])
}
}
}