正規表現のいろはにほへと
まずは基本を押さえよう
Shibuya Perl Mongers
小山 浩之 OYAMA Hiroyuki

oyama@cpan.org

http://module.jp/¡追加

はじめに¡削除¡分割

現在Webアプリケーションの実装で利用されているプログラミング言語のほとんどに正規表現が組み込まといった処理を頻繁に行っています．プログラミングれています．正規表現を使うことで，ユーザからの入言語のプリミティブな機能だけでこれらの処理を行う力を検査したり，文字列の中から必要な情報を取り出と非常に多くの手数を要し，予期しないバグを作り込したり，別の文字列に整形したりといった煩雑な処理む原因になってしまいます．しかしプログラミング言をコンパクトかつシンプルに表現することができます．

語が正規表現をサポートしていれば事情が変わってき本特別企画では正規表現について解説していきます．

ます．正規表現によって文字列に対するさまざまな操

まず本章では正規表現の概要を説明し，その表記法や作をシンプルに記述できるようになり，高度で複雑な簡単な使い方を説明します．第 2 章以降ではJava，処理でさえも高い抽象度でシンプルに記述することがPHP，.NET における正規表現の利用方法と注意すべできます．正規表現は文字列の処理において，効率的きポイントと，具体的な利用例を解説していきます．

で柔軟で非常に強力で重要なツールなのです．
たとえばAmazon.co.jp の商品紹介ページのHTML正規表現とは？

から売上ランキングを抜き出したいとき，正規表現内蔵言語の代表格であるPerl を使うと，リスト1 のようWeb アプリケーションのプログラミングの多くは文にたった2 行のコードで記述することができます．

字列の操作です．ユーザからの入力や，データベース

リスト1は商品紹介ページのHTMLを保持した変数から取り出した値，データファイルの内容，最終的に$html から正規表現でランキングを抽出し，その値を出力するHTMLなどなど，さまざまな場面で文字列を変数$ranking にコピーしています．

相手にプログラミングする必要があります．私たちはもし正規表現を使わない場合は，文字列に対して¡比較

q\n<b>Amazon.co.jp売上ランキング： </b>\nという文字列を検索¡抽出

wそれに続く数字もしくは,（カンマ）の文字列を記憶¡置換

eそれに続く\nを発見したら終了▼リスト 1 Perl で Amazon.co.jp 売上ランキングを抽出$html =˜ m|\n<b>Amazon.co.jp売上ランキング： </b>\n([\d,]+)\n|;$ranking = $1;

148● WEB +DB PRESS Vol.19と複数のステップを踏む必要があるでしょう．さらに言語によっては一時変数や処理ステップを記憶する変数を用意するといった，処理の本質とは遠い煩雑な手正規表現のいろはにほへとまずは基本を押さえよう続きが必要になる場合もあります．このように正規表抽出・置換・追加・削除・分割といった処理を行う

現は文字列処理にかかる面倒な処理を高度に抽象化しことができます．て確実に表現する，文字列処理に特化した言語と言えます．

これらの処理を大ざっぱに一般化すると¡マッチングプログラミング言語から正規表現を利用する方法
は，その言語によってさまざまな手段が用意されてい¡置換¡分割ます．Javaの場合は最近の実装では標準のクラスライブラリとして利用できますし，サードパーティ製の正という3 種類の処理に分類できます．正規表現の実装

規表現パッケージを別途利用することもできます．その多くで，この3 種類の処理のためのインタフェース

れとは異なりPerlの場合はプログラミング言語に組みが用意されています．Perl の場合にはマッチングを行込まれた演算子でシームレスに正規表現を利用するこうm//演算子，置換を行うs///演算子，分割を行うとができます．他にも関数として組み込まれている場

split演算子が用意されています注1．

合などもあり，プログラミング言語によって正規表現マッチングを利用する手続きは異なります．
また，モダンなプログラミング言語に用意されてい特定の変数に保持している文字列にマッチングを行

うたる正規表現の多くは「Perl バージョン5 互換」を謳っう場合，=˜または!˜のバインディング演算子を使用ており，その実装や利用できる機能はある程度似ていします．たとえば変数$text に格納した文字列にマッます．以前のように「ここでPerlの正規表現が使えた

チングを行う場合はリスト2 - qのように，らどんなに楽か…」といった不自由な思いをすることは少なくなってきていますが，それでも細かいところ

変数名 バインディング演算子 正規表現（m//演算子）で挙動の違いがあったり独自の機能拡張が含まれていと記述します．この際 =˜はマッチする場合に真，マる場合があったり，利用できない機能があったりする

ッチしない場合は偽の値を返します．!˜はその逆でのが実状ですので，それぞれのプログラミング言語にマッチする場合に偽，マッチしない場合に真を返しま実装されている正規表現の特徴を捉えておく必要があす．

ります．

m//演算子は正規表現をくくるためにデリミタ/（スプログラミング言語「正規表現」

ラッシュ）を必要としますが，このデリミタは任意の文字に変更することができます．たとえばHTMLタグを含む文字列を正規表現で表す場合，デリミタが/の

それでは正規表現の実装のデファクトスタンダード

ままだとリスト3 のように \（バックスラッシュ）でであるPerl を例に見ながら，正規表現の基本的な記いちいちエスケープする必要があります．この場合デ法や利用方法を説明します．ここでは正規表現の一
般的な記法を理解してもらうことを目的としているた▼リスト 2 Perl でのマッチング

め，最新のPerl バージョン5.8 系で実装されている正#!/usr/bin/perl
use strict;

規表現の拡張機能についてはあえて触れませんのでご了承ください．

利用方法
正規表現は文字列に対して，先述したように比較・

my $text = "Hello World!";
if ($text =˜ m/Hello/) { …q# $textはHelloを含んでいる．
}
else {# $textはHelloを含んでいない．
}

注 1）もちろんマッチングの結果として文字列を分割することもできます．さらに Perl にはこの他にも正規表現オブジェクトを生成する
qr//演算子や，tr///演算子など，関連する演算子が用意されているのですがここでは割愛します．

WEB +DB PRESS Vol.19 ●149

特別企画

1

文字列処理はこれでバッチリ！
▼表 1 一般的なメタ文字や文字クラスリミタを/以外の文字，たとえばリスト4 のように |メタ文字

役割や # などの文字に変更すれば，/をエスケープする必^

文字列の先頭を示す

要はなくなります注2．

$

文字列の末尾を示す.

任意の1文字にマッチ\t

タブ文字にマッチ\n

改行文字にマッチ\r

キャリッジリターンにマッチ\s

スペース・タブ・改行・キャリッジリターンなどの空白文
字にマッチ

\w

a〜z，A〜Z，0〜9の英数字と_（アンダースコア）に置換
変数に保持している文字列を正規表現で置換したい
場合はs///演算子を使用します．たとえば変数$textに格納したIISという文字列をApacheに置換する場合は，リスト5 のように記述します．
マッチする部分が複数ある場合は最初にマッチしたマッチ箇所で置換を行って処理を終了します．マッチするす\d0〜9の数字にマッチべての箇所を置換したい場合はリスト6 のようにgオ[...]...のいずれかの文字にマッチ（例：[abc]はa，b，cのプションを指定することでグローバルに置換するよういずれかにマッチ）\p{Prop}

ロックにマッチ\S\s以外の文字にマッチ\W\w以外の文字にマッチ\D\d以外の文字にマッチ[^...]\P{Prop}

るオプションについては後記します．

メタ文字
マッチングと置換の例を見てきましたが，ここまで...以外の文字にマッチ（例：[^abc]はa，b，c以外のの正規表現は単純なもので，そのパワーはまったく現文字にマッチ）れていません．正規表現には特定の文字種に一致させPropで指定したUnicodeプロパティ・スクリプト・ブたり，文字や文字列の出現回数を指定したり，複数ロック以外の文字にマッチ(...)

グループ化とキャプチャ(?:...)

グループ化のみ|or条件（例：正規表現(Perl|Ruby)はPerlとRubyにマッチ）?に動作が変更されます．マッチングと置換で使用でき

Propで指定したUnicodeプロパティ・スクリプト・ブ

0もしくは1つ（例：A?pacheはApacheとpatchのいずれかにマッチ）の条件を指定したりするためのメタ文字が用意されています．使用できるメタ文字は正規表現の実装によって異なりますが，一般的なものとして表1 に示すようなメタ文字があります．
これらのメタ文字を組み合わせることで，たとえば
m/^\d{3}-?(\d{2}|\d{4})$/は*0以上の繰り返し（例：\d*は1や12345や，長さ0の空の文字などにマッチ）

q先頭から（^）+1以上の繰り返し（例：\d+は1や12345などにマッチ）

w続いて数字3 文字（^\d{3}）{n}n個の繰り返し（例：\d{3}は3桁の数字にマッチ）

e続いて省略可能な-（-?）{n,}n個以上の繰り返し（例：\d{2,}は2桁以上の数字にマッチ）

r続いて2 または4 文字の数字（(\d{2}|\d{4})）{n,m}n個以上m個以下の繰り返し

t続いて末尾（$）▼リスト 3 デフォルトのデリミタ#!/usr/bin/perl
use strict;
my $text =˜ m/<head><title>Hello World!<\/title><\/head>/;▼リスト 4 デリミタを | に変更#!/usr/bin/perl
use strict;に一致する日本の郵便番号の文字列を表します．
文字の繰り返しを指定する*や+などの量指定子は正規表現の実装によって動作が異なるので注意が必要です．
たとえばPerlでは，

my $text =˜ m|<head><title>Hello World!</title></head>|;
注 2）他にもデリミタを(と)や{と}といった，対応する括弧で指定することもできます．

150● WEB +DB PRESS Vol.19

正規表現のいろはにほへと
まずは基本を押さえよう<a href="http://example.jp/"> 続きを読む</a>す．これを使用することにより，表2 のような文字の特性（プロパティ）や，言語別の書記体系（スクリプといった文字列からHTML タグだけを取り除き「続ト）や，文字コード上の範囲（ブロック）を正規表現

きを読む」だけを取り出したい場合，リスト7 のようで指定することができます．

な正規表現ではHTML タグ以外の文字列まで取り除

たとえばUnicodeプロパティを用いて一般的な日本いてしまいます．リスト7を実行すると変数$textには語の文字列にマッチする正規表現を記述すると，リス文字列 「．」（ 句 点 ） だけが格納されます．これはト10のように複数のプロパティとスクリプトの組み合<.+>という正規表現が「<に続く任意の文字1文字以わせになります．ここで使用しているグルーピング用上に『できるだけ多く』マッチした後に>」という文字列括弧(?:...)については後記します．

を示しているためです．例に挙げた文字列とこの正規

これらUnicode プロパティを用いたマッチングは非表現を照らし合わせると図1 のような範囲でマッチし常に便利ですが，正規表現の実装によっては基本的てしまっています．

なプロパティのみのサポートでスクリプトやブロック期待する動作は図2 のような「<に続く任意の文字1をサポートしないもの，プロパティとブロックのみを文字以上に『最小限に』マッチしたあとに>」という文字サポートするものなど，環境によっては利用できない

列です．

ものがあるので注意が必要です．また，ブロックの指図 2 のようにマッチさせる場合は * や + といった定 方 法 は P e r l や J a v a では \p{InLatin1「欲張り」な量指定子ではなく，リスト8 のように*?
や+?の「非欲張り」な量指定子を使用します．リス▼リスト 5 置換#!/usr/bin/perl

ト8 を実行すると変数$text は文字列「続きを読む．」 use strict;が格納されます．
また欲張りな量指定子を使用した場合でもリスト9

my $text = "IISのWebサーバを管理する．";$text =˜ s/IIS/Apache/; # 「ApacheのWebサーバを管理する．
」に置換のようにマッチする文字を明示的に指定し，目的を達 ▼リスト 6 グローバルに置換成することもできます．リスト9 は「<に続く『>以外の文字列』にマッチした後に>」という正規表現になります．

#!/usr/bin/perl
use strict;
my $text = '!NAME!さんこんにちは．'.
'今日は!NAME!さん限定でお得な情報をおしらせします．';$text =˜ s/!NAME!/正規表現/g;▼リスト 7 欲張りな量指定子● Unicode プロパティ
Perl やJava や.NET などUnicode 対応の正規表現エンジンでは，Unicode プロパティやスクリプトもしく#!/usr/bin/perl
use strict;
my $text = '<a href="http://example.jp/">続きを読む</a>．';$text =˜ s/<.+>//g;はブロックを\p{Prop}というメタ文字で指定できま▼リスト 8 非欲張りな量指定子
図 1 ●欲張りな量指定子でマッチする範囲#!/usr/bin/perl
use strict;< a href="http://example.jp/">続きを読む</a > ．
< .+>図 2 ●非欲張りな量指定子でマッチする範囲< a href="http://example.jp/" > 続きを読む</a>．
< .+?
▼リスト 10>

my $text = '<a href="http://example.jp/">続きを読む</a>．';$text =˜ s/<.+?>//g;▼リスト 9

否定文字クラスによるマッチ#!/usr/bin/perl
use strict;
my $text = '<a href="http://example.jp/">続きを読む</a>．';$text =˜ s/<[^>]+>//g;

一般的な日本語にマッチする正規表現

m/(?:(?:\p{Hiragana}|\p{Katakana}|\p{Han}|\p{Latin}|\p{Common})(?:\p{Inherited}|\p{Me}|\p{Mn})?)+/WEB +DB PRESS Vol.19 ●151

特別企画

1

文字列処理はこれでバッチリ！
Supplement}など接頭子 Inを使用するのに対正規表現のオプション指定方法は実装やAPIによってし，.NET では¥p{IsLatin1Supplement}など接異なるので注意が必要です．

頭子 Isを使用するといった差異がある点にも注意が

通常，正規表現m/abc/は文字列abcにだけマッチ必要です．利用できるUnicodeプロパティ・スクリプ

して文字列ABCにはマッチしませんが，m/abc/iとト・ブロックの種類とその指定方法についてはそれぞオプションi を付与した場合はABCやAbcのように大れの環境のドキュメントを参照してください ．

文字と小文字の違いを無視してマッチします．

注3

オプション

オプション m を付与すると行単位でマッチングを行うようになります．^ と $ は通常「文字列全体の先頭正規表現の動作はオプションによって変更することと末尾」を表すメタ文字ですが，オプション m を付与ができます．一般的なオプションを表 3 に示します．

すると「各行の行頭と行末」に役割が変化します．
これに対しオプション sは改行を含む文字列を1 本▼表 2 一般的な Unicode プロパティの指定の文字列として扱いたい場合に使用します．オプショ

プロパティ

性質

ン s の場合は任意の文字を示すメタ文字.（ピリオド）\p{L}

表示可能な文字が示す文字が，「改行文字 \nを含む任意の文字」に\p{M}

他の文字と組み合わせて使用する文字

\p{Z}

区切り文字

\p{S}

記号

\p{N}

数字

\p{P}

句読点

\p{C}

L，M，Z，S，N，P以外のすべての文字\p{Ll}

小文字\p{Lu}

大文字\p{Lo}

ヘブライ語や日本語などの大文字と小文字を持た取り出すことができます．Perl の場合キャプチャ結果ない文字は特殊変数$1で参照できます．

拡張されます．

キャプチャマッチした文字の一部分を取り出したり，置換結果に埋め込みたい場合には正規表現のキャプチャを使用することができます．リスト11 を実行するとキャプチャ用括弧(と)で指定した範囲にマッチした文字列を\p{Sm}

数学記号

キャプチャ用括弧が複数ある場合は，括弧の出現\p{Sc}

通貨記号

順に応じて $1，$2，$3，$4…と対応した番号の変\p{Cc}

ASCIIとLatin-1の制御文字数に結果がセットされます．リスト12 はaタグから参スクリプト

対象

照先のURLとマークアップされた文字を抜き出して整\p{Katakana}

カタカナ\p{Hiragana}

ひらがな\p{Han}漢字\p{Latin}

英数字▼リスト 11

スペースや句読点など#!/usr/bin/perl
use strict;\p{Common}▼表 3 正規表現オプション形する例です．実行するとマッチした文字列は図3 のようにキャプチャされて，変数 $text は「Here (url:キャプチャの例

my $text = 'Name: hiroyuki oyama';
if ($text =˜ m/^Name:\s+(.+)$/) {my $value = $1;# 「hiroyuki oyama」を取り出す}

オプション

用途i

大文字と小文字を無視する

g

文字列全体の複数箇所でマッチングする▼リスト 12

行単位でマッチングする#!/usr/bin/perl
use strict;ms

改行を含む文字列全体でマッチングする

x

正規表現中の空白を無視し，コメントの記述を許可する

複数のキャプチャと置換

my $text = '<a href="http://example.jp/">Here</a>'$text =˜ s|<a href="(.+?)">(.+?)</a>|$2 (url: $1)|;

注 3）Perl の場合は perldoc perlunicode もしくは http://www.perldoc.com/perl5.8.2/pod/perlunicode.html を参照してください．

152● WEB +DB PRESS Vol.19

正規表現のいろはにほへと
まずは基本を押さえよう
図 3 ●複数のキャプチャ▼リスト 13<a href=" http://example.jp/ "> Here </a>
(.+?)

(.+?)

$1$2

キャプチャしない括弧#!/usr/bin/perl
use strict;
my $text = "<a href=\"http://example.jp/\">Read more...</a>\n".
"<img src=\"http://img.example.jp/path/to/file.png\">\n";while ($text =˜ m/<(?:a href|img src)="(.+?)"/g) {my $url = $1;
print $url, "\n";}▼リスト 14

http://example.jp/)」に置換されます．

文字列の分割#!/usr/bin/perl
use strict;

キャプチャ用括弧はグルーピングにも使用されます．もしキャプチャを必要とせずに単にグルーピングしたい場合はリスト13 のように(?:...)
でグルーピングします．リスト13 はa タグとimgタグの参照先URL を取り出す例で，この正規表
現はmy $text = "root:*:0:0:System Administrator:/var/root:bin/sh";my @user = split m/:/, $text;
printf "useradd -c '%s' -d %s -g %d -s %s -u %d %s\n",$user[4], $user[5], $user[3], $user[6], $user[2], $user[0];▼リスト 15n 番目の要素まで分割#!/usr/bin/perl
use strict;
my $text = "root:*:0:0:System Administrator:/var/root:bin/sh";my @user = split m/:/, $text, 3;
printf 'User %sのUIDは %dです．', $user[0], $user[2];q<w qに続く文字列 a hrefもしくはimg src（キャプチャしない）
e wに続く文字列="

r eに続く1 文字以上で最小限の任意の文字（キャプチャする）
t rに続く"root -g 0 -s bin/sh -u 0 root（実際は1行）という文字列を出力します．
split演算子は第1 引数に文字列の分割位置を指定する正規表現，第2引数に分割対象の文字列を指定し使用します．また，分割結果がn番目まで必要な場に繰り返しマッチします．wの括弧(?:...)はキャ

合は，リスト15のように第3引数に分割し取り出したプチャせずグルーピングのみを行い，rのキャプチャい要素数を指定します．リスト15 は変数$text から :用括弧内にマッチした文字列が特殊変数$1にセットで分割した3つの要素を取り出し配列@userに格納しされます．リスト13を実行すると「http://example.jp/」ています．と「http://img.example.jp/path/to/file.png」が出力されます．

分割まとめ正規表現の実装のデファクトスタンダードである文字列を特定の文字や文字列で分割したい場合にPerl を例に，正規表現の基本的な利用方法を説明しも正規表現が利用できます．Perl の場合はsplit演ました．正規表現の実装と利用方法は個々のツール算子を使用し，リスト14 のように文字列の境界を正や環境によって差異があります．それでもPHPやRuby

規表現で指定して分割結果の文字列を配列として取得やPython，Javaや.NETといった現在利用できるモダすることができます．リスト14 はpassword ファイル

ンな環境であれば，APIや微妙な挙動や独自の拡張との1エントリを格納した変数$textを，デリミタ:で分いった差異はあるものの，基本となる利用方法や考え割し，結果を配列@userに格納します．このコードを方はすべて同じものです．故に正規表現を文字列表現実行するとや文字列操作における基本ツールとして身につけておけば，たとえ環境が変わっても同じように使いこなす

useradd -c 'System Administrator' -d /var/ことができるでしょう．#
WEB +DB PRESS Vol.19 ●153