正規表現
お昼休みに正規表現の練習させてもらいました。
※コードはすべてF#です。
「XPathを扱ってみましょう。」
準備
open System.Text.RegularExpressions let matches input pattern = seq { for x in Regex.Matches(input, pattern) -> x} let values input pattern = matches input pattern |> Seq.map(fun x -> x.Value) let x = "/hoge/piyo/text()"
まずは
"/hoge/piyo/text()"から/hoge, /piyo, /textをそれぞれ取り出す。
[]で囲めばいいのでは!
「文字クラスですね。」
values x "/[a-z]"
val it : seq<string> = seq ["/h"; "/p"; "/t"]
...(´・ω・`)
「+つけて。」
values x "/[a-z]+"
val it : seq<string> = seq ["/hoge"; "/piyo"; "/text"]
文字クラス […]
[]内に指定された任意の文字1個をマッチするメタ文字。
文字クラス内の各文字はorが間にあるものとして解釈される。
また、ダッシュ(-)という「文字クラス用メタ文字」は文字の範囲を示す。
例) gr[ae]y : grayとgreyにマッチする。
例) [a-e1-6] : 小文字のアルファベットabcdeと数字123456にマッチする。
プラス記号 +
直前にある要素1個以上を意味するメタ文字。(量指定子)
かたまりで取りたいよね
"/hoge/piyo/text()"から/hoge/piyo/text()を取り出す。
/と()を足せば!
values x "/[a-z/()]+"
val it : seq<string> = seq ["/hoge/piyo/text()"]
/hoge/piyo/text(aaa)は弾きたいよね
"/hoge/piyo/text()"から/hoge/piyo/text()を取り出す。 "/hoge/piyo/text(aaa)"から"/hoge/piyo/text(aaa)"は取り出さない。←new!
()だけ外に出そう。
文字クラスの外に出したら、エスケープが要るんでしたっけ。
values x "/[a-z/]+\(\)"
val it : seq<string> = seq ["/hoge/piyo/text()"]
できたー。
let y = "/hoge/piyo/text(aaa)" values y "/[a-z/]+\(\)"
val it : seq<string> = seq []
よし。
ちょっと書き換える
「[a-z]は\wで書けます。」
「()でくくって、後に+つければいい。」
values x "(/\w+)+\(\)"
val it : seq<string> = seq ["/hoge/piyo/text()"]
単語構成文字 \w *1
.NETでは[a-zA-Z0-9]。
おおむね[a-zA-Z0-9_]と同じ。
ツールによってアンダースコアを含まないこともあれば、そのロケール内のすべての英数字を含むこともある。
Unicodeがサポートされている場合は通常すべての英数字を意味する。
(例外:SunのJava正規表現では、「\w」と「[a-zA-Z0-9_]」は全く同じ意味になる。)
()
以下に用いられるメタ文字。
- 選択の範囲を示す
- 量指定子(?、*、+など)の範囲を示す←今回はこれ
- 後方参照の範囲を示す
/hoge()/piyoは拾いたいね
"/hoge/piyo/text()"から/hoge/piyo/text()を取り出す。 "/hoge/piyo/text(aaa)"から"/hoge/piyo/text(aaa)"は取り出さない。 "/hoge()/piyo"から"/hoge()/piyo"を取り出す。←new!
「| 使って、()で終わるのと終わらないの両方取れるようにすれば。」
()の1と一緒に使えば!
values x "(/\w+\(\)|/\w+)+"
val it : seq<string> = seq ["/hoge/piyo/text()"]
できてる。
values z "(/\w+\(\)|/\w+)+"
val it : seq<string> = seq ["/hoge()/piyo"]
おー。
選択 |
この記号によって隔てられているいずれかの表現とマッチするメタ文字。
ここでお昼休みが終わりましたが
"/hoge/piyo/text(aaa)"から"/hoge/piyo/text(aaa)"は取り出さない。
この記事を書いていて、↑を満たしていないことに気づきました。
values y "(/\w+\(\)|/\w+)+"
val it : seq<string> = seq ["/hoge/piyo/text"]
"/\w+" が "/text(aaa)" から "/text" までを取り出してる。
しばらく悩んで解決できなかったので、相談したところ、FParsecをお勧めいただいたので今回は保留。
宿題:ORは使わなくても書けるよ
"/hoge/piyo/text()"から/hoge/piyo/text()を取り出す。 "/hoge()/piyo"から"/hoge()/piyo"を取り出す。
"/hoge/piyo/text(aaa)"から"/hoge/piyo/text(aaa)"は取り出さない。をとりあえず外す。
values x "(/\w+(\(\))?)+"
val it : seq<string> = seq ["/hoge/piyo/text()"]
できたー。
values z "(/\w+(\(\))?)+"
val it : seq<string> = seq ["/hoge()/piyo"]
今回はここまで。
*1:2014.5.13.修正