正規表現のvフラグ
ES2024でECMAScriptに追加された正規表現のvフラグについて調べた。
参考
https://v8.dev/features/regexp-v-flag
https://zenn.dev/pixiv/articles/54e5d29c54e7f5
https://webkit.org/blog/15443/news-from-wwdc24-webkit-in-safari-18-beta/#javascript
ECMAScriptの正規表現フラグ追加
ES2015
y フラグ
u フラグ
ES2018
s フラグ
ES2024
v フラグ
yフラグ: 粘着的正規表現(sticky)
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/RegExp/sticky
y フラグはこの正規表現が対象の文字列を lastIndex プロパティで示されたインデックスからのみ照合を試みることを示します(そしてグローバル正規表現とは異なり、それ以降のインデックスからの照合は試みません)。
code:js
const str1 = 'table football';
const regex1 = /foo/y;
regex1.lastIndex = 6;
console.log(regex1.test(str1));
// Expected output: true
console.log(regex1.test(str1));
// Expected output: false
uフラグ: Unicode関連機能を有効にする
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/RegExp/unicode
Unicode コードポイントエスケープ ( \u{xxxx}, \p{UnicodePropertyValue}) は、ID エスケープの代わりにそのように解釈されます。例えば、 /\u{61}/u は "a" に一致しますが、/\u{61}/ (u フラグなし)は "u".repeat(61) に一致します。 \u が u 1 文字と同等になるからです。
サロゲートペアは 2 つの別々の文字ではなく、全体の文字として解釈されます。例えば /😄/u は"😄" にのみ一致し、"\ud83d" には一致しません。
lastIndex が自動的に進む場合(exec() を呼び出した場合など)、Unicode 正規表現は UTF-16 コード単位ではなく Unicode コードポイント単位で進みます。
code:js
const regex1 = /\u{61}/;
const regex2 = /\u{61}/u;
console.log(regex1.test("a"));
// Expected output: "false"
console.log(regex2.test("a"));
// Expected output: "true"
sフラグ: dotAll
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/RegExp/dotAll
s フラグは、ドット特殊文字 (.) が追加で行末記号 ("newline") 文字と一致することを示します。これ以外の場合は一致しません。
code:js
const regex1 = /foo.bar/;
const regex2 = /foo.bar/s
console.log(regex1.test('foo\nbar'));
// Expected output: false
console.log(regex2.test('foo\nbar'));
// Expected output: true
vフラグ: Unicode機能アップグレード
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/RegExp/unicodeSets
v フラグは u フラグを「アップグレード」したもので、Unicode 関連の機能をより有効にするものです(u と v は同じ正規表現を互換性のない方法で解釈するので、両方のフラグを使用すると SyntaxError になります。)
v フラグを使用すると、u フラグの説明で述べたすべての機能に加えて、以下の機能が得られます。
\p エスケープシーケンスは、文字だけでなく、文字列のプロパティにも一致します。
文字クラス構文がアップグレードされ、複数の Unicode 文字の照合だけでなく、交差、和集合、差集合の構文ができるようになります。
文字クラスの補集合の構文 ^... は、一致結果を否定する代わりに補集合クラスを構築し、大文字小文字を区別しない照合との混乱を避けることができます。詳しくは 補集合クラスと大文字小文字を区別しない照合を参照してください。
https://2ality.com/2022/11/regexp-v-flag.html
code:js
const flag = "🇺🇳";
console.log(flag.length); // 2
console.log(/\p{RGI_Emoji_Flag_Sequence}/v.exec(flag)); // '🇺🇳'
\p: Unicode 文字クラスエスケープ
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Regular_expressions/Unicode_character_class_escape
指定できる文字クラス
https://tc39.es/ecma262/multipage/text-processing.html#table-binary-unicode-properties
vモードで増える文字列クラス
https://tc39.es/ecma262/multipage/text-processing.html#table-binary-unicode-properties-of-strings
vモード文字クラス
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Regular_expressions/Character_class#v_モード文字クラス
v フラグの最も重要な機能の 1 つは、文字クラス内での「セット表記」です。前回述べたように、通常の文字クラスは 2 つの範囲を連結することで論理和を発生させることができます。例えば、[A-Z0-9] を使用して「集合 [A-Z] と集合 [0-9] の論理和」を意味しています。しかし、交差や差のような文字集合を使った他の処理を表す簡単な方法はありません。
v フラグを使うと、交差は && で表現され、差集合は -- で表現されます。どちらもない場合は論理和となります。または -- の 2 つのオペランドは文字、文字エスケープ、文字クラスエスケープ、別の文字クラスのいずれかを取ることができます。例えば、「アンダースコアでない単語文字」を表すには [ \w--_] を使うことができます。
vモードまとめ
code:js
// Unicodeモード
console.log(/^🙂$/.test('🙂')); // false
console.log(/^🙂$/u.test('🙂')); // true
console.log(/^🙂$/v.test('🙂')); // true
// Unicode複数文字 \q
console.log(/^🇯🇵$/u.test('🇯🇵')); // false
console.log(/^\p{Emoji}$/v.test('🇯🇵')); // false
console.log(/^\q{🇯🇵}$/v.test('🇯🇵')); // true
// 文字列プロパティ
console.log(/^\p{RGI_Emoji_Flag_Sequence}$/v.test('🇯🇵')); // true
// 積集合・差集合
console.log(/\p{ASCII}&&\p{Decimal_Number}/v.test('4')) // true
console.log(/^\w--a$/v.test('a')) // false