Commit 1eecdf34 authored by Mathias Bynens's avatar Mathias Bynens Committed by Commit Bot

Update RegExp sequence property support

This patch aligns --harmony-regexp-sequence with the latest version of
the corresponding TC39 and Unicode proposals.

The list of supported properties has been changed:

- https://github.com/tc39/proposal-regexp-unicode-sequence-properties#proposed-solution
- https://unicode.org/reports/tr18/#Full_Properties

Furthermore, the Unicode data now uses Unicode v13.0.0 instead of v12.0.0.

Bug: v8:7467
Change-Id: I1ac386d87af68d68e84e919cb5ffc1313443844a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2497163Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Commit-Queue: Mathias Bynens <mathias@chromium.org>
Cr-Commit-Position: refs/heads/master@{#70752}
parent 165467c4
This diff is collapsed.
......@@ -14,9 +14,11 @@ namespace internal {
class UnicodePropertySequences : public AllStatic {
public:
static const uc32 kEmojiFlagSequences[];
static const uc32 kEmojiTagSequences[];
static const uc32 kEmojiZWJSequences[];
static const uc32 kBasicEmojis[];
static const uc32 kRGIEmojiModifierSequences[];
static const uc32 kRGIEmojiTagSequences[];
static const uc32 kRGIEmojiZWJSequences[];
static const uc32 kRGIEmojis[];
};
} // namespace internal
......
......@@ -1462,12 +1462,17 @@ RegExpTree* RegExpParser::GetPropertySequence(const ZoneVector<char>& name_1) {
const char* name = name_1.data();
const uc32* sequence_list = nullptr;
JSRegExp::Flags flags = JSRegExp::kUnicode;
if (NameEquals(name, "Emoji_Flag_Sequence")) {
sequence_list = UnicodePropertySequences::kEmojiFlagSequences;
} else if (NameEquals(name, "Emoji_Tag_Sequence")) {
sequence_list = UnicodePropertySequences::kEmojiTagSequences;
} else if (NameEquals(name, "Emoji_ZWJ_Sequence")) {
sequence_list = UnicodePropertySequences::kEmojiZWJSequences;
// https://github.com/tc39/proposal-regexp-unicode-sequence-properties#proposed-solution
if (NameEquals(name, "Basic_Emoji")) {
sequence_list = UnicodePropertySequences::kBasicEmojis;
} else if (NameEquals(name, "RGI_Emoji_Modifier_Sequence")) {
sequence_list = UnicodePropertySequences::kRGIEmojiModifierSequences;
} else if (NameEquals(name, "RGI_Emoji_Tag_Sequence")) {
sequence_list = UnicodePropertySequences::kRGIEmojiTagSequences;
} else if (NameEquals(name, "RGI_Emoji_ZWJ_Sequence")) {
sequence_list = UnicodePropertySequences::kRGIEmojiZWJSequences;
} else if (NameEquals(name, "RGI_Emoji")) {
sequence_list = UnicodePropertySequences::kRGIEmojis;
}
if (sequence_list != nullptr) {
// TODO(yangguo): this creates huge regexp code. Alternative to this is
......@@ -1484,40 +1489,6 @@ RegExpTree* RegExpParser::GetPropertySequence(const ZoneVector<char>& name_1) {
}
return builder.ToRegExp();
}
if (NameEquals(name, "Emoji_Keycap_Sequence")) {
// https://unicode.org/reports/tr51/#def_emoji_keycap_sequence
// emoji_keycap_sequence := [0-9#*] \x{FE0F 20E3}
RegExpBuilder builder(zone(), flags);
ZoneList<CharacterRange>* prefix_ranges =
zone()->New<ZoneList<CharacterRange>>(2, zone());
prefix_ranges->Add(CharacterRange::Range('0', '9'), zone());
prefix_ranges->Add(CharacterRange::Singleton('#'), zone());
prefix_ranges->Add(CharacterRange::Singleton('*'), zone());
builder.AddCharacterClass(
zone()->New<RegExpCharacterClass>(zone(), prefix_ranges, flags));
builder.AddCharacter(0xFE0F);
builder.AddCharacter(0x20E3);
return builder.ToRegExp();
} else if (NameEquals(name, "Emoji_Modifier_Sequence")) {
// https://unicode.org/reports/tr51/#def_emoji_modifier_sequence
// emoji_modifier_sequence := emoji_modifier_base emoji_modifier
RegExpBuilder builder(zone(), flags);
ZoneList<CharacterRange>* modifier_base_ranges =
zone()->New<ZoneList<CharacterRange>>(2, zone());
LookupPropertyValueName(UCHAR_EMOJI_MODIFIER_BASE, "Y", false,
modifier_base_ranges, zone());
builder.AddCharacterClass(
zone()->New<RegExpCharacterClass>(zone(), modifier_base_ranges, flags));
ZoneList<CharacterRange>* modifier_ranges =
zone()->New<ZoneList<CharacterRange>>(2, zone());
LookupPropertyValueName(UCHAR_EMOJI_MODIFIER, "Y", false, modifier_ranges,
zone());
builder.AddCharacterClass(
zone()->New<RegExpCharacterClass>(zone(), modifier_ranges, flags));
return builder.ToRegExp();
}
return nullptr;
}
......
This diff is collapsed.
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-regexp-sequence
// These tests have been generated by the script at
// https://gist.github.com/mathiasbynens/3b42c99a227521dabfe68d9e63f00f42.
// Do not modify this file directly!
const re = /\p{Emoji_Keycap_Sequence}/u;
assertTrue(re.test('#\uFE0F\u20E3'));
assertTrue(re.test('9\uFE0F\u20E3'));
assertTrue(re.test('0\uFE0F\u20E3'));
assertTrue(re.test('1\uFE0F\u20E3'));
assertTrue(re.test('2\uFE0F\u20E3'));
assertTrue(re.test('3\uFE0F\u20E3'));
assertTrue(re.test('*\uFE0F\u20E3'));
assertTrue(re.test('5\uFE0F\u20E3'));
assertTrue(re.test('6\uFE0F\u20E3'));
assertTrue(re.test('7\uFE0F\u20E3'));
assertTrue(re.test('8\uFE0F\u20E3'));
assertTrue(re.test('4\uFE0F\u20E3'));
This diff is collapsed.
// Copyright 2018 the V8 project authors. All rights reserved.
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-regexp-sequence
// TODO(mathias): Update these tests once a Unicode 12-friendly ICU
// version rolls into V8.
// These tests have been generated by the script at
// https://gist.github.com/mathiasbynens/3b42c99a227521dabfe68d9e63f00f42.
// Do not modify this file directly!
const re = /\p{Emoji_Modifier_Sequence}/u;
const re = /\p{RGI_Emoji_Modifier_Sequence}/u;
assertTrue(re.test('\u261D\u{1F3FB}'));
assertTrue(re.test('\u{1F9DD}\u{1F3FF}'));
assertTrue(re.test('\u261D\u{1F3FC}'));
assertTrue(re.test('\u261D\u{1F3FD}'));
assertTrue(re.test('\u261D\u{1F3FE}'));
assertTrue(re.test('\u261D\u{1F3FF}'));
......@@ -164,6 +165,21 @@ assertTrue(re.test('\u{1F469}\u{1F3FC}'));
assertTrue(re.test('\u{1F469}\u{1F3FD}'));
assertTrue(re.test('\u{1F469}\u{1F3FE}'));
assertTrue(re.test('\u{1F469}\u{1F3FF}'));
assertTrue(re.test('\u{1F46B}\u{1F3FB}'));
assertTrue(re.test('\u{1F46B}\u{1F3FC}'));
assertTrue(re.test('\u{1F46B}\u{1F3FD}'));
assertTrue(re.test('\u{1F46B}\u{1F3FE}'));
assertTrue(re.test('\u{1F46B}\u{1F3FF}'));
assertTrue(re.test('\u{1F46C}\u{1F3FB}'));
assertTrue(re.test('\u{1F46C}\u{1F3FC}'));
assertTrue(re.test('\u{1F46C}\u{1F3FD}'));
assertTrue(re.test('\u{1F46C}\u{1F3FE}'));
assertTrue(re.test('\u{1F46C}\u{1F3FF}'));
assertTrue(re.test('\u{1F46D}\u{1F3FB}'));
assertTrue(re.test('\u{1F46D}\u{1F3FC}'));
assertTrue(re.test('\u{1F46D}\u{1F3FD}'));
assertTrue(re.test('\u{1F46D}\u{1F3FE}'));
assertTrue(re.test('\u{1F46D}\u{1F3FF}'));
assertTrue(re.test('\u{1F46E}\u{1F3FB}'));
assertTrue(re.test('\u{1F46E}\u{1F3FC}'));
assertTrue(re.test('\u{1F46E}\u{1F3FD}'));
......@@ -274,7 +290,7 @@ assertTrue(re.test('\u{1F590}\u{1F3FC}'));
assertTrue(re.test('\u{1F590}\u{1F3FD}'));
assertTrue(re.test('\u{1F590}\u{1F3FE}'));
assertTrue(re.test('\u{1F590}\u{1F3FF}'));
assertTrue(re.test('\u261D\u{1F3FC}'));
assertTrue(re.test('\u{1F595}\u{1F3FB}'));
assertTrue(re.test('\u{1F595}\u{1F3FC}'));
assertTrue(re.test('\u{1F595}\u{1F3FD}'));
assertTrue(re.test('\u{1F595}\u{1F3FE}'));
......@@ -354,6 +370,16 @@ assertTrue(re.test('\u{1F6CC}\u{1F3FC}'));
assertTrue(re.test('\u{1F6CC}\u{1F3FD}'));
assertTrue(re.test('\u{1F6CC}\u{1F3FE}'));
assertTrue(re.test('\u{1F6CC}\u{1F3FF}'));
assertTrue(re.test('\u{1F90C}\u{1F3FB}'));
assertTrue(re.test('\u{1F90C}\u{1F3FC}'));
assertTrue(re.test('\u{1F90C}\u{1F3FD}'));
assertTrue(re.test('\u{1F90C}\u{1F3FE}'));
assertTrue(re.test('\u{1F90C}\u{1F3FF}'));
assertTrue(re.test('\u{1F90F}\u{1F3FB}'));
assertTrue(re.test('\u{1F90F}\u{1F3FC}'));
assertTrue(re.test('\u{1F90F}\u{1F3FD}'));
assertTrue(re.test('\u{1F90F}\u{1F3FE}'));
assertTrue(re.test('\u{1F90F}\u{1F3FF}'));
assertTrue(re.test('\u{1F918}\u{1F3FB}'));
assertTrue(re.test('\u{1F918}\u{1F3FC}'));
assertTrue(re.test('\u{1F918}\u{1F3FD}'));
......@@ -454,6 +480,11 @@ assertTrue(re.test('\u{1F93E}\u{1F3FC}'));
assertTrue(re.test('\u{1F93E}\u{1F3FD}'));
assertTrue(re.test('\u{1F93E}\u{1F3FE}'));
assertTrue(re.test('\u{1F93E}\u{1F3FF}'));
assertTrue(re.test('\u{1F977}\u{1F3FB}'));
assertTrue(re.test('\u{1F977}\u{1F3FC}'));
assertTrue(re.test('\u{1F977}\u{1F3FD}'));
assertTrue(re.test('\u{1F977}\u{1F3FE}'));
assertTrue(re.test('\u{1F977}\u{1F3FF}'));
assertTrue(re.test('\u{1F9B5}\u{1F3FB}'));
assertTrue(re.test('\u{1F9B5}\u{1F3FC}'));
assertTrue(re.test('\u{1F9B5}\u{1F3FD}'));
......@@ -474,6 +505,26 @@ assertTrue(re.test('\u{1F9B9}\u{1F3FC}'));
assertTrue(re.test('\u{1F9B9}\u{1F3FD}'));
assertTrue(re.test('\u{1F9B9}\u{1F3FE}'));
assertTrue(re.test('\u{1F9B9}\u{1F3FF}'));
assertTrue(re.test('\u{1F9BB}\u{1F3FB}'));
assertTrue(re.test('\u{1F9BB}\u{1F3FC}'));
assertTrue(re.test('\u{1F9BB}\u{1F3FD}'));
assertTrue(re.test('\u{1F9BB}\u{1F3FE}'));
assertTrue(re.test('\u{1F9BB}\u{1F3FF}'));
assertTrue(re.test('\u{1F9CD}\u{1F3FB}'));
assertTrue(re.test('\u{1F9CD}\u{1F3FC}'));
assertTrue(re.test('\u{1F9CD}\u{1F3FD}'));
assertTrue(re.test('\u{1F9CD}\u{1F3FE}'));
assertTrue(re.test('\u{1F9CD}\u{1F3FF}'));
assertTrue(re.test('\u{1F9CE}\u{1F3FB}'));
assertTrue(re.test('\u{1F9CE}\u{1F3FC}'));
assertTrue(re.test('\u{1F9CE}\u{1F3FD}'));
assertTrue(re.test('\u{1F9CE}\u{1F3FE}'));
assertTrue(re.test('\u{1F9CE}\u{1F3FF}'));
assertTrue(re.test('\u{1F9CF}\u{1F3FB}'));
assertTrue(re.test('\u{1F9CF}\u{1F3FC}'));
assertTrue(re.test('\u{1F9CF}\u{1F3FD}'));
assertTrue(re.test('\u{1F9CF}\u{1F3FE}'));
assertTrue(re.test('\u{1F9CF}\u{1F3FF}'));
assertTrue(re.test('\u{1F9D1}\u{1F3FB}'));
assertTrue(re.test('\u{1F9D1}\u{1F3FC}'));
assertTrue(re.test('\u{1F9D1}\u{1F3FD}'));
......@@ -538,4 +589,4 @@ assertTrue(re.test('\u{1F9DD}\u{1F3FB}'));
assertTrue(re.test('\u{1F9DD}\u{1F3FC}'));
assertTrue(re.test('\u{1F9DD}\u{1F3FD}'));
assertTrue(re.test('\u{1F9DD}\u{1F3FE}'));
assertTrue(re.test('\u{1F595}\u{1F3FB}'));
assertTrue(re.test('\u{1F9DD}\u{1F3FF}'));
// Copyright 2019 the V8 project authors. All rights reserved.
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
......@@ -8,7 +8,7 @@
// https://gist.github.com/mathiasbynens/3b42c99a227521dabfe68d9e63f00f42.
// Do not modify this file directly!
const re = /\p{Emoji_Tag_Sequence}/u;
const re = /\p{RGI_Emoji_Tag_Sequence}/u;
assertTrue(re.test('\u{1F3F4}\u{E0067}\u{E0062}\u{E0065}\u{E006E}\u{E0067}\u{E007F}'));
assertTrue(re.test('\u{1F3F4}\u{E0067}\u{E0062}\u{E0073}\u{E0063}\u{E0074}\u{E007F}'));
......
......@@ -5,84 +5,90 @@
// Flags: --harmony-regexp-sequence
// Normal usage.
assertDoesNotThrow("/\\p{Emoji_Flag_Sequence}/u");
assertTrue(/\p{Emoji_Flag_Sequence}/u.test("\u{1F1E9}\u{1F1EA}"));
assertDoesNotThrow("/\\p{Basic_Emoji}/u");
assertTrue(/\p{Basic_Emoji}/u.test("\u{1F6E2}\uFE0F"));
assertDoesNotThrow("/\\p{Emoji_Keycap_Sequence}/u");
assertTrue(/\p{Emoji_Keycap_Sequence}/u.test("\u0023\uFE0F\u20E3"));
assertDoesNotThrow("/\\p{RGI_Emoji}/u");
assertTrue(/\p{RGI_Emoji}/u.test("\u{1F1E9}\u{1F1EA}"));
assertTrue(/\p{RGI_Emoji}/u.test("\u0023\uFE0F\u20E3"));
assertDoesNotThrow("/\\p{Emoji_Keycap_Sequence}/u");
assertFalse(/\p{Emoji_Keycap_Sequence}/u.test("\u0022\uFE0F\u20E3"));
assertDoesNotThrow("/\\p{RGI_Emoji_Modifier_Sequence}/u");
assertTrue(/\p{RGI_Emoji_Modifier_Sequence}/u.test("\u26F9\u{1F3FF}"));
assertDoesNotThrow("/\\p{Emoji_Modifier_Sequence}/u");
assertTrue(/\p{Emoji_Modifier_Sequence}/u.test("\u26F9\u{1F3FF}"));
assertDoesNotThrow("/\\p{RGI_Emoji_ZWJ_Sequence}/u");
assertTrue(/\p{RGI_Emoji_ZWJ_Sequence}/u.test("\u{1F468}\u{200D}\u{1F467}"));
assertDoesNotThrow("/\\p{Emoji_ZWJ_Sequence}/u");
assertTrue(/\p{Emoji_ZWJ_Sequence}/u.test("\u{1F468}\u{200D}\u{1F467}"));
// Without unicode flag.
assertDoesNotThrow("/\\p{Emoji_Flag_Sequence}/");
assertFalse(/\p{Emoji_Flag_Sequence}/.test("\u{1F1E9}\u{1F1EA}"));
assertTrue(/\p{Emoji_Flag_Sequence}/.test("\\p{Emoji_Flag_Sequence}"));
// Without Unicode flag.
assertDoesNotThrow("/\\p{RGI_Emoji}/");
assertFalse(/\p{RGI_Emoji}/.test("\u{1F1E9}\u{1F1EA}"));
assertTrue(/\p{RGI_Emoji}/.test("\\p{RGI_Emoji}"));
// Negated and/or inside a character class.
assertThrows("/\\P{Emoji_Flag_Sequence}/u");
assertThrows("/\\P{Emoji_Keycap_Sequence}/u");
assertThrows("/\\P{Emoji_Modifier_Sequence}/u");
assertThrows("/\\P{Emoji_Tag_Sequence}/u");
assertThrows("/\\P{Emoji_ZWJ_Sequence}/u");
assertThrows("/[\\p{Emoji_Flag_Sequence}]/u");
assertThrows("/[\\p{Emoji_Keycap_Sequence}]/u");
assertThrows("/[\\p{Emoji_Modifier_Sequence}]/u");
assertThrows("/[\\p{Emoji_Tag_Sequence}]/u");
assertThrows("/[\\p{Emoji_ZWJ_Sequence}]/u");
assertThrows("/[\\P{Emoji_Flag_Sequence}]/u");
assertThrows("/[\\P{Emoji_Keycap_Sequence}]/u");
assertThrows("/[\\P{Emoji_Modifier_Sequence}]/u");
assertThrows("/[\\P{Emoji_Tag_Sequence}]/u");
assertThrows("/[\\P{Emoji_ZWJ_Sequence}]/u");
assertThrows("/[\\w\\p{Emoji_Flag_Sequence}]/u");
assertThrows("/[\\w\\p{Emoji_Keycap_Sequence}]/u");
assertThrows("/[\\w\\p{Emoji_Modifier_Sequence}]/u");
assertThrows("/[\\w\\p{Emoji_Tag_Sequence}]/u");
assertThrows("/[\\w\\p{Emoji_ZWJ_Sequence}]/u");
assertThrows("/[\\w\\P{Emoji_Flag_Sequence}]/u");
assertThrows("/[\\w\\P{Emoji_Keycap_Sequence}]/u");
assertThrows("/[\\w\\P{Emoji_Modifier_Sequence}]/u");
assertThrows("/[\\w\\P{Emoji_Tag_Sequence}]/u");
assertThrows("/[\\w\\P{Emoji_ZWJ_Sequence}]/u");
assertThrows("/\\P{Basic_Emoji}/u");
assertThrows("/\\P{RGI_Emoji_Modifier_Sequence}/u");
assertThrows("/\\P{RGI_Emoji_Tag_Sequence}/u");
assertThrows("/\\P{RGI_Emoji_ZWJ_Sequence}/u");
assertThrows("/\\P{RGI_Emoji}/u");
assertThrows("/[\\p{Basic_Emoji}]/u");
assertThrows("/[\\p{RGI_Emoji_Modifier_Sequence}]/u");
assertThrows("/[\\p{RGI_Emoji_Tag_Sequence}]/u");
assertThrows("/[\\p{RGI_Emoji_ZWJ_Sequence}]/u");
assertThrows("/[\\p{RGI_Emoji}]/u");
assertThrows("/[\\P{Basic_Emoji}]/u");
assertThrows("/[\\P{RGI_Emoji_Modifier_Sequence}]/u");
assertThrows("/[\\P{RGI_Emoji_Tag_Sequence}]/u");
assertThrows("/[\\P{RGI_Emoji_ZWJ_Sequence}]/u");
assertThrows("/[\\P{RGI_Emoji}]/u");
assertThrows("/[\\w\\p{Basic_Emoji}]/u");
assertThrows("/[\\w\\p{RGI_Emoji_Modifier_Sequence}]/u");
assertThrows("/[\\w\\p{RGI_Emoji_Tag_Sequence}]/u");
assertThrows("/[\\w\\p{RGI_Emoji_ZWJ_Sequence}]/u");
assertThrows("/[\\w\\p{RGI_Emoji}]/u");
assertThrows("/[\\w\\P{Basic_Emoji}]/u");
assertThrows("/[\\w\\P{RGI_Emoji_Modifier_Sequence}]/u");
assertThrows("/[\\w\\P{RGI_Emoji_Tag_Sequence}]/u");
assertThrows("/[\\w\\P{RGI_Emoji_ZWJ_Sequence}]/u");
assertThrows("/[\\w\\P{RGI_Emoji}]/u");
// Two regional indicators, but not a country.
assertFalse(/\p{Emoji_Flag_Sequence}/u.test("\u{1F1E6}\u{1F1E6}"));
assertFalse(/\p{RGI_Emoji}/u.test("\u{1F1E6}\u{1F1E6}"));
// ZWJ sequence as in two ZWJ elements joined by a ZWJ, but not in the list.
assertFalse(/\p{Emoji_ZWJ_Sequence}/u.test("\u{1F467}\u{200D}\u{1F468}"));
assertFalse(/\p{RGI_Emoji_ZWJ_Sequence}/u.test("\u{1F467}\u{200D}\u{1F468}"));
// Unsupported properties.
assertThrows("/\\p{Emoji_Flag_Sequence}/u");
assertThrows("/\\p{Emoji_Keycap_Sequence}/u");
assertThrows("/\\p{Emoji_Modifier_Sequence}/u");
assertThrows("/\\p{Emoji_Tag_Sequence}/u");
assertThrows("/\\p{Emoji_ZWJ_Sequence}/u");
// More complex regexp
// More complex regexp.
assertEquals(
["country flag: \u{1F1E6}\u{1F1F9}"],
/Country Flag: \p{Emoji_Flag_Sequence}/iu.exec(
/Country Flag: \p{RGI_Emoji}/iu.exec(
"this is an example of a country flag: \u{1F1E6}\u{1F1F9} is Austria"));
assertEquals(
["country flag: \u{1F1E6}\u{1F1F9}", "\u{1F1E6}\u{1F1F9}"],
/Country Flag: (\p{Emoji_Flag_Sequence})/iu.exec(
/Country Flag: (\p{RGI_Emoji})/iu.exec(
"this is an example of a country flag: \u{1F1E6}\u{1F1F9} is Austria"));
assertEquals(
["country flag: \u{1F1E6}\u{1F1F9}"],
/Country Flag: ..(?<=\p{Emoji_Flag_Sequence})/iu.exec(
/Country Flag: ..(?<=\p{RGI_Emoji})/iu.exec(
"this is an example of a country flag: \u{1F1E6}\u{1F1F9} is Austria"));
assertEquals(
["flag: \u{1F1E6}\u{1F1F9}", "\u{1F1E6}\u{1F1F9}"],
/Flag: ..(?<=(\p{Emoji_Flag_Sequence})|\p{Emoji_Keycap_Sequence})/iu.exec(
/Flag: ..(?<=(\p{RGI_Emoji})|\p{Basic_Emoji})/iu.exec(
"this is an example of a country flag: \u{1F1E6}\u{1F1F9} is Austria"));
// Partial sequences.
assertFalse(/\p{Emoji_Flag_Sequence}/u.test("\u{1F1E6}_"));
assertFalse(/\p{Emoji_Keycap_Sequence}/u.test("2\uFE0F_"));
assertFalse(/\p{Emoji_Modifier_Sequence}/u.test("\u261D_"));
assertFalse(/\p{Emoji_Tag_Sequence}/u.test("\u{1F3F4}\u{E0067}\u{E0062}\u{E0065}\u{E006E}\u{E0067}_"));
assertFalse(/\p{Emoji_ZWJ_Sequence}/u.test("\u{1F468}\u200D\u2764\uFE0F\u200D_"));
assertFalse(/\p{Basic_Emoji}/u.test("\u{1F6E2}_"));
assertFalse(/\p{RGI_Emoji_Modifier_Sequence}/u.test("\u261D_"));
assertFalse(/\p{RGI_Emoji_Tag_Sequence}/u.test("\u{1F3F4}\u{E0067}\u{E0062}\u{E0065}\u{E006E}\u{E0067}_"));
assertFalse(/\p{RGI_Emoji_ZWJ_Sequence}/u.test("\u{1F468}\u200D\u2764\uFE0F\u200D_"));
assertFalse(/\p{RGI_Emoji}/u.test("\u{1F1E6}_"));
assertFalse(/\p{RGI_Emoji}/u.test("2\uFE0F_"));
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment