5.4 正規表現

(1/1)
シマフクロウのイラスト
ここで、正規表現 (せいきひょうげん) について触れておこう。
ファイル名のあいまい検索を行うとき、ワイドルカード *.* を使う。正規表現は、これを拡張したものと考えてもらえばいい。ファイル名検索だけでなく、広く文字列の検索・抽出などに利用することができる。JavaScriptにも、正規表現を使うためのメソッドが用意されている。

目次

サンプル・プログラム

正規表現とは

たとえば複数のテキスト・ファイルの中から、"macOS" という単語を検索したいとする。Googleを使って簡単にできることだが、自分でプログラムを組んで、ローカルファイルに対して同じ処理をさせようとすると、かなり苦労をする。
というのは、"macOS" のスペリングとして "macOS" 以外に、過去のスペリングとして "Mac OS X", "MacOS X", "OS X" などがあるからだ。さすがに "mac os x" や "os x" と書く人は少ないと思うが、絶対にいないとは言えない。文字列検索では、こうした表記ゆれが付きものだ。

となると、複数のスペリングに合致するような検索プログラムを書かなければならない。これを if文で表現しようとすると、
if ($str == "macOS" || $str == "Mac OS X" || $str == "MacOS X" || $str == "OS X") {
となるだろう。switch文で書くとしても、表記ゆれの数だけプログラムは複雑になり、プログラムのメンテナンス性が低下する。そこで登場するのが正規表現だ。

JavaScriptの正規表現を用いると
/(Mac)?\s*OS(\s*X)*/
と1行で、すべての表記ゆれをカバーすることができる。
初めての方には怪しげな記号が並んでいるだけと映るかもしれないが、これは "OSX" にもマッチする。想定外の検索パターンが出てきた場合、柔軟に対応できるのが正規表現の強みである。
さらに "mac os x" や "os x" も検索対象としたいなら、正規表現はそのままで、フラグ "i" を追加することで、大文字・小文字を区別しなくなる。
/(Mac)?\s*OS(\s*X)*/i

正規表現による部分文字列置換

では、JavaScriptで正規表現を使ったプログラムを作ってみることにしよう。
"url2link.html" は、入力したテキスト中にあるURLをハイパーリンクに置換するプログラムである。
正規表現による部分文字列置換

  23: //正規表現パターン
  24: const REGEX = /(https?\:\/\/[\-_\.\!\~\*\'\(\)a-zA-Z0-9\;\/\?\:\@\&\=\+\$\,\%\#]+)/i;

URLを正規表現で表す前に、URLで使えるすべての文字の種類を把握しておく必要がある。
URLの書き方は、RFC 1738 Uniform Resource Locators (URL)和訳】に定義されている。これによると、
"http(s)://" 以降に記述できる文字は、英数字(大文字・小文字)と記号類(- _ . ! ~ * ' ( ) ; / ? : @ & = + $ , % #)であることがわかる。

これを正規表現で表すと、
/https?\:\/\/[\-_\.\!\~\*\'\(\)a-zA-Z0-9\;\/\?\:\@\&\=\+\$\,\%\#]+/i
となる。順に説明していこう。
?
直前1文字の0または1回の繰り返し。
ここでは、httpとhttps の両方にマッチする。
[...]
文字クラス。 この中に記述された文字の並びのうちの1文字を表す。
-
文字の範囲指定。
a-z はアルファベット小文字すべてに、A-Zはアルファベット大文字すべてに、0-9は数字すべてにマッチする。
+
直線1文字の1回以上の繰り返し。 ここでは、文字クラス[...]に記述された文字、いずれかの1回以上の繰り返し――すなわち、URL 文字列にマッチすることになる。
(...)
サブパターン。 マッチングだけであれば不要だが、置換を行うために、マッチした部分文字列に番号を付けてやる必要がある。その場合にサブパターンを用いる。
"url2link.html" で定数 REGEX に代入する正規表現は、
/(https?\:\/\/[\-_\.\!\~\*\'\(\)a-zA-Z0-9\;\/\?\:\@\&\=\+\$\,\%\#]+)/i
とすることで、URL全体をサブパターンで囲んで部分文字列として扱うことができるようにした。
JavaScriptの正規表現は、テキストと異なるリテラル文字で表される。クォーテーションではなく、スラッシュ / で囲む。これ以外に、RegExcp オブジェクトを使って表現することもできる。

  76:     //正規表現による置換
  77:     let dest = sour.replace(REGEX, replacer);

URLにマッチする部分文字列を置換するのは、この1行だけである。replace メソッドを利用する。第1引数に正規表現を、第2引数にユーザー定義の置換関数を指定する。

  54: /**
  55:  * 置換関数
  56:  * @param  String gmatch 一致した部分文字列
  57:  * @param  String p1     1番目の部分文字列
  58:  * @return    String p1の置換後文字列
  59: */
  60: function replacer(match, p1) {
  61:     return '<a href="' + p1 + '">' + p1 + '</a>';
  62: }

ユーザー定義の置換関数 replacer は、第1引数に一致した部分文字列が、第2引数には1番目の部分文字列が、第3引数には2番目の部分文字列が‥‥代入される。ここでは、第2引数までを指定する。
置換は、HTMLの a タグを作る式を用意した。

コラム:表記ゆれとオントロジー

表記ゆれ
かつて使用されていた記憶媒体フロッピーディスクは、それを開発したIBMによって「フレキシブル・ディスケット」または単に「ディスケット」と呼ばれた。取扱説明書には「フロッピーディスク」と書かれることもあった。
フロッピー」はIBMの商標と言われることがあるが、実際には日立製作所が商標をとっている(現在は放棄)。
このように同じ記憶媒体を指すにも表記ゆれがあり、さらにJIS規格の用語定義には「フレキシブルディスク」と「フレキシブルディスクカートリッジ」の2つがあった。
設計書にはJIS用語を使うのが筋だが、当時、フレキシブルディスクが通じる若手技術者はいなかった。
このように、表記ゆれは、コミュニケーションを阻害する。

話は現代に戻る。ディープラーニングを使ったテキストマイニングでは、学習用テキストにある表記ゆれを避けられない。フロッピーディスクフレキシブルディスクも同じ意味であることを認識できなければ、ラーニングが成立しない。

表記ゆれを解決するために、さまざまな同義語辞書が考えられているが、決定的な解決には至っていない。
一方、情報科学の分野ではオントロジーの研究が進んでいる。これは、リアル世界をどのように概念化(コード化)したかを研究するものである。
たとえばフロッピーディスクの場合、コンピュータの磁気記憶媒体であり、取り出し可能で、携行が容易であり、8インチ、5インチ、3.5インチなどの複数のサイズや記憶容量があるという概念を整理して伝えることができれば、コミュニケーションやラーニングが成立するというものである。
ディープラーニングの学習データにオントロジーを適用するのは、まだまだハードルが高いが、テキストを中心に使うSNSで、概念が正しく伝わらなければコミュニケーションが成立しない。その意味で、オントロジーの研究はますます盛んになることだろう。
(この項おわり)
header