JavaScriptのreplaceでIEだけ違う挙動をする例

JavaScriptのreplaceはマッチした文字列を置換パターンに含めることができます。
次の例は、英数字の文字列の数字部分を「x」と「y」で挟みます。 (さらに…)

PHPで漢字を表す正規表現

PHPは5.1以降であれば「\p{xxxxx}」という形式のUnicode文字プロパティというものがpreg系の正規表現として使えます。
漢字は「\p{Han}」とします。「p」は小文字です。大文字だと漢字以外になります。「Han」の先頭は大文字です。
次のようにすると漢字に合致するかどうか調べられます。パターン修飾子として「u」を使います。 (さらに…)

JavaScriptで漢字を表す正規表現

正規表現を使って漢字を表す方法を毎回、忘れてしまい、その都度、調べています。
調べた結果をまとめてみました。今回はJavaScriptの場合です。 (さらに…)

JavaScriptのreplaceとmatchのパターンの違い

JavaScriptで文字列の置換をするときはreplaceを使います。また文字列の比較をするときはmatchを使います。いずれも引数にパターンを与えますが、使い方がちょっと異なります。 (さらに…)

日付を判定する正規表現

日付を8桁の数列で表示するケースがあります。2015年2月5日ならば「20150205」とするような場合です。
逆に8桁の数列が日付かどうか判定する方法を考えます。
JavaScriptの正規表現を使います。 (さらに…)

Excel、VBAで正規表現によるマッチング

前にExcelで正規表現による置換をするためのユーザー定義関数を考えました。
このユーザー定義関数はワークシートでもVBAでも使えます。

Excelで正規表現による置換 | You Look Too Cool

これは一般的なプログラミング言語では「replace」に相当するものです。
同様にExcel、VBAで正規表現によるマッチング、「match」に相当するユーザー定義関数「reg_match」を考えました。
正規表現はVBScriptに準拠します。置換では「Replace」を使いますが、マッチングでは「Test」を使います。
マッチすると「TRUE」を返します。
次のように使います。

If reg_match(str, "^[0-3][0-9]$") Then
    '処理を記載
End If

reg_match

Function reg_match(str, reg_pattern, Optional flg_ignorecase = False, Optional flg_global = False)
    Set re = CreateObject("VBScript.RegExp")
    re.Pattern = reg_pattern
    re.IgnoreCase = flg_igonorecase
    re.Global = flg_global
    reg_match = re.Test(str)
End Function

reg_replace

再掲になります。正規表現による置換をするためのユーザー定義関数です。

Function reg_replace(str, reg_pattern, str_after, Optional flg_ignorecase = False, Optional flg_global = False)
    Set re = CreateObject("VBScript.RegExp")
    re.Pattern = reg_pattern
    re.IgnoreCase = flg_igonorecase
    re.Global = flg_global
    reg_replace = re.Replace(str, str_after)
End Function

Wordで「正規表現」を使う

Wordの検索、置換にはワイルドカードという仕組みがあります。
テキストエディタやプログラム言語でおなじみの正規表現のように使えます。 (さらに…)

電話番号を取得するための正規表現

日本の電話番号を正規表現を使って取得する方法を考えます。 (さらに…)

JavaScriptは肯定先読みはできるが肯定後読みはできない

JavaScriptの正規表現で該当文字列を全て抽出」について考えました。
matchで抽出した文字列に対しreplaceで無駄な部分を省く方法を使いました。
フラグ「g」を使うと必要な部分だけを抽出することができないからです。
しかし二度手間なのでスマートではありません。

「肯定先読み」を使うとあらかじめ無駄な部分を省くことができます。正規表現で「(?=パターン)」を使うとパターンに合致するか判定しますが抽出には含まれません。
しかしJavaScriptでは「肯定後読み」ができないそうです。
郵便番号を抽出する例で確認してみます。

元のテキスト

「郵便番号は001-1234、002-12345、0003-1234のどれか」という文字列から郵便番号を抽出します。
正しければ「001-1234」だけを抽出します。

通常

正規表現に「\d{3}-\d{4}」を使います。

001-1234
002-1234
003-1234

2番目と3番目も抽出してしまいました。

後が数値でない

まず後が数値でないケースを考えます。
正規表現として「\d{3}-\d{4}(?=\D)」を使います。肯定先読みです。
「\D」は半角数値以外を表します。「(?=\D)」とすると半角数値以外なのですが、抽出する文字列に含まれません。

001-1234
003-1234

2番目の「002-12345」は「002-1234」の後に「5」という半角数値があるので抽出されませんでした。
一方、3番目の「003-1234」はやはり抽出されてしまいました。

前が数値でない

次に前が数値でないケースを考えます。
肯定後読みを使いたいところです。肯定後読みは一般的には「(?<=パターン)」を使います。 正規表現として「(?<=\D)\d{3}-\d{4}」とするのですが、JavaScriptではエラーになります。 IEでは「正規表現で構文エラーが発生しました。」というメッセージが出ました。

JavaScriptの正規表現で該当文字列を全て抽出

JavaScriptにはmatchという関数(メソッド)があり、正規表現を使って、主に次の二つのことができます。

  • 文字列が条件に合致しているかどうかを判定。
  • 条件に合致した文字列を抽出。

これを利用して文字列から郵便番号を抽出してみます。
郵便番号は「163-8019」のような文字列です。
「半角数字3文字」+「半角ハイフン」+「半角数字4文字」であるとします。

これを正規表現で表わすと「\d{3}-\d{4}」となります。
「\d」は半角数字を表します。「{n}」はn文字を表します。「\d{3}」で半角数字3文字を表します。

条件に合致した文字列を抽出するには次のようにします。

matches = list.match(/\d{3}-\d{4}/g);

「macth(/正規表現/フラグ)」のように使います。フラグに「g」を指定すると合致する文字列を全て抽出し、配列で返します。
一般的にはこれで大丈夫なのですが、実際に使ってみると色々と不具合が起きます。

元のテキスト

次の文字列から郵便番号を抽出します。

001-1234
002-1234
〒003-1234
郵便番号は004-1234です。
00-0005-1234
00006-12345
007-1234

期待されるのは1,2,3,4,7番目です。
5番目は電話番号風、6番目は何らかのコードですので、これらは不要です。

通常

正規表現を「\d{3}-\d{4}」とした場合です。
結果は次の通りです。

001-1234
002-1234
003-1234
004-1234
005-1234
006-1234
007-1234

5番目と6番目も抽出してしまいました。

前後が数値でない

郵便番号の前後が半角数字でないケースのみを抽出することにします。
正規表現を「\D\d{3}-\d{4}\D」とします。「\D」と大文字にすると半角数値以外となります。

002-1234
〒003-1234
は004-1234で

文字列の先頭である1番目と末尾である7番目が漏れてしまいました。

前後が数値でない、または先頭・末尾である

さらに先頭と末尾のケースを抽出することにします。
正規表現を「(^|\D)\d{3}-\d{4}($|\D)」とします。「^」は文字列全体の先頭、「$」は文字列全体の末尾を表します。

001-1234
002-1234
〒003-1234
は004-1234で
007-1234

一応、期待するケースが抽出できましたが、余計な文字が付いてしまいました。

前後を削除

実はmatchには括弧で挟んだ部分だけを抽出する機能があるので余計な文字を省くことができます。しかしフラグ「g」を使うとその機能が使えなくなります。
そこで配列に取り込んだ文字列に対して、それぞれreplaceを使い、必要な部分だけを抽出します。

matches = list.match(/(^|\D)\d{3}-\d{4}($|\D)/gm);
for(i = 0; i < matches.length; i ++){
    matches[i] = matches[i].replace(/\D?(\d{3}-\d{4})\D?/, "$1");
}

括弧で挟んだ部分「(\d{3}-\d{4})」は「$1」で取り出せます。
「は004-1234で」を「004-1234」に置換するという感じです。

001-1234
002-1234
003-1234
004-1234
007-1234
古い記事

タグ

カテゴリー

最近の投稿

最近のコメント

固定ページ

アーカイブ

stabucky

写真

メタ情報