肯定先読み~否定後読み
正規表現!M@STERでは肯定先読み、否定先読み、肯定後読み、否定後読みの全てが使えます。
正規表現の上級?テクニック、覚えると便利なこれらの表現についての説明です。
なお、この説明では、当サイトのブラウザツール、正規表現!M@STER(下記参照)の使用を前提にしております。
↓当サイトのWEBツール(無料)を使いながら読むと、理解や習得がはるかに早くなるかも・・・。
(学習用だけじゃなく作業の補助にも使えます。製作者が言うのもなんですがかなり便利です。)
※正規表現のパターン例は見やすさ重視から全角で打っているのでコピペで使えません。直に半角で入力して下さい。
- 肯定先読み、後読みとは~(?=)、(?<=)
- 否定先読み、後読みとは~(?!)、(?<!)
- 応用~<タグ>の中から目的のブツを抜き出せ!
- 応用2~ダブルクオーテーション "" (二重引用符)の中を抜き出したい!
肯定先読み、後読みとは~(?=)、(?<=)
名前から定義とかぐだぐだ説明しても分かりづらい上に間違いやすいので具体例を挙げますと
例えば
国民の、国民による、国民のための政治の頭に"日本"を忘れている日本の政治
という文字列があったとします。(ぇ
もし「国民」で検索した場合は
国民の、国民による、国民のための政治の頭に"日本"を忘れている日本の政治
となり、国民が3つ抽出されました。
ここで肯定先読み(?=パターン)を使ってみましょう。
国民(?=による)
結果は・・・
国民の、国民による、国民のための政治の頭に"日本"を忘れている日本の政治
となります。
国民は3つありますが、肯定先読み(?=による)をつけることで
「による」が含まれる「国民」だけがマッチしたということです。
ここでポイントなのは、マッチした「による」が結果に含まれていないことです。
肯定先読みは後に特定の言葉を含んでいる条件を満たす文字列のみを抽出したい!という時に使えるわけです。
肯定後読みは逆に、前に特定の言葉を含んでいる条件を満たす文字列のみを抽出する時に使います。
例えば「政治」で検索すると
国民の、国民による、国民のための政治の頭に"日本"を忘れている日本の政治
と「政治」が二つ抽出されてしまうので
(?<=日本の)政治
とすることで結果は
国民の、国民による、国民のための政治の頭に"日本"を忘れている日本の政治
となり、頭に「日本の」とつく「政治」のみが抽出されます。
ようするに前に条件をつけたければ肯定後読み(?<=)
後ろに条件をつけたければ肯定先読み(?=)を使えばいいわけです。
否定先読み、後読みとは~(?!)、(?<!)
先ほどの内容を理解できればすぐに分かると思います。ほとんど同じです。
違いは肯定ではなく否定であるということだけ。
ということで例を見てみましょう。
Windows95 Windows98 Windows2000 WindowsME OfiiceXP WindowsXP WindowsVista Windows7 Windows8
ざっと思い浮かぶメジャーな窓シリーズ(と異物)の文字列があるとします。(SEとかserverとか除外
肯定先読みで Windows(?=ME) と打つと
Windows95 Windows98 Windows2000 WindowsME OfiiceXP WindowsXP WindowsVista Windows7 Windows8
となるわけですが、否定先読み Windows(?!ME) で打つとどうなるでしょうか。
Windows95 Windows98 Windows2000 WindowsME OfiiceXP WindowsXP WindowsVista Windows7 Windows8
と、WindowsME以外のWindowsがすべて抽出されます。
文字通り、該当する文字列を否定するというわけです。
肯定と同様に、否定後読みの場合はこの前方バージョンとなります。
否定後読みで (?<!Windows)XP
と入力してみましょう。
Windows95 Windows98 Windows2000 WindowsME OfiiceXP WindowsXP WindowsVista Windows7 Windows8
結果はWinodws以外のXP、すなわちOfficeXPの「XP」のみが抽出されます。
応用~<タグ>の中から目的のブツを抜き出せ!
応用として私がよく使うパターンを一つ出してみます。
<tag>タグの中身ですがナニか?</tag>
<question>君の魔術「正規表現」で抜けるかな?</question>
<content>中身だけだよ?それ以外はダメなんだよ?</content>
<notice>いらない両端のゴミ文字までつけないでね</notice>
<order>当たり前だけど一つの表現で全部抜き取るんだよ</order>
<elegant>エレガントに抜き取ってみせてこそ魔術師よ</elegant>
という文字列(うざい)があり、タグ(<tag></tag>~<elegant></elegant>)で囲まれた中身だけを全て取り出したいとします。
さて、これを 一つのパターンだけで全て抜き出すとしたらどうしましょうか。
とりあえず・・・
>.+?<
と打ち込んでみます。
結果は・・・
>タグの中身ですがナニか?<
(改行)
>君の魔術「正規表現」で抜けるかな?<
(改行)
>中身だけだよ?それ以外はダメなんだよ?<
(改行)
>いらない両端のゴミ文字までつけないでね<
(改行)
>当たり前だけど一つの表現で全部抜き取るんだよ<
(改行)
>エレガントに抜き取ってみせてこそ魔術師よ<
抽出結果、11箇所
・・・6箇所抜き出すはずが、他のタグの間に囲まれた改行(\n)までマッチしてしまいました。
(例)
</tag>(改行)
<question>
これは、正規表現!M@STERを使う場合、デフォルトでg、m、sフラグがたっているからです。
というわけで.(ドット)に改行を含めないようにsフラグをはずします。
結果は・・・
>タグの中身ですがナニか?<
>君の魔術「正規表現」で抜けるかな?<
>中身だけだよ?それ以外はダメなんだよ?<
>いらない両端のゴミ文字までつけないでね<
>当たり前だけど一つの表現で全部抜き取るんだよ<
>エレガントに抜き取ってみせてこそ魔術師よ<
抽出結果、6箇所
となりました。
うん、これである程度は目的を達成できていますが、両端の><がいらないですよね。
ここで肯定先読み、肯定後読みを使います。
(?<=>).+?(?=<)
それぞれ両端のいらない部分を肯定先読みと肯定後読みに含ませます。
本ツールを抽出モードに指定し、区切り線を改行のみにしてさっそく実行。
抽出の結果は・・・
タグの中身ですがナニか?
君の魔術「正規表現」で抜けるかな?
中身だけだよ?それ以外はダメなんだよ?
いらない両端のゴミ文字までつけないでね
当たり前だけど一つの表現で全部抜き取るんだよ
エレガントに抜き取ってみせてこそ魔術師よ
抽出結果、6箇所
思惑通り中身だけを抜き出せました。見事にミッションコンプリートです。お疲れ様でした。
応用2~ダブルクオーテーション ”” (二重引用符)の中を抜き出せ!
以前Twitterで宣伝の返しに頂いた質問の内容です。
”” (二重引用符:ダブルコーテーション)で囲まれた文字列を抜き出したい!
ということでさっそく例題をば。
<meta name="keywords" content="正規表現マスター,RegExp,置換,パターン登録,データベース,チェックツール,WEBツール,フリーツール,javascript,エスケープ文字" />
当サイトのソースの一部です。我ながら検索に引っかかりたくて必死な感じです。
それならもっとSEO対策しろよって話ですがそこまでがっつきたくない複雑神妙な心の葛藤。
さて、このソースに含まれる ”” の中身がほしい場合も肯定先読み、肯定後読みが大活躍です。
"" で囲まれている抜き出したい中身というとURLがお約束ですし、
正規表現!M@STERにも登録されている、h?ttp://[\w\d/%#$&?()~_.=+-]+ という呪文で抜き出すことはできます。
が、この場合はリンクではないので "" の中身を抜き出すことができません。
というわけで、リンク関係無しにダブルクオーテーションで囲まれている部分のみを抜き出してみましょう。
まず、"" で囲まれていて、そこに何文字か分からないけど何か書かれているので
”.+?”
と、とりあえず試してみます。すると・・・
<meta name="keywords" content="正規表現マスター,RegExp,置換,パターン登録,データベース,チェックツール,WEBツール,フリーツール,javascript,エスケープ文字" />
初手から良い感じでマッチしてます。あとは ”” を取り除いてしまえばいいわけです。
さっそく肯定先読み、肯定後読みを使いましょう。
(?<=").+?(?=")
・・・これでも、当ツール等を使用した場合、一応は目的を達成できます。
しかし、プログラミングやマクロなどのコード中に正規表現を使用する場合は ”” をエスケープ(¥)しないとエラーを起こします。
また、この例の短いソースなら問題有りませんが、長大なソースコードでも誤動作を起こさないように、
”” の手前に必ずついているお約束の = も条件につけて確実性を高めましょう。
↓今までエラーなしですんでる答えの一つ
(?<==¥").+?(?=¥")
結果は・・・
<meta name="keywords" content="正規表現マスター,RegExp,置換,パターン登録,データベース,チェックツール,WEBツール,フリーツール,javascript,エスケープ文字" />
となり、"" の中身だけ見事に抜き出せました。
ポイントは = を " の前に付け足して差別化したところでしょうか。
ちなみに
name = "keywords"
のように、= にスペースが入っているパターンも含めてマッチさせたい場合は
(?<==¥"|=¥s¥").+?(?=¥")
とすると、どちらにも対応できます。(なぜか\s?ではできない。なんでだろ?)