TypeScriptの正規表現で凡ミスをした。
その備忘録。
ワテの場合は、JavaScriptでなくTypeScriptを良く使う。
今回のミスはJavaScriptでも当てはまる。
ワテの開発環境は以下の通り。
- 自作Windows10x64パソコン(詳細)
- Visual Studio 2017 Community 15.8.1
- .NET Framework 4.7.2
では本題に入ろう。
Visual Studio 2017 でTypeScriptを使う
Visual Studio 2017でTypeScriptを使うのは簡単だ。
ワテの場合は、Visual Studio 2017 Communityの全パッケージをインストールしている。
そうすると、TypeScriptも全自動でインストールされる。
Visual Studio 2013や2015の時には、確か、自分でTypeScriptコンパイラーをマイクロソフト社のサイトからダウンロードしてインストールする必要が有った。
でもVS2017ではそんな作業は必要は無い。
ワテみたいに全パッケージをインストールしていない人は、インストールの画面でTypeScript関連をチェックしておけば良いだろう。
TypeScriptプロジェクトを作る
さて、TypeScriptのプロジェクトを作ってみよう。
TypeScriptを使うには、幾つかの選択肢があるが、ここではNode.jsのコンソールアプリを作ってみる。
他の選択肢としては、ASP.NET、ASP.NET MVC、ASP.NET CoreなどのWEBプロジェクトを作成して、その中でTypeScriptを使っても良い。
下図のように
新しいプロジェクト
TypeScript
空のNode.jpコンソールアプリケーション
を選択する。
プロジェクトの名前はデフォルトのまま[OK]をクリック。
まあ、必要ならプロジェクトの名前を変更しても良いが。
app.ts を編集する
デフォルトで数個のファイルが追加されるが、その中にある app.ts を編集する。
このファイルにTypeScriptでプログラムを書けば良い。
ちなみに、プロジェクトをビルドして実行するとこのapp.tsが実行される理由は、プロジェクトのプロパティでスタートアップファイル に app.ts が指定されているから。
なので、必要なら別のTypeScriptをファイルを指定しても良い。
さて、デフォルトでは app.ts に以下の一行のみが記述されている。
console.log('Hello world');
TypeScriptで正規表現を試す
例えば、こんな処理を実行してみた。
var name_before = '東京都(12)'; var regexp = /^(.+)\([0-9]+\)$/; var name_after = name_before.replace(regexp, "$1"); console.log('name_after =' + name_after); console.log('name_before=' + name_before);
つまりまあ、この正規表現パターンの意味は、文字列末尾にある
(数字)
の部分を除去する目的で作成した。
その実行結果
name_after =東京都 name_before=東京都(12)
となり、期待通り実行出来た。
正規表現リテラル /・・・/
ちなみに、この正規表現パターン
var regexp = /^(.+)\([0-9]+\)$/;
の右辺は文字列では無いのでクオーテーションマークで囲われていない。
このような記述方法を「正規表現リテラル」と言うらしい。
ワテの場合、初めてJavaScriptを習い始めた時には、この記述方法を見て、文字列でもないし、何だかおかしな記述だなあと当惑した記憶がある。
何じゃこりゃ!?
と言う印象。
最近では慣れたが、今一つ、違和感がある。
RegExp()で書き換えてみる
TypeScriptやJavaScriptでは、正規表現パターンを記述方法としては、先ほど紹介した
var regexp = /・・・/ ;
と言う正規表現リテラル式の書き方とは別に、RegExp() と言うコンストラクタを使う方式もある。
上の例をRegExp()で書き換えてみた。
コンストラクタなのでnew を付ける必要がある。
var regexp_x = new RegExp('/^(.+)\([0-9]+\)$/'); // 間違い var regexp_o = new RegExp('^(.+)\\([0-9]+\\)$'); // 正解
さて、ワテの失敗はここからだ。
当初は、一行目のように書いてしまった。
つまり、最初に紹介した正規表現リテラルのパターンをそのままシングルクォーテーションで囲って、 RegExp(‘・・・’) の引数に入れたのだ。
ところが、実行してもマッチしない。
30分くらい試行錯誤して、ようやく原因が判明した。
var regexp_x = new RegExp('/^(.+)\([0-9]+\)$/'); // 間違い
この記述は間違いなのだ。
正しくは、前後のスラッシュ / を取り除く必要がある。
かつ、バックスラッシュ記号(=円記号)は二重にする必要があるのだ。
それが以下のようになる。
var regexp_o = new RegExp('^(.+)\\([0-9]+\\)$'); // 正解
注意すべき点は、RegExp()コンストラクタ引数は文字列で有る点だ。
このように記述すると、冒頭で紹介した以下のリテラル方式の記述
var regexp = /^(.+)\([0-9]+\)$/;
と同じ意味の正規表現パターンとなるのだ。
これで一件落着。
と言う訳で、ワテの凡ミスでした。
では、正規表現リテラルとRegExp()のどっちを使うべきか気になる。
正規表現リテラルとRegExp()のどっちを使うべき?
まあ、正規表現パターンが固定されている場合にはどっちを使っても良いだろう。
でも、正規表現パターンを変数から作りたい場合には、文字列でパターンを与えられる RegExp()方式が便利だ。
例えば、こんな感じ。
var word = '大阪'; var regexp_o = new RegExp('^' + word + '\\([0-9]+\\)$');
文字列変数 word を使ってRegExpの引数を作り出している。
この辺りが、RegExp()を使うメリットだろう。
おまけ
Node.jpプロジェクトを実行するとコンソールウインドウが勝手に閉じる問題の対策
今回の実験をしていて気付いたのだが、Node.jpプロジェクトを実行するとコンソールウインドウが勝手に閉じる。
デバッグ実行時には、勝手に閉じずに何らかのキー入力が有るまではウインドウは閉じないのだが、デバッグ無し実行時には勝手に閉じてしまうのだ。
これが煩わしい。
その対策としては、Node.jpのオプション設定で可能だ。
下図に示すオプション設定ウインドウでNode.jpの項目を開く。
上図に於いて、
☑ プロセスが正常終了した場合に入力を待機する。
のようにチェックをしておくと、ウインドウは閉じないように出来る。
まとめ
自称プログラミングの変人のワテが、最近遭遇したTypeScriptでの正規表現での凡ミスを紹介した。
要点をまとめると以下の通り。
- TypeScript/JavaScriptの正規表現パターン記述には二種類の方法がある。
- 一つは正規表現リテラル方式 var rgx = /・・・/ ;
- もう一つはRegExp()オブジェクトコンストラクタ
- RegExp()を使う場合は前後のスラッシュ / は不要
- RegExp()を使う場合はエスケープの\記号は二重にする必要がある
- RegExp()を使うメリットは、引数が文字列なので演算で求めた値を使える
などである。
なので、まあ、通常は正規表現リテラルを使えば分かり易いので良いだろう。
円記号を二重にする必要もないし。
もし正規表現パターンを演算で求めて動的に変化する場合には、RegExp()オブジェクトコンストラクタを使うと良い。
コメント