標準のRにおける正規表現
標準のRが使う正規表現が何なのかを説明する。正規表現そのものが何なのかについてはあんまり説明しない(各自がんばろう)。
Rでの正規表現に関する一般的なヘルプは?regex
で参照できる(そしてこのテキストの元ネタでもある)ので、一読しておくと良い。
正規表現はどこで使用できるのか
Rで正規表現を扱える関数はいくつかあり、grep
、grepl
、regexpr
、gregexpr
、sub
、gsub
、strsplit
などの様々な関数の内部で、テキストの抽出や置換、分割などを行うために正規表現を指定できる。
Rで使える正規表現は拡張正規表現とPerl風正規表現の2種類があるが(後述)、標準では拡張正規表現が使用される。
また、場合によってはパターンを正規表現として解釈してほしくない、ただの文字列として解釈して欲しいという場合もあるだろう。fixed=TRUE
を指定すればパターンはパターンではなくただの文字列リテラルとして解釈される。
tmp <- c("abc", "*bc", ".*c")
grep(".*", tmp)
[1] 1 2 3
grep(".*", tmp, fixed=TRUE)
[1] 3
他にもapropos
、browseEnv
、help.search
、list.files
、ls
などの関数でパターンの記述に正規表現が使えるが、これらは内部的にgrep
を呼び出している場合が多い。そして、これらの関数では拡張正規表現しか使えない場合が多い。
Rが扱う正規表現の種類
前述のように標準のRでは拡張正規表現とPerl風正規表現という2種類の正規表現を使うことができる。
拡張正規表現(ERE)
拡張正規表現(Extended Regular Expressions: ERE)はPOSIX 1003.2で規定されている(cf. Regular Expressions)が、Rで使われているEREは、標準のEREよりも若干拡張されている。例えばEREでは定義されていない後方参照を使うことができる。
tmp <- c("1234", "1212", "3434", "3456")
grep("(\\d\\d)\\1", tmp) # 2桁の数字の繰り返しにマッチ
[1] 2 3
これはライブラリとしてTRE(cf. TRE — The free and portable approximate regex matching library.)を使用していることによる。TREはPOSIX 1003.2の仕様に厳密に従っているため、標準的なEREに沿った正規表現は通るはずだが、逆にTREで通ったからといって必ずしもEREに従っているとは言い切れない。
TREは後方参照以外にもキャプチャなしの括弧(?:
や、(?i)
のような一部のモード修飾子の埋め込みにも対応している。つまり、perl=TRUE
でなくともPerlっぽい記法が結構通ってしまう。TREのRoadmapには先読み・後読みのようなPerl互換記法も載っているので、将来的にperl=TRUE
との差はもっと小さくなるかもしれない。
なお、古いバージョンのRでは基本正規表現(BRE)も扱え、extended=
という引数によってBREとEREの切り替えができたが、現在はdeprecatedとなっている(cf.Regular Expressions with grep, regexp and sub in the R Language)。
Perl風正規表現
perl=TRUE
の指定でRはPCREライブラリを使用するようになる。これにより、Perl 5.xの正規表現が使用可能になる(若干の違いはある)。詳しくはPCREのman(perlre - perldoc.perl.org)を参照のこと。
perl風正規表現を有効にすると、後先読みなどが使えるようになる。ちなみにperl=TRUE
を指定しないままperl風正規表現を使うと...は不正な正規表現です、理由は 'Invalid regexp'
というエラーが出る場合が多い(経験者談)。
ところで、?regex
を読むと、Perl風正規表現を有効にした場合に使えるようになる(?...)
記法の例として(?i)
が真っ先に挙げてあるが、前述のようにTREは(?i)
をサポートしているので、これは別にperl=TRUE
を指定しなくても使える。
パターン記述時の注意点
大抵の場合、パターンは文字列として記述することになるだろう。Rで文字列を記述する上での注意事項として、バックスラッシュを記述したい場合にはバックスラッシュ二重にする必要があるという点に注意する必要がある。
正規表現のパターン中でのエスケープとは別にエスケープが必要という点に注意しなければならない。つまり、もしパターン中でバックスラッシュそのものを記述したかったら、エスケープ用のバックスラッシュとバックスラッシュ本体それぞれにエスケープが必要なので、4つのバックスラッシュを並べる必要がある。
tmp <- c("\\", "\\\\", "\\\\\\", "\\\\\\\\")
grep("^\\\\$", tmp) # 単一のバックスラッシュからなる文字列を探している!!
[1] 1
それぞれの関数についてはまたこんど。