正規表現入門

Sam Marsden
Sam Marsden

2019-01-09公開

 

正規表現を活用する

正規表現はHTMLマークアップ、ログファイル、URL、ドキュメントなどのソースからテキスト情報を検出、抽出するのに非常に便利です。正規表現には様々な活用方法があり、サーバーログのフィルタリング、URLの上書き、またリンクからのアンカーテキスト抽出などができる点で、SEO担当者にとって強い味方となります。

まずはじめに、正規表現に関する基本的な知識について説明します。正規表現には、それぞれ異なる構文をサポートするたくさんのバリエーションがあることを理解しましょう。

この記事では、Rubyの正規表現(英語)について説明します。

Regex

このレベルの正規表現になれてきたら、グループのキャプチャ、略式の文字クラス、mode modifiers、無効文字クラスなどのような重要なトピックについての理解を深めていきましょう。なお、これらは今後のガイドで扱う予定です。さらに深いレベルのトピックは、条件付きマッチング、lookaround、catastrophic backtracking、アトミックグループなどとなります。

正規表現の習得には忍耐を持って臨みましょう。これらのトピックを学ぶのに順番に学ぶ必要はありませんが、基礎をしっかり理解することが非常に重要となります。実践で試行錯誤を重ねながら、DeepCrawlのプロジェクトやレポート内で正規表現を習得し、DeepCrawlをより有効活用してください。

このドキュメントで使われる例を検証するために、ここではRubular.com(英語)を使います。 Rubularでは、他の正規表現とは異なり、Rubyがスラッシュを予約語として検出するのに使うがゆえに、スラッシュの代わりにダブルクォーテーション (“)を利用しなければならないことに注意してください。
 

基礎的な正規表現のトークン

正規表現とは何でしょうか?また、何が”正規”なのでしょうか?要は、正規表現は数学で言うxのようなものなのです。 一方で、正規表現は、以下のように嫌になるほど複雑で難しい形式をとる場合があります。: //[^/]+/(?:blog/)?(?!dcb|sfb) ([a-zA-Z]{2}(?:[-_](?:[a-zA-Z]{2}|d{2,3})b)?)(?:/|$)

正規表現のパターンは、URLであろうと、HTMLマークアップであろうと、膨大なデータからなるサーバーログファイルであろうと、その長短にかかわらずどんなテキストの中でも検索するために利用できます。ドキュメント内のテキストを指定して検出することに加え、正規表現は特定の配列で並んだテキストを検出するのにも活用できます。例えば、従来型の”que”に関する検出では、以下のような単語がマッチします。quest, obliquenessまたはrisque

とにかく重要なのは、正規表現は非常に強力で驚くほど役立つ手法であるということです。膨大な量の中から任意の文字を探し出すことを考えてみてください。ここで「”q”を含むがその次の文字に”u”が来ない場合」を見つけ出すことは不可能に見えると思いますが、正規表現を使えばこれはとても簡単です。

ご想像の通り、正規表現には、特定の意味を持つようにあらかじめ設定された文字や文字の配列パターンが数多くあり、これらは正規表現のトークンと呼ばれています。以下はよく使われるトークンの例です。 (矢印は正規表現のトークンではありません)

. → あらゆる1つの文字と合致
* →0以上の文字と合致
+ → 1以上の文字と合致
? → 0以上の文字と合致し、かつ前の正規表現が任意である

最も基本的な正規表現のトークンはドットオペレーター”.”です。これは任意の1文字として利用します。つまり、ドット”.”は文字、数字、スペース、句読点などあらゆる1文字に合致します。繰り返しはアスタリスク”*”またはプラス”+”が使われます。 任意の文字を、あらゆる1つ以上の文字と合致させるには、”.+.”の表現を利用します。

したがって、”the..”という正規表現は、このパターンがちょうど5文字を指定しているため、”there”や”their”に該当しますが、”them”は対象外となります。これに対し、直前の正規表現を “the.*”に変更すれば、これら全ての単語”there”, ”their”, ”them”に加え”the”という文字も含まれることになります。これは繰り返しを意味するトークン “.*”がどんな文字とも0回以上合致しているということを意味するからです。

あらかじめ設定されたメタ文字を検索内に含むようにしたい場合、代わりにバックスラッシュを使って”文字通りの”文字を示すようにしてください。例えば、 “dog.”という表現を使うと、”dog.”とは合致しますが、”dogs”という表現には合致しません。

単語の単数形と複数形の両方を検出したい場合、”s”の後に任意という意味を表すクエスチョンマークをつけてください。こうすれば、例えば”dogs?”という表現は、”dog”と”dogs”の両方にマッチすることになります。

正規表現はデフォルトでは貪欲であると理解しておくことが重要です。これは、例えば”.+”という正規表現が現在のポジションから始まってソース文字列の最後までにある少なくとも1文字と合致するものを抽出してしまうということです。”Please call her Ms. Smith."という文章から敬称のみをマッチさせたいとしましょう。このとき、”M[rs]+.”という表現を使って、Mr, Ms. Mrsを含むようにしたいと思うかもしれませんが、正規表現の貪欲さゆえ、その文章の最後まで含んでしまいます。 +と?を付け加えて”M[rs]+?..”という表現にしてはじめて、意図するような”Ms”のみを拾うことができます。
 

正規表現の改善

トークンや厳密な文字列を使って正規表現を記述することに加え、論理和指定子、グルーピング、文字セット、量指定子、アンカーといった要素も正規表現に活用できます。正規表現をより精緻なものにするために使われるトークンには、以下のようなものがあります。

| → 論理和指定子:代替パターンを指定する。これは”or”と同義。
() → グルーピング:グループを指定するためにカッコを利用する。
[] → 文字セット・クラス:このカッコ内の1つの文字と合致する。
{x,y} → 量指定子:正規表現がX回〜Y回合致しなければならない。
^ $ b → アンカー:特定の文字と合致するというものではなく、特定のポジションで合致する。

選択とグルーピング

それぞれがマッチする複数の正規表現を使うと有効です。例えば、"travels", "traveler"または"traveling"といった単語を見つけるには、”travels|traveled|traveler|traveling”のように、”|“を使って選択する単語のリストを分けます。この方法はAlternation(選択)と呼ばれています。

長い表現を簡易化して読みやすさを向上させるために、カッコを使って正規表現の特定の部分をグループ化します。これにより、以前の正規表現は “travel(s|ed|er|ing)”という表現に簡易化され、”travel”の文字を含み、更にその後 “s”, “ed”, “er”, “ing”が続く文字列に合致します。

では、"travelled" or "travelling"に見られるように”l”を連続して利用することに関するイギリス英語の特徴などに関してはどうでしょうか?この場合、2つめの”l”を任意にするために”?”トークンを使って、 travell?(s|ed|er|ing)のように表現すれば良いことになります。この正規表現はtravels, traveled, travelled, traveler, traveller, travelingまたはtravellingのどの表現にも合致することになります。

文字セットと文字クラス

文字セットとは、角カッコを使ってリスト化されたあらゆる1文字に合致するために用いる簡易リストのことです。文字のリストを分けるために”|”を使った正規表現の選択は必要ありません。例えば、”[aeiou]”は全ての母音1文字に合致し、”[wkrp]”は w, k, rまたはpの文字のみに合致します。

文字クラスとは、ハイフンによって分けられ、角カッコによりリスト化された、類似の文字に関する序数的な範囲のことです。アルファベットや数字のような特定の文字の種類を表します。例えば、”[a-z]”という正規表現はアルファベットの文字を示し、”[0-9]”は数字を表します。

ほとんどの正規表現は、大文字小文字を区別して認識することにご注意ください。これは例えば、”[a-z]”が小文字のアルファベットのみ、”[A-Z]”が大文字のみと合致するということです。

また、文字クラス内の文字の序列は関係ないため、”[z-a]”と”[a-z]”という表現は同義となります。全てのアルファベット26文字(大文字小文字を区別するのであれば52文字)をリスト化するよりも明らかに文字クラスを利用する方が簡単で、これは10文字からなる[0123456789]のような文字セットについても当てはまります。

文字セットとして複数の文字をリスト化するのと同様に、複数の文字と文字セットを組み合わせることもできます。例えば、正規表現における”[0-9A-Za-z_,]”という文字セットは、3つの異なる文字クラスから成り、数字、文字(大文字または小文字)、下線、コンマのいずれか1文字にマッチします。

文字クラスは、文字の種類の特定の部分のみを表すこともできます。例えば、”[a-m]”という表現であれば、アルファベットの最初の13文字のみとマッチします。同様に、 “[A-Fa-f0-9]”という表現は、7A (122)F1 (241)といった16進法の数字にマッチします。

+”のようなトークンを後につけることで、あらゆる1つの文字を1回以上のマッチする文字と照合する際のデフォルトでのスコープを拡張することができます。例えば、”[A-Za-z0-9]+”という正規表現は1つ以上のあらゆる文字や数字の組み合わせとマッチし、この場合サイズに関係なく1つの単語を形成します。

量指定子

量指定子とは、正規表現のトークンがマッチする回数を指定するためもので、”{x,y}”のような形式を取ります。xとyに入る数字は共に整数であり、この場合、x回からy回マッチするということを示しています。”{x}”など1つの値のみの場合、正規表現のトークンはx回のみマッチすることになります。また、1つの値の前後にコンマをつけることもできます。”{x,}”という表現の場合、正規表現は少なくともx回マッチし、”{,y}”とコンマを前につけた場合、最大でy回マッチするということを意味します。

以下のような文字列(文章)を例に取ってみましょう。 “I’m pleased to make your acquaintance.” 母音を2つか3つ含む組み合わせを見つける場合、”[aeiou]{2,3}”のような正規表現を記述し、"ea", "ou" や "uai" を含む文字列のある"pleased"や"your"、"acquaintance"をそれぞれマッチさせることができます。3つの母音を上限として検索に制限をかけるには、”[aeiou]{2,}”という正規表現を記述し、同様に3つの文字列と合致するようにします。最後に、厳密に3つの母音をもつ文字列のみマッチさせる場合の正規表現は”[aeiou]{3}”となります。

アンカー

正規表現を使う中でアンカーと呼ばれる特別なトークンを使うことにより、文脈や検索テキストの特定のポジションに応じて検索ターゲットを更に詳細に絞り込むことができます。アンカーは文字とマッチするという性質のものではなく、ポジションを表すものであると理解してください。以下のようなアンカーが正規表現ではよく使われます。

^ → 以降の正規表現がテキストの初めの部分とマッチすると断定

$ → 以前の正規表現がテキストの終わりの部分とマッチすると断定

b → このポジションが単語境界となっていると断定

 

例えば、チャールズ・ディケンズの『二都物語』の冒頭に出てくる"It was the best of times, it was the worst of times…"という部分に含まれる、"it was the best"という初めの部分のみ検索したい場合、”^it was the best”という正規表現を使います。”^”というアンカーが除外されていると、"regarding Friday, it was the best day of my life"や"thanks for the gift - it was the best!"といった、どちらもテキストの初めの部分にはない表現を検索してしまうことになります。

正規表現のトークンについて更に詳しく説明するにあたり、”que”が単語の終わりに位置している場合のみ検出したい場合はどうすれば良いでしょうか?ここではアンカーのbが単語境界となり、この位置でターゲットパターンに隣接できるのはスペース、句読点、またはハイフンやアンパサンドなどの非言語文字のみとなります。正規表現は”queb”となり、"baroque"や"bisque"などがマッチしますが、"banquet"は排除されます。更に、”que”という単語全体がほしい場合には、”bqueb”という表現を使ってください。

”queb”という表現は"risque"や"que"にマッチすることに注意してください。もし”que”で終わる4文字以上の単語を探している場合は、”.+queb”と記述してください。
 

正規表現応用編

正規表現の知識を深めていただくため、上記でカバーしたトピックを使った例をご紹介します。このセクションでは、正規表現の基本的な表現を踏まえ、上記で述べた例を発展させたり、見落としやすい点、注意すべきこと、間違えやすい点をについて説明したりすることを目的としています。

論理和指定子の代わりになるもの

例えば、5文字の単語”there”または”these”のみ検索して、それ以外の単語は除外したい場合があるとします。この時、正規表現で”the.e”と記述することもできますが、この記述では”theme”や”thebe”といった単語も検索してしまいます。”there”または”these”のみを検索したい場合、”there|these”、またはグループ化した”(there|these)”と記述してください。もしくは、文字クラスを使用して”the[rs]e”と記述することで、単語の4文字目の文字を”r”もしくは”s”に詳細に指定することができます。次のサイトでこの例をご確認いただけます。正規表現テストツールhttp://rubular.com/r/uSoqH4T8nG

“Travel”に関する再検証

選択とグルーピングのセクションで学んだ”travel”を使ったケースを振り返ってみましょう。そのセクションでは、最終的に”travell?(s|ed|er|ing)”という正規表現を作成しました。この正規表現を使うと、”travel”の接尾辞が異なる7パターンの単語を検索することも、”travell”とlが2つ続く場合の単語を検索することもできます。

お気づきの方もいらっしゃるかと思いますが、この表現を使うとベースとなる活用しない部分(例題では”travel”)を検索することができません。”travel”を検索する場合、単純に論理和指定子とグルーピングのオプションを使って”travell?(s|ed|er|ing)?”のように記述してください。

この正規表現を使うと、”travel”自体の場合、”travell”とlが続く場合、それぞれに接尾辞"s", "ed", "er"または"ing"が付く場合の単語すべてを検索することができます。

一方、この正規表現のベースとなる単語はアメリカの旅行代理店名である”travelocity”にも含まれており、この会社名もマッチしてしまいます。このような誤検知を避けるためには、単語境界トークンを必ず追加してください。

正規表現テストツール: http://rubular.com/r/i0aagNR71Y

 

HTMLタグ

DeepCrawl内では、カスタム抽出でも正規表現を活用いただけます。 <h1>のような基本的なタグを検出したい場合は、 “(<h1>.*</h1>)”と記述するだけで簡単に抽出することができます。ただ、<h1>タグに、<h1 class="JX0GPIC-a-g">のように可変長のクラス値のプロパティが含まれる場合、もしくは別のプロパティも含まれる場合はどうなるでしょうか。DeepCrawlはこのシナリオをこのガイドのパート2でカバーする予定ですが、以下のURLで、無効文字クラスを使用するその内容を少しだけお見せします。http://rubular.com/r/BzDQfSjwBu.
 

正規表現を使ってクロールを最大限に活用しましょう

クロールを最大限に活用する方法にご興味をお持ちの場合、こちらのガイドで正規表現を使ったDeepCrawlのカスタム抽出についてより詳しく学ぶことができます。DeepCrawlをまだご存知ないようでしたら、フリートライアルをお試しいただき、どのようにサイトの技術的健全性を改善できるかご確認ください。

Author

Sam Marsden
Sam Marsden

Sam Marsdenは、DeepCrawlのSEOおよびコンテンツマネージャーです。 Samは、SMXやBrightonSEOなどのマーケティングカンファレンスで定期的に講演を行っており、Search Engine JournalやState of Digitalなどの業界出版物のコンテンツに貢献しています。

ご質問はありますか?

どのプランにするかご検討中の場合は、お問い合わせページからご連絡ください。ご質問があれば喜んでお答えします。

メッセージを送信する