LoginSignup
30
27

More than 5 years have passed since last update.

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

Last updated at Posted at 2014-10-23

追記

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

replace.go
package main

import (
  "fmt"
  "regexp"
)

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

参考


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

30
27
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
30
27