先日、Yuji@勉強部屋さんと電話で話していて、文字クラスの理解が正規表現の「一里塚」だなぁ、と感じました。InDesignで初めて正規表現に接する方も多く、戸惑われている人もいらっしゃると思います。

文字クラスは正規表現の中でもちょっと特別な存在です。文字クラス内だけで使えるメタ文字や、位置によって意味が変わるメタ文字もあります。文字クラスについては、日頃使い慣れた人でも間違えやすい部分もあり、結構奥が深いのでおさらいの意味も込めてまとめておきます。


文字クラスの基本

ここで言う「文字クラス」は、「POSIXブラケット表現」とも呼ばれます。違うサイトや書籍などで、これらの用語が混在することがありますが、ほぼ同じと考えて差し支えありません。

文字クラスは任意の1文字にマッチするできます。

簡単な例から見てみましょう。たとえば「お母さん」と「お父さん」のどちらにもマッチさせたい時、

お[父母]さん

と書くことができます。「お[父母兄姉]さん」と書けば、「お兄さん」にも「お姉さん」にもマッチするようになります。

つまり、[ ]で囲われた文字のどれかにマッチするような表現ができるわけです。

HTMLで<H1>から<H5>の見出しを探したいなら「<H[12345]>」とすればOKです。


否定文字クラス

否定文字クラスは、示された文字以外を表します。つまり、そこにマッチさせたくない文字を列挙します。書き方は

[^マッチさせない文字]

となります。ブラケットの最初に「^」キャレットを書くんですね。たとえば、価格でない数字列は数字の後に「円」が付かないと予想して、「[0123456789,.]+[^円]」と表現できます。「1984年」や「3.141592…」にはマッチしますが、「198円」や「2,980円」にはマッチしません。

【注意】否定文字クラスを使うと、改行文字にもマッチする

否定文字クラスは、「全文字」に対して指定文字の補集合ですから、(明示的に改行文字を指定しない限り)改行文字にもマッチします。一般的に「.」(ピリオド:任意の1文字)が改行を含まない経験則から、否定文字クラスも改行を含まないと思い込んでしまいがちです。たとえば、「(?s)」シングルラインモードで「(?s)[^。]+。」と書いて「ひとつづきの文」にマッチするでしょうか? こんな感じになります。

たしかに、InDesignでは明示的にシングルラインモードにする必要があります(説明のためにやや無理がある^^)が、通常のエディタなどではこうしたマッチになってしまうのが普通です。否定文字クラスを使うときには、明示的に

[^。\r]+。

と、改行を含むように習慣付けましょう。

#InDesign内の正規表現では改行文字を「\r」で表しますが、アプリケーションによっては「\n」で表すものが多いようです。


文字クラスの中のメタ文字

文字クラスでは、文字クラスの中でしか使えないメタ文字があります。先に説明した否定文字クラスの「^」も、否定を表すメタ文字です。ただし、「^」を最初(「[」の直後)に書いた時だけ、メタ文字になります。

もうひとつ、文字クラス内でのみ使える重要なメタ文字は「-」(ハイフン)です。これは通常、文字コード範囲を表します。たとえば、大文字のアルファベットを表したければ「[A-Z]」と表現できます。漢字を表したければ「[一-龠]」になります。【注意】ここでお気づきになる方もいらっしゃるかもしれません。このします。InDesignではUnicodeを使用しますので、漢字の範囲が「[一-龠]」になるわけです。書籍によっては(なんの説明もなく)「[亜-煕]」を漢字だと説明しているものがありますが、これはShift-JISの並びです。アプリケーションがどの文字コードを使っているかによって文字範囲は変わります。

実はこの「-」は文字と文字の間に挟まれた時だけ文字コード範囲を表します。つまり、「[0-9-]」と書いた時、「0から9までの数字とハイフン」にマッチします。文字に挟まれたハイフンはメタ文字としてコード範囲を表しますが、文字クラスの最初または最後に書かれたハイフンは、ハイフン文字そのものを表します。

【Note】文字クラスの中では「通常の文字」(リテラル)として扱われる文字

文字クラスの中で「.」を書いた時、通常の「任意の1文字」という意味ではなくなります。文字クラスの中で「.」は、「.」文字そのものです。ほかにも、「$」「?」「+」「(」などもそれぞれの文字そのものを表します。文字クラスの中だけの例外処理です。

逆に「]」(閉じブラケット)は「\]」と書かなければなりません。

【Note】ハイフンやピリオドを明示的にエスケープして見やすくする

正規表現的には「[0-9.-]」と書けば、「数字とピリオドとハイフン」にマッチします。でも見た目が分かりにくいですよね。こういう時は

[0-9\.\-]

と明示的に「\.」「\-」と書いて、これがピリオドやハイフンそのもだと見た目に分かりやすくするとよいでしょう。

これは、メタ文字以外の文字の直前にある「\」(バックスラッシュ)は無効と見なされるからです。たとえば「\あ」と書けば、「あ」そのものを表したのと同じです。多用する方法ではありませんが、前述のような「わかりやすさ」を表現できます。

【Note】文字リテラルではなく、コードポイントで文字範囲を指定する。

これはあまり多用する記法ではないのですが、文字コードを使ってコード範囲を表現します。たとえば、フォントによって文字を持たない範囲を含めたりすることができます。また、InDesign CS3ではカタカナにマッチしないバカバグがあって、こうした時の逃げ道にも利用できます。カタカナの範囲を指定したければ

[\x{30a1}-\x{30fe}]

と表現します。これは、Unicodeで30a1~30feを指定したのと同じことになります。


文字クラスの略記法

文字を表す正規表現の多くは文字クラスの略記法です。たとえば、「\d」は「[0-9]」と同じ意味になります。極端に言うなら、「.」ピリオドは「[^\r\n]」改行以外の文字すべてと書き換えることができます。主な略記法を下記に示します。

略記法意味文字クラス記法備考
\d数字[0-9] 
\D数字以外の文字[^0-9] 
\sホワイトスペース[ \t\r\n]全角スペースを含めたいときは「全角半角を区別」がONにするか、素直に[ \s]とする。EMスペースなどにはマッチしない。
\Sスペース以外の文字[^ \t\r\n] 
\u任意の大文字[A-Z] 
\U大文字以外の文字[^A-Z] 
\l任意の小文字[a-z] 
\L小文字以外の文字[^a-z] 
【Note】略記法を多用しないこと

たとえば、「[\l\u]」を「[a-zA-Z]」と読める人は、よほど正規表現に詳しい人です。しかし正規表現に詳しい人は「[\l\u]」と書きません。自分にも他人にも優しくないですから。「\l」がlower case、「\u」がupper caseの略だというのは、正規表現を一種のマジックワードにしています。

また、正規表現のバージョンや実装によってはこうした略記法をサポートしないアプリケーションも多数あります。さらに、「\w」のようにロケールに依存する場合もあります。ですから、正規表現の略記法の使用は「\d」や「\s」程度にとどめておくのが賢明でしょう。


  • 文字の字形セットをサポートする

ということです。文字の字形セットとは、「a」という文字に対して、「a、à、á、â、ã、ä、å、A、À、Á、Â、Ã、Ä、Å」などの文字セットを含むということです。ロケールに依存するので、日本語なら全角文字にもマッチします。

POSIX文字クラスを使いこなすのは、かなり上級編と言えるでしょう。主なPOSIX文字クラスを下記に示します。

記法意味備考
[[:alnum:]]任意のアルファベットと数字[[:alpha:]] + [[:digit:]]と同じ。ロケールに依存する。日本語では\w相当にあたるため、アルファベット+数字とは言えない。[[:^alnum:]]で否定集合を表す。
[[:alpha:]]任意のアルファベット文字[[:lower:]] + [[:upper:]]と同じ。[A-Za-z]のアルファベットおよびその字形集合を含む。ロケールに依存するため、日本語ではアルファベットに限らず単語を構成する文字に相当する。
[[:blank:]]任意の空白文字基本的に半角スペースとタブにマッチだが、日本語ロケールでは、全角スペースやEMスペース、1/6スペースなどにもマッチする。
[[:cntrl:]]任意の制御文字[\x00-\x1F\x7F]と同じ。\x7FはDEL。InDesignではいくつかの制御文字が、「改ページ」や「自動ページ番号」「セクションマーカー」などに割り振られている。
[[:digit:]]任意の数字[0-9]の数字およびその字形集合と同じ。日本語では全角数字にもマッチする。丸付き数字や時計数字にはマッチしない。
[[:graph:]]印字可能かつ表示可能な任意の文字スペースは印字可能だが表示可能ではない。
[[:lower:]]任意のアルファベット小文字[a-z]とその字形集合と同じ。日本語では全角英字の小文字にもマッチする。
[[:print:]]任意の印刷可能文字印刷可能なすべての文字と字形集合。日本語ではなぜかタブも含んでしまう。
[[:punct:]]任意の記号文字パンクチュエーション(記号)文字。日本語では句読点や括弧類にもマッチする。
[[:space:]]空白文字、タブ、改行、水平タブ、給紙、キャリッジリターン、空白「全角半角の区別」をオフにすると、(なぜか)どのスペースにもマッチしない。
コードが255より大きい任意の文字広幅特徴を持つクラスのみに適用(※これについては、ちょっとよくわからない)
[[:upper:]]任意のアルファベット大文字[A-Z]とその字形集合と同じ。日本語では全角アルファベットの大文字にもマッチする。
[[:word:]]   [[:alnum:]]とアンダーバーとその字形集合。日本語では単語を構成する文字を表す。
[[:xdigit:]]0~9、a~fおよびA~Fの任意の16進を構成できる数字[0-9A-Fa-f]とその字形集合と同じ。日本語では全角英数字にもマッチする。
[[=a=]]特定の文字の字形セット「a、à、á、â、ã、ä、å、A、À、Á、Â、Ã、Ä、Å」などにマッチする。日本語で[[=あ=]]などとすれば丸付きの「あ」にもマッチする。

参照

*1:実際には、使われるエンジンや記法が若干異なるのだけど、そこまで厳密に区別できるほど用法は区別されていません

*2Unicodeでは[一-龠]だけが漢字ではありません。しかし、過去の遺産も含めて各社もろもろの拡張漢字の範囲や、それらを実装している文字セットや、サロゲートペア、SING外字などを考える時、正規表現としての正確さを期することは難しいのではないかと思っています。 [一-龠]といえば漢字ですね、くらいの解説です。もし「より正確な」書き方を望まれるのであれば、ものかのさんの「Unicodeで「漢字」の正規表現」などを参照してください

*3InDesign中では正規表現ダイアログの半角全角などのオプションにかかわらず、\dや\wなどの全角半角を同一視してしまいます。ご注意ください、というか個人的にはInDesignでの略記法の使用はおすすめしません。

momo DBPublisher/i 活用ガイドを参考にさせていただいております。
一桁数字を全角に変換したく、正規表現の置換の所に<calgf:FullWidthForm>$1<calgf:>を入れて置換しましたが、検索した数字がそのまま<calgf:FullWidthForm>$1<calgf:>になってしまいました。Windows環境、Macどちらも試しましたができずに困っています。何か別に「全角数字」を表すものがあったら教えてください。

スパム対策のためのダミーです。もし見えても何も入力しないでください


画像認証