修正 ECMAScript 正規表現文法
このページは syntax_option_type を ECMAScript
(デフォルト) に設定して std::basic_regex が構築されたときに使用される正規表現文法を説明します。 サポートされている他の正規表現文法については syntax_option_type を参照してください。
C++ の ECMAScript
正規表現文法は以下のような (C++ only) で示される変更点が加えられた ECMA-262 の文法です。
目次 |
[編集] Alternative
正規表現パターンは1個以上の Alternative を論理和演算子 |
で区切ったものです (別の言い方をすると、論理和演算子の優先順位は最低です)。
Pattern ::
- Disjunction
Disjunction ::
- Alternative
- Alternative
|
Disjunction
パターンはまず Disjunction をスキップして左の Alternative に残りの (Disjunction の後の) 正規表現のマッチを試みます。
左の Alternative、右の Disjunction および残りの正規表現がすべて選択点を持つ場合、左の Alternative の次の選択肢に移動する前に残りの正規表現のすべての選択肢が試みられます。 左の Alternative の選択肢が尽きた場合は、左の Alternative の代わりに右の Disjunction が試みられます。
スキップされた Alternative 内部のあらゆるキャプチャ付き括��は空の部分マッチを生成します。
#include <iostream> #include <regex> void show_matches(const std::string& in, const std::string& re) { std::smatch m; std::regex_search(in, m, std::regex(re)); if(m.empty()) { std::cout << "input=[" << in << "], regex=[" << re << "]: NO MATCH\n"; } else { std::cout << "input=[" << in << "], regex=[" << re << "]: "; std::cout << "prefix=[" << m.prefix() << "] "; for(std::size_t n = 0; n < m.size(); ++n) std::cout << " m[" << n << "]=[" << m[n] << "] "; std::cout << "suffix=[" << m.suffix() << "]\n"; } } int main() { show_matches("abcdef", "abc|def"); show_matches("abc", "ab|abc"); // left Alernative matched first // Match of the input against the left Alternative (a) followed // by the remained of the regex (c|bc) succeeds, which results // in m[1]="a" and m[4]="bc". // The skipped Alternatives (ab) and (c) leave their submatches // m[3] and m[5] empty. show_matches("abc", "((a)|(ab))((c)|(bc))"); }
出力:
input=[abcdef], regex=[abc|def]: prefix=[] m[0]=[abc] suffix=[def] input=[abc], regex=[ab|abc]: prefix=[] m[0]=[ab] suffix=[c] input=[abc], regex=[((a)|(ab))((c)|(bc))]: prefix=[] m[0]=[abc] m[1]=[a] m[2]=[a] m[3]=[] m[4]=[bc] m[5]=[] m[6]=[bc] suffix=[]
[編集] Term
それぞれの Alternative は、空であるか、 Term の並びです (Term 間の区切りはありません)。
Alternative ::
- [empty]
- Alternative Term
空の Alternative は常にマッチし、入力を一切消費しません。
連続する Term は入力の連続する部分に同時にマッチを試みます。
左の Alternative、右の Term および残りの正規表現がすべて選択点を持つ場合、右の Term の次の選択肢に移動する前に残りの正規表現のすべての選択肢が試みられ、左の Alternative の次の選択肢に移動する前に右の Term のすべての選択肢が試みられます。
#include <iostream> #include <regex> void show_matches(const std::string& in, const std::string& re) { std::smatch m; std::regex_search(in, m, std::regex(re)); if(m.empty()) { std::cout << "input=[" << in << "], regex=[" << re << "]: NO MATCH\n"; } else { std::cout << "input=[" << in << "], regex=[" << re << "]: "; std::cout << "prefix=[" << m.prefix() << "] "; for(std::size_t n = 0; n < m.size(); ++n) std::cout << " m[" << n << "]=[" << m[n] << "] "; std::cout << "suffix=[" << m.suffix() << "]\n"; } } int main() { show_matches("abcdef", ""); // empty regex is a single empty Alternative show_matches("abc", "abc|"); // left Alernative matched first show_matches("abc", "|abc"); // left Alernative matched first, leaving abc unmatched }
出力:
input=[abcdef], regex=[]: prefix=[] m[0]=[] suffix=[abcdef] input=[abc], regex=[abc|]: prefix=[] m[0]=[abc] suffix=[] input=[abc], regex=[|abc]: prefix=[] m[0]=[] suffix=[abc]
[編集] Quantifier
- それぞれの Term は Assertion (後述)、または Atom (後述)、または Atom の直後に Quantifier が続いたものです。
Term ::
- Assertion
- Atom
- Atom Quantifier
それぞれの Quantifier は、貪欲な量指定子 (ひとつの QuantifierPrefix だけから構成されます) または非貪欲な量指定子 (ひとつの QuantifierPrefix に続く疑問符 ?
から構成されます) の、いずれかです。
Quantifier ::
- QuantifierPrefix
- QuantifierPrefix
?
それぞれの QuantifierPrefix は、2つの数値、最小繰り返し回数および最大繰り返し回数を、以下のように決定します。
QuantifierPrefix | 最小 | 最大 |
---|---|---|
*
|
0 | 無限 |
+
|
1 | 無限 |
?
|
0 | 1 |
{ DecimalDigits }
|
DecimalDigits の値 | DecimalDigits の値 |
{ DecimalDigits , }
|
DecimalDigits の値 | 無限 |
{ DecimalDigits , DecimalDigits }
|
コンマの前の DecimalDigits の値 | コンマの後の DecimalDigits の値 |
個々の DecimalDigits の値は各桁に std::regex_traits::value(C++ only) を呼ぶことによって取得されます。
Quantifier が続いた Atom は、その Quantifier によって指定された回数だけ繰り返されます。 Quantifier は非貪欲であることも貪欲であることもできます。 非貪欲な場合、 Atom のパターンは、まだ残りの正規表現にマッチするとき、可能な限り少ない回数だけ繰り返されます。 貪欲な場合、 Atom のパターンは、まだ残りの正規表現にマッチするとき、可能な限り多くの回数繰り返されます。
繰り返されるものは、マッチした入力ではなく、 Atom のパターンです。 そのため、 Atom の繰り返しの各回ごとに入力の異なる部分文字列にマッチし得ます。
Atom および残りの正規表現がすべて選択点を持つ場合、まず Atom が可能な限り多い (非貪��な場合は少ない) 回数マッチします。 Atom の最後の繰り返し内の次の選択肢に移動する前に残りの正規表現のすべての選択肢が試みられます。 Atom の最後の前 (n-1 回目) の繰り返し内の次の選択肢が試みられる前に Atom の最後の (n 回目の) 繰り返し内のすべての選択肢が試みられます。 Atom の n-1 回目の繰り返し内の次の選択肢に移動する前にそれらは使い果たされます。 その時点で Atom のより多いまたは少ない繰り返しが可能であると判明するかもしれません。
Atom のキャプチャは繰り返されるたびにクリアされます (以下の "(z)((a+)?(b+)?(c))*" の例を参照してください)。
#include <iostream> #include <regex> void show_matches(const std::string& in, const std::string& re) { std::smatch m; std::regex_search(in, m, std::regex(re)); if(m.empty()) { std::cout << "input=[" << in << "], regex=[" << re << "]: NO MATCH\n"; } else { std::cout << "input=[" << in << "], regex=[" << re << "]: "; std::cout << "prefix=[" << m.prefix() << "] "; for(std::size_t n = 0; n < m.size(); ++n) std::cout << " m[" << n << "]=[" << m[n] << "] "; std::cout << "suffix=[" << m.suffix() << "]\n"; } } int main() { // greedy match, repeats [a-z] 4 times show_matches("abcdefghi", "a[a-z]{2,4}"); // non-greedy match, repeats [a-z] 2 times show_matches("abcdefghi", "a[a-z]{2,4}?"); // Choice point ordering for quantifiers results in a match // with two repetitions, first matching the substring "aa", // second matching the substring "ba", leaving "ac" not matched // ("ba" appears in the capture clause m[1]) show_matches("aabaac", "(aa|aabaac|ba|b|c)*"); // Choice point ordering for quantifiers makes this regex // calculate the greatest common divisor between 10 and 15 // (the answer is 5, and it populates m[1] with "aaaaa") show_matches("aaaaaaaaaa,aaaaaaaaaaaaaaa", "^(a+)\\1*,\\1+$"); // the substring "bbb" does not appear in the capture clause m[4] // because it is cleared when the second repetition of the atom // (a+)?(b+)?(c) is matching the substring "ac" show_matches("zaacbbbcac", "(z)((a+)?(b+)?(c))*"); }
出力:
input=[abcdefghi], regex=[a[a-z]{2,4}]: prefix=[] m[0]=[abcde] suffix=[fghi] input=[abcdefghi], regex=[a[a-z]{2,4}?]: prefix=[] m[0]=[abc] suffix=[defghi] input=[aabaac], regex=[(aa|aabaac|ba|b|c)*]: prefix=[] m[0]=[aaba] m[1]=[ba] suffix=[ac] input=[aaaaaaaaaa,aaaaaaaaaaaaaaa], regex=[^(a+)\1*,\1+$]: prefix=[] m[0]=[aaaaaaaaaa,aaaaaaaaaaaaaaa] m[1]=[aaaaa] suffix=[] input=[zaacbbbcac], regex=[(z)((a+)?(b+)?(c))*]: prefix=[] m[0]=[zaacbbbcac] m[1]=[z] m[2]=[ac] m[3]=[a] m[4]=[] m[5]=[c] suffix=[]
[編集] Assertion
Assertion は、入力文字列の部分文字列ではなく、条件にマッチします。 入力からいかなる文字も消費しません。 それぞれの Assertion は以下のいずれかです。
Assertion ::
-
^
-
$
-
\
b
-
\
B
-
(
?
=
Disjunction)
-
(
?
!
Disjunction)
アサーション ^
(行頭) は以下にマッチします。
アサーション $
(行末) は以下にマッチします。
上記の2つのアサーションおよび後述するアトム .
において、 LineTerminator は4つの文字 U+000A
(\n
または改行)、 U+000D
(\r
または復帰)、 U+2028
(行区切り)、または U+2029
(段落区切り) のいずれかです。
アサーション \b
(単語境界) は以下にマッチします。
アサーション \B
(非単語境界) は以下を除くすべてにマッチします。
アサーション (
?
=
Disjunction )
(ゼロ幅肯定先読み) は、 Disjunction が現在の位置で入力にマッチするであろう場合に、マッチします。
アサーション (
?
!
Disjunction )
(ゼロ幅否定先読み) は、 Disjunction が現在の位置に入力にマッチしないであろう場合に、マッチします。
先読みアサーションのどちらについても、 Disjunction がマッチするとき、残りの正規表現にマッチする前に位置は進められません。 また、 Disjunction が現在の位置で何通りかにマッチ可能な場合は、最初のもののみが試みられます。
ECMAScript は先読み Disjunction 内へのバックトラックを禁止しています。 これは残りの正規表現からの肯定先読み内への後方参照の動作に影響を与えます (下の例を参照してください)。 残りの正規表現からの否定先読み内への後方参照は常に未定義です (続行するためには先読み Disjunction が失敗しなければならないため)。
ノート: 先読みアサーションは複数の正規表現間の論理積を作成するために使用することができます (以下の例を参照してください)。
#include <iostream> #include <regex> void show_matches(const std::string& in, const std::string& re) { std::smatch m; std::regex_search(in, m, std::regex(re)); if(m.empty()) { std::cout << "input=[" << in << "], regex=[" << re << "]: NO MATCH\n"; } else { std::cout << "input=[" << in << "], regex=[" << re << "]: "; std::cout << "prefix=[" << m.prefix() << "] "; for(std::size_t n = 0; n < m.size(); ++n) std::cout << " m[" << n << "]=[" << m[n] << "] "; std::cout << "suffix=[" << m.suffix() << "]\n"; } } int main() { // matches the a at the end of input show_matches("aaa", "a$"); // matches the o at the end of the first word show_matches("moo goo gai pan", "o\\b"); // the lookahead matches the empty string immediately after the first b // this populates m[1] with "aaa" although m[0] is empty show_matches("baaabac", "(?=(a+))"); // because backtracking into lookaheads is prohibited, // this matches aba rather than aaaba show_matches("baaabac", "(?=(a+))a*b\\1"); // logical AND via lookahead: this password matches IF it contains // at least one lowercase letter // AND at least one uppercase letter // AND at least one punctuation character // AND be at least 6 characters long show_matches("abcdef", "(?=.*[[:lower:]])(?=.*[[:upper:]])(?=.*[[:punct:]]).{6,}"); show_matches("aB,def", "(?=.*[[:lower:]])(?=.*[[:upper:]])(?=.*[[:punct:]]).{6,}"); }
出力:
input=[aaa], regex=[a$]: prefix=[aa] m[0]=[a] suffix=[] input=[moo goo gai pan], regex=[o\b]: prefix=[mo] m[0]=[o] suffix=[ goo gai pan] input=[baaabac], regex=[(?=(a+))]: prefix=[b] m[0]=[] m[1]=[aaa] suffix=[aaabac] input=[baaabac], regex=[(?=(a+))a*b\1]: prefix=[baa] m[0]=[aba] m[1]=[a] suffix=[c] input=[abcdef], regex=[(?=.*[[:lower:]])(?=.*[[:upper:]])(?=.*[[:punct:]]).{6,}]: NO MATCH input=[aB,def], regex=[(?=.*[[:lower:]])(?=.*[[:upper:]])(?=.*[[:punct:]]).{6,}]: prefix=[] m[0]=[aB,def] suffix=[]
[編集] Atom
Atom は以下のいずれかです。
Atom ::
- PatternCharacter
-
.
-
\
AtomEscape - CharacterClass
-
(
Disjunction)
-
(
?
:
Disjunction)
ただし
AtomEscape ::
- DecimalEscape
- CharacterEscape
- CharacterClassEscape
異なる種類のアトムは異なるように評価されます。
[編集] 部分表現
アトム (
Disjunction )
は部分表現としてマークされます。 Disjunction を実行し、 Disjunction によって消費された入力の部分文字列のコピーを、正規表現全体でこの時点までにマーク付き部分表現の左開き括弧 (
に遭遇した回数に対応するインデックスで submatch 配列に格納します。
キャプチャされた部分マッチは、 std::match_results に返されると共に、後方参照 (\1
, \2
, ...) としてアクセスでき、 std::regex_replace 内で参照できます。
アトム (
?
:
Disjunction )
(マークなし部分表現) は、単純に Disjunction を評価します。 その結果を submatch に格納しません。 これは純粋に字句的なグループ化です。
This section is incomplete Reason: no example |
[編集] 後方参照
DecimalEscape ::
- DecimalIntegerLiteral [lookahead ∉ DecimalDigit]
\
に先頭が 0
でない10進数値 N
が続く場合、そのエスケープシーケンスは後方参照とみなされます。 各桁に std::regex_traits::value(C++ only) を呼び、その結果を10進算術を用いて組み合わせることによって、値 N
が取得されます。 N
が正規表現全体のキャプチャ付き左括弧の合計数より大き場合は、エラーです。
後方参照 \N
が Atom として現れたとき、それは submatch 配列の N 番目の要素に現在格納されている内容と同じ部分文字列にマッチします。
10進エスケープ \0
は後方参照ではありません。 これはヌル文字を表す文字エスケープです。 これに10進数字を続けることはできません。
This section is incomplete Reason: no example |
[編集] 単一文字のマッチ
アトム .
は、入力文字列から、 LineTerminator (U+000D
、 U+000A
、 U+2029
または U+2028
) を除いた任意の1文字にマッチし、それを消費します。
アトム PatternCharacter は、その PatternCharacter に等しい場合、入力からの1文字にマッチし、それを消費します。 ただし PatternCharacter は文字 ^ $ \ . * + ? ( ) [ ] { } |
を除く任意の SourceCharacter です。
この等しさおよび他のすべての単一文字のマッチは以下のように定義されます。
エスケープ文字 \
とそれに続く CharacterEscape から構成されるそれぞれの Atom および特殊な DecimalEscape である \0
は、 CharacterEscape によって表される文字と等しい場合、入力からの1文字にマッチし、それを消費します。 以下の文字エスケープシーケンスが認識されます。
CharacterEscape ::
- ControlEscape
-
c
ControlLetter - HexEscapeSequence
- UnicodeEscapeSequence
- IdentityEscape
ここで、 ControlEscape は5つの文字 f n r t v
のいずれかです。
ControlEscape | コードユニット | 名前 |
---|---|---|
f
|
U+000C | 改頁 |
n
|
U+000A | 改行 |
r
|
U+000D | 復帰 |
t
|
U+0009 | 水平タブ |
v
|
U+000B | 垂直タブ |
ControlLetter は小文字または大文字の任意の ASCII 文字であり、この文字エスケープは ControlLetter のコードユニットの値を 32 で割った余りに等しいコードユニットの文字にマッチします。 例えば、 \cD
と \cd
は、 'D' が U+0044
で 0x44 % 32 == 4
であり、 'd' が U+0064
で 0x64 % 32 == 4
であるため、どちらもコードユニット U+0004
(EOT) にマッチします。
HexEscapeSequence は文字 x
にちょうど2桁の HexDigit が続いたものです (ただし HexDigit は 0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F
のいずれかです)。 この文字エスケープはその2桁の16進数の数値と等しいコードユニットの文字にマッチします。
UnicodeEscapeSequence は文字 u
にちょうど4桁の HexDigit が続いたものです。 この文字エスケープはその4桁の16進数の数値と等しいコードユニットの文字にマッチします。 その値がこの std::basic_regex の CharT に収まらない場合は std::regex_error が投げられます(C++ only)。
IdentityEscape は任意の非数値文字になれます。 例えば、もうひとつのバックスラッシュなどです。 これはその文字に as-is でマッチします。
This section is incomplete Reason: no example |
[編集] 文字クラス
アトムは文字クラスを表すことができます。 つまり、文字が定義済みの文字のグループのいずれかに属する場合、その文字にマッチし、それを消費します。
文字クラスは文字クラスエスケープ
Atom ::
-
\
CharacterClassEscape
または
Atom ::
- CharacterClass
によって導入できます。
文字クラスエスケープは以下のような一般的な文字クラスのいくつかに対する短縮形です。
CharacterClassEscape | ClassName 表現(C++ only) | 意味 |
---|---|---|
d
|
[[:digit:]]
|
数字 |
D
|
[^[:digit:]]
|
非数字 |
s
|
[[:space:]]
|
ホワイトスペース文字 |
S
|
[^[:space:]]
|
非ホワイトスペース文字 |
w
|
[_[:alnum:]]
|
アルファベット、数字、および _
|
W
|
[^_[:alnum:]]
|
アルファベット、数字、または _ 以外の文字
|
CharacterClass は角括弧で囲まれた ClassRanges の並びです。 オプションで否定演算子 ^
を先頭に付けることができます。 ^
で始まる場合、この Atom はすべての ClassRanges の和によって表される文字集合内にない任意の文字にマッチします。 そうでなければ、この Atom はすべての ClassRanges の和によって表される文字集合内にある任意の文字にマッチします。
CharacterClass ::
-
[
[
lookahead ∉ {^
}] ClassRanges]
-
[
^
ClassRanges]
ClassRanges ::
- [empty]
- NonemptyClassRanges
NonemptyClassRanges ::
- ClassAtom
- ClassAtom NonemptyClassRangesNoDash
- ClassAtom - ClassAtom ClassRanges
空でないクラス範囲が ClassAtom - ClassAtom
の形式を持つ場合、それは以下のように定義される範囲の任意の文字にマッチします。(C++ only)
1つめの ClassAtom は単一の照合要素 c1
にマッチしなければならず、2つめの ClassAtom は単一の照合要素 c2
にマッチしなければなりません。 入力文字 c
がこの範囲によってマッチされるかどうかをテストするために、以下のステップが取られます。
c
は c1 <= c && c <= c2
の場合にマッチされます。c
, c1
, c2
) が std::regex_traits::translate_nocase に渡されます。c
, c1
, c2
) が std::regex_traits::translate に渡されます。変換後の c1 <= 変換後の c && 変換後の c <= 変換後の c2
であれば c
がマッチされます。以下の場合、文字 -
は文字通りに扱われます。
- ClassRanges の最初または最後の文字である。
- ダッシュ区切りの範囲指定の先頭または終端の ClassAtom である。
- ダッシュ区切りの範囲指定の直後である。
- CharacterEscape としてバックスラッシュでエスケープされている。
NonemptyClassRangesNoDash ::
- ClassAtom
- ClassAtomNoDash NonemptyClassRangesNoDash
- ClassAtomNoDash - ClassAtom ClassRanges
ClassAtom ::
-
-
- ClassAtomNoDash
- ClassAtomExClass(C++ only)
- ClassAtomCollatingElement(C++ only)
- ClassAtomEquivalence(C++ only)
ClassAtomNoDash ::
- SourceCharacter (ただし
\ ] -
のいずれでもない) -
\
ClassEscape
それぞれの ClassAtomNoDash は単一の文字を表します。 as-is の SourceCharacter であるか、以下のようにエスケープされます。
ClassEscape ::
- DecimalEscape
-
b
- CharacterEscape
- CharacterClassEscape
特別なクラスエスケープ \b
はコードユニット U+0008 (バックスペース) にマッチする文字集合を生成します。 これは CharacterClass の外では単語境界の Assertion です。
CharacterClass 内部での \B
の使用およびあらゆる後方参照 (ゼロ以外の DecimalEscape) の使用はエラーです。
状況によっては文字 -
および ]
はアトムとして扱われるためにはエスケープされる必要があります。 CharacterClass の外側で特別な意味を持つそれ以外の文字 (*
や ?
など) はエスケープする必要はありません。
This section is incomplete Reason: no example |
[編集] POSIX ベースの文字クラス
これらの文字クラスは ECMAScript 文法に対する拡張であり、 POSIX の正規表現にある文字クラスと同等です。
ClassAtomExClass(C++ only) ::
-
[:
ClassName:]
名前付き文字クラス ClassName のメンバであるすべての文字を表します。 名前は、その名前に対して std::regex_traits::lookup_classname が非ゼロを返す場合にのみ有効です。 std::regex_traits::lookup_classname で説明されている通り、 alnum, alpha, blank, cntrl, digit, graph, lower, print, punct, space, upper, xdigit, d, s, w
のみが認識されることが保証されています。 追加の名前はシステム供給ロケールによって提供されたり (日本語の jdigit
や jkanji
など)、ユーザ定義の拡張として実装されるかもしれません。
ClassAtomCollatingElement(C++ only) ::
-
[.
ClassName.]
名前付き照合要素を表します。 チェコ語における [.tilde.]
や [.ch.]
などの、設定されているロケールにおいて単一の要素として照合される単一の文字または一連の文字を表すことができます。 名前は std::regex_traits::lookup_collatename が空文字列でない場合にのみ有効です。
std::regex_constants::collate を使用するときは、照合要素は範囲の端点として常に使用可能です (例えばハンガリー語における [[.dz.]-g]
など)。
ClassAtomEquivalence(C++ only) ::
-
[=
ClassName=]
名前付き照合要素と同じ等価クラスのメンバであるすべての文字を表します。 つまり、プライマリ照合キーが照合要素 ClassName に対するものと同じであるすべての文字です。 名前は、その名前に対する std::regex_traits::lookup_collatename が空文字列でなく、その std::regex_traits::lookup_collatename の呼び出しの結果に対して std::regex_traits::transform_primary によって返される値が空文字列でない場合に飲み、有効です。
プライマリソートキーは大文字小文字、アクセント、およびロケール固有の調整を無視します。 そのため例えば [[=a=]]
は a, À, Á, Â, Ã, Ä, Å, A, à, á, â, ã, ä and å.
の任意の文字にマッチします。
ClassName(C++ only) ::
- ClassNameCharacter
- ClassNameCharacter ClassName
ClassNameCharacter(C++ only) ::
-
. = :
以外の SourceCharacter
This section is incomplete Reason: no example |