# 7.3 正規表現の処理 正規表現はパターンマッチとテキスト操作の複雑で強力なツールです。正規表現は純粋なテキストマッチングに比べ効率は劣りますが、より柔軟性に富みます。この文法規則に従い作り出されるパターンはオリジナルのテキストからあなたが必要とするほとんどすべての文字列の組み合わせをフィルターすることができます。もしWeb開発の中でなにかしらのテキストデータソースからデータを取り出す必要があれば、この文法規則にしたがって正確なパターン文字列を作ることで意味のあるテキスト情報をデータソースから取り出すことができます。 Go言語は`regexp`標準パッケージを使うことでオフィシャルに正規表現をサポートしています。もしあなたが他のプログラミング言語において提供されている正規表現と同等の機能を使ったことがあるのであれば、Go言語バージョンでもそれほど門外漢というわけではないはずです。しかしこれらの間でも少しばかりの違いがあります。なぜならGoが実装しているのはRE2スタンダードで、\Cを除いて詳細な文法の説明は以下をご参照ください:`http://code.google.com/p/re2/wiki/Syntax` 文字列処理はそもそも`strings`パッケージを使うことで検索(Contains、Index)、置換(Replace)と懐石(Split、Join)といった操作を行うことができました。しかしこれらはどれも簡単な文字列操作にすぎません。これらの検索はどれも大文字と小文字を区別しますし、固定された文字列です。もし可変のこういったマッチングを行う必要があれば、実現する方法がありません。当然もし`strings`パッケージがあなたの問題を解決できるのであれば、できるかぎりこれを使って解決すべきです。なぜならこれらは簡単で、性能と可読性も正規表現に比べてよいからです。 前のフォームの検証の節ですでに正規表現に触れたことを覚えていらっしゃるかもしれません。その時はこれを使って入力された情報が何らかの予め設定された条件を満足しているか検証するのに使いました。使用に際して注意すべきことは:いかなる文字列もすべてUTF-8でエンコードされているということです。以降ではより深くGo言語の`regexp`パッケージに関連する知識を学んでいきましょう。 ## 正規表現を使ってマッチングするか判断する `regexp`パッケージでは3つの関数を使ってマッチングを判断します。もしマッチングすればtrueを返し、さもなければfalseを返します。 func Match(pattern string, b []byte) (matched bool, error error) func MatchReader(pattern string, r io.RuneReader) (matched bool, error error) func MatchString(pattern string, s string) (matched bool, error error) 上の3つの関数は同じ機能を実現しています。つまり、`pattern`が入力ソースにマッチするかを判断しています。マッチングしたらtrueを返し、もし正規表現の解析でエラーが出たらerrorを返します。3つの関数の入力ソースはそれぞれbyte slice、RuneReaderとstringです。 入力がIPアドレスであるかどうか検証したい場合は、どのように判断すべきでしょうか?以下をご覧ください func IsIP(ip string) (b bool) { if m, _ := regexp.MatchString("^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$", ip); !m { return false } return true } ご覧のとおり、`regexp`のpatternと我々が通常使用している正規表現は全く一緒です。もう一つ例を見てみましょう:ユーザが文字列を入力し、この入力が正しいかどうか知りたいものとします: func main() { if len(os.Args) == 1 { fmt.Println("Usage: regexp [string]") os.Exit(1) } else if m, _ := regexp.MatchString("^[0-9]+$", os.Args[1]); m { fmt.Println("数字です。") } else { fmt.Println("数字ではありません。") } } 上の2つの例では、Match(Reader|String)を使って文字列が我々の要求に合致しているか判断しています。これらは非常に便利です。 ## 正規表現を使って内容を取得する Matchパターンは文字列の判断に対してのみ使うことができ、文字列の一部分を切り取ったり、文字列にフィルターをかけたり、合致する条件の文字列を取り出したりすることはできません。これらの需要を満足したければ、正規表現の複雑なパターンを使用する必要があります。 我々はよく一種のスクレイピングプログラムが必要となります。下ではスクレイピングを例にどのように正規表現を使って取得したデータに対しフィルタリングまたは切り取りを行うかご説明します: package main import ( "fmt" "io/ioutil" "net/http" "regexp" "strings" ) func main() { resp, err := http.Get("http://www.baidu.com") if err != nil { fmt.Println("http get error.") } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { fmt.Println("http read error") return } src := string(body) //HTMLタグを全て小文字に変換します re, _ := regexp.Compile("\\<[\\S\\s]+?\\>") src = re.ReplaceAllStringFunc(src, strings.ToLower) //