Help us understand the problem. What is going on with this article?

Go言語で後方参照を用いた置換処理

More than 5 years have passed since last update.

追記

下記の記事では、後方参照を使用する方法はないという内容になっていますが、
最新バージョンでは使用できるようになっています。

replace.go
package main

import (
  "fmt"
  "regexp"
)

func main() {
  re := regexp.MustCompile("a(x*)b")
  fmt.Println(re.ReplaceAllString("-ab-axxb-", "$1"))
}

参考

http://golang.org/pkg/regexp/#Regexp.ReplaceAllString


regexpパッケージのページをざっと確認したところ、
\1$1などの後方参照を行う方法がないようなので、
ReplaceAllStringFunc関数とFindAllStringSubmatch関数を用いて、
置換処理を行うことにした。

ReplaceAllStringFunc関数は、マッチした各文字列を処理し変換後文字列を返す無名関数を設定する仕様になっている。

FindAllStringSubmatch関数は、正規表現中の丸括弧()で囲った文字列を返してくれる。後方参照の代替として使用。

replace.go
package main

import (
        "fmt"
        "regexp"
)

func main() {
        // タグから置換するデータ
        var data = map[string]string{
                "NAME": "Tarou",
                "AGE":  "30",
        }

        // テンプレート
        template := "名前は{T_NAME}。年齢は{T_AGE}歳。{T_HOGEHOGE}"

        // 正規表現
        regex_str := "{T_([A-Z]+?)}"
        re, err := regexp.Compile(regex_str)
        if err != nil {
                panic(err)
        }

        // 置換処理用関数
        cb := func(s string) string {
                // 正規表現の「([A-Z]+?)」の部分を取得
                tname := re.FindStringSubmatch(s)
                if len(tname) == 2 {
                        // タグ名に応じてデータを置換する
                        if ret := data[tname[1]]; ret != "" {
                                return ret
                        } else {
                                return s
                        }
                }
                return s
        }

        // 置換処理
        ret := re.ReplaceAllStringFunc(template, cb)

        // 結果表示
        fmt.Println(ret)
}

今回の調査のために書いたregexpの関数サンプルと実行結果を載せておく。
基本的に、[]bytes型とstring型のそれぞれに対して、同じ機能を備えた関数が用意されている。

関数名にStringが含まれている関数は、string型を渡し、
含まれていない関数は、[]byte型を渡すようになっている。

replace.go
package main

import (
        "fmt"
        "regexp"
)

func main() {
        str := "テスト1{T_NAME}テスト2{T_AGE}テスト3"
        re, err := regexp.Compile("{T_(.+?)}")
        if err != nil {
                panic(err)
        }

        fmt.Println("---------- Find ------------")
        fmt.Println(string(re.Find([]byte(str))))

        fmt.Println("---------- FindAll ------------")
        rets_findall := re.FindAll([]byte(str), -1)
        for _, ret := range rets_findall {
                fmt.Println(string(ret))
        }

        fmt.Println("---------- FindAllIndex ------------")
        rets_findallindex := re.FindAllIndex([]byte(str), -1)
        for _, ret := range rets_findallindex {
                fmt.Println(ret)
        }

        fmt.Println("---------- FindAllString ------------")
        rets_findallstring := re.FindAllString(str, -1)
        for _, ret := range rets_findallstring {
                fmt.Println(ret)
        }

        fmt.Println("---------- FindAllStringIndex ------------")
        rets_findallstringindex := re.FindAllStringIndex(str, -1)
        for _, ret := range rets_findallstringindex {
                fmt.Println(ret)
        }

        fmt.Println("---------- FindAllStringSubmatch ------------")
        rets_findallstringsubmatch := re.FindAllStringSubmatch(str, -1)
        for _, ret := range rets_findallstringsubmatch {
                fmt.Println(ret)
        }

        fmt.Println("---------- FindAllStringSubmatchIndex ------------")
        rets_findallstringsubmatchindex := re.FindAllStringSubmatchIndex(str, -1)
        for _, ret := range rets_findallstringsubmatchindex {
                fmt.Println(ret)
        }

        fmt.Println("---------- FindIndex ------------")
        rets_findindex := re.FindIndex([]byte(str))
        fmt.Println(rets_findindex)

        fmt.Println("---------- FindString ------------")
        rets_findstring := re.FindString(str)
        fmt.Println(rets_findstring)

        fmt.Println("---------- FindStringIndex ------------")
        rets_findstringindex := re.FindStringIndex(str)
        fmt.Println(rets_findstringindex)

        fmt.Println("---------- FindStringSubmatch ------------")
        rets_findstringsubmatch := re.FindStringSubmatch(str)
        fmt.Println(rets_findstringsubmatch)

        fmt.Println("---------- FindStringSubmatchIndex ------------")
        rets_findstringsubmatchindex := re.FindStringSubmatchIndex(str)
        fmt.Println(rets_findstringsubmatchindex)

        fmt.Println("---------- FindSubmatch ------------")
        rets_findsubmatch := re.FindSubmatch([]byte(str))
        fmt.Println(rets_findsubmatch)

        fmt.Println("---------- FindSubmatchIndex ------------")
        rets_findsubmatchindex := re.FindSubmatchIndex([]byte(str))
        fmt.Println(rets_findsubmatchindex)

        fmt.Println("---------- Match ------------")
        rets_match := re.Match([]byte(str))
        fmt.Println(rets_match)

        fmt.Println("---------- MatchString ------------")
        rets_matchstring := re.MatchString(str)
        fmt.Println(rets_matchstring)

        fmt.Println("---------- NumSubexp ------------")
        rets_numsubexp := re.NumSubexp()
        fmt.Println(rets_numsubexp)

        fmt.Println("---------- ReplaceAll ------------")
        rets_replaceall := re.ReplaceAll([]byte(str), []byte("REPLACE"))
        fmt.Println(string(rets_replaceall))

        fmt.Println("---------- ReplaceAllFunc ------------")
        rets_replaceallfunc := re.ReplaceAllFunc([]byte(str), func(b []byte) []byte { fmt.Println(string(b)); return []byte("REPLACE") })
        fmt.Println(string(rets_replaceallfunc))

        fmt.Println("---------- ReplaceAllString ------------")
        rets_replaceallstring := re.ReplaceAllString(str, "REPLACE")
        fmt.Println(rets_replaceallstring)

        fmt.Println("---------- ReplaceAllStringFunc ------------")
        rets_replaceallstringfunc := re.ReplaceAllStringFunc(str, func(s string) string { fmt.Println(s); return "REPLACE" })
        fmt.Println(rets_replaceallstringfunc)
}
result
--------- Find ------------
{T_NAME}
---------- FindAll ------------
{T_NAME}
{T_AGE}
---------- FindAllIndex ------------
[10 18]
[28 35]
---------- FindAllString ------------
{T_NAME}
{T_AGE}
---------- FindAllStringIndex ------------
[10 18]
[28 35]
---------- FindAllStringSubmatch ------------
[{T_NAME} NAME]
[{T_AGE} AGE]
---------- FindAllStringSubmatchIndex ------------
[10 18 13 17]
[28 35 31 34]
---------- FindIndex ------------
[10 18]
---------- FindString ------------
{T_NAME}
---------- FindStringIndex ------------
[10 18]
---------- FindStringSubmatch ------------
[{T_NAME} NAME]
---------- FindStringSubmatchIndex ------------
[10 18 13 17]
---------- FindSubmatch ------------
[[123 84 95 78 65 77 69 125] [78 65 77 69]]
---------- FindSubmatchIndex ------------
[10 18 13 17]
---------- Match ------------
true
---------- MatchString ------------
true
---------- NumSubexp ------------
1
---------- ReplaceAll ------------
テスト1REPLACEテスト2REPLACEテスト3
---------- ReplaceAllFunc ------------
{T_NAME}
{T_AGE}
テスト1REPLACEテスト2REPLACEテスト3
---------- ReplaceAllString ------------
テスト1REPLACEテスト2REPLACEテスト3
---------- ReplaceAllStringFunc ------------
{T_NAME}
{T_AGE}
テスト1REPLACEテスト2REPLACEテスト3

参考

regexp パッケージ
http://golang.jp/pkg/regexp

uchiko
エンジニアです。最近はAWSでサーバレス開発しています。 Go/AWS/Docker/TypeScript/Processing。AWS認定システムアーキテクトプロフェッショナル保持。全社員フルリモートワークの会社で働いています。愛知県岡崎市在住。 Twitter: @memememomo
https://github.com/memememomo
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away