Skip to content

About

C++ regular expression engine for ukagaka modules

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

uka_regexp

wchar_t 専用の正規表現エンジンです。PCRE2(Perl 互換)に近い書き方で、日本語を含む文字列の検索と置換ができます。

こんなとき 読むところ
C++ のプログラムに組み込む、エンジンを改造する DEVELOPERS.md(使い方・API・ビルドとテスト)
正規表現をこれから使ってみる 正規表現入門
使える構文を正確に調べる 仕様書

採用プロジェクト

伺か(Ukagaka)まわりの次のプロジェクトで使われています。

正規表現入門

正規表現とは

正規表現は、「こういう並びの文字列」を 1 本の式で書き表す方法です。たとえば「数字 3 桁、ハイフン、数字 4 桁」(郵便番号のような形)は、次のように書けます。

\d{3}-\d{4}

この式をパターン、調べる相手の文字列を対象と呼びます。パターンは、対象の中から左から順に探して最初に見つかった部分に一致します。対象全体に一致する必要はありません。

\d{3}-\d{4} を 〒123-4567 に当てると、123-4567 の部分に一致します。

以下、「パターン → 対象 → 一致した部分」の形で例を示します。

ふつうの文字と .

英数字や日本語は、そのままその文字に一致します。大文字と小文字は区別されます。

パターン 対象 一致する部分
cat a cat sat cat
c.t cut cut

.(ドット)は「改行以外のどれか 1 文字」を表します。

次の記号は特別な意味を持っています。

. * + ? ( ) [ ] { } ^ $ | \

これらを文字そのものとして探したいときは、前に \ を付けます。

パターン 対象 一致する部分
\d+\.\d+ pi 3.14 3.14
\$\d+ cost $250 $250

長い文字列を丸ごと文字として扱いたいときは \Q...\E で囲めます(\Qa.b\E は a.b だけに一致)。

文字の集まり [ ]

[abc] は「a か b か c の 1 文字」です。- で範囲を、先頭の ^ で「それ以外」を表します。

パターン 対象 一致する部分
gr[ae]y grey gray grey(最初の 1 つ)
[a-zA-Z_][a-zA-Z0-9_]* 123 foo_bar9 foo_bar9
[^,]+ ab,cd ab(カンマ以外が続く部分)

よく使う集まりには短い書き方があります。

書き方 意味
\d 数字 0-9
\w 英数字と _(A-Za-z0-9_)
\s 空白(スペース・タブ・改行など)
\D \W \S それぞれの「それ以外」

注意: \d \w \s は既定では ASCII だけが対象です。全角の数字(123)には \d は一致しません。日本語の文字には「日本語を扱う」の書き方を使うか、パターンの先頭に (*UCP) を書いて Unicode 対応にします。

繰り返し

直前のものを何回繰り返すかを指定します。

書き方 意味
? 0 回か 1 回
* 0 回以上
+ 1 回以上
{3} ちょうど 3 回
{2,4} 2 回から 4 回
{2,} 2 回以上
パターン 対象 一致する部分
colou?r color colour color(u があってもなくても)
\d+ abc 123 def 123
\d{2,4} 12345 1234(できるだけ長く)
a* baaa (先頭の空の位置。* は 0 回でも一致する)

位置を指定する

文字ではなく「場所」に一致するものです。

書き方 意味
^ 文字列の先頭
$ 文字列の末尾
\b 単語の境目(英数字と、それ以外の間)
\B 単語の境目ではない場所
パターン 対象 結果
^\d+$ 12345 一致(全体が数字だけ)
^\d+$ 12a45 一致しない
\bcat\b concat cat 後ろの cat に一致(concat の中の cat は単語の途中なので除外)

パターン全体を ^ と $ で挟むと、「対象全体がこの形であること」を調べられます。

どれか / まとめる | ( )

| は「または」です。( ) は、ひとまとめにして繰り返したり、| の範囲を限定したりするのに使います。

パターン 対象 一致する部分
cat|dog hotdog dog
gr(a|e)y grey grey
(?:ab)+ ababab ababab(ab の繰り返し)
^\s+|\s+$ ␣␣hi␣␣(前後に空白) 先頭の空白(^\s+)と末尾の空白(\s+$)のどちらか

| は結びつきがいちばん弱いので、^\s+|\s+$ は「^\s+ または \s+$」の意味になります。

(?:...) は、後で取り出す必要がないグループです(次の項目を参照)。

一致した部分を取り出す・再利用する

( ) で囲んだ部分は、グループとして別々に取り出せます。番号は、開き括弧の順に 1, 2, ... です(全体は 0)。

パターン 対象 全体 グループ 1 / 2 / 3
(\d+)年(\d+)月(\d+)日 今日は2026年10月19日です 2026年10月19日 2026 / 10 / 19
(\w+)@(\w+)\.com mail: taro@example.com taro@example.com taro / example

グループには名前も付けられます: (?<year>\d{4})-(?<month>\d{2})。

同じパターンの中で、取り出した文字列をもう一度使うことを後方参照と呼び、\1, \2, ... と書きます。

パターン 対象 一致する部分
(\w)\1 hello ll(同じ文字が 2 つ続く)
(?<n>a)\k<n> xaa aa(名前での参照)

できるだけ長く / できるだけ短く

繰り返しは、ふつうできるだけ長く一致しようとします。後ろに ? を付けるとできるだけ短くなります。

パターン 対象 一致する部分
<.+> <b>bold</b> <b>bold</b>(全部)
<.+?> <b>bold</b> <b>(最初のタグだけ)

*? +? ?? {2,4}? が同様に使えます。

前後の条件を見る(先読みと後読み)

「ここの前(後ろ)がこうなっていること」だけを条件にして、その部分は一致に含めない書き方です。

書き方 意味
(?=...) 後ろに ... が続くこと
(?!...) 後ろに ... が続かないこと
(?<=...) 前に ... があること
(?<!...) 前に ... がないこと
パターン 対象 一致する部分
\d+(?= 円) 100 円 100(円 は含まない)
(?<=\$)\d+ cost $250 250($ は含まない)
(?<!\d)\d{3}(?!\d) 1234 567 567(ちょうど 3 桁の数字)

大文字小文字などの設定(オプション)

パターンの先頭に (?i) のように書いて、振る舞いを変えられます。

書き方 意味
(?i) 大文字小文字を区別しない
(?m) ^ $ が各行の先頭・末尾に一致する
(?s) . が改行にも一致する
(?x) パターン中の空白を無視し、# から行末までをコメントにする(長いパターンを読みやすく書ける)
パターン 対象 一致する部分
(?i)hello HeLLo HeLLo
(?m)^\d+ 3 行のうち 1 行目が 12 12(行頭の数字)
(?s)a.b a と b の間に改行 a 改行 b((?s) が無いと一致しない)

日本語を扱う

ひらがな・カタカナ・漢字などは、\p{名前} で指定します。

書き方 意味
\p{Hiragana} ひらがな(長音符「ー」も含む)
\p{Katakana} カタカナ(長音符「ー」も含む)
\p{Han} 漢字
\p{Nd} 数字(全角の 123 を含む)
\p{Lu} 大文字
[ぁ-ん] 文字の範囲を直接書いてもよい
パターン 対象 一致する部分
\p{Hiragana}+ これはテストです これは
\p{Katakana}+ これはテストです テスト
\p{Han}+ 日本語のテキスト 日本語
^\p{Katakana}+$ コーヒー 一致(全部カタカナ)
\p{Nd}+ 123 123

\X は、見た目の「1 文字」(結合文字や肌の色付きの絵文字なども 1 つとして)に一致します。

置換

一致した部分を別の文字列に置き換えるとき、置換後の文字列の中で $1, $2 ... と書くと、その番号のグループに一致した文字列が入ります。

パターン 置換後 対象 結果
(\d+)年(\d+)月(\d+)日 $1/$2/$3 2026年10月19日 2026/10/19
(\w+) (\w+) $2 $1 hello world world hello
(?<y>\d{4})-(?<m>\d{2}) ${m}/${y} 2026-10 10/2026
\d+(全部置換) <$&> a1b22 a<1>b<22>($& は一致した全体)
\s+(全部置換) (1 つの空白) a␣␣␣b a␣b
^\s+|\s+$(全部置換) (空) ␣␣hi␣␣ hi(前後の空白を除去)

$ そのものを入れたいときは $$ と書きます。細かい書き方は置換文字列を参照してください。

よくある例

用途 パターン 一致する例
郵便番号 \d{3}-\d{4} 123-4567
国内の電話番号 0\d{1,3}-\d{1,4}-\d{4} 03-1234-5678
日付 \d{4}年\d{1,2}月\d{1,2}日 2026年1月5日
符号付きの整数 [-+]?\d+ -42
URL https?://[^\s]+ https://example.com/a?b=1
メールアドレス(簡易) ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$ taro.y@example.co.jp
変数名 [a-zA-Z_][a-zA-Z0-9_]* foo_bar9
ひらがなだけ ^\p{Hiragana}+$ らーめん
カタカナだけ ^\p{Katakana}+$ コーヒー
数字と英小文字を両方含む 8 文字以上 ^(?=.*\d)(?=.*[a-z]).{8,}$ abcd1234

つまずきやすい点

  • 記号は \ で打ち消す: . * ( などを文字として探すときは \. \* \( と書きます。
  • \d \w \s \b は既定では ASCII だけ: 全角数字や日本語は対象外です。日本語の判定には \p{...} を使うか、パターンの先頭に (*UCP) を書きます。
  • . は改行に一致しません: 複数行を . で越えたいときは (?s) を付けます。
  • 全体が一致するか調べるときは ^...$: これがないと、対象のどこか一部が一致しただけで「一致」になります。$ は「末尾の改行の手前」にも一致するので、厳密に末尾だけにしたいときは \z を使います。
  • * は 0 回でも一致します: a* は何もない場所にも一致します。「1 文字以上」のつもりなら + です。
  • 長すぎる計算は打ち切られます: (.*a){12}c のような、入れ子になった繰り返しを多用したパターンは、対象によっては時間が爆発的にかかります。そのためエンジンは一定の回数で諦め、エラーにします。

仕様書

このエンジンが対応する構文の仕様です。C++ からの呼び出し方は DEVELOPERS.md を参照してください。

PCRE2 との関係と意図的な違い

構文と意味は PCRE2(Perl 互換)に合わせることを基本方針にしています。PCRE2 のパターンをそのまま、またはわずかな修正で使えることを目指しています。

PCRE2 にある機能のうち、次のものを実装しています: 文字クラスと POSIX クラス、Unicode のプロパティ(カテゴリ・スクリプト・一部の二値プロパティ)、最短・所有量指定子、アトミックグループ、先読み・後読み、名前付き・ブランチリセット、後方参照、再帰・サブルーチン呼び出し、条件、\R \N \X \K \G、\Q…\E、インラインオプション、バックトラック制御動詞、改行規約。 このほか、.NET のバランシンググループ、\U…\E \L…\E、可変長の後読み、GLOBAL のような独自の拡張があります。

PCRE2 と意図的に違う点は次のとおりです。

項目 このエンジン PCRE2
同じ名前のグループ 同じグループ番号を共有(.NET 方式) (?J) なしではエラー、ありでは別番号
後読み 可変長・上限なしでも可 固定長(10.43 以降は上限ありの可変長)
知らない英字のエスケープ(\y など) その文字そのもの エラー
未対応 \C (*THEN) (*ACCEPT) (*SKIP:NAME) (*MARK) の取得、コールアウト、部分一致、(?J) (?(VERSION…) あり

文字

構文 意味
a 1 あ など その文字そのもの
\. \* \\ など 記号の前に \ を付けると、その記号そのもの
\t \n \r \f \a \e タブ・LF・CR・改ページ・ベル・エスケープ(垂直タブは \x0b か \cK。\v は下の空白のクラス)
\xHH 16 進 2 桁(\x41 は A)
\uHHHH 16 進 4 桁(4 桁に満たないときは普通の u)
\x{...} \u{...} \o{...} \N{U+...} 16 進/8 進/Unicode 番号。U+10000 以上も書ける(\u{1F600})。U+10FFFF を超えるとエラー
\0 \012 \cA 8 進(\0 + 最大 2 桁)/制御文字
\Q...\E 間の文字列を記号も含めてそのまま扱う(\Qa.b\E)。\E が無ければ最後まで。直後の量指定子は最後の 1 文字にかかる
\U...\E \L...\E 間の文字列を大文字・小文字に変換してから、そのまま扱う(Unicode の 1 対 1 変換)

知らない英字のエスケープ(\y など)は、その文字そのものの意味になります(\C は未対応のエラー)。

文字クラス

構文 意味
. 改行以外の任意の 1 文字(SINGLELINE では改行にも一致)
\N 改行以外の任意の 1 文字(SINGLELINE でも改行には一致しない)
[abc] [a-z] [^abc] 集合・範囲・否定。[]a] [^]a] の先頭の ]、先頭・末尾の - は普通の文字。[z-a] はエラー
\d \D 数字 0-9 / それ以外((*UCP) では \p{Nd} / それ以外)
\w \W 単語の文字 A-Za-z0-9_ / それ以外((*UCP) では \p{L} \p{N} と _ / それ以外)
\s \S 空白(スペース・\t\n\v\f\r)/ それ以外((*UCP) では \p{Z} と \t\n\v\f\r / それ以外)
\h \H 横方向の空白 / それ以外。スペース・タブのほか NBSP・U+1680・U+180E・U+2000〜200A・U+202F・U+205F・全角スペース U+3000 を含む
\v \V 縦方向の空白 / それ以外。LF・VT・FF・CR・NEL(U+0085)・LS(U+2028)・PS(U+2029)
[[:alpha:]] POSIX クラス: alnum alpha ascii blank cntrl digit graph lower print punct space upper xdigit と word。[[:^alpha:]] は否定。既定は ASCII だけで、(*UCP) では次のとおり Unicode 対応になる
\R あらゆる改行: CRLF(分けない)・LF・VT・FF・CR・NEL・LS・PS。BSR_ANYCRLF なら CRLF・LF・CR だけ。バックトラックで CRLF を分けない
\X 拡張書記素クラスタ(Unicode UAX #29)。結合文字や絵文字の ZWJ 列、国旗、ハングルの字母列などを 1 つとして扱う

\d \w \s \h \v \p{..} は [...] の中でも使えます([\d_] [\p{Lu}\d])。クラスの中の \b はバックスペースです。[a-\d] のように範囲の端がクラスのときは、- は普通の文字になります。\N{U+41} は使えますが、\N \R \X \B \C は [...] の中ではエラーです。 \d \w \s \b と POSIX クラスは、既定では ASCII だけが対象です(\d は全角数字に一致しません)。

Unicode 対応((*UCP) / UCP)

パターンの先頭に (*UCP) を書くか、C++ のフラグ UCP を渡すと、PCRE2 の UCP と同じく \d \w \s \b \B と POSIX クラスが Unicode のプロパティで判定されます。既定は OFF です。パターン内から切り替える (?…) の書き方はありません。

書き方 (*UCP) のときの意味
\d \w \s \p{Nd} / \p{L} \p{N} と _ / \p{Xps}(\p{Z} と TAB・LF・VT・FF・CR)。\D \W \S はそれ以外
\b \B \w を基準にした単語の境界
[[:alpha:]] [[:lower:]] [[:upper:]] \p{L} / \p{Ll} / \p{Lu}(IGNORECASE では lower upper とも大文字小文字どちらにも一致)
[[:alnum:]] [[:digit:]] [[:word:]] \p{Xan} / \p{Nd} / \p{Xwd}
[[:space:]] [[:blank:]] [[:cntrl:]] \p{Xps} / \h / \p{Cc}
[[:graph:]] [[:print:]] \p{L} \p{M} \p{N} \p{P} \p{S} \p{Cf}(U+061C・U+180E・U+2066〜2069 を除く)/ それに \p{Zs} を加えたもの
[[:punct:]] \p{P} と、U+00FF 以下の \p{S}
[[:ascii:]] [[:xdigit:]] 変わらない(ASCII だけ)

\h \v \R \X と、IGNORECASE の扱いは (*UCP) と関係なく変わりません。

Unicode プロパティ

\p{L} \pL \P{L} \p{^L} の形で、[...] の中にも書けます。Unicode 15.1 のデータを内蔵しています。名前は PCRE2 と同じくゆるく比較します(大文字小文字、空白、_、- を無視: \p{Script_Extensions=Hira} と \p{ script extensions : hira } は同じ)。

名前 意味
L M N P S Z C 一般カテゴリの大分類
Lu Ll Lt Lm Lo Mn Mc Me Nd Nl No Pc Pd Ps Pe Pi Pf Po Sm Sc Sk So Zs Zl Zp Cc Cf Cs Co Cn 2 文字のカテゴリ名すべて
Letter Uppercase_Letter Decimal_Number Punctuation など カテゴリの正式名・別名
L& LC Lu Ll Lt
Hiragana Katakana Han Latin Greek Cyrillic Hangul Thai Common Inherited など スクリプト(Unicode のすべてのスクリプトの正式名と Hira Kana Hani のような 4 文字の略称)。Script_Extensions で判定するので、\p{Hiragana} は長音符「ー」にも一致する(PCRE2・Perl と同じ)
sc:Hira Script=Hiragana Script(拡張なし)で判定。「ー」には一致しない
scx:Hira Script_Extensions=Hiragana Script_Extensions で判定(名前だけの指定と同じ)
gc:Lu General_Category=Lu 一般カテゴリを明示
Alphabetic (Alpha) Emoji Emoji_Presentation (EPres) Emoji_Modifier (EMod) Emoji_Modifier_Base (EBase) Emoji_Component (EComp) Extended_Pictographic (ExtPict) 二値プロパティ
Any Assigned ASCII 任意の文字 / 割り当て済み / U+0000〜007F
White_Space Space Unicode の空白(全角スペース・U+2028・U+0085 なども)
Word 単語の文字(L M Nd Nl Pc と U+200C/200D)
Xan Xwd Xsp Xps PCRE 互換: 文字と数字 / 文字・数字・_ / 空白(Z と \t\n\v\f\r)/ 空白

知らない名前は、\p{..} ならどの文字にも一致せず、\P{..} ならすべての文字に一致します(エラーにはしません)。ブロック(\p{InHiragana})にも対応していません。 IGNORECASE のとき \p{Lu} \p{Ll} \p{Lt} は、大文字・小文字・タイトルケースのどれにも一致します。

位置

構文 意味
^ 文字列の先頭。MULTILINE では行頭(文字列の末尾にある改行の後ろは除く)
$ 文字列の末尾、または末尾の改行の直前(PCRE2 と同じ)。MULTILINE では行末。C++ のフラグ DOLLAR_ENDONLY で末尾だけにできる
\A / \z 文字列の先頭 / 末尾(末尾の改行の直前には一致しない)
\Z 文字列の末尾、または末尾の改行の直前(MULTILINE なしの $ と同じ)
\b \B 単語(ASCII。(*UCP) では Unicode)の境界 / 境界以外
\G 検索を始めた位置。GLOBAL なら前回の一致が終わった位置
\K 一致の開始位置をここにする。それより前は条件として調べるだけで、一致には含めない(foo=\Kbar)。先読み・後読みの中に書くとエラー(PCRE2 10.38 以降と同じ)

^ \b などは、途中の位置から探したときも、文字列全体を基準に判断します。

量指定子

構文 意味
* + ? {n} {n,} {n,m} 繰り返し(n, m は 65535 まで)。{n,m} で n > m はエラー
*? +? ?? {n,m}? 最短一致
*+ ++ ?+ {n,m}+ 所有量指定子(繰り返した分を手放さない)

{,m} は {0,m} と同じです(a{,3} は a{0,3}。PCRE2 10.43 以降と同じ)。量指定子として読めない {(a{ a{1 a{,} a{,x})は普通の文字です。前に何も無い * + ? も普通の文字になります。a** のように重ねて書くこともできます(32 個まで)。 空文字列にマッチする繰り返しは、1 周で何も進まなければそこで打ち切ります。

グループと参照

構文 意味
(...) キャプチャするグループ(開き括弧の順に 1, 2, ...)
(?:...) キャプチャしない
(?<name>...) (?'name'...) (?P<name>...) 名前付き。名前は英数字・_・非 ASCII 文字。同じ名前を複数回使うと同じグループ番号を共有
(?<2>...) 番号指定。以降の自動番号はその次から
(?|...|...) ブランチリセット。選択肢ごとに同じ番号から振り直す
(?>...) アトミックグループ
\1 \2 ... 後方参照。\10 以上は、その数のグループがすでにあれば参照、無ければ 8 進文字。参加していないグループへの参照は失敗する。存在しないグループ(\9 など)はエラー
\k<name> \k'name' \k{name} (?P=name) 名前による後方参照(\k<1> のように番号も可)
\g1 \g-1 \g{1} \g{-1} \g{name} 番号・相対番号・名前による後方参照
(?#...) コメント

IGNORECASE のとき後方参照も大文字小文字を無視して比べます。大文字小文字の無視は、ASCII に限らず Unicode の単純な case folding(д/Д、σ/ς/Σ、K/U+212A など)に従います。ß と SS のような複数文字への展開は扱いません。 繰り返しの中のグループは、最後に参加した周の値を保ちます(次の周で参加しなくても消えません)。

先読み・後読み・条件・再帰

構文 意味
(?=...) (?!...) 肯定先読み / 否定先読み
(?<=...) (?<!...) 肯定後読み / 否定後読み。中身は可変長でもよい((?<=ab+)c)。短い方から順に試すので、後読みの中のグループには最短の候補が入ります。上限の無い後読みは、文字ごとに先頭まで遡る可能性があるので重くなります
(*pla:...) (*nla:...) (*plb:...) (*nlb:...) (*atomic:...) 英字で書くアサーション(positive_lookahead negative_lookahead positive_lookbehind negative_lookbehind の長い名前も可)
(?(1)yes|no) (?(name)yes|no) (?(<name>)..) (?('name')..) グループが一致していれば yes、そうでなければ no(|no は省略可)
(?(?=...)yes|no) 先読み・後読み(?= ?! ?<= ?<!)の結果で分岐
(?(R)yes|no) (?(R1)..) (?(R&name)..) 再帰の中にいるか(グループ指定なら、そのグループの呼び出しの中にいるか)
(?(DEFINE)...) 中身は実行せず、(?&name) などで呼び出すための定義だけを置く
(?R) (?0) パターン全体を再帰的に呼び出す
(?1) (?-1) (?+1) (?R1) (?&name) (?P>name) (?R<name>) (?R'name') \g<1> \g<-1> \g<name> \g'name' 指定したグループを呼び出す(-1 は直前に開いたグループ、+1 は次に開くグループ)。^(\((?1)*\))$ は対応の取れた括弧に一致
(?<name-other>...) (?<-other>...) .NET 互換のバランシンググループ
  • 再帰・呼び出しは中でバックトラックできます。呼び出しから戻ると、呼び出しの中で変わったグループの値は呼び出し前に戻ります。同じ位置で自分自身を呼び出す無限の左再帰は、その経路が失敗するだけです。
  • バランシンググループ: (?<other>...) が一致するたびに値が積まれ、(?<-other>...) が一致すると最後の値を 1 つ取り除きます(積まれていなければ失敗)。(?<name-other>...) は、取り除いた other の終わりからこのグループの開始までを name に記録します。取り除いた後は (?(other)...) で「まだ残っているか」を調べられます。例: ^(?:[^()]|(?<o>\()|(?<-o>\)))*(?(o)(?!))$ は対応の取れた括弧に一致します。
  • 否定先読み・否定後読みの中で設定されたグループは、先読みを抜けると破棄されます。
  • パターンの中に定義が無い名前のサブルーチン呼び出し((?&date) など)は、組み込み先のアプリが定義を提供していれば解決されます。提供が無ければ ERR_SYNTAX です(DEVELOPERS.md の「サブルーチンの外部定義」)。

バックトラック制御動詞

構文 意味
(*FAIL) (*F) その場で失敗させる。a(*SKIP)(*FAIL)|b のように使う
(*COMMIT) ここより後ろで失敗してここまで戻ってきたら、マッチ全体を失敗にする(開始位置をずらして再試行もしない)
(*PRUNE) ここまで戻ってきたら、この開始位置からのマッチを諦めて次の開始位置へ進む
(*SKIP) (*PRUNE) と同じだが、次の開始位置を (*SKIP) に到達した位置にする
(*:NAME) (*MARK:NAME) (*COMMIT:NAME) (*PRUNE:NAME) 名前は受け付けるが使わない(取得できない)
  • パターンの先頭が固定の文字なら、先にその文字まで検索位置を進めます。そのため (*COMMIT)x は PCRE2 と同じく、文字列の先頭から x までを飛ばして一致します(アンカーにはなりません)。
  • アトミックグループ((?>…) やグループへの所有量指定子)の中の動詞は、PCRE2 と同じくグループの中でだけ効きます。グループを抜けた後の失敗で戻ってきても効きません((?>a(*COMMIT))b|ac は ac に一致します)。先読み・後読みの中では (*COMMIT) (*PRUNE) (*SKIP) を使えません(エラー)。再帰・サブルーチン呼び出しの中でも、効果は呼び出しの中に閉じず、マッチ全体に及びます。
  • (*THEN) (*ACCEPT) (*SKIP:NAME) は未対応でエラーです。

パターンの先頭には、次のオプション動詞を並べて書けます: (*UTF) (*UTF8) (*UTF16) (*UTF32)(何もしません)、(*LF) (*CR) (*CRLF) (*ANYCRLF) (*ANY)、(*BSR_ANYCRLF) (*BSR_UNICODE)、(*NOTEMPTY) (*NOTEMPTY_ATSTART)、(*LIMIT_MATCH=n)、(*NO_START_OPT) など PCRE2 の最適化・上限の指定(何もしません)。(*UCP) は \d \w \s \b と POSIX クラスを Unicode 対応にします(「Unicode 対応」の項)。(*NUL) は未対応でエラーです。 (*LIMIT_MATCH=n) は、バックトラック回数の上限を n 以下に下げます(制限)。

オプション

パターンの中に (?i) のように書いて、照合の振る舞いを変えます。

構文 意味
(?i) 大文字と小文字を区別しない(IGNORECASE)
(?m) ^ $ を行頭・行末に一致させる(MULTILINE)
(?s) . を改行にも一致させる(SINGLELINE)
(?x) パターン中の空白を無視し、# から行末までをコメントにする。[...] の中は除く(EXTENDED)
(?g) GLOBAL。一致を 1 つずつでなく、続けて全部探す/置換するようにする

(?i) はその位置からグループの終わりまで有効です。(?i:...) は括弧の中だけ、(?-i) は解除です。(?im-sx) のようにまとめて書けます。 選択肢の途中で変えた設定は、同じグループの後続の選択肢にも続きます((a(?i)b|c) の c も大文字小文字を区別しません)。 (?g) はどこに書いても、パターン全体を GLOBAL にします。

パターンの中だけで使えるオプションもあります。

構文 意味
(?^) (?^i:...) imsx を既定に戻してから指定のものを設定
(?n) (...) をキャプチャしない(名前付きグループは従来どおりキャプチャ)
(?xx) x に加えて、[...] の中の空白とタブも無視
(?U) 量指定子の最短・最長を入れ替える(a* が最短、a*? が最長)

同じ設定は、C++ からフラグとして渡すこともできます(DEVELOPERS.md の「フラグ」)。

改行の扱い

既定では、. ^ $(MULTILINE)\Z が見る改行は LF だけです。パターンの先頭に次の動詞を書くか、C++ の NEWLINE_* フラグで変えられます(PCRE2 と同じ)。

動詞 改行とみなすもの
(*LF) LF(既定)
(*CR) CR
(*CRLF) CR LF の 2 文字の並びだけ
(*ANYCRLF) CR・LF・CRLF
(*ANY) 上に加えて VT・FF・NEL(U+0085)・LS(U+2028)・PS(U+2029)

. と \N は改行に一致しません(CRLF モードでは、\r\n の並びの \r に一致しない)。MULTILINE の ^ は文字列の末尾にある改行の後ろには一致しません(PCRE2 と同じ)。$(MULTILINE)は改行の手前と文字列の末尾に一致します。「末尾の改行」も、ここで選んだ改行規約に従います。 \R の対象を CR・LF・CRLF だけにするには、パターンの先頭に (*BSR_ANYCRLF) を書きます。

置換文字列

Replace で使う置換文字列の中では、次の $ の指定が使えます。

構文 意味
$1 $2 ... その番号のグループが一致した文字列。$10 はグループが 10 個以上あれば 10 番、無ければ $1 の後ろに 0
${name} ${1} 名前・番号で指定(番号の後ろに数字が続くときに便利)
$& / $0 一致した文字列全体(\K を使えば \K 以降)
$` / $' 一致した部分より前 / 後ろの、元の文字列
$+ 一致したグループのうち番号が最大のもの
$_ 元の文字列全体
$$ $ という文字

存在しないグループや形式が合わない $ は、そのままの文字として残ります。参加していないグループは空文字列になります。

不正なパターン

閉じていない ( [ や余分な )、存在しないグループへの参照、範囲の逆転([z-a] a{3,2})、未知の POSIX クラス名、未知のオプション文字((?z))、未知・未対応の (*VERB)、[...] の中の \N \R \X、深すぎる入れ子(200 段)などは ERR_SYNTAX の例外になります。それ以外の曖昧な書き方は、できるだけ解釈してコンパイルします(上の表の各所を参照)。

制限

  • 文字の単位: wchar_t が 32 bit の環境(Linux・macOS)では、wchar_t 1 個が 1 文字です。16 bit の環境(Windows)では UTF-16 として読み、上位サロゲートに下位サロゲートが続く並びを 1 文字(U+10000 以上)として扱います。. [^a] \W や 😀+ [😀-😎] \p{..} \X (?<=.) などは、どちらの環境でも同じ結果になります。😀 のように書いたサロゲートの対も 1 文字になります。単独のサロゲートは、それだけで 1 文字です。マッチの開始位置と終了位置がペアの途中になることはありません(Match() の start にペアの途中を指定した場合は、次の文字の境界から探します)。
  • 位置の単位: GetStart() GetEnd() などの位置は、どちらの環境でも wchar_t 単位です。16 bit の環境では、U+10000 以上の文字 1 つが位置を 2 進めます。
  • 未対応の機能: ブロックの \p、コールアウト、部分一致、JIT はありません。
  • バックトラックの上限: (.*a){12}c のようなパターンは入力によって指数時間かかるため、バックトラック回数に上限があります。既定は 1000000 + 256 × 入力の長さ で、超えると照合を打ち切ってエラー(ERR_STEP_LIMIT)にします。\w+@ を単語文字が何万文字も続く入力に当てるような二乗オーダーのパターンも打ち切られます(入力に @ が 1 つも無ければ、下の「検索の近道」で試す前に失敗が分かります)。バックトラック用スタックにも入力長に比例した上限があります。上限の変更は DEVELOPERS.md を参照してください。
  • 失敗した状態の記憶: ^(a+)+b$ を aaaa…ac に当てるような、同じ場所を指数的に調べ直すパターンは、一度失敗した状態(パターンのどの位置に、入力のどの位置で来たか)を覚えておき、二度目からは調べずに失敗として扱うので、多項式時間で終わります((a*)*b (a|aa)+b (x+x+)+y (\w+\s?)*$ a*a*a*a*b など)。1 回の照合でバックトラックが 4096 回を超えたときから働き、普通のパターンの速さは変わりません。結果(マッチの範囲も捕獲グループの値も)は覚えない場合と同じです。対象は、後方参照・先読み・後読み・アトミックグループ((?>…) と、グループへの所有量指定子 (…)++。a++ のような 1 文字への指定は対象)・サブルーチン呼び出しと再帰・制御動詞・\K・条件式・回数指定のあるグループのループ((ab){2,5} (ab){3}。1 文字の繰り返し a{2,5} は対象)を含まないパターンです。それ以外のパターンは従来どおり上限で打ち切られます。対象のパターンでも、(a+)+b を何千文字もの a に当てるような場合は二乗オーダーの手数が残るので、上限に当たることがあります。
  • 検索の近道: 結果を変えずに、試す開始位置を減らします。パターンの先頭が固定の文字ならその文字まで、そうでなくても最初の 1 文字になりうる文字が限られる(\d+ [a-z]+ing fox|dog など)ならそのどれかまで、検索位置を進めます(制御動詞が先頭の文字より前にあるときは、固定の文字の場合を除いて使いません)。また、どの一致にも必ず含まれる文字(.*zzz の z など)が入力の残りに無ければ、すぐに失敗を返します。1 文字の貪欲な繰り返しの直後が固定の文字なら、戻るときにその文字の位置だけを試します(飛ばした位置もバックトラック回数には数えるので、上限に当たるかどうかは変わりません)。

About

C++ regular expression engine for ukagaka modules

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages