メインコンテンツへスキップ
  1. ノート/
  2. 正規表現/

正規表現 30 分入門

·4999 文字·10 分· loading · loading · · ·
ICE345
著者
ICE345
CS Student | System | Linux | OCaml
この記事は中国語版をもとにした日本語版です。技術用語は、必要に応じて English term(日本語の専門用語)という形で表記します。説明は原文の構成と内容に対応させつつ、日本語として読みやすい形に整えています。

版: v2.4.1(2019-11-15) 著者: deerchao 原文: 正規表現30分入門

目次
#

  1. この記事の目標
  2. このチュートリアルの読み方
  3. 正規表現とは何か
  4. 入門
  5. 正規表現をテストする
  6. メタ文字
  7. 文字のエスケープ
  8. 繰り返し
  9. 文字クラス
  10. 選択肢
  11. 否定
  12. グループ
  13. 後方参照
  14. ゼロ幅アサーション
  15. 否定のゼロ幅アサーション
  16. コメント
  17. 貪欲 matching と lazy matching
  18. オプション
  19. バランスグループと再帰
  20. その他の機能
  21. 著者への連絡
  22. 参考資料
  23. 更新履歴

この記事の目標
#

30分で、正規表現が何をするものかを理解し、プログラムや Web ページの中で基本的なパターンを使えるようになることを目指します。

このチュートリアルの読み方
#

複雑そうな表現が出てきても、最初から暗記する必要はありません。例を読み、少し書き換え、実際にテストすることで理解が深まります。

正規表現を一度読んだだけで、すべての構文を覚えられないのは普通です。この記事では基本原理と、日常的に参照できる構文をまとめています。実際に使うときは、必要な部分を検索しながら少しずつ練習してください。

この記事で扱う構文の多くは複数の正規表現エンジンで利用できますが、細部には違いがあります。ここでは主に .NET の正規表現を前提にしています。別の環境で利用する場合は、各エンジンの公式ドキュメントも確認してください。

正規表現は便利ですが、HTML やプログラミング言語の構文全体を解析する目的には向かないことがあります。入れ子構造や複雑な文法を扱う場合は、専用のパーサーを検討してください。

正規表現とは何か
#

正規表現(regular expression)は、文字列がどのような規則に従っているかを表すためのパターンです。文字列の検索、抽出、置換、入力値の検証などに利用できます。

文字は、ソフトウェアがテキストを扱うときの基本単位です。アルファベット、数字、記号、空白、改行などが文字に当たります。文字列は、0個以上の文字が並んだものです。

たとえば、次のような形式の電話番号を探すことを考えます。

  • 先頭が 0
  • 続いて 2〜3 桁の数字
  • ハイフン
  • 続いて 7〜8 桁の数字

この規則を正規表現で表すと、入力値の形式を機械的に確認できます。

ワイルドカードの * や ? を使ったファイル検索に似ていますが、正規表現のほうが文字の位置、繰り返し回数、前後の条件などを細かく指定できます。

入門
#

正規表現を学ぶときは、まず短い例から始めるのが分かりやすい方法です。

英語の文章から、単語としての hi だけを探したいとします。単純に次のパターンを使うとします。

hi

これは hi という2文字を含む場所に一致します。そのため him、history、high の中にある hi も一致してしまいます。単語としての hi だけに限定するには、単語境界を表す \b を使います。

\bhi\b

\b は文字そのものではなく、単語の始端または終端にある位置に一致します。前後の文字を消費しないため、ゼロ幅のメタ文字と呼ばれます。

hi という単語の後ろに、少し離れて Lucy という単語が続く場所を探すなら、次のように書けます。

\bhi\b.*\bLucy\b

. は改行以外の任意の1文字、* は直前の要素の0回以上の繰り返しを表します。したがって .* は、改行を除く任意の文字列に一致します。

改行は通常、改行コード \n として表されます。ASCII では 10(16進数では 0x0A)です。

数字を表す \d と、繰り返し回数を指定する {n} を組み合わせると、次のようなパターンになります。

0\d{2}-\d{8}

これは、0、2桁の数字、ハイフン、8桁の数字という形式に一致します。たとえば、010-12345678 のような文字列が対象になります。

正規表現をテストする
#

正規表現は短くても意味を読み取りにくく、入力ミスも起こりやすいものです。実際の文字列を使って、意図した部分だけに一致するかを確認してください。

原文では .NET 用の Regester と、JavaScript 用の Wegester が紹介されています。

現在は、使用する言語やエンジンに合ったテストツールを選ぶとよいでしょう。JavaScript なら RegExp.prototype.test、.NET なら Regex.IsMatch などを利用できます。

\s は空白文字、\w は単語文字、\d は数字に一致します。ただし、\w に Unicode 文字を含めるかどうかはエンジンによって異なるため、公式ドキュメントを確認してください。

基本的なメタ文字
#

パターン意味
.改行以外の任意の1文字
\w単語文字、数字、アンダースコアなど
\s任意の空白文字
\d数字
\b単語境界
^文字列または行の先頭
$文字列または行の末尾

^ と $ は文字そのものではなく、位置に一致します。たとえば、5〜12桁の数字だけを許可するなら次のように書けます。

^\d{5,12}$

^ と $ があるため、文字列全体が 5〜12 桁の数字でなければ一致しません。これらを付けなければ、より長い文字列の一部に数字が含まれているだけでも一致する可能性があります。

多くの正規表現 API には、「文字列全体」ではなく「文字列のどこかに一致するか」を調べる関数があります。入力値全体を検証したい場合は、アンカーや完全一致用の API を意識して使ってください。

文字のエスケープ
#

.、*、[、( などは特別な意味を持つメタ文字です。メタ文字そのものを検索したい場合は、バックスラッシュでエスケープします。

\.
\*
\[
\(
C:\\Windows

たとえば \. はピリオド、\* はアスタリスクそのものに一致します。バックスラッシュ自体を検索する場合は \\ のように表します。

繰り返し
#

直前の文字やグループを何回繰り返すかは、量指定子で表します。

量指定子意味
*0回以上
+1回以上
?0回または1回
{n}n回
{n,}n回以上
{n,m}n回以上 m回以下

例:

Windows\d+
^\w+

Windows\d+ は Windows の後ろに1桁以上の数字が続く文字列に一致します。^\w+ は、オプションによって、行または文字列の先頭にある単語に一致します。

文字クラス
#

あらかじめ用意された \d、\w、\s だけでは表現できない集合は、角括弧で指定できます。

[aeiou]
[.?!]
[0-9]
[a-zA-Z0-9_]

[aeiou] は英語の母音のいずれか1文字、[.?!] は3種類の記号のいずれか1文字に一致します。ハイフンは範囲を表すため、文字そのものを含めたい場合は先頭または末尾に置くか、エスケープしてください。

電話番号の形式を例にすると、次のようなパターンを作れます。

\(?0\d{2}[) -]?\d{8}

これは、括弧で囲まれた市外局番、ハイフンや空白で区切られた市外局番、区切りのない形式などに対応します。ただし、開き括弧と閉じ括弧の対応までは検証しません。

選択肢
#

複数の形式のいずれかに一致させたい場合は、| で選択肢を区切ります。

0\d{2}-\d{8}|0\d{3}-\d{7}

これは、市外局番3桁・番号8桁、または市外局番4桁・番号7桁の形式に一致します。グループと組み合わせると、括弧の有無なども表現できます。

\(0\d{2}\)[- ]?\d{8}|0\d{2}[- ]?\d{8}

選択肢の順序には注意が必要です。多くのエンジンは左から順に試し、最初に一致した選択肢を採用します。短い選択肢を先に置くと、長い文字列の一部だけに一致することがあります。

否定
#

特定の文字クラスに含まれない文字を指定するには、否定を使います。

パターン意味
\W単語文字ではない文字
\S空白ではない文字
\D数字ではない文字
\B単語境界ではない位置
[^x]x 以外の任意の1文字
[^aeiou]a、e、i、o、u 以外の任意の1文字

例:

\S+
<a[^>]+>

\S+ は空白を含まない文字列、<a[^>]+> は a で始まり、> 以外の文字を1文字以上含むタグ風の文字列に一致します。

グループ
#

括弧で囲んだ部分はグループになります。グループには、次のような役割があります。

  • 複数の文字をひとまとまりとして繰り返す
  • 選択肢の範囲を指定する
  • 一致した内容を後で参照する
  • キャプチャーを無効にして、構造だけをまとめる

たとえば、単純な IPv4 形式は次のように表せます。

(\d{1,3}\.){3}\d{1,3}

これは、1〜3桁の数字とピリオドの組を3回繰り返し、最後に1〜3桁の数字を置くパターンです。ただし 256.300.888.999 のような範囲外の値にも一致します。

各オクテットを 0〜255 に限定するには、より長いパターンが必要です。

((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}
(2[0-4]\d|25[0-5]|[01]?\d\d?)

正規表現だけで数値の範囲を表すと、可読性が下がります。実務では、正規表現で大まかな形式を確認したあと、プログラム側で各数値を変換して 0〜255 の範囲を検証する方法も有効です。

後方参照
#

キャプチャーグループが一致した文字列は、パターンの中で後から参照できます。番号付きグループの1番目は、通常 \1 で参照します。

\b(\w+)\b\s+\1\b

このパターンは、同じ単語が空白を挟んで2回続く箇所に一致します。

名前付きグループを使うと、番号よりも意図が明確になります。.NET では次のように書けます。

(?<Word>\w+)
\b(?<Word>\w+)\b\s+\k<Word>\b

非キャプチャーグループは、構造だけをまとめたいときに使います。

(?:exp)
| 構文 | 意味 | | --- | --- | | (exp) | キャプチャーグループ | | (?exp) | 名前付きキャプチャーグループ(.NET) | | (?:exp) | 非キャプチャーグループ | | (?=exp) | 肯定先読み | | (?<=exp) | 肯定後読み | | (?!exp) | 否定先読み | | (?

ゼロ幅アサーション
#

ゼロ幅アサーションは、文字を消費せずに、現在位置の前後が特定の条件を満たすかどうかを確認します。

肯定先読み
#

\b\w+(?=ing\b)

これは、ing で終わる単語について、ing より前の部分に一致します。

肯定後読み
#

(?<=\bre)\w+\b

これは、re で始まる単語について、re より後ろの部分に一致します。固定長の後読みしか許可しないエンジンもあるため、実行環境を確認してください。

否定先読み
#

q の後ろに u が続かない単語を探す例です。

\b\w*q(?!u)\w*\b

単語末尾の q を扱うなら、\b\wq(?!u)\w\b のように位置条件を組み合わせます。

例:

  • \d{3}(?!\d): 後ろに数字が続かない3桁の数字
  • (?<=<\w+>).*?(?=</\w+>): タグ風の文字列に挟まれた内容

タグや HTML の解析を正規表現だけで行う場合は、入れ子構造や属性を正しく扱えないことがある点に注意してください。

貪欲マッチと最短マッチ
#

量指定子は、初期状態ではできるだけ長く一致しようとします。これを貪欲マッチと呼びます。

a.*b

このパターンは、a から始まり b で終わる範囲のうち、最も長い範囲に一致しやすい挙動を示します。

量指定子の後ろに ? を付けると、できるだけ短く一致する lazy matching になります。

a.*?b

同じ入力に複数の b がある場合、最初に条件を満たす b までの短い範囲に一致します。貪欲さはエンジンや周辺の条件にも左右されるため、実際の入力で確認してください。

オプション
#

正規表現エンジンには、マッチングの規則を変更するオプションがあります。

オプション意味
IgnoreCase大文字と小文字を区別しない
Multiline^ と $ を各行の先頭・末尾として扱う
Singleline. が改行にも一致するようにする
IgnorePatternWhitespaceパターン中の空白を無視し、コメントを許可する
ExplicitCapture明示的に名前を付けたグループだけをキャプチャーする

JavaScript のようにフラグをパターン末尾へ付ける方式、.NET のように API やオプションで指定する方式など、書き方は言語によって異なります。

バランスグループと再帰
#

括弧やタグのような入れ子構造を正規表現で扱うために、.NET にはバランスグループがあります。一部のエンジンには再帰パターンもあります。

次は、入れ子になった山括弧の数を確認する .NET 風の例です。

<
  [^<>]*
  (
    (
      (?<Open><)
      [^<>]*
    )+
    (
      (?<-Open>>)
      [^<>]*
    )+
  )*
  (?(Open)(?!))
>

このような機能はエンジン依存です。また、HTML や XML 全体を処理するなら、正規表現より専用パーサーを使うほうが安全です。

その他の機能
#

パターン意味
\a警告音の文字
\b単語境界(文字クラス内ではバックスペース)
\tタブ
\r復帰
\n改行
\xnn16進数で指定した ASCII 文字
\unnnnUnicode 文字
\A文字列の先頭
\Z文字列の末尾または末尾の改行直前(エンジン依存)

まとめ
#

正規表現は、文字列に含まれる規則を短いパターンで表現するための道具です。まずは文字列の検索、文字クラス、量指定子、グループ、選択肢、アンカーから覚えると使いやすくなります。

実際に利用するときは、次の順番を意識すると安全です。

  1. 何を一致させたいかを日本語で書く。
  2. パターンを小さな条件に分解する。
  3. 代表例だけでなく、空文字、境界値、想定外の入力もテストする。
  4. 正規表現で形式を確認し、数値や構造の厳密な検証はプログラムやパーサーに任せる。
  5. 複雑なパターンにはコメントとテストケースを残す。

参考資料
#


评论