Asial Blog

Recruit! Asialで一緒に働きませんか?

正規表現入門(1) - 正規表現を使ってみよう

カテゴリ :
バックエンド(プログラミング)
タグ :
Tech
正規表現

はじめまして。4月から入社した宇都宮と申します。アシアルではPHPエンジニアですが、前職では、HTMLコーダー兼PHPエンジニア、必要に応じて(Action|Java)Scriptと、色々やってました。


様々な言語を書いてたわけですが、言語を問わずいつも使っていた便利ツールがあります。それが「正規表現」。というわけで、今回は正規表現について書きます。


正規表現とは


正規表現とは、 (Action|Java) といった感じで、文字列をパターン化して表現する方法のことをいいます。この例だと、「"Action"又は"Java"のいずれか」という意味になります。


この記事において、「正規表現」とは、各種ソフトウェアやプログラム言語で利用できる特殊な文字列パターンのことを指します。


正規表現を使うのに、プログラミングの知識・経験は必要ありません。日々大量のテキストと格闘している人であれば、正規表現を覚えることで効率的に作業を行える場面があるはずです。


正規表現は、JavaScriptやPHPなどのプログラム言語のほか、各種のエディタでも正規表現がサポートされています。Microsoft Wordの検索・置換機能でも、正規表現が使えます。


今回は、正規表現の入門として、具体的な場面に則したイントロダクションを行います。


正規表現の使いどころ


正規表現は、「一定の規則性があるが、バラバラな部分もある」文字列に対して、最も威力を発揮します。一例として、以下のfontタグを使ったHTMLを、spanタグにstyle属性を指定したものに変換してみます。


  1. <font color="blue">test</font>

これをspanタグに置換するには、2つステップが必要になります。まず、fontタグを検索して、置換後も引き継ぎたい文字列を保持しておきます(上の例では、「blue」と「test」)。文字列を保持しておくことを、「キャプチャ」といいます。検索とキャプチャには、以下のような正規表現が使えます。


  1. <font color="(.+)">(.+)</font>

次に、置換用の文字列を用意します。


  1. <span style="color:$1">$2</span>

$1、$2というのは、キャプチャされた文字列の入る場所です。$1には「blue」、$2には「test」が入ります。


それでは、実際に置換してみましょう。


<font color="blue">test</font>


「置換」ボタンを押すと、fontタグがspanタグに変換されたはずです。次に、いま使用した正規表現について解説していきます。


いちばんやさしい正規表現


  1. <font color="blue">test</font>

という文字列に合致する正規表現を、ゼロから組み立てて行きましょう(ちなみに、正規表現のパターンに合致する文字列がみつかることを「マッチする」といいます)。


最も簡単な正規表現は、「検索対象文字列そのもの」です。


  1. <font color="blue">test</font>

を見つけるのに


  1. <font color="blue">test</font>

という正規表現を使います。ただし、これでは、検索対象文字列が1文字でも変わるとマッチしなくなってしまいます。そこで、「どんな文字でも表すことができる文字」を使ってみましょう。


任意の1文字を表す.(ドット)


正規表現には、「メタ文字」という文字があります。一見すると通常の文字と同じですが、特別な意味をもっています。(「メタ」とは「高次な」という意味で、メタ文字とは、「文字を記述するための文字」という意味です)


最初に覚えてほしいメタ文字が、.(ドット)です。これは、任意の1文字にマッチします。ちなみに、「任意の」とは、「何でも」という意味です。


.

という正規表現は、文字が1文字あれば何でもマッチします。「a」でも「123」でもマッチします。正規表現は前から順に照合していくので、1文字目(「a」「1」)にマッチします。


.(ドット)の数を増やすと、その数だけマッチします。


...

であれば、「123」「abc」「12345」などにマッチします(前から3文字にマッチ)。一方、「12」や「ab」は、文字数が足りないのでマッチしません。それでは、.(ドット)を使って、正規表現を書き換えましょう。


  1. <font color="....">test</font>

これで、colorが「blue」だけでなく、「pink」や「cyan」でもマッチするようになりました。次に、「....」でマッチした部分の値をキャプチャしてみましょう。


()(カッコ)でキャプチャ


マッチした部分の値を取得するには、()(カッコ)を使います。


(...)

とすれば、任意の3文字をキャプチャします。キャプチャされた文字列は、$1、$2といった「$ + 連番の数字」という名前の変数(容れ物)に格納されます1。この変数を置換後の文字列に配置すれば、キャプチャした文字列を展開することができます。


これによって、color属性の値をキャプチャできるようになりました。正規表現を書き換えましょう。


  1. <font color="(....)">test</font>

次に、置換対象文字列を用意します。


  1. <span style="color:$1">test</span>

これで、colorの部分に指定された任意の4文字がcolor:の後ろに挿入されるようになりました。でも、まだまだ実用的とはいえませんね。次は、任意の文字数を取得できるようにしてみましょう。


+(プラス)は、「1文字以上の繰り返し」


量を表すメタ文字は、まず+(プラス)を覚えましょう。+(プラス)は、「1文字以上の繰り返し」を表します。繰り返される文字の後ろに+(プラス)をくっつけて使います。


a+

という正規表現は、「a」が1文字以上繰り返される文字列にマッチします。たとえば、「a」「aaa」「bbaacc」などです。1文字以上の繰り返しを表す+(プラス)と、任意の1文字を表す.(ドット)を使えば、「任意の文字の1文字以上の繰り返し」を表すパターンになります。


それでは、+(プラス)を使って、正規表現を書き換えましょう。


  1. <font color="(.+)">test</font>

これで、colorの部分の文字数が1文字以上なら取得できるようになりました。同様のメタ文字を用いて、fontタグに囲まれている部分も取得しましょう


  1. <font color="(.+)">(.+)</font>

これで完成です。


まとめ


今回は、正規表現で検索して、キャプチャして、置換して、という一連の流れを体験するため、最低限の内容を紹介しました。今回使用したメタ文字は、いずれも頻繁に使うので、この機会に覚えてしまいましょう。



  • 任意の1文字を表す.(ドット)

  • 1文字以上の繰り返しを表す+(プラス)

  • 文字列をキャプチャする()(カッコ)


次回は、より実践的な内容を紹介したいと思います。


おまけ:Dreamweaverで正規表現を使おう


Adobe製のHTMLオーサリングツールであるDreamweaverには、強力な検索・置換機能が備わっています。中でも便利な、「検索・置換文字列を保存しておく」機能を紹介します。


HTML編集の際には、定型的な置換を行いたくなることがあります。たとえば、<br><br /><br/>。バラバラでも実害はありませんが、気持ち悪いですよね。検索文字列を<br[^>]*>、置換文字列をいずれかのパターンのbrタグにしてやれば、簡単に検索・置換を行えます。([^>]*は、「>以外の文字の0個以上の繰り返し」という意味)


毎回検索・置換文字列を入力するのは面倒なので、何回も使いそうな検索・置換文字列は、名前をつけて保存しておきましょう。


dreamweaver

brタグ置換と並んで、よく使ってたのが以下の正規表現です2。(1)はcolor属性の値と囲まれた部分を保持して置換、(2)は属性値を無視して、fontタグに囲まれた部分だけ保持して置換を行います。(1)→(2)の順に使えば、colorを保持して置換できます。color属性も不要、という場合は(2)だけ走らせればOK。


検索文字列(1)


  1. <font.+color="([^"]*)"[^>]*>([^<]*)</font>

置換文字列(1)


  1. <span style="color:$1">$2</span>

検索文字列(2)


  1. <font[^>]*>([^<]*)</font>

置換文字列(2)


  1. <span>$1</span>

全てのfontタグを、リリース前に消し去りたい!







  1. 処理系によって変わるかも。JavaScript/PHP/Perl/Sublime Text 2/Dreamweaverについては、$1, $2, …となることを確認済み。



  2. 前職では、HTML5なのにfontタグでコーディングしてるソースによく遭遇しました。アシアルのソースでは、今のところfontタグを見てません。