正規表現の後読みと先読みとAtomic grouping
R言語上級ハンドブックを使って勉強会をしてて、perl互換の正規表現というところで引っかかったのでメモ。
31ページから引用
# Perl互換の正規表現による柔軟な文字列抽出 text <- "@bar foo@example.com @foo@" # 先読み・後読みなどの利用 strapply(text, "(?<!\\w)@(?>\\w+)(?!@)", backref = 0, perl = TRUE)
\が二重になってるのはRの仕様で文字列中の\をエスケープしないと関数に\として渡せないかららしい。
perlの正規表現では(?~)は特別な意味を持っていて、そのうち先読みと後読み、それからAtomic groupingの3つがここで使われてる。
ちなみに上記のマッチの結果は@barになる。
先読みと後読み
マッチする条件を前後に拡張する。
パターン | 意味 |
---|---|
(?<=hoge) | 前にhogeがあるときだけマッチ |
(?<!hoge) | 前にhogeがないときだけマッチ |
(?=hoge) | 後にhogeがあるときだけマッチ |
(?!hoge) | 後にhogeがないときだけマッチ |
さっきの正規表現の最初と最後はそれぞれ
- (?<!\\w)
- (次に続く@の)前に\wがない
- (?!@)
- (前にある“@(?>\\w+)”の)後に@がない
という意味になる。
先読みと後読みを効果的に使う例として桁のカンマを挿入するcommafying numbersが有名で
my $text = "The population of 298444215 is growing"; text =~ s/(?<=\d)(?=(\d\d\d)+(?!\d))/,/g; print "$text\n"; # The population of 298,444,215 is growing
とかできる。
atomic grouping
真ん中の正規表現(?>\\w+)はatomic groupingというやつで「強欲な」マッチングをする。
強欲の説明はコードをみたほうが話が早い。
my $text = "something"; if($text =~ /\w+ing/){ print "MATCH\n"; }else{ print "NOT match\n"; } if($text =~ /(?>\w+)ing/){ print "MATCH\n"; }else{ print "NOT match\n"; }
これを実行すると
MATCH NOT match
となる。
はじめの\w+は単純な正規表現ですべての半角英数字とアンダースコアが1つ以上続くという意味。そのあとにingが続いている。この場合マッチングではingの部分はパターン中のingに譲って\w+はsomethにマッチする。
つぎの(?>\w+)は「強欲な」マッチングで後に続くingに譲らない。そのため(?>\w+)がsomething全体にマッチする。結局(?>\w+)ingはsomethingにマッチできない。
このテキストで、atomic groupingを使って結果が変わるわけでもないのにどうして採用したのか分からないけど、強欲なマッチングについて知らなかったのでタメにはなった。
参考にしたサイト
参考にした本
- 作者: Jeffrey E.F. Friedl,株式会社ロングテール,長尾高弘
- 出版社/メーカー: オライリージャパン
- 発売日: 2008/04/26
- メディア: 大型本
- 購入: 24人 クリック: 754回
- この商品を含むブログ (84件) を見る
- 作者: 荒引健,石田基広,高橋康介,二階堂愛,林真広
- 出版社/メーカー: シーアンドアール研究所
- 発売日: 2013/09/25
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (11件) を見る