NIRE

 NIREはC++用の正規表現テンプレートライブラリです。

 NIREの開発は終了しました。新機能の追加や性能の向上についてはもう行わず、必要に応じてバグ修正のみ行う予定です。

目次

概要

 NIREはSRELLをフォークした正規表現ライブラリです。次のような特徴をSRELLから継承しています。

 一方SRELLから継承しなかったものは、1) <regex>互換のインターフェイス、2) 任意のイテレータへの対応などです。
 NIREのインターフェイスについては、ECMAScript (JavaScript) の仕様を参考にしています。

 動作確認済みコンパイラのうちもっとも古いものはVC++2005です。

Download

使い方

 nire.hpp をincludeするだけです。

//  Example 01:
#include <cstdio>
#include <string>
#include <iostream>
#include "nire.hpp"

int main()
{
    nire::RegExp re;    //  正規表現オブジェクト。
    nire::Match m;      //  結果を収めるオブジェクト。

    re = "\\d+[^-\\d]+";    //  正規表現をコンパイル。
    m = re.exec("1234-5678-90ab-cdef"); //  検索する。
    if (m)
    {
        std::printf("result: %s\n", m[0].str().c_str());    //  printfを使うなら。
        std::cout << "result: " << m[0] << std::endl;       //  iostreamを使うなら。
    }
    return 0;
}
	

 Zipアーカイヴ内の reame_ja.txt も併せてご覧ください。

API

 NIREは次の4クラスから成り立ちます。すべてnamespace nireの下に置かれています。

 上3つはテンプレートとして実装されていて、charTの部分には検索に使用する文字型を指定します。
 あらかじめ次のような型がtypedefされていますので、通常はこのいずれかを使います。

基本3クラスのtypedef一覧
regexpre_matchre_group 文字列の解釈 備考
char u8cRegExpMatchGroup UTF-8
wchar_t u16wRegExpwMatchwGroup UTF-16 WCHAR_MAX0xFFFF以上、0x10FFFF未満の場合のみ。
u32wRegExp UTF-32 WCHAR_MAX0x10FFFF以上の場合のみ。
char8_t u8RegExpu8Matchu8Group UTF-8
char16_t u16RegExpu16Matchu16Group UTF-16
char32_t u32RegExpu32Matchu32Group UTF-32
char bRegExpMatchGroup 0からUCHAR_MAXまでの値の連続。

 最後のbRegExpというのはバイナリ配列のようなものに対して検索を行うためのものです。詳しくは後述します。

regexp<charT>

 正規表現オブジェクトの作成、保持ならびに検索や置換を行います。NIREの中核をなすクラスで、ECMAScript (JavaScript) のRegExpクラスの仕様を参考にしています。
 次のメンバ変数ならびにメンバ函数が定義されています。

コンストラクタとフラグ

 インスタンスの作成と同時に正規表現オブジェクトの新規作成も行う場合、正規表現文字列の渡し方としては「1) ヌル終端文字列へのポインタを渡す」「2) ポインタと文字列の長さとを渡す」「3) std::basic_stringへのconst参照を渡す」の3通りがあります。
 それぞれフラグの渡し方に「a) nire::flag::type型の値を渡す」「b) フラグ文字列へのポインタを渡す」の2通りがありますので、3×2=6通りの渡し方が存在するということになります。

regexp();
regexp(const regexp &r);    //  既存のものをコピー。
regexp(regexp &&r) noexcept;    //  C++11以降。

//  ポインタ
regexp(const charT *const p, const flag::type f = flag::ECMAScript);
regexp(const charT *const p, const charT *const flags);

//  ポインタと文字列長
regexp(const charT *const p, const std::size_t len, const flag::type f);
regexp(const charT *const p, const std::size_t len, const charT *const flags);

//  basic_string
regexp(const std::basic_string<charT> &str, const flag::type f = flag::ECMAScript);
regexp(const std::basic_string<charT> &str, const charT *const flags);
				

 フラグには次のものがあります。
 nire::flag::type型の値として渡す時は | (or) で区切ることにより複数のフラグを同時に渡すことが出来ます。
 文字列として渡す時は、"im" のように書くことにより複数のフラグを渡すことが出来ます。

フラグ一覧
nire::flag::type型の値として渡す時 文字列として渡す時
nire::flag::global "g" グローバル検索。マッチした箇所の直後の位置をlastIndexメンバに記録し、次はそこを起点に検索する。
nire::flag::icase "i" 大文字小文字の区別がない検索。
nire::flag::multiline "m" ^$とが改行文字の前後にもマッチするようにする。
nire::flag::dotall "s" .が改行文字も含むあらゆる文字にマッチするようにする。
nire::flag::sticky "y" 文字列のlastIndex番目の要素からマッチするかどうかのみを調べる。
nire::flag::noflags
nire::flag::ECMAScript
"" フラグ無しであることをあえて指定したい場合。
assign()

 既存の正規表現オブジェクトのコピー、移動(C++11以降のみ)または新規作成を行います。
 新規作成の場合、正規表現文字列およびフラグの渡し方にはコンストラクタ同様6通りあります。

regexp &assign(const regexp &r);
regexp &assign(regexp &&r) noexcept;    //  C++11以降。

//  ポインタ
regexp &assign(const charT *const p, const flag::type f = flag::ECMAScript);
regexp &assign(const charT *const p, const charT *const flags);

//  ポインタと文字列長
regexp &assign(const charT *const p, std::size_t len, const flag::type f);
regexp &assign(const charT *const p, std::size_t len, const charT *const flags);

//  basic_string
regexp &assign(const std::basic_string<charT> &str, const flag::type f = flag::ECMAScript);
regexp &assign(const std::basic_string<charT> &str, const charT *const flags);
				
operator=()

 既存の正規表現オブジェクトのコピー、移動(C++11以降のみ)または新規作成を行います。
 コンストラクタやassign()とは異なり、引数を1つしか指定できませんので、新規作成の場合は「1) ヌル終端文字列へのポインタを渡す」「2) std::basic_stringへのconst参照を渡す」の2択です。

regexp &operator=(const regexp &r);
regexp &operator=(regexp &&r) noexcept; //  C++11以降。

//  ポインタ
regexp &operator=(const charT *const p)

//  basic_string
regexp &operator=(const std::basic_string<charT> &str)
				
lastIndex変数

 パターンコンパイル時にglobalフラグかstickyフラグかが指定されていた場合、対象文字列のlastIndex番目の要素から検索が行われるようになります。どちらのフラグもセットされていない場合はlastIndexの値は無視され、常に対象文字列の先頭から検索が行われます。

 検索して正規表現にマッチする位置が見つかった場合、その範囲の次([begin, end) で言うところのend)のオフセット値がlastIndexに書き込まれます。見つからなかった場合は0にリセットされます。

 検索対象文字列を変えた場合でもlastIndexは自動的にクリアされません。

 このメンバはmutable指定されていますので、regexpのインスタンスそのものがconst指定されていても書き込むことが出来ます。

exec() const

 検索を行うメンバ函数です。
 検索対象文字列の渡し方には「1) ヌル終端文字列へのポインタを渡す」「2) ポインタと文字列の長さとを渡す」「3) std::basic_stringへのconst参照を渡す」の3通りがあります。
 結果の受け取り方には「a) re_match型インスタンスの参照を引数として渡しておき、検索結果はそこに書き込んでもらう」「b) 検索結果を書き込んだre_match型インスタンスを戻り値としてreturnしてもらう」の2通りがあります。

 re_match型インスタンスの参照を引数として渡した場合、戻り値は「マッチしたかどうかを表すbool値」です。

//  ポインタ
bool exec(
    re_match<charT> &m,
    const charT *const str
) const;

re_match<charT> exec(
    const charT *const str
) const;

//  ポインタと文字列長
bool exec(
    re_match<charT> &m,
    const charT *const str,
    const std::size_t len
) const;

re_match<charT> exec(
    const charT *const str,
    const std::size_t len
) const;

//  basic_string
bool exec(
    re_match<charT> &m,
    const std::basic_string<charT> &str
) const;

re_match<charT> exec(
    const std::basic_string<charT> &str
) const;
				

 globalフラグかstickyフラグかが指定されていた場合、検索はlastIndexで指定されたオフセット位置より始まります。そしてマッチする箇所があった時にはそのマッチした範囲 [begin, end) のendのオフセット位置がlastIndexに書き込まれ、なかった時にはlastIndexには0が書き込まれます。

 繰り返しの中で使う場合はre_match型インスタンスを参照で渡す版の使用をお勧めします。

test() const

 検索対象文字列の中にマッチする箇所があるかないかだけを調べます。それ以外はexec()と同じです。

//  ポインタ
bool test(
    const charT *const str
) const;

//  ポインタと文字列長
bool test(
    const charT *const str,
    const std::size_t len
) const;

//  basic_string
bool test(
    const std::basic_string<charT> &str
) const;
				
replace() const

 JavaScriptのString.prototype.replace(RegExpオブジェクト, 置換文字列またはコールバック函数)に準拠した動作をします。
 検索対象文字列中の「正規表現とマッチする箇所」を別の文字列に置き換えます。置き換えられた文字列は戻り値としてreturnされてきて、元の検索対象文字列はそのまま残ります。
 置換後の文字列の指定方法としては「1) 書式文字列を渡す」「2) コールバック函数を渡す」の2通りがあります。

 globalフラグがセットされていた時は、対象文字列中の正規表現にマッチする箇所すべてが置換の対象となります。それ以外の時は最初にマッチした部分だけが対象となります。

//  書式文字列による置換
//  ポインタ
std::basic_string<charT> replace(
    const charT *const str,
    const charT *const fmt
) const;

//  ポインタと文字列長
std::basic_string<charT> replace(
    const charT *const str,
    const std::size_t len,
    const charT *const fmt_text,
    const std::size_t fmt_len
) const;

//  basic_string
std::basic_string<charT> replace(
    const std::basic_string<charT> &str,
    const std::basic_string<charT> &fmt
) const;

//  コールバック函数による置換
typedef std::basic_string<charT> (*replace_function)(const re_match<charT> &);

//  ポインタ
std::basic_string<charT> replace(
    const charT *const str,
    const replace_function repfunc
) const;

//  ポインタと文字列長
std::basic_string<charT> replace(
    const charT *str,
    const std::size_t len,
    const replace_function repfunc
) const;

//  basic_string
std::basic_string<charT> replace(
    const std::basic_string<charT> &str,
    const replace_function repfunc
) const;
				

書式文字列による置換

 ECMAScript仕様書の Runtime Semantics: GetSubstitutionの表に定められているものが書式文字列として使えます。
 この表にない文字はそのまま置換後の文字列として使われます。

書式文字列として使えるテキストシンボル一覧
テキストシンボル 置換テキスト
$$ $そのもの。
$& マッチした箇所全体。
$` マッチした箇所に先行する部分。
$' マッチした箇所より後方の部分。
$1 $2 $3 $4 $5 $6 $7 $8 $9
(後ろに数字が続かぬこと)
正規表現中の対応する括弧で捕獲された文字列。該当する括弧が何も捕獲していない場合は空文字に置換される。正規表現中のキャプチャ括弧の個数より大きな数が指定された場合は置換されず。
$nnnnは01から99までの範囲) 正規表現中の対応する括弧で捕獲された文字列。該当する括弧が何も捕獲していない場合は空文字に置換される。正規表現中のキャプチャ括弧の個数より大きな数が指定された場合は置換されず。
$<NAME>
  1. 正規表現中に「名前付きキャプチャ」が存在しない場合、置換されずそのまま出力される。
  2. 存在する場合、NAMEという名前の丸括弧によって捕獲された文字列と置換される。NAMEに相当する名前のグループ名が正規表現中にないか、あっても何もキャプチャされていなければ空文字列に置換される。
//  書式指定による置換例。
#include <cstdio>
#include <string>
#include "nire.hpp"

int main()
{
    const nire::RegExp re("(\\d)(\\d)", "g");   //  数字が2つ続いている箇所を探す。
    const std::string rep = re.replace("abc0123456789def", "($2$1)");
        //  $1と$2との順番を入れ替えて括弧でくくる。

    std::printf("Result: %s\n", rep.c_str());
    return 0;
}
---- 実行結果 ----
Result: abc(10)(32)(54)(76)(98)def
					

コールバック函数による置換

 マッチした箇所の情報を函数内部のre_match<charT>型インスタンスにセットし、それへのconst参照を引数とするコールバック函数を呼び出します。
 コールバック函数の側は、置換後の文字列をstd::basic_string<charT>型インスタンスにセットしてreturnする必要があります。なおこちらの方法では前述の書式文字列は使えません。

//  コールバック函数による置換例。
#include <cstdio>
#include <string>
#include "nire.hpp"

std::string repfunc1(const nire::Match &m)
{
    return " [" + m[1].str() + ", " + m[2].str() + "] ";
}

int main()
{
    const nire::RegExp re("(\\d)(\\d)", "g");
    const std::string text("abc0123456789def");
    std::string rep;

    rep = re.replace(text, repfunc1);
    std::printf("Result1(C++98/C++03): %s\n", rep.c_str());

    //  C++11以降のラムダ式による置換。
    rep = re.replace(text, [](const nire::Match &m) -> std::string {
        return " [" + m[1].str() + ", " + m[2].str() + "] ";
    });
    std::printf("Result2(C++11): %s\n", rep.c_str());

    //  C++14以降。
    rep = re.replace(text, [](const auto &m) {
        return " [" + m[1].str() + ", " + m[2].str() + "] ";
    });
    std::printf("Result3(C++14): %s\n", rep.c_str());

    return 0;
}
---- 実行結果 ----
Result1(C++98/C++03): abc [0, 1]  [2, 3]  [4, 5]  [6, 7]  [8, 9] def
Result2(C++11): abc [0, 1]  [2, 3]  [4, 5]  [6, 7]  [8, 9] def
Result3(C++14): abc [0, 1]  [2, 3]  [4, 5]  [6, 7]  [8, 9] def
					
split() const

 JavaScriptのString.prototype.split(RegExpオブジェクト, リミット)に準拠した動作をします。
 検索対象文字列中の「正規表現とマッチする箇所」の前後を分割してstd::basic_string型インスタンスを作り、それらを配列コンテナに詰め込んでreturnします。
 正規表現の中にキャプチャ括弧があった場合はそれらもすべて配列コンテナに詰め込まれます。何も捕獲していない括弧のところも飛ばされず、空文字列がpushされます。

 結果を受け取るコンテナ型は、clear(), size(), push_back()の3つが実装されていれば何でも使えます。戻り値はpush_back()が行われた回数です。

//  ポインタ
template <typename ContainerT>
std::size_t split(
    ContainerT &out,
    const charT *const str,
    const std::size_t limit = static_cast<std::size_t>(-1),
    const bool push_remainder = false
) const;

//  ポインタと文字列長(lengthのほうが先なのはオーヴァーロード解決のため)
template <typename ContainerT>
std::size_t split(
    ContainerT &out,
    const std::size_t len,
    const charT *const str,
    const std::size_t limit = static_cast<std::size_t>(-1),
    const bool push_remainder = false
) const;

//  basic_string
template <typename ContainerT>
std::size_t split(
    ContainerT &out,
    const std::basic_string<charT> &str,
    const std::size_t limit = static_cast<std::size_t>(-1),
    const bool push_remainder = false
) const;
				

 引数のlimitは分割する回数の上限値です。例えば分割する正規表現が /,/limit5であった場合、検索対象文字列中に5回 ',' を発見した時点で分割処理は終了します。

 分割回数の上限が指定できるsplit()というのはスクリプト言語によくある機能ですが、JavaScriptのsplit()は少し変わっていて、マッチングがlimitで指定された回数に達するとそれ以降のまだ調べていない部分の文字列は戻り値の中に含めず、そのまま捨ててしまいます。
 この挙動は個人的にあまり嬉しくありませんので、NIREでは独自拡張機能として「分割がlimitの回数に達した時、それより後ろのまだ調べていない部分の文字列も戻り値の中に含めるかどうか」を指定するpush_remainderフラグを追加してあります。
 push_remaindertrueの時は、最大でlimit + 1個分の要素が返されてくることになります。これは結果的にPythonのsplit()と似た挙動になっています。

//  limitとpush_remainderフラグの挙動。
#include <cstdio>
#include <string>
#include <vector>
#include "nire.hpp"

int main()
{
    const nire::RegExp re(":");
    const std::string text("0:12:345:6789:abcdef");
    std::vector<std::string> res;

    //  無制限分割。
    re.split(res, text);
    for (std::size_t i = 0; i < res.size(); ++i)
        std::printf("%s%s", i == 0 ? "[" : ", ", res[i].c_str());
    std::puts("]");

    //  limit=2. 残りは捨てられる。
    re.split(res, text, 2);
    for (std::size_t i = 0; i < res.size(); ++i)
        std::printf("%s%s", i == 0 ? "[" : ", ", res[i].c_str());
    std::puts("]");

    //  limit=2 かつ push_remainder=true. 残りは最後に一括してpushされる。
    re.split(res, text, 2, true);
    for (std::size_t i = 0; i < res.size(); ++i)
        std::printf("%s%s", i == 0 ? "[" : ", ", res[i].c_str());
    std::puts("]");

    return 0;
}
---- 実行結果 ----
[0, 12, 345, 6789, abcdef]
[0, 12]
[0, 12, 345:6789:abcdef]
				
swap()

 インスタンスの内容を交換します。re1.swap(re2)nire::swap(re1, re2)とが定義されています。

フラグの読み出し

 以下は正規表現オブジェクト作成時に指定されたフラグを読み出すためのメンバ函数です。函数名はいずれもJavaScriptにおける同名のプロパティー名から来ています。

フラグの読み出し函数一覧
函数名 戻り値
std::basic_string<charT> flags(); パターンコンパイル時に渡されたフラグを文字列化したもの。
bool global(); nire::flag::global または "g" が指定されたか否か。
bool ignoreCase(); nire::flag::icase または "i" が指定されたか否か。
bool multiline(); nire::flag::multiline または "m" が指定されたか否か。
bool dotAll(); nire::flag::dotall または "s" が指定されたか否か。
bool unicode(); 常にtrueが返る。
bool sticky(); nire::flag::sticky または "y" が指定されたか否か。

re_match<charT>

 RegExp.exec()によって正規表現検索の結果が収められるクラスです。
 JavaScriptのRegExp.exec()の返り値を参考に次のメンバが定義されています。

bool値へのキャスト

 re_match型インスタンスは正規表現にマッチしたかどうかを示すbool値にキャストすることが出来ます。

std::size_t length() const
std::size_t size() const

 直前のマッチが成功していた場合、正規表現中に出てくるキャプチャ括弧の数+1が返ってきます。失敗していた場合やインスタンス作成後まだ一度も検索の結果を受け取っていない場合は0が返ってきます。+1されるのは「正規表現全体にマッチした箇所は暗黙の0番括弧によって捕獲された」と見なされるためです。

 C++のクラスでは.size()という名前のメンバ函数を通して要素の数を取得することが多いのに対して、JavaScriptでは.lengthというプロパティーを使って要素の数を読み書きする仕組みになっています。どちらでもお好みで使えるようにNIREではsize()length()との両方用意してあります。

const re_group<charT> &operator[](unsigned int n) const
const re_group<charT> &operator[](const charT *gname) const
const re_group<charT> &operator[](const std::basic_string<charT> &gname) const

 re_match型インスタンスをmとした時、m[0]には正規表現にマッチした箇所全体の位置情報が収められています。m[1]以降にはそれぞれ対応する番号の括弧で捕獲された文字列の位置情報が収められています。
 引数として指定できるのは、0からlength()の値-1までです。

 引数が文字列の場合はgnameというグループ名で捕獲された文字列の位置情報を返します。

 戻り値であるre_group<charT>型はstd::basic_string<charT>にキャストできますので、マッチした部分の情報を直接文字列として受け取ることも可能です。この型の詳細については後述します。

std::size_t index(unsigned int n = 0) const
std::size_t index(const charT *gname) const
std::size_t index(const std::basic_string<charT> &gname) const

 引数で指定されたグループの範囲 [begin, end) のbeginが、検索対象文字列において何番目(0起点)の要素に当たるかを返します。

std::size_t endIndex(unsigned int n = 0) const
std::size_t endIndex(const charT *gname) const
std::size_t endIndex(const std::basic_string<charT> &gname) const

 引数で指定されたグループの範囲 [begin, end) のendが、検索対象文字列において何番目(0起点)の要素に当たるかを返します。

swap()

 インスタンスの内容を交換します。re1.swap(re2)nire::swap(re1, re2)とが定義されています。

re_group<charT>

 正規表現にマッチした範囲の位置情報を保持する構造体です。この型はis_trivially_copyableですのでmemcpyでコピーすることも出来ます。
 この型が保持しているのは位置情報だけですので、文字列を取り出す際には検索対象文字列がその時点でまだメモリ上に存在している必要があります。

 次のメンバが定義されています。

bool値へのキャスト

 re_group型インスタンスは、内部の位置情報が有効な範囲を指し示しているかどうかを示すbool値にキャストすることが出来ます。

std::basic_string<charT>へのキャスト
std::basic_string<charT> str() const

 re_group内で保持している位置情報を元にstd::basic_string<charT>型の文字列を作り、それをreturnします。

std::size_t length() const
std::size_t size() const

 保持している範囲がコードユニット何個分になるかを返します。何もキャプチャしていない時は0が返ります。

 例によってsize()length()との両方用意してあります。

matched() const

 文字列が捕獲されているかどうかを示すbool値を返します。

比較

 re_group<charT>同士またはstd::basic_string<charT>との比較用に==, !=, <, <=, >, >=が定義されています。

re_error

 パターンコンパイル時または照合時にエラーが発生すると、nire::re_errorthrowされてきます。
 nire::re_errorstd::runtime_errorの派生クラスで次のメンバが定義されています。

//  nire::re_errorのメンバ。
const char *what() const;       //  std::runtime_errorより継承したもの。
re_error::type code() const;    //  エラー番号の読み出しを行う。
		

 エラー番号は次の通りです。

エラー番号一覧
エラー値 エラー内容 備考
escape 不正なエスケープ。\ の後ろに変な文字が続いているか、\ で文字列が終わっている。 パターンコンパイル時に発生するエラー。
backref 後方参照エラー。対応するキャプチャ括弧が正規表現中にない。
sqbrack [] が非対称。
paren () が非対称。
brace {} が非対称。
badbrace {} 内におかしな文字がある。
range 文字クラス内で [b-a] のような範囲指定がされている。-の左側の文字のほうが右側の文字よりコードポイント値が大きい。
badrepeat 量指定子 * ? + {n,m} の前に変な文字がある。
utf8 UTF-8として不正なバイト列がある。
complexity 複雑な照合 照合時に発生するエラー。

 これらの他、メモリの確保に失敗した時にはstd::bad_allocthrowされてきます。

C++11の機能

 C++11以降で導入された機能のうち、NIREが利用することもあるのは以下のものです。

 2020年 5月現在、NIREではこれらの使用可否を次のようにして判定しています。

#ifdef __cpp_unicode_characters
  #ifndef NIRE_CPP11_CHAR1632_ENABLED
  #define NIRE_CPP11_CHAR1632_ENABLED   //  char16_t, char32_t用のtypedefを行う。
  #endif
#endif

#ifdef __cpp_rvalue_references
  #ifndef NIRE_CPP11_MOVE_ENABLED
  #define NIRE_CPP11_MOVE_ENABLED   //  コンストラクタや代入でmoveを有効にする。
  #endif
#endif

#ifdef __cpp_char8_t
  #ifndef NIRE_CPP20_CHAR8_ENABLED
  #define NIRE_CPP20_CHAR8_ENABLED  //  char8_t用のtypedefを行う。
  #endif
#endif
	

 該当する機能がお使いのコンパイラでサポートされているにもかかわらず、コンパイラが__cpp_*マクロを適切に設定しないためにこれらの機能が有効にならない場合、NIREをincludeする前に上記マクロのうち必要なNIRE_CPP_*を定義しておくと、対応する機能を強制的にオンにすることが出来ます

NIREの正規表現

 NIREではECMAScript 2020 (ES11.0) のRegExp互換の正規表現が使えます(uフラグは常に指定されていると見なされる)。

 具体的には次の通りです。

NIREで使用可能な正規表現一覧
文字
.

改行以外の文字にマッチ(ECMAScriptにおける改行文字は、U+000A, U+000D, U+2028, U+2029の4文字)。
パターンコンパイル時にdotallオプションが指定されている時は、前記4文字も含むすべての文字にマッチする([\u{0}-\u{10ffff}]と等価)。Perl 5の//sに相当。

\0

NULL文字 (\u0000) にマッチ。

\t

水平タブ (\u0009) にマッチ。

\n

Line Feed (\u000a) にマッチ。

\v

垂直タブ (\u000b) にマッチ。

\f

Form Feed (\u000c) にマッチ。

\r

Carriage Return (\u000d) にマッチ。

\cX

(Xの文字コード & 0x1f) に相当するコントロール文字にマッチ。Xの範囲は [A-Za-z] のみ有効。
\c の後ろにA-Zまたはa-zが続いていない時はerror_escapethrowされてくる。

\\

バックスラッシュそのもの (\u005c) にマッチ。

\xHH

UTF-16におけるコードユニット値が、2桁の16進数HHで表される値に等しい文字にマッチ。
\x の後ろに2桁の16進数が続いていない時はerror_escapethrowされてくる。

UTF-16において0x00-0xFFのコードユニット値はそれぞれU+0000~U+00FFの文字を表すので、この表現は事実上Unicodeのコードポイント値を表すとも言える。

\uHHHH

Unicodeのコードポイント値が、4桁の16進数HHHHで表される値に等しい文字にマッチ。
\u の後ろに4桁の16進数が続いていない時はerror_escapethrowされてくる。

連続する\uHHHHがUTF-16におけるサロゲートペアを構成している場合は、そのペアによって表されるUnicode値に変換される。例えば /\uD842\uDF9F//\u{20B9F}/ と解釈される。

\u{H...}

1桁以上の16進数H...で表されるUnicodeのコードポイントにマッチ。
\u{...}{} 内が1桁以上の16進数ではない時や、コードポイントの上限値 (0x10FFFF) を超えている時、閉じ '}' がない時などにはerror_escapethrowされてくる。

\

\^ $ . * + ? ( ) [ ] { } | / のうちのどれかが続いている時は、その続いている文字そのものを表す。正規表現において特殊な意味を持つ字の特殊性を失わせ、文字通りに認識させたい時に使う('/' も含まれているのはおそらくECMAScriptでは正規表現を // で囲うため)。
後述する文字クラス内では前記14字に加えて '-'"\-" の形で使える。

^$.*+?()[]{}|\/
以外の文字

その文字そのものを表す。

選択
A|B

正規表現AまたはBにマッチ。/abc|def|ghi?|jkl?/ のように '|' はいくつでも並べることが出来る。
'|' によって区切られた各正規表現ブロックは左から右へと順番にマッチングが試みられ、最初にマッチングが成功したもののみが採用される。
たとえば "abcdef" に対して /abc|abcdef/ でマッチングを行った場合、結果は "abc" となる。

文字クラス
[]

文字クラス。文字集合。

  • [ABC]……ABCかにマッチ。
  • [^DEF]……最初が^の時は補集合。この例の場合DでもEでもFでもない文字にマッチ。
  • [G^H]……冒頭以外にある^^そのものを表す。この例の場合G^Hかにマッチ。
  • [I-K]……IJKかにマッチ。文字1-文字2という並びは「文字1のUnicodeにおけるコードポイント値から文字2の同コードポイント値までの範囲に含まれる文字のどれか」を意味する。
  • [-LM]……上記のような並び以外に位置する--そのものを表す。この例の場合-LMかにマッチ。
  • [N-P-R]……範囲指定直後の--そのものを表す。この例の場合はN, O, P, -, Rのいずれかにマッチ。Qは含まれず。
  • [S\-U]……'S''-''U'かにマッチ。\でエスケープされた'-''-'そのものを表す("\-"は文字クラス内でのみ使用可能)。
  • [.|({]…….|({かにマッチ。これらも文字クラスの中ではその特殊性を失う。
  • []……空集合。どの文字にもマッチせぬため、これが現れると照合は常にそこで失敗する。
  • [^]……空集合の補集合。どの文字にもマッチする。[\0-\u{10FFFF}]と同じ。

Perlの正規表現には「'[' の直後にある ']'']' そのものを表す」という特例があるが、ECMAScriptの正規表現にはそのような例外はない。従って ']' を文字クラスに含めるには常に '\' でエスケープして "\]" と書く必要がある。

'['']' とが非対称な時にはerror_brackthrowされる。また [b-a] のように範囲指定がおかしい時にはerror_rangethrowされる。

定義済み文字クラス
\d

[0-9]に同じ。[\d!"#$%&'()] のように文字クラス内([]の中)でも使用可能。

\D

[^0-9]に同じ。\d同様に文字クラス内([]の中)でも使用可能。

\s

[ \t\n\v\f\r\u00a0\u1680\u2000-\u200a\u2028-\u2029\u202f\u205f\u3000\ufeff]に同じ。\d同様に文字クラス内でも使用可能。

Note: 厳密にはWhiteSpaceとLineTerminatorとに一致します。今後UnicodeカテゴリのZsに新たな文字が追加されることがあれば、その都度WhiteSpaceの右辺値は増えます。

\S

[^ \t\n\v\f\r\u00a0\u1680\u2000-\u200a\u2028-\u2029\u202f\u205f\u3000\ufeff]に同じ。\d同様に文字クラス内でも使用可能。

\w

[0-9A-Za-z_]に同じ。\d同様に文字クラス内でも使用可能。

\W

[^0-9A-Za-z_]に同じ。\d同様に文字クラス内でも使用可能。

\p{...}

...の部分で指定されたUnicode property値を持つ文字にマッチ。例えば \p{scx=Hiragana} はUnicodeに存在するあらゆるひらがなにマッチする。\d同様に文字クラス内でも使用可能。

Note: 2020年現在、ECMAScriptもUnicodeも毎年新版がリリースされていますが、Unicodeの新版がリリースされる時期よりもECMAScriptの新版の仕様が確定する時期のほうが少し早いため、ECMAScriptの仕様書に掲載される「\p\Pで利用可能な値一覧」はほぼ1年遅れ、1つ前のUnicode仕様に準拠しているという状況が続いています。
ECMAScript仕様書のドラフトにはその時点で最新のUnicode規格に準拠した値一覧が掲載されていますので、NIREではこちらを参照し、ECMAScriptの仕様書に翌年以降掲載されることになる値にも対応しています。

\P{...}

...の部分で指定されたUnicode property値を持たぬ文字にマッチ。\d同様に文字クラス内でも使用可能。

量指定子(回数指定)
*
*?

直前の正規表現による照合を0回以上繰り返す。*は最長一致を優先、*?は最短一致を優先する。

先行する表現なしにいきなり回数指定が現れた時にはerror_badrepeatthrowされる。以下5つも同じ。

+
+?

直前の正規表現による照合を1回以上繰り返す。+は最長一致を優先、+?は最短一致を優先する。

?
??

直前の正規表現による照合を0回ないし1回繰り返す。?は最長一致を優先、??は最短一致を優先する。

{n}

直前の正規表現による照合をきっちりn回繰り返す。

'{''}' とが非対称な時にはerror_bracethrowされる。以下2つも同じ。

{n,}
{n,}?

直前の正規表現による照合をn回以上繰り返す。{n,}は最長一致を優先、{n,}?は最短一致を優先する。

{n,m}
{n,m}?

直前の正規表現による照合をn回以上・m回以下繰り返す。{n,m}は最長一致を優先、{n,m}?は最短一致を優先する。

{3,2}のように範囲指定がおかしい時にはerror_badbracethrowされる。

括弧・後方参照・グループ化
(...)

正規表現のグループ化および文字列の捕獲。正規表現全体において開き括弧 '(' が左のほうにあるものから順に、各括弧には1, 2, 3...と参照用の番号が自動的に割り振られ、括弧内の正規表現にマッチした文字列をその番号によって正規表現中の他の場所から参照できる。
'('')' とが非対称な時にはerror_parenthrowされる。

括弧自身またはその外側の正規表現に繰り返し指定がある場合、捕獲した文字列はループのたびに未定義値相当にクリアされる。そのためキャプチャした文字列を次のループに持ち越すことは出来ない。

\N
(※Nは正の
整数)

後方参照。\の後ろに1-9で始まる十進数が続く時は、対応する番号の()で捕獲した文字列を使って照合が行われる。対応する番号の括弧が正規表現中に存在していない時はerror_backrefthrowされる。
例えば /(と|ト).\1/ は、「とまと」や「トマト」にはマッチするが、「トマと」にはマッチしない。

ECMAScriptの正規表現では、文字列を捕獲する括弧が対応する後方参照よりも先行している必要はない。そのため /\1(abc)//(abc\1)/ のような表現も有効でありエラーとはならない。

対応する括弧が何も捕獲していない時、後方参照は未定義値 (undefined) を参照しているものとされる。これは空文字相当として扱われ、照合は常に成功する。

(?<NAME>...)

名前付きの (...)。括弧内の正規表現とマッチした文字列は、括弧の番号に加えてNAMEという名前でも参照できるということ以外は (...) に同じ。
例えば /(?<year>\d+)\/(?<month>\d+)\/(?<day>\d+)/ という正規表現の場合、最初の括弧は\1という表現でも\k<year>という表現でも参照できる。

\k<NAME>

NAMEという名前の括弧によって捕獲された文字列を参照する。該当する括弧が正規表現中に存在していなければerror_backrefthrowされる。

(?:...)

グループ化。(...) とは異なりグループ化のみを行って文字列の捕獲は行わない。そのため後方参照用の番号も割り振られない。
たとえば /白(?:い|く|かった)/ は、「白い・白く・白かった」のいずれかにマッチするが、送り仮名の部分を後から参照することはできない。文字列の捕獲を行わぬかわりに照合処理が少し速くなる。

位置にマッチするもの
^

文字列の最初にマッチ。
multilineオプション指定時には、それに加えて文字列中のあらゆる改行の直後(行頭)にもマッチ。

$

文字列の最後にマッチ。
multilineオプション指定時には、それに加えて文字列中のあらゆる改行の直前にもマッチ。

\b

文字クラスの外側では\w\Wとの境界にマッチ。
文字クラスの内側ではBEL (\u0008) にマッチ。

\B

文字クラスの外側では\bがマッチしないところにマッチ。
文字クラスの内側で使うとerror_escapethrowされる。

(?=...)

肯定先読み。たとえば /白(?=い|く|かった)/ は、後ろに「い・く・かった」のいずれかが続く「白」にマッチする。

(?!...)

否定先読み。たとえば /白(?!い|く|かった)/ は、後ろに「い・く・かった」のいずれもが続かない「白」にマッチする(白黒、白鳥等)。

(?<=...)

肯定戻り読み。たとえば /(?<=あん|アン)パン/ は、前に「あん・アン」のいずれかが先行する「パン」にマッチする。

(?<!...)

否定戻り読み。たとえば /(?<!あん|アン)パン/ は、前に「あん・アン」のいずれも先行しない「パン」にマッチする(餡パン、フライパン、シャンパン等)。

その他

bRegExp

 bRegExpはバイナリ配列のようなものに対して検索を行うことを想定したもので、入力文字列を「0から((1 << CHAR_BIT) - 1)までの値の連続」として解釈します。

//  bRegExpのテスト。
#include <cstdio>
#include <string>
#include "nire.hpp"

int main()
{
    //  "\xE3\x81\x82" はひらがなの「あ (U+3042)」
    //  "\xC3\xA3" は ã (U+00E3)
    const std::string text("\xe3\x81\x82""\xc3\xa3");
    nire::RegExp re("\\xe3");   //  Unicode値がU+00E3である文字を探す。
    nire::bRegExp bre("\\xe3"); //  バイト値が0xE3である箇所を探す。
    nire::Match mr, mbr;

    mr = re.exec(text);
    mbr = bre.exec(text);
    std::printf("RegExp:%u+%u bRegExp:%u+%u\n", mr.index(), mr[0].length(), mbr.index(), mbr[0].length());

    return 0;
}
---- 実行結果 ----
RegExp:3+2 bRegExp:0+1
			

 RegExp型のreは、U+00E3をUTF-8で表現した箇所を探したのに対してbRegExp型のbreは、オクテット値が0xE3である箇所を探したことが分かります。

長考対策

 ECMAScriptの正規表現(およびその元となったPerlの正規表現)では通常、バックトラッキングと呼ばれる方法を使って照合が行われます。このバックトラッキング方式には、「量指定子(回数指定)が入れ子になっている正規表現」や「量指定子を伴う文字ないし文字クラスが連続していて、かつそれらが互いに排他的な集合になっていない正規表現」で検索を行うと、オートマトンが著しい長考に入ってしまうことがあるという問題が存在します。

 次のような例が有名です。

  • "aaaaaaaaaaaaaaaaaaaaaaaaaaaaa" =~ /(a*)*b/
  • "aaaaaaaaaaaaaaaaaaaaaaaaaaaaa" =~ /a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaaaaaaaaaaaaaaa/

 残念ながらこの現象に対しては、あらゆる状況に適用できる根本的な解決策というものが見つかっていません。そこで制御が長時間返ってこなくなる事態を避けるため、NIREは同じ位置からの照合が一定回数以上失敗するとre_error(re_error::type::complexity)throwするようになっています。
 回数の既定値は16777216(256の3乗)ですが、regexp型インスタンスのbacktrackingLimitメンバ変数に任意の値を代入することで変更することも出来ます。

 以下は外部のサイトです。

ECMAScriptのRegExp関連