From 19afa9daff2596f9f362409da63b992bcf8626c2 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Tue, 25 Jun 2024 05:54:11 -0700 Subject: [PATCH 01/61] updates --- .../Texl/Builtins/Match.cs | 84 ++++++++++++++++++- .../ExpressionTestCases/Match_Limited.txt | 35 ++++++++ 2 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index 83f2945e2d..ff3f646719 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Globalization; using System.Text.RegularExpressions; using Microsoft.PowerFx.Core.App.ErrorContainers; using Microsoft.PowerFx.Core.Binding; @@ -87,7 +88,88 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp } string regularExpression = nodeValue; - return fValid && TryCreateReturnType(regExNode, regularExpression, errors, ref returnType); + fValid &= LimitRegularExpression(regExNode, regularExpression, errors); + fValid &= TryCreateReturnType(regExNode, regularExpression, errors, ref returnType); + return fValid; + } + + // Disallow self referncing groups and consitently treat all "\[1-9][0-9]*" as a backreference. + // This avoids inconsistencies between .net and JavaScript regular expression behavior + // while maintaining Unicode definition of words, by avoiding the use of RegexOptions.ECMAScript. + // See https://learn.microsoft.com/en-us/dotnet/standard/base-types/regular-expression-options#ecmascript-matching-behavior + private bool LimitRegularExpression(TexlNode regExNode, string regexPattern, IErrorContainer errors) + { + // scans the regular expression, counting capture groups and comparing with backreference numbers. + var groupPunctuationRE = new Regex( + @"( + \\(\d+)| # valid backreference or octal character is accepted, others are an error + \\[^\d]| # any other escaped character is ignored, but must be paired so that '\\(' is seen as '\\' followed by '(' + \(|\)| # parens that aren't escaped that could start/end a group, provided they are outside a character class + \[|\] # character class start/end + )", RegexOptions.IgnorePatternWhitespace); + var groupStack = new Stack(); // int is the group number, -1 is used for non capturing groups + var groupCounter = 0; // last group number defined + var openCharacterClass = false; // are we inside square brackets where parens do not need to be escaped? + + foreach (Match groupMatch in groupPunctuationRE.Matches(regexPattern)) + { + switch (groupMatch.Value[0]) + { + case '\\': + // backslash with anything but digits is always accepted + // octal characters are accepted that start with a '0' + if (groupMatch.Groups[2].Value != string.Empty && groupMatch.Groups[2].Value[0] != '0') + { + int backslashNum = Convert.ToInt32(groupMatch.Groups[2].Value, CultureInfo.InvariantCulture); + + // group isn't defined, or not defined yet + if (backslashNum > groupCounter) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegEx); + return false; + } + + // group is not closed and thus self referencing + if (groupStack.Contains(backslashNum)) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegEx); + return false; + } + } + + break; + + case '(': + // parens do not need to be escaped within square brackets + if (!openCharacterClass) + { + // non capturing group still needs to match closing paren, but does not define a new group + groupStack.Push(groupMatch.Value.StartsWith("(?:", StringComparison.InvariantCulture) ? -1 : ++groupCounter); + } + + break; + + case ')': + // parens do not need to be escaped within square brackets + if (!openCharacterClass) + { + groupStack.Pop(); + } + + break; + + case '[': + // note that square brackets do not nest, "[[]]" is "[[]" followed by the character "]" + openCharacterClass = true; + break; + + case ']': + openCharacterClass = false; + break; + } + } + + return true; } // Creates a typed result: [Match:s, Captures:*[Value:s], NamedCaptures:r[:s]] diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt new file mode 100644 index 0000000000..816f0d9518 --- /dev/null +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt @@ -0,0 +1,35 @@ +#SETUP: RegEx + +// For conssitent regular expressions across hosts, these tests check that we are +// limiting .NET regular expresions to what we can also support in JavaScript with XRegExp +// See https://learn.microsoft.com/en-us/dotnet/standard/base-types/regular-expression-options#ecmascript-matching-behavior +// We run without the RegexOptions.ECMASScript because we want Unicode letters for words + +// Unicode letters as word characters is allowed + +>> Match( "the whole world", "\b(\w+\s*)+" ) +{FullMatch:"the whole world",StartMatch:1,SubMatches:Table({Value:"world"})} + +>> Match( "целый мир", "\b(\w+\s*)+" ) +{FullMatch:"целый мир",StartMatch:1,SubMatches:Table({Value:"мир"})} + +>> Match( "el niño", "\b(\w+\s*)+" ) +{FullMatch:"el niño",StartMatch:1,SubMatches:Table({Value:"niño"})} + +// Self referncing groups are disallowed + +>> Match( "aa aaaa aaaaaa ", "((a+)(\1) ?)+" ) +Errors: Error 26-41: Invalid regular expression.|Error 0-5: The function 'Match' has some invalid arguments. + +// Backreferences without a group are disallowed + +>> Match( "hello howdy", "([hi]).*\1" ) +{FullMatch:"hello h",StartMatch:1,SubMatches:Table({Value:"h"})} + +>> Match( "hello howdy", "([hi]).*\2" ) +Errors: Error 22-34: Invalid regular expression.|Error 0-5: The function 'Match' has some invalid arguments. + +// Octal characters are allowed + +>> Match( "as$df", "\044" ) +{FullMatch:"$",StartMatch:3,SubMatches:Table()} From 0016eb8d31dee3769005ca83ea07239bbc2550ee Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Mon, 1 Jul 2024 13:39:37 -0700 Subject: [PATCH 02/61] Updates --- .../Localization/Strings.cs | 11 + .../Texl/Builtins/Match.cs | 184 +- src/strings/PowerFxResources.en-US.resx | 40 + .../ExpressionTestCases/Match_Limited.txt | 60 +- .../ExpressionTestCases/rust_fx.txt | 1534 +++++++++++++++++ ...rosoft.PowerFx.Core.Tests.Shared.projitems | 10 - .../FileExpressionEvaluationTests.cs | 5 +- 7 files changed, 1776 insertions(+), 68 deletions(-) create mode 100644 src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/rust_fx.txt diff --git a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs index d4b4021b31..1e9fc163a0 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs @@ -721,6 +721,17 @@ internal static class TexlStrings public static ErrorResourceKey ErrDecimalRequiresPowerFxV1 = new ErrorResourceKey("ErrDecimalNeedsPowerFxV1"); public static ErrorResourceKey ErrInvalidRegEx = new ErrorResourceKey("ErrInvalidRegEx"); + public static ErrorResourceKey ErrInvalidRegExBadOptions = new ErrorResourceKey("ErrInvalidRegExBadOptions"); + public static ErrorResourceKey ErrInvalidRegExBadOptionsNotAtFront = new ErrorResourceKey("ErrInvalidRegExBadOptionsNotAtFront"); + public static ErrorResourceKey ErrInvalidRegExBadOctal = new ErrorResourceKey("ErrInvalidRegExBadOctal"); + public static ErrorResourceKey ErrInvalidRegExBadBackRefSelfReferencing = new ErrorResourceKey("ErrInvalidRegExBadBackRefSelfReferencing"); + public static ErrorResourceKey ErrInvalidRegExBadBackRefNotDefined = new ErrorResourceKey("ErrInvalidRegExBadBackRefNotDefined"); + public static ErrorResourceKey ErrInvalidRegExBadBalancing = new ErrorResourceKey("ErrInvalidRegExBadBalancing"); + public static ErrorResourceKey ErrInvalidRegExBadSingleQuoteNamedCapture = new ErrorResourceKey("ErrInvalidRegExBadSingleQuoteNamedCapture"); + public static ErrorResourceKey ErrInvalidRegExBadEscape = new ErrorResourceKey("ErrInvalidRegExBadEscape"); + public static ErrorResourceKey ErrInvalidRegExBadCharacterClassSubtraction = new ErrorResourceKey("ErrInvalidRegExBadCharacterClassSubtraction"); + public static ErrorResourceKey ErrInvalidRegExBadConditional = new ErrorResourceKey("ErrInvalidRegExBadBadConditional"); + public static ErrorResourceKey ErrVariableRegEx = new ErrorResourceKey("ErrVariableRegEx"); public static ErrorResourceKey InfoRegExCaptureNameHidesPredefinedFullMatchField = new ErrorResourceKey("InfoRegExCaptureNameHidesPredefinedFullMatchField"); public static ErrorResourceKey InfoRegExCaptureNameHidesPredefinedSubMatchesField = new ErrorResourceKey("InfoRegExCaptureNameHidesPredefinedSubMatchesField"); diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index ff3f646719..81ffa4ac83 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -99,73 +99,153 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp // See https://learn.microsoft.com/en-us/dotnet/standard/base-types/regular-expression-options#ecmascript-matching-behavior private bool LimitRegularExpression(TexlNode regExNode, string regexPattern, IErrorContainer errors) { + // todo: + // group range // scans the regular expression, counting capture groups and comparing with backreference numbers. var groupPunctuationRE = new Regex( - @"( - \\(\d+)| # valid backreference or octal character is accepted, others are an error - \\[^\d]| # any other escaped character is ignored, but must be paired so that '\\(' is seen as '\\' followed by '(' - \(|\)| # parens that aren't escaped that could start/end a group, provided they are outside a character class - \[|\] # character class start/end - )", RegexOptions.IgnorePatternWhitespace); - var groupStack = new Stack(); // int is the group number, -1 is used for non capturing groups + @" + (?\\(?:(?[1-9]\d*)|k<(?\w+)>)) | # valid backreference are accepted, others are an error + (?\\0[0-7]{0,3}) | + # any other escaped character is ignored, but must be paired so that '\\(' is seen as '\\' followed by '(' + (?\\(?:[bBtrvfnwWsSdD]|[pP]\{\w+\}|c[a-zA-Z]|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4})) | # missing are AaeGZz that are not supported with XRegExp, other common are u{} and o + (?\\[a-zA-Z_]) | + (?\\.) | # any other escaped character is ignored, but must be paired so that '\\(' is seen as '\\' followed by '(' and not '\' folloed by '\(' + + (?^\(\?[imns]+\)) | + (?\(\?<(\w+)>) | + (?\(\?:) | + (?\(\?(?:\w*-\w+|\w+)(?::|\))?) | + (?\(\?(?:<|')\w*-\w+(?:>|')?) | + (?\(\?'\w+'?) | + (?\(\?\(\?) | + + (?\() | + (?\)) | # parens that aren't escaped that could start/end a group, provided they are outside a character class + (?\[) | + (?\]) # character class start/end + ", RegexOptions.IgnorePatternWhitespace); + var groupNumStack = new Stack(); // int is the group number, -1 is used for non capturing groups + var groupNameDict = new Dictionary(); var groupCounter = 0; // last group number defined var openCharacterClass = false; // are we inside square brackets where parens do not need to be escaped? foreach (Match groupMatch in groupPunctuationRE.Matches(regexPattern)) { - switch (groupMatch.Value[0]) + if (groupMatch.Groups["backRefNum"].Success) { - case '\\': - // backslash with anything but digits is always accepted - // octal characters are accepted that start with a '0' - if (groupMatch.Groups[2].Value != string.Empty && groupMatch.Groups[2].Value[0] != '0') - { - int backslashNum = Convert.ToInt32(groupMatch.Groups[2].Value, CultureInfo.InvariantCulture); - - // group isn't defined, or not defined yet - if (backslashNum > groupCounter) - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegEx); - return false; - } - - // group is not closed and thus self referencing - if (groupStack.Contains(backslashNum)) - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegEx); - return false; - } - } + var backRefNum = int.Parse(groupMatch.Groups["backRefNum"].Value, CultureInfo.InvariantCulture); - break; + // group isn't defined, or not defined yet + if (backRefNum > groupCounter) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefNotDefined, groupMatch.Groups["backRef"].Value); + return false; + } - case '(': - // parens do not need to be escaped within square brackets - if (!openCharacterClass) - { - // non capturing group still needs to match closing paren, but does not define a new group - groupStack.Push(groupMatch.Value.StartsWith("(?:", StringComparison.InvariantCulture) ? -1 : ++groupCounter); - } + // group is not closed and thus self referencing + if (groupNumStack.Contains(backRefNum)) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefSelfReferencing, groupMatch.Groups["backRef"].Value); + return false; + } + } + else if (groupMatch.Groups["backRefName"].Success) + { + var backRefName = groupMatch.Groups["backRefName"].Value; - break; + // group isn't defined, or not defined yet + if (!groupNameDict.TryGetValue(groupMatch.Groups["backRefName"].Value, out var groupNum)) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefNotDefined, groupMatch.Groups["backRef"].Value); + return false; + } - case ')': - // parens do not need to be escaped within square brackets - if (!openCharacterClass) + // group is not closed and thus self referencing + if (groupNumStack.Contains(groupNum)) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefSelfReferencing, groupMatch.Groups["backRef"].Value); + return false; + } + } + else if (groupMatch.Groups["badOctal"].Success) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadOctal, groupMatch.Groups["badOctal"].Value); + return false; + } + else if (groupMatch.Groups["badBalancing"].Success) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBalancing, groupMatch.Groups["badBalancing"].Value); + return false; + } + else if (groupMatch.Groups["badOptions"].Success) + { + if (groupMatch.Groups["badOptions"].Index > 0) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadOptionsNotAtFront, groupMatch.Groups["badOptions"].Value); + } + else + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadOptions, groupMatch.Groups["badOptions"].Value); + } + + return false; + } + else if (groupMatch.Groups["badSingleQuoteNamedCapture"].Success) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadSingleQuoteNamedCapture, groupMatch.Groups["badSingleQuoteNamedCapture"].Value); + return false; + } + else if (groupMatch.Groups["badConditional"].Success) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadConditional, groupMatch.Groups["badConditional"].Value); + return false; + } + else if (groupMatch.Groups["badEscapeAlpha"].Success) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadEscape, groupMatch.Groups["badEscapeAlpha"].Value); + return false; + } + else if (groupMatch.Groups["openCapture"].Success || groupMatch.Groups["goodNonCapture"].Success || groupMatch.Groups["goodNamedCapture"].Success) + { + // parens do not need to be escaped within square brackets + if (!openCharacterClass) + { + // non capturing group still needs to match closing paren, but does not define a new group + groupNumStack.Push(groupMatch.Groups["goodNonCapture"].Success ? -1 : ++groupCounter); + if (groupMatch.Groups["goodNamedCapture"].Success) { - groupStack.Pop(); + groupNameDict.Add(groupMatch.Groups["goodNamedCapture"].Value, groupCounter); } + } + } + else if (groupMatch.Groups["closeCapture"].Success) + { + if (!openCharacterClass) + { + groupNumStack.Pop(); + } + } + else if (groupMatch.Groups["openCharacterClass"].Success) + { + if (openCharacterClass) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadCharacterClassSubtraction); + return false; + } - break; - - case '[': - // note that square brackets do not nest, "[[]]" is "[[]" followed by the character "]" - openCharacterClass = true; - break; - - case ']': - openCharacterClass = false; - break; + openCharacterClass = true; + } + else if (groupMatch.Groups["closeCharacterClass"].Success) + { + openCharacterClass = false; + } + else if (groupMatch.Groups["goodEescape"].Success || groupMatch.Groups["goodEscapeAlpha"].Success || groupMatch.Groups["goodOptions"].Success) + { + // all is well, nothing to do + } + else + { + throw new NotImplementedException("Internal error in LimitRegularExpression"); } } diff --git a/src/strings/PowerFxResources.en-US.resx b/src/strings/PowerFxResources.en-US.resx index 5e8a9161df..78a094f9a7 100644 --- a/src/strings/PowerFxResources.en-US.resx +++ b/src/strings/PowerFxResources.en-US.resx @@ -4375,6 +4375,46 @@ Invalid regular expression. Error message indicating that the regular expression entered by the user is invalid. + + Invalid regular expression: Inline options must appear at the beginning of the regular expression; found "{0}" later. + Error message indicating that the regular expression has inline options not at the front. + + + Invalid regular expression: Inline options are limited to a combination of the letters [imns], cannot disable options, and cannot be used on a subexpression; found "{0}". + Error message indicating that the regular expression has bad inline options. + + + Invalid regular expression: Octal \0 character codes are not supported, use hexadecimal \x or Unicode \u instead; found "{0}". + Error message indicating that the regular expression has octal characters. + + + Invalid regular expression: Invalid escape code; found "{0}". + Error message indicating that the regular expression has an invalid alphanumeric escape code. + + + Invalid regular expression: Character class subtraction is not supported. + Error message indicating that the regular expression does not support character class subtraction. + + + Invalid regular expression: Capture group "{0}" not defined. + Error message indicating that the regular expression capture group is not defined. + + + Invalid regular expression: Self-referencing capture groups are not supported; found "{0}". + Error message indicating that the regular expression has self-referencing capture groups. + + + Invalid regular expression: Balancing capture groups is not supported; found "{0}". + Error message indicating that the regular expression has balancing capture groups. + + + Invalid regular expression: Using single quoted named captures is not supported, use (?<...>) syntax instead; found "{0}". + Error message indicating that the regular expression has single quoted named capture. + + + Invalid regular expression: Conditionals are not supported; found "{0}". + Error message indicating that the regular expression has conditionals. + Regular expressions must be constant values. Error Message. diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt index 816f0d9518..9e7f20edf2 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt @@ -16,10 +16,15 @@ >> Match( "el niño", "\b(\w+\s*)+" ) {FullMatch:"el niño",StartMatch:1,SubMatches:Table({Value:"niño"})} +>> Match( "Müller", "^\w+$" ) +{FullMatch:"Müller",StartMatch:1,SubMatches:Table()} + // Self referncing groups are disallowed >> Match( "aa aaaa aaaaaa ", "((a+)(\1) ?)+" ) -Errors: Error 26-41: Invalid regular expression.|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 26-41: Invalid regular expression: Self-referencing capture groups are not supported; found "\1".|Error 0-5: The function 'Match' has some invalid arguments. + +// named self reference? // Backreferences without a group are disallowed @@ -27,9 +32,56 @@ Errors: Error 26-41: Invalid regular expression.|Error 0-5: The function 'Match' {FullMatch:"hello h",StartMatch:1,SubMatches:Table({Value:"h"})} >> Match( "hello howdy", "([hi]).*\2" ) -Errors: Error 22-34: Invalid regular expression.|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 22-34: Invalid regular expression: Capture group "\2" not defined.|Error 0-5: The function 'Match' has some invalid arguments. -// Octal characters are allowed +// Octal characters are not allowed >> Match( "as$df", "\044" ) -{FullMatch:"$",StartMatch:3,SubMatches:Table()} +Errors: Error 16-22: Invalid regular expression: Octal \0 character codes are not supported, use hexadecimal \x or Unicode \u instead; found "\044".|Error 0-5: The function 'Match' has some invalid arguments. + +// options are allowed at the front of the regular expression only + +>> Match( "hello"&Char(10)&"howdy", "o$" ) +Blank() + +>> Match( "hello"&Char(10)&"howdy", "o$", MatchOptions.Multiline ) +{FullMatch:"o",StartMatch:5,SubMatches:Table()} + +>> Match( "hello"&Char(10)&"howdy", "(?im)o$" ) +{FullMatch:"o",StartMatch:5,SubMatches:Table()} + +>> Match( "hello"&Char(10)&"howdy", "(?m)o$" ) +{FullMatch:"o",StartMatch:5,SubMatches:Table()} + +>> Match( "hello"&Char(10)&"howdy", "(?-m)o$" ) +Errors: Error 33-42: Invalid regular expression: Inline options are limited to a combination of the letters [imns], cannot disable options, and cannot be used on a subexpression; found "(?-m)".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "hello"&Char(10)&"howdy", "(?i-m)o$" ) +Errors: Error 33-43: Invalid regular expression: Inline options are limited to a combination of the letters [imns], cannot disable options, and cannot be used on a subexpression; found "(?i-m)".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "hello"&Char(10)&"howdy", "^(?m)o$" ) +Errors: Error 33-42: Invalid regular expression: Inline options must appear at the beginning of the regular expression; found "(?m)" later.|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "hello"&Char(10)&"howdy", "^(?i-m)o$" ) +Errors: Error 33-44: Invalid regular expression: Inline options must appear at the beginning of the regular expression; found "(?i-m)" later.|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "hello"&Char(10)&"howdy", "^(?m:o$)" ) +Errors: Error 33-43: Invalid regular expression: Inline options must appear at the beginning of the regular expression; found "(?m:" later.|Error 0-5: The function 'Match' has some invalid arguments. + +// inline options overriding explicit options, conflicts? + +// balancing groups + +>> Match( "(hello world)", "(?)a") +Errors: Error 24-35: Invalid regular expression: Balancing capture groups is not supported; found "(?".|Error 0-5: The function 'Match' has some invalid arguments. + +// groups with single ticks + +>> Match( "(hello wrold)", "(?'name'l)") +Errors: Error 24-36: Invalid regular expression: Using single quoted named captures is not supported, use (?<...>) syntax instead; found "(?'name'".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "(hello wrold)", "(?'s-e'l)") +Errors: Error 24-35: Invalid regular expression: Balancing capture groups is not supported; found "(?'s-e'".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Fail +Fail diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/rust_fx.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/rust_fx.txt new file mode 100644 index 0000000000..ac38138aa6 --- /dev/null +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/rust_fx.txt @@ -0,0 +1,1534 @@ +#SETUP: RegEx + +# 1: yield return (@"^$", "", new[] { (0, 0) }); +>> ForAll( MatchAll( "", "^$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0}) + +# 2: yield return (@"^$^$^$", "", new[] { (0, 0) }); +>> ForAll( MatchAll( "", "^$^$^$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0}) + +# 3: yield return (@"^^^$$$", "", new[] { (0, 0) }); +>> ForAll( MatchAll( "", "^^^$$$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0}) + +# 4: yield return (@"$^", "", new[] { (0, 0) }); +>> ForAll( MatchAll( "", "$^" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0}) + +# 5: yield return (@"(?:^$)*", "a\nb\nc", new[] { (0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5) }); +>> ForAll( MatchAll( "a\nb\nc", "(?:^$)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3},{B:4,E:4},{B:5,E:5}) + +# 6: yield return (@"(?:$^)*", "a\nb\nc", new[] { (0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5) }); +>> ForAll( MatchAll( "a\nb\nc", "(?:$^)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3},{B:4,E:4},{B:5,E:5}) + +# 7: yield return (@"", "", new[] { (0, 0) }); +>> ForAll( MatchAll( "", "" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0}) + +# 8: yield return (@"", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); +>> ForAll( MatchAll( "abc", "" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) + +# 9: yield return (@"()", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); +>> ForAll( MatchAll( "abc", "()" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) + +# 10: yield return (@"()*", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); +>> ForAll( MatchAll( "abc", "()*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) + +# 11: yield return (@"()+", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); +>> ForAll( MatchAll( "abc", "()+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) + +# 12: yield return (@"()?", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); +>> ForAll( MatchAll( "abc", "()?" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) + +# 13: yield return (@"()()", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); +>> ForAll( MatchAll( "abc", "()()" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) + +# 14: yield return (@"()+|z", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); +>> ForAll( MatchAll( "abc", "()+|z" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) + +# 15: yield return (@"z|()+", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); +>> ForAll( MatchAll( "abc", "z|()+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) + +# 16: yield return (@"()+|b", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); +>> ForAll( MatchAll( "abc", "()+|b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) + +# 17: yield return (@"b|()+", "abc", new[] { (0, 0), (1, 2), (2, 2), (3, 3) }); +>> ForAll( MatchAll( "abc", "b|()+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:2},{B:2,E:2},{B:3,E:3}) + +# 18: yield return (@"|b", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); +>> ForAll( MatchAll( "abc", "|b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) + +# 19: yield return (@"b|", "abc", new[] { (0, 0), (1, 2), (2, 2), (3, 3) }); +>> ForAll( MatchAll( "abc", "b|" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:2},{B:2,E:2},{B:3,E:3}) + +# 20: yield return (@"|z", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); +>> ForAll( MatchAll( "abc", "|z" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) + +# 21: yield return (@"z|", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); +>> ForAll( MatchAll( "abc", "z|" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) + +# 22: yield return (@"|", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); +>> ForAll( MatchAll( "abc", "|" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) + +# 23: yield return (@"||", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); +>> ForAll( MatchAll( "abc", "||" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) + +# 24: yield return (@"||z", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); +>> ForAll( MatchAll( "abc", "||z" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) + +# 25: yield return (@"(?:)|b", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); +>> ForAll( MatchAll( "abc", "(?:)|b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) + +# 26: yield return (@"b|(?:)", "abc", new[] { (0, 0), (1, 2), (2, 2), (3, 3) }); +>> ForAll( MatchAll( "abc", "b|(?:)" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:2},{B:2,E:2},{B:3,E:3}) + +# 27: yield return (@"(?:|)", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); +>> ForAll( MatchAll( "abc", "(?:|)" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) + +# 28: yield return (@"(?:|)|z", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); +>> ForAll( MatchAll( "abc", "(?:|)|z" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) + +# 29: yield return (@"a(?:)|b", "abc", new[] { (0, 1), (1, 2) }); +>> ForAll( MatchAll( "abc", "a(?:)|b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1},{B:1,E:2}) + +# 30: yield return (@"a$", "a", new[] { (0, 1) }); +>> ForAll( MatchAll( "a", "a$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1}) + +# 31: yield return (@"(?m)^[a-z]+$", "abc\ndef\nxyz", new[] { (0, 3), (4, 7), (8, 11) }); +>> ForAll( MatchAll( "abc\ndef\nxyz", "(?m)^[a-z]+$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3},{B:4,E:7},{B:8,E:11}) + +# 32: yield return (@"(?m)^$", "abc\ndef\nxyz", new ValueTuple[] { }); +>> ForAll( MatchAll( "abc\ndef\nxyz", "(?m)^$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 33: yield return (@"(?m)^", "abc\ndef\nxyz", new[] { (0, 0), (4, 4), (8, 8) }); +>> ForAll( MatchAll( "abc\ndef\nxyz", "(?m)^" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:4,E:4},{B:8,E:8}) + +# 34: yield return (@"(?m)$", "abc\ndef\nxyz", new[] { (3, 3), (7, 7), (11, 11) }); +>> ForAll( MatchAll( "abc\ndef\nxyz", "(?m)$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:3,E:3},{B:7,E:7},{B:11,E:11}) + +# 35: yield return (@"(?m)^[a-z]", "abc\ndef\nxyz", new[] { (0, 1), (4, 5), (8, 9) }); +>> ForAll( MatchAll( "abc\ndef\nxyz", "(?m)^[a-z]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1},{B:4,E:5},{B:8,E:9}) + +# 36: yield return (@"(?m)[a-z]^", "abc\ndef\nxyz", new ValueTuple[] { }); +>> ForAll( MatchAll( "abc\ndef\nxyz", "(?m)[a-z]^" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 37: yield return (@"(?m)[a-z]$", "abc\ndef\nxyz", new[] { (2, 3), (6, 7), (10, 11) }); +>> ForAll( MatchAll( "abc\ndef\nxyz", "(?m)[a-z]$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:2,E:3},{B:6,E:7},{B:10,E:11}) + +# 38: yield return (@"(?m)$[a-z]", "abc\ndef\nxyz", new ValueTuple[] { }); +>> ForAll( MatchAll( "abc\ndef\nxyz", "(?m)$[a-z]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 39: yield return (@"(?m)^$", "", new[] { (0, 0) }); +>> ForAll( MatchAll( "", "(?m)^$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0}) + +# 40: yield return (@"(?m)(?:^$)*", "a\nb\nc", new[] { (0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5) }); +>> ForAll( MatchAll( "a\nb\nc", "(?m)(?:^$)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3},{B:4,E:4},{B:5,E:5}) + +# 41: yield return (@"(?m)(?:^|a)+", "a\naaa\n", new[] { (0, 0), (2, 2), (3, 5), (6, 6) }); +>> ForAll( MatchAll( "a\naaa\n", "(?m)(?:^|a)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:2,E:2},{B:3,E:5},{B:6,E:6}) + +# 42: yield return (@"(?m)(?:^|a)*", "a\naaa\n", new[] { (0, 0), (1, 1), (2, 2), (3, 5), (5, 5), (6, 6) }); +>> ForAll( MatchAll( "a\naaa\n", "(?m)(?:^|a)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:5},{B:5,E:5},{B:6,E:6}) + +# 43: yield return (@"(?m)(?:^[a-z])+", "abc\ndef\nxyz", new[] { (0, 1), (4, 5), (8, 9) }); +>> ForAll( MatchAll( "abc\ndef\nxyz", "(?m)(?:^[a-z])+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1},{B:4,E:5},{B:8,E:9}) + +# 44: yield return (@"(?m)(?:^[a-z]{3}\n?)+", "abc\ndef\nxyz", new[] { (0, 11) }); +>> ForAll( MatchAll( "abc\ndef\nxyz", "(?m)(?:^[a-z]{3}\n?)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:11}) + +# 45: yield return (@"(?m)(?:^[a-z]{3}\n?)*", "abc\ndef\nxyz", new[] { (0, 11), (11, 11) }); +>> ForAll( MatchAll( "abc\ndef\nxyz", "(?m)(?:^[a-z]{3}\n?)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:11},{B:11,E:11}) + +# 46: yield return (@"(?m)(?:\n?[a-z]{3}$)+", "abc\ndef\nxyz", new[] { (0, 11) }); +>> ForAll( MatchAll( "abc\ndef\nxyz", "(?m)(?:\n?[a-z]{3}$)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:11}) + +# 47: yield return (@"(?m)(?:\n?[a-z]{3}$)*", "abc\ndef\nxyz", new[] { (0, 11), (11, 11) }); +>> ForAll( MatchAll( "abc\ndef\nxyz", "(?m)(?:\n?[a-z]{3}$)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:11},{B:11,E:11}) + +# 48: yield return (@"(?m)^*", "\naa\n", new[] { (0, 0), (1, 1), (2, 2), (3, 3), (4, 4) }); +>> ForAll( MatchAll( "\naa\n", "(?m)^*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3},{B:4,E:4}) + +# 49: yield return (@"(?m)^+", "\naa\n", new[] { (0, 0), (1, 1), (4, 4) }); +>> ForAll( MatchAll( "\naa\n", "(?m)^+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1},{B:4,E:4}) + +# 50: yield return (@"(?m)$*", "\naa\n", new[] { (0, 0), (1, 1), (2, 2), (3, 3), (4, 4) }); +>> ForAll( MatchAll( "\naa\n", "(?m)$*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3},{B:4,E:4}) + +# 51: yield return (@"(?m)$+", "\naa\n", new[] { (0, 0), (3, 3), (4, 4) }); +>> ForAll( MatchAll( "\naa\n", "(?m)$+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:3,E:3},{B:4,E:4}) + +# 52: yield return (@"(?m)(?:$\n)+", "\n\naaa\n\n", new[] { (0, 2), (5, 7) }); +>> ForAll( MatchAll( "\n\naaa\n\n", "(?m)(?:$\n)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2},{B:5,E:7}) + +# 53: yield return (@"(?m)(?:$\n)*", "\n\naaa\n\n", new[] { (0, 2), (2, 2), (3, 3), (4, 4), (5, 7), (7, 7) }); +>> ForAll( MatchAll( "\n\naaa\n\n", "(?m)(?:$\n)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2},{B:2,E:2},{B:3,E:3},{B:4,E:4},{B:5,E:7},{B:7,E:7}) + +# 54: yield return (@"(?m)(?:$\n^)+", "\n\naaa\n\n", new[] { (0, 2), (5, 7) }); +>> ForAll( MatchAll( "\n\naaa\n\n", "(?m)(?:$\n^)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2},{B:5,E:7}) + +# 55: yield return (@"(?m)(?:^|$)+", "\n\naaa\n\n", new[] { (0, 0), (1, 1), (2, 2), (5, 5), (6, 6), (7, 7) }); +>> ForAll( MatchAll( "\n\naaa\n\n", "(?m)(?:^|$)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:5,E:5},{B:6,E:6},{B:7,E:7}) + +# 56: yield return (@"\b", "a b c", new[] { (0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5) }); +>> ForAll( MatchAll( "a b c", "\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3},{B:4,E:4},{B:5,E:5}) + +# 57: yield return (@"^a|b", "ba", new[] { (0, 1) }); +>> ForAll( MatchAll( "ba", "^a|b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1}) + +# 58: yield return (@"[0-9][0-9][0-9]000", "153.230000\n", new[] { (4, 10) }); +>> ForAll( MatchAll( "153.230000\n", "[0-9][0-9][0-9]000" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:4,E:10}) + +# 59: yield return (@"((?i)foo)|Bar", "foo Foo bar Bar", new[] { (0, 3), (4, 7), (12, 15) }); +>> ForAll( MatchAll( "foo Foo bar Bar", "((?i)foo)|Bar" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3},{B:4,E:7},{B:12,E:15}) + +# 60: yield return (@"()?01", "z?01", new[] { (2, 4) }); +>> ForAll( MatchAll( "z?01", "()?01" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:2,E:4}) + +# 61: yield return (@"\b", "", new ValueTuple[] { }); +>> ForAll( MatchAll( "", "\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 62: yield return (@"\b", "a", new[] { (0, 0), (1, 1) }); +>> ForAll( MatchAll( "a", "\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1}) + +# 63: yield return (@"\b", "ab", new[] { (0, 0), (2, 2) }); +>> ForAll( MatchAll( "ab", "\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:2,E:2}) + +# 64: yield return (@"^\b", "ab", new[] { (0, 0) }); +>> ForAll( MatchAll( "ab", "^\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0}) + +# 65: yield return (@"\b$", "ab", new[] { (2, 2) }); +>> ForAll( MatchAll( "ab", "\b$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:2,E:2}) + +# 66: yield return (@"^\b$", "ab", new ValueTuple[] { }); +>> ForAll( MatchAll( "ab", "^\b$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 67: yield return (@"\bbar\b", "nobar bar foo bar", new[] { (6, 9), (14, 17) }); +>> ForAll( MatchAll( "nobar bar foo bar", "\bbar\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:6,E:9},{B:14,E:17}) + +# 68: yield return (@"a\b", "faoa x", new[] { (3, 4) }); +>> ForAll( MatchAll( "faoa x", "a\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:3,E:4}) + +# 69: yield return (@"\bbar", "bar x", new[] { (0, 3) }); +>> ForAll( MatchAll( "bar x", "\bbar" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 70: yield return (@"\bbar", "foo\nbar x", new[] { (4, 7) }); +>> ForAll( MatchAll( "foo\nbar x", "\bbar" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:4,E:7}) + +# 71: yield return (@"bar\b", "foobar", new[] { (3, 6) }); +>> ForAll( MatchAll( "foobar", "bar\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:3,E:6}) + +# 72: yield return (@"bar\b", "foobar\nxxx", new[] { (3, 6) }); +>> ForAll( MatchAll( "foobar\nxxx", "bar\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:3,E:6}) + +# 73: yield return (@"(foo|bar|[A-Z])\b", "foo", new[] { (0, 3) }); +>> ForAll( MatchAll( "foo", "(foo|bar|[A-Z])\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 74: yield return (@"(foo|bar|[A-Z])\b", "foo\n", new[] { (0, 3) }); +>> ForAll( MatchAll( "foo\n", "(foo|bar|[A-Z])\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 75: yield return (@"\b(foo|bar|[A-Z])", "foo", new[] { (0, 3) }); +>> ForAll( MatchAll( "foo", "\b(foo|bar|[A-Z])" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 76: yield return (@"\b(foo|bar|[A-Z])\b", "X", new[] { (0, 1) }); +>> ForAll( MatchAll( "X", "\b(foo|bar|[A-Z])\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1}) + +# 77: yield return (@"\b(foo|bar|[A-Z])\b", "XY", new ValueTuple[] { }); +>> ForAll( MatchAll( "XY", "\b(foo|bar|[A-Z])\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 78: yield return (@"\b(foo|bar|[A-Z])\b", "bar", new[] { (0, 3) }); +>> ForAll( MatchAll( "bar", "\b(foo|bar|[A-Z])\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 79: yield return (@"\b(foo|bar|[A-Z])\b", "foo", new[] { (0, 3) }); +>> ForAll( MatchAll( "foo", "\b(foo|bar|[A-Z])\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 80: yield return (@"\b(foo|bar|[A-Z])\b", "foo\n", new[] { (0, 3) }); +>> ForAll( MatchAll( "foo\n", "\b(foo|bar|[A-Z])\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 81: yield return (@"\b(foo|bar|[A-Z])\b", "ffoo bbar N x", new[] { (10, 11) }); +>> ForAll( MatchAll( "ffoo bbar N x", "\b(foo|bar|[A-Z])\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:10,E:11}) + +# 82: yield return (@"\b(fo|foo)\b", "fo", new[] { (0, 2) }); +>> ForAll( MatchAll( "fo", "\b(fo|foo)\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2}) + +# 83: yield return (@"\b(fo|foo)\b", "foo", new[] { (0, 3) }); +>> ForAll( MatchAll( "foo", "\b(fo|foo)\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 84: yield return (@"\b\b", "", new ValueTuple[] { }); +>> ForAll( MatchAll( "", "\b\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 85: yield return (@"\b\b", "a", new[] { (0, 0), (1, 1) }); +>> ForAll( MatchAll( "a", "\b\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1}) + +# 86: yield return (@"\b$", "", new ValueTuple[] { }); +>> ForAll( MatchAll( "", "\b$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 87: yield return (@"\b$", "x", new[] { (1, 1) }); +>> ForAll( MatchAll( "x", "\b$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:1,E:1}) + +# 88: yield return (@"\b$", "y x", new[] { (3, 3) }); +>> ForAll( MatchAll( "y x", "\b$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:3,E:3}) + +# 89: yield return (@"\b.$", "x", new[] { (0, 1) }); +>> ForAll( MatchAll( "x", "\b.$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1}) + +# 90: yield return (@"^\b(fo|foo)\b", "fo", new[] { (0, 2) }); +>> ForAll( MatchAll( "fo", "^\b(fo|foo)\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2}) + +# 91: yield return (@"^\b(fo|foo)\b", "foo", new[] { (0, 3) }); +>> ForAll( MatchAll( "foo", "^\b(fo|foo)\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 92: yield return (@"^\b$", "", new ValueTuple[] { }); +>> ForAll( MatchAll( "", "^\b$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 93: yield return (@"^\b$", "x", new ValueTuple[] { }); +>> ForAll( MatchAll( "x", "^\b$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 94: yield return (@"^\b.$", "x", new[] { (0, 1) }); +>> ForAll( MatchAll( "x", "^\b.$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1}) + +# 95: yield return (@"^\b.\b$", "x", new[] { (0, 1) }); +>> ForAll( MatchAll( "x", "^\b.\b$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1}) + +# 96: yield return (@"^^^^^\b$$$$$", "", new ValueTuple[] { }); +>> ForAll( MatchAll( "", "^^^^^\b$$$$$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 97: yield return (@"^^^^^\b.$$$$$", "x", new[] { (0, 1) }); +>> ForAll( MatchAll( "x", "^^^^^\b.$$$$$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1}) + +# 98: yield return (@"^^^^^\b$$$$$", "x", new ValueTuple[] { }); +>> ForAll( MatchAll( "x", "^^^^^\b$$$$$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 99: yield return (@"^^^^^\b\b\b.\b\b\b$$$$$", "x", new[] { (0, 1) }); +>> ForAll( MatchAll( "x", "^^^^^\b\b\b.\b\b\b$$$$$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1}) + +# 100: yield return (@"\b.+\b", "$$abc$$", new[] { (2, 5) }); +>> ForAll( MatchAll( "$$abc$$", "\b.+\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:2,E:5}) + +# 101: yield return (@"\b", "a b c", new[] { (0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5) }); +>> ForAll( MatchAll( "a b c", "\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3},{B:4,E:4},{B:5,E:5}) + +# 102: yield return (@"\Bfoo\B", "n foo xfoox that", new[] { (7, 10) }); +>> ForAll( MatchAll( "n foo xfoox that", "\Bfoo\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:7,E:10}) + +# 103: yield return (@"a\B", "faoa x", new[] { (1, 2) }); +>> ForAll( MatchAll( "faoa x", "a\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:1,E:2}) + +# 104: yield return (@"\Bbar", "bar x", new ValueTuple[] { }); +>> ForAll( MatchAll( "bar x", "\Bbar" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 105: yield return (@"\Bbar", "foo\nbar x", new ValueTuple[] { }); +>> ForAll( MatchAll( "foo\nbar x", "\Bbar" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 106: yield return (@"bar\B", "foobar", new ValueTuple[] { }); +>> ForAll( MatchAll( "foobar", "bar\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 107: yield return (@"bar\B", "foobar\nxxx", new ValueTuple[] { }); +>> ForAll( MatchAll( "foobar\nxxx", "bar\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 108: yield return (@"(foo|bar|[A-Z])\B", "foox", new[] { (0, 3) }); +>> ForAll( MatchAll( "foox", "(foo|bar|[A-Z])\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 109: yield return (@"(foo|bar|[A-Z])\B", "foo\n", new ValueTuple[] { }); +>> ForAll( MatchAll( "foo\n", "(foo|bar|[A-Z])\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 110: yield return (@"\B", "", new[] { (0, 0) }); +>> ForAll( MatchAll( "", "\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0}) + +# 111: yield return (@"\B", "x", new ValueTuple[] { }); +>> ForAll( MatchAll( "x", "\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 112: yield return (@"\B(foo|bar|[A-Z])", "foo", new ValueTuple[] { }); +>> ForAll( MatchAll( "foo", "\B(foo|bar|[A-Z])" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 113: yield return (@"\B(foo|bar|[A-Z])\B", "xXy", new[] { (1, 2) }); +>> ForAll( MatchAll( "xXy", "\B(foo|bar|[A-Z])\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:1,E:2}) + +# 114: yield return (@"\B(foo|bar|[A-Z])\B", "XY", new ValueTuple[] { }); +>> ForAll( MatchAll( "XY", "\B(foo|bar|[A-Z])\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 115: yield return (@"\B(foo|bar|[A-Z])\B", "XYZ", new[] { (1, 2) }); +>> ForAll( MatchAll( "XYZ", "\B(foo|bar|[A-Z])\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:1,E:2}) + +# 116: yield return (@"\B(foo|bar|[A-Z])\B", "abara", new[] { (1, 4) }); +>> ForAll( MatchAll( "abara", "\B(foo|bar|[A-Z])\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:1,E:4}) + +# 117: yield return (@"\B(foo|bar|[A-Z])\B", "xfoo_", new[] { (1, 4) }); +>> ForAll( MatchAll( "xfoo_", "\B(foo|bar|[A-Z])\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:1,E:4}) + +# 118: yield return (@"\B(foo|bar|[A-Z])\B", "xfoo\n", new ValueTuple[] { }); +>> ForAll( MatchAll( "xfoo\n", "\B(foo|bar|[A-Z])\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 119: yield return (@"\B(foo|bar|[A-Z])\B", "foo bar vNX", new[] { (9, 10) }); +>> ForAll( MatchAll( "foo bar vNX", "\B(foo|bar|[A-Z])\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:9,E:10}) + +# 120: yield return (@"\B(fo|foo)\B", "xfoo", new[] { (1, 3) }); +>> ForAll( MatchAll( "xfoo", "\B(fo|foo)\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:1,E:3}) + +# 121: yield return (@"\B(foo|fo)\B", "xfooo", new[] { (1, 4) }); +>> ForAll( MatchAll( "xfooo", "\B(foo|fo)\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:1,E:4}) + +# 122: yield return (@"\B\B", "", new[] { (0, 0) }); +>> ForAll( MatchAll( "", "\B\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0}) + +# 123: yield return (@"\B\B", "x", new ValueTuple[] { }); +>> ForAll( MatchAll( "x", "\B\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 124: yield return (@"\B$", "", new[] { (0, 0) }); +>> ForAll( MatchAll( "", "\B$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0}) + +# 125: yield return (@"\B$", "x", new ValueTuple[] { }); +>> ForAll( MatchAll( "x", "\B$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 126: yield return (@"\B$", "y x", new ValueTuple[] { }); +>> ForAll( MatchAll( "y x", "\B$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 127: yield return (@"\B.$", "x", new ValueTuple[] { }); +>> ForAll( MatchAll( "x", "\B.$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 128: yield return (@"^\B(fo|foo)\B", "fo", new ValueTuple[] { }); +>> ForAll( MatchAll( "fo", "^\B(fo|foo)\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 129: yield return (@"^\B(fo|foo)\B", "foo", new ValueTuple[] { }); +>> ForAll( MatchAll( "foo", "^\B(fo|foo)\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 130: yield return (@"^\B", "", new[] { (0, 0) }); +>> ForAll( MatchAll( "", "^\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0}) + +# 131: yield return (@"^\B", "x", new ValueTuple[] { }); +>> ForAll( MatchAll( "x", "^\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 132: yield return (@"^\B\B", "", new[] { (0, 0) }); +>> ForAll( MatchAll( "", "^\B\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0}) + +# 133: yield return (@"^\B\B", "x", new ValueTuple[] { }); +>> ForAll( MatchAll( "x", "^\B\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 134: yield return (@"^\B$", "", new[] { (0, 0) }); +>> ForAll( MatchAll( "", "^\B$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0}) + +# 135: yield return (@"^\B$", "x", new ValueTuple[] { }); +>> ForAll( MatchAll( "x", "^\B$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 136: yield return (@"^\B.$", "x", new ValueTuple[] { }); +>> ForAll( MatchAll( "x", "^\B.$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 137: yield return (@"^\B.\B$", "x", new ValueTuple[] { }); +>> ForAll( MatchAll( "x", "^\B.\B$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 138: yield return (@"^^^^^\B$$$$$", "", new[] { (0, 0) }); +>> ForAll( MatchAll( "", "^^^^^\B$$$$$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0}) + +# 139: yield return (@"^^^^^\B.$$$$$", "x", new ValueTuple[] { }); +>> ForAll( MatchAll( "x", "^^^^^\B.$$$$$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 140: yield return (@"^^^^^\B$$$$$", "x", new ValueTuple[] { }); +>> ForAll( MatchAll( "x", "^^^^^\B$$$$$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 141: yield return (@"\bx\b", "\u00ABx", new[] { (1, 2) }); +>> ForAll( MatchAll( UniChar(Hex2Dec("00ABx")), "\bx\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:1,E:2}) + +# 142: yield return (@"\bx\b", "x\u00BB", new[] { (0, 1) }); +>> ForAll( MatchAll( "x"&UniChar(Hex2Dec("00BB")), "\bx\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1}) + +# 143: yield return (@"\bx\b", "\u00E1x\u00DF", new ValueTuple[] { }); +>> ForAll( MatchAll( UniChar(Hex2Dec("00E1x"))&UniChar(Hex2Dec("00DF")), "\bx\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 144: yield return (@"\Bx\B", "\u00E1x\u00DF", new[] { (1, 2) }); +>> ForAll( MatchAll( UniChar(Hex2Dec("00E1x"))&UniChar(Hex2Dec("00DF")), "\Bx\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:1,E:2}) + +# 145: yield return (@" \b", " \u03B4", new[] { (0, 1) }); +>> ForAll( MatchAll( " "&UniChar(Hex2Dec("03B4")), " \b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1}) + +# 146: yield return (@" \B", " \u03B4", new ValueTuple[] { }); +>> ForAll( MatchAll( " "&UniChar(Hex2Dec("03B4")), " \B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 147: yield return (@"\w+", "a\u03B4", new[] { (0, 2) }); +>> ForAll( MatchAll( "a"&UniChar(Hex2Dec("03B4")), "\w+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2}) + +# 148: yield return (@"\d+", "1\u0968\u09699", new[] { (0, 4) }); +>> ForAll( MatchAll( "1"&UniChar(Hex2Dec("0968"))&UniChar(Hex2Dec("09699")), "\d+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:4}) + +# 149: yield return (@"[^a]", "\u03B4", new[] { (0, 1) }); +>> ForAll( MatchAll( UniChar(Hex2Dec("03B4")), "[^a]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1}) + +# 150: yield return (@"a", "\xFFa", new ValueTuple[] { }); +>> ForAll( MatchAll( Char(Hex2Dec("FFa")), "a" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 151: yield return (@"a", "a", new[] { (0, 1) }); +>> ForAll( MatchAll( "a", "a" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1}) + +# 152: yield return (@"[-+]?[0-9]*\.?[0-9]+", "0.1", new[] { (0, 3) }); +>> ForAll( MatchAll( "0.1", "[-+]?[0-9]*\.?[0-9]+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 153: yield return (@"[-+]?[0-9]*\.?[0-9]+", "0.1.2", new[] { (0, 3), (3, 5) }); +>> ForAll( MatchAll( "0.1.2", "[-+]?[0-9]*\.?[0-9]+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3},{B:3,E:5}) + +# 154: yield return (@"[-+]?[0-9]*\.?[0-9]+", "a1.2", new[] { (1, 4) }); +>> ForAll( MatchAll( "a1.2", "[-+]?[0-9]*\.?[0-9]+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:1,E:4}) + +# 155: yield return (@"^[-+]?[0-9]*\.?[0-9]+$", "1.a", new ValueTuple[] { }); +>> ForAll( MatchAll( "1.a", "^[-+]?[0-9]*\.?[0-9]+$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 156: yield return (@"[^ac]", "acx", new[] { (2, 3) }); +>> ForAll( MatchAll( "acx", "[^ac]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:2,E:3}) + +# 157: yield return (@"[^a,]", "a,x", new[] { (2, 3) }); +>> ForAll( MatchAll( "a,x", "[^a,]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:2,E:3}) + +# 158: yield return (@"[^,]", ",,x", new[] { (2, 3) }); +>> ForAll( MatchAll( ",,x", "[^,]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:2,E:3}) + +# 159: yield return (@"((?:.*)*?)=", "a=b", new[] { (0, 2) }); +>> ForAll( MatchAll( "a=b", "((?:.*)*?)=" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2}) + +# 160: yield return (@"((?:.?)*?)=", "a=b", new[] { (0, 2) }); +>> ForAll( MatchAll( "a=b", "((?:.?)*?)=" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2}) + +# 161: yield return (@"((?:.*)+?)=", "a=b", new[] { (0, 2) }); +>> ForAll( MatchAll( "a=b", "((?:.*)+?)=" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2}) + +# 162: yield return (@"((?:.?)+?)=", "a=b", new[] { (0, 2) }); +>> ForAll( MatchAll( "a=b", "((?:.?)+?)=" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2}) + +# 163: yield return (@"((?:.*){1,}?)=", "a=b", new[] { (0, 2) }); +>> ForAll( MatchAll( "a=b", "((?:.*){1,}?)=" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2}) + +# 164: yield return (@"((?:.*){1,2}?)=", "a=b", new[] { (0, 2) }); +>> ForAll( MatchAll( "a=b", "((?:.*){1,2}?)=" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2}) + +# 165: yield return (@"((?:.*)*)=", "a=b", new[] { (0, 2) }); +>> ForAll( MatchAll( "a=b", "((?:.*)*)=" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2}) + +# 166: yield return (@"((?:.?)*)=", "a=b", new[] { (0, 2) }); +>> ForAll( MatchAll( "a=b", "((?:.?)*)=" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2}) + +# 167: yield return (@"((?:.*)+)=", "a=b", new[] { (0, 2) }); +>> ForAll( MatchAll( "a=b", "((?:.*)+)=" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2}) + +# 168: yield return (@"((?:.?)+)=", "a=b", new[] { (0, 2) }); +>> ForAll( MatchAll( "a=b", "((?:.?)+)=" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2}) + +# 169: yield return (@"((?:.*){1,})=", "a=b", new[] { (0, 2) }); +>> ForAll( MatchAll( "a=b", "((?:.*){1,})=" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2}) + +# 170: yield return (@"((?:.*){1,2})=", "a=b", new[] { (0, 2) }); +>> ForAll( MatchAll( "a=b", "((?:.*){1,2})=" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2}) + +# 171: yield return (@"abracadabra$", "abracadabracadabra", new[] { (7, 18) }); +>> ForAll( MatchAll( "abracadabracadabra", "abracadabra$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:7,E:18}) + +# 172: yield return (@"a...b", "abababbb", new[] { (2, 7) }); +>> ForAll( MatchAll( "abababbb", "a...b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:2,E:7}) + +# 173: yield return (@"XXXXXX", "..XXXXXX", new[] { (2, 8) }); +>> ForAll( MatchAll( "..XXXXXX", "XXXXXX" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:2,E:8}) + +# 174: yield return (@"\)", "()", new[] { (1, 2) }); +>> ForAll( MatchAll( "()", "\)" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:1,E:2}) + +# 175: yield return (@"a]", "a]a", new[] { (0, 2) }); +>> ForAll( MatchAll( "a]a", "a]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2}) + +# 176: yield return (@"\}", "}", new[] { (0, 1) }); +>> ForAll( MatchAll( "}", "\}" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1}) + +# 177: yield return (@"\]", "]", new[] { (0, 1) }); +>> ForAll( MatchAll( "]", "\]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1}) + +# 178: yield return (@"]", "]", new[] { (0, 1) }); +>> ForAll( MatchAll( "]", "]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1}) + +# 179: yield return (@"^a", "ax", new[] { (0, 1) }); +>> ForAll( MatchAll( "ax", "^a" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1}) + +# 180: yield return (@"\^a", "a^a", new[] { (1, 3) }); +>> ForAll( MatchAll( "a^a", "\^a" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:1,E:3}) + +# 181: yield return (@"a\^", "a^", new[] { (0, 2) }); +>> ForAll( MatchAll( "a^", "a\^" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2}) + +# 182: yield return (@"a$", "aa", new[] { (1, 2) }); +>> ForAll( MatchAll( "aa", "a$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:1,E:2}) + +# 183: yield return (@"a\$", "a$", new[] { (0, 2) }); +>> ForAll( MatchAll( "a$", "a\$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2}) + +# 184: yield return (@"^$", "", new[] { (0, 0) }); +>> ForAll( MatchAll( "", "^$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0}) + +# 185: yield return (@"$^", "", new[] { (0, 0) }); +>> ForAll( MatchAll( "", "$^" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0}) + +# 186: yield return (@"a($)", "aa", new[] { (1, 2) }); +>> ForAll( MatchAll( "aa", "a($)" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:1,E:2}) + +# 187: yield return (@"a*(^a)", "aa", new[] { (0, 1) }); +>> ForAll( MatchAll( "aa", "a*(^a)" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1}) + +# 188: yield return (@"(..)*(...)*", "a", new[] { (0, 0), (1, 1) }); +>> ForAll( MatchAll( "a", "(..)*(...)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1}) + +# 189: yield return (@"(..)*(...)*", "abcd", new[] { (0, 4), (4, 4) }); +>> ForAll( MatchAll( "abcd", "(..)*(...)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:4},{B:4,E:4}) + +# 190: yield return (@"(ab)c|abc", "abc", new[] { (0, 3) }); +>> ForAll( MatchAll( "abc", "(ab)c|abc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 191: yield return (@"a{0}b", "ab", new[] { (1, 2) }); +>> ForAll( MatchAll( "ab", "a{0}b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:1,E:2}) + +# 192: yield return (@"a*(a.|aa)", "aaaa", new[] { (0, 4) }); +>> ForAll( MatchAll( "aaaa", "a*(a.|aa)" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:4}) + +# 193: yield return (@"(a|b)?.*", "b", new[] { (0, 1), (1, 1) }); +>> ForAll( MatchAll( "b", "(a|b)?.*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1},{B:1,E:1}) + +# 194: yield return (@"(a|b)c|a(b|c)", "ac", new[] { (0, 2) }); +>> ForAll( MatchAll( "ac", "(a|b)c|a(b|c)" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2}) + +# 195: yield return (@"(a|b)*c|(a|ab)*c", "abc", new[] { (0, 3) }); +>> ForAll( MatchAll( "abc", "(a|b)*c|(a|ab)*c" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 196: yield return (@"(a|b)*c|(a|ab)*c", "xc", new[] { (1, 2) }); +>> ForAll( MatchAll( "xc", "(a|b)*c|(a|ab)*c" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:1,E:2}) + +# 197: yield return (@"a?(ab|ba)ab", "abab", new[] { (0, 4) }); +>> ForAll( MatchAll( "abab", "a?(ab|ba)ab" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:4}) + +# 198: yield return (@"a?(ac{0}b|ba)ab", "abab", new[] { (0, 4) }); +>> ForAll( MatchAll( "abab", "a?(ac{0}b|ba)ab" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:4}) + +# 199: yield return (@"ab|abab", "abbabab", new[] { (0, 2), (3, 5), (5, 7) }); +>> ForAll( MatchAll( "abbabab", "ab|abab" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2},{B:3,E:5},{B:5,E:7}) + +# 200: yield return (@"aba|bab|bba", "baaabbbaba", new[] { (5, 8) }); +>> ForAll( MatchAll( "baaabbbaba", "aba|bab|bba" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:5,E:8}) + +# 201: yield return (@"aba|bab", "baaabbbaba", new[] { (6, 9) }); +>> ForAll( MatchAll( "baaabbbaba", "aba|bab" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:6,E:9}) + +# 202: yield return (@"ab|a", "xabc", new[] { (1, 3) }); +>> ForAll( MatchAll( "xabc", "ab|a" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:1,E:3}) + +# 203: yield return (@"ab|a", "xxabc", new[] { (2, 4) }); +>> ForAll( MatchAll( "xxabc", "ab|a" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:2,E:4}) + +# 204: yield return (@"[^-]", "--a", new[] { (2, 3) }); +>> ForAll( MatchAll( "--a", "[^-]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:2,E:3}) + +# 205: yield return (@"[a-]*", "--a", new[] { (0, 3), (3, 3) }); +>> ForAll( MatchAll( "--a", "[a-]*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3},{B:3,E:3}) + +# 206: yield return (@"[a-m-]*", "--amoma--", new[] { (0, 4), (4, 4), (5, 9), (9, 9) }); +>> ForAll( MatchAll( "--amoma--", "[a-m-]*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:4},{B:4,E:4},{B:5,E:9},{B:9,E:9}) + +# 207: yield return (@"[\p{Lu}]", "A", new[] { (0, 1) }); +>> ForAll( MatchAll( "A", "[\p{Lu}]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1}) + +# 208: yield return (@"[\p{Ll}]+", "`az{", new[] { (1, 3) }); +>> ForAll( MatchAll( "`az{", "[\p{Ll}]+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:1,E:3}) + +# 209: yield return (@"[\p{Lu}]+", "@AZ[", new[] { (1, 3) }); +>> ForAll( MatchAll( "@AZ[", "[\p{Lu}]+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:1,E:3}) + +# 210: yield return (@"xxx", "xxx", new[] { (0, 3) }); +>> ForAll( MatchAll( "xxx", "xxx" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 211: yield return (@".*", "\u263A\u007F", new[] { (0, 2), (2, 2) }); +>> ForAll( MatchAll( UniChar(Hex2Dec("263A"))&UniChar(Hex2Dec("007F")), ".*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2},{B:2,E:2}) + +# 212: yield return (@"a*a*a*a*a*b", "aaaaaaaaab", new[] { (0, 10) }); +>> ForAll( MatchAll( "aaaaaaaaab", "a*a*a*a*a*b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:10}) + +# 213: yield return (@"^", "", new[] { (0, 0) }); +>> ForAll( MatchAll( "", "^" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0}) + +# 214: yield return (@"$", "", new[] { (0, 0) }); +>> ForAll( MatchAll( "", "$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0}) + +# 215: yield return (@"^$", "", new[] { (0, 0) }); +>> ForAll( MatchAll( "", "^$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0}) + +# 216: yield return (@"^a$", "a", new[] { (0, 1) }); +>> ForAll( MatchAll( "a", "^a$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1}) + +# 217: yield return (@"abc", "abc", new[] { (0, 3) }); +>> ForAll( MatchAll( "abc", "abc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 218: yield return (@"abc", "xabcy", new[] { (1, 4) }); +>> ForAll( MatchAll( "xabcy", "abc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:1,E:4}) + +# 219: yield return (@"abc", "ababc", new[] { (2, 5) }); +>> ForAll( MatchAll( "ababc", "abc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:2,E:5}) + +# 220: yield return (@"ab*c", "abc", new[] { (0, 3) }); +>> ForAll( MatchAll( "abc", "ab*c" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 221: yield return (@"ab*bc", "abc", new[] { (0, 3) }); +>> ForAll( MatchAll( "abc", "ab*bc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 222: yield return (@"ab*bc", "abbc", new[] { (0, 4) }); +>> ForAll( MatchAll( "abbc", "ab*bc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:4}) + +# 223: yield return (@"ab*bc", "abbbbc", new[] { (0, 6) }); +>> ForAll( MatchAll( "abbbbc", "ab*bc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:6}) + +# 224: yield return (@"ab+bc", "abbc", new[] { (0, 4) }); +>> ForAll( MatchAll( "abbc", "ab+bc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:4}) + +# 225: yield return (@"ab+bc", "abbbbc", new[] { (0, 6) }); +>> ForAll( MatchAll( "abbbbc", "ab+bc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:6}) + +# 226: yield return (@"ab?bc", "abbc", new[] { (0, 4) }); +>> ForAll( MatchAll( "abbc", "ab?bc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:4}) + +# 227: yield return (@"ab?bc", "abc", new[] { (0, 3) }); +>> ForAll( MatchAll( "abc", "ab?bc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 228: yield return (@"ab?c", "abc", new[] { (0, 3) }); +>> ForAll( MatchAll( "abc", "ab?c" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 229: yield return (@"^abc$", "abc", new[] { (0, 3) }); +>> ForAll( MatchAll( "abc", "^abc$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 230: yield return (@"^abc", "abcc", new[] { (0, 3) }); +>> ForAll( MatchAll( "abcc", "^abc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 231: yield return (@"abc$", "aabc", new[] { (1, 4) }); +>> ForAll( MatchAll( "aabc", "abc$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:1,E:4}) + +# 232: yield return (@"^", "abc", new[] { (0, 0) }); +>> ForAll( MatchAll( "abc", "^" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0}) + +# 233: yield return (@"$", "abc", new[] { (3, 3) }); +>> ForAll( MatchAll( "abc", "$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:3,E:3}) + +# 234: yield return (@"a.c", "abc", new[] { (0, 3) }); +>> ForAll( MatchAll( "abc", "a.c" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 235: yield return (@"a.c", "axc", new[] { (0, 3) }); +>> ForAll( MatchAll( "axc", "a.c" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 236: yield return (@"a.*c", "axyzc", new[] { (0, 5) }); +>> ForAll( MatchAll( "axyzc", "a.*c" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:5}) + +# 237: yield return (@"a[bc]d", "abd", new[] { (0, 3) }); +>> ForAll( MatchAll( "abd", "a[bc]d" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 238: yield return (@"a[b-d]e", "ace", new[] { (0, 3) }); +>> ForAll( MatchAll( "ace", "a[b-d]e" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 239: yield return (@"a[b-d]", "aac", new[] { (1, 3) }); +>> ForAll( MatchAll( "aac", "a[b-d]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:1,E:3}) + +# 240: yield return (@"a[-b]", "a-", new[] { (0, 2) }); +>> ForAll( MatchAll( "a-", "a[-b]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2}) + +# 241: yield return (@"a[b-]", "a-", new[] { (0, 2) }); +>> ForAll( MatchAll( "a-", "a[b-]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2}) + +# 242: yield return (@"a]", "a]", new[] { (0, 2) }); +>> ForAll( MatchAll( "a]", "a]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2}) + +# 243: yield return (@"a[]]b", "a]b", new[] { (0, 3) }); +>> ForAll( MatchAll( "a]b", "a[]]b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 244: yield return (@"a[^bc]d", "aed", new[] { (0, 3) }); +>> ForAll( MatchAll( "aed", "a[^bc]d" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 245: yield return (@"a[^-b]c", "adc", new[] { (0, 3) }); +>> ForAll( MatchAll( "adc", "a[^-b]c" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 246: yield return (@"a[^]b]c", "adc", new[] { (0, 3) }); +>> ForAll( MatchAll( "adc", "a[^]b]c" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 247: yield return (@"ab|cd", "abc", new[] { (0, 2) }); +>> ForAll( MatchAll( "abc", "ab|cd" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2}) + +# 248: yield return (@"ab|cd", "abcd", new[] { (0, 2), (2, 4) }); +>> ForAll( MatchAll( "abcd", "ab|cd" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2},{B:2,E:4}) + +# 249: yield return (@"a\(b", "a(b", new[] { (0, 3) }); +>> ForAll( MatchAll( "a(b", "a\(b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 250: yield return (@"a\(*b", "ab", new[] { (0, 2) }); +>> ForAll( MatchAll( "ab", "a\(*b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2}) + +# 251: yield return (@"a\(*b", "a((b", new[] { (0, 4) }); +>> ForAll( MatchAll( "a((b", "a\(*b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:4}) + +# 252: yield return (@"a+b+c", "aabbabc", new[] { (4, 7) }); +>> ForAll( MatchAll( "aabbabc", "a+b+c" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:4,E:7}) + +# 253: yield return (@"a*", "aaa", new[] { (0, 3), (3, 3) }); +>> ForAll( MatchAll( "aaa", "a*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3},{B:3,E:3}) + +# 254: yield return (@"(a*)*", "-", new[] { (0, 0), (1, 1) }); +>> ForAll( MatchAll( "-", "(a*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1}) + +# 255: yield return (@"(a*)+", "-", new[] { (0, 0), (1, 1) }); +>> ForAll( MatchAll( "-", "(a*)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1}) + +# 256: yield return (@"(a*|b)*", "-", new[] { (0, 0), (1, 1) }); +>> ForAll( MatchAll( "-", "(a*|b)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1}) + +# 257: yield return (@"(a+|b)*", "ab", new[] { (0, 2), (2, 2) }); +>> ForAll( MatchAll( "ab", "(a+|b)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2},{B:2,E:2}) + +# 258: yield return (@"(a+|b)+", "ab", new[] { (0, 2) }); +>> ForAll( MatchAll( "ab", "(a+|b)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2}) + +# 259: yield return (@"(a+|b)?", "ab", new[] { (0, 1), (1, 2), (2, 2) }); +>> ForAll( MatchAll( "ab", "(a+|b)?" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1},{B:1,E:2},{B:2,E:2}) + +# 260: yield return (@"[^ab]*", "cde", new[] { (0, 3), (3, 3) }); +>> ForAll( MatchAll( "cde", "[^ab]*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3},{B:3,E:3}) + +# 261: yield return (@"(^)*", "-", new[] { (0, 0), (1, 1) }); +>> ForAll( MatchAll( "-", "(^)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1}) + +# 262: yield return (@"a*", "", new[] { (0, 0) }); +>> ForAll( MatchAll( "", "a*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0}) + +# 263: yield return (@"([abc])*d", "abbbcd", new[] { (0, 6) }); +>> ForAll( MatchAll( "abbbcd", "([abc])*d" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:6}) + +# 264: yield return (@"([abc])*bcd", "abcd", new[] { (0, 4) }); +>> ForAll( MatchAll( "abcd", "([abc])*bcd" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:4}) + +# 265: yield return (@"a|b|c|d|e", "e", new[] { (0, 1) }); +>> ForAll( MatchAll( "e", "a|b|c|d|e" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1}) + +# 266: yield return (@"(a|b|c|d|e)f", "ef", new[] { (0, 2) }); +>> ForAll( MatchAll( "ef", "(a|b|c|d|e)f" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:2}) + +# 267: yield return (@"((a*|b))*", "-", new[] { (0, 0), (1, 1) }); +>> ForAll( MatchAll( "-", "((a*|b))*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1}) + +# 268: yield return (@"abcd*efg", "abcdefg", new[] { (0, 7) }); +>> ForAll( MatchAll( "abcdefg", "abcd*efg" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:7}) + +# 269: yield return (@"ab*", "xabyabbbz", new[] { (1, 3), (4, 8) }); +>> ForAll( MatchAll( "xabyabbbz", "ab*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:1,E:3},{B:4,E:8}) + +# 270: yield return (@"ab*", "xayabbbz", new[] { (1, 2), (3, 7) }); +>> ForAll( MatchAll( "xayabbbz", "ab*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:1,E:2},{B:3,E:7}) + +# 271: yield return (@"(ab|cd)e", "abcde", new[] { (2, 5) }); +>> ForAll( MatchAll( "abcde", "(ab|cd)e" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:2,E:5}) + +# 272: yield return (@"[abhgefdc]ij", "hij", new[] { (0, 3) }); +>> ForAll( MatchAll( "hij", "[abhgefdc]ij" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 273: yield return (@"(a|b)c*d", "abcd", new[] { (1, 4) }); +>> ForAll( MatchAll( "abcd", "(a|b)c*d" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:1,E:4}) + +# 274: yield return (@"(ab|ab*)bc", "abc", new[] { (0, 3) }); +>> ForAll( MatchAll( "abc", "(ab|ab*)bc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 275: yield return (@"a([bc]*)c*", "abc", new[] { (0, 3) }); +>> ForAll( MatchAll( "abc", "a([bc]*)c*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 276: yield return (@"a[bcd]*dcdcde", "adcdcde", new[] { (0, 7) }); +>> ForAll( MatchAll( "adcdcde", "a[bcd]*dcdcde" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:7}) + +# 277: yield return (@"(ab|a)b*c", "abc", new[] { (0, 3) }); +>> ForAll( MatchAll( "abc", "(ab|a)b*c" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 278: yield return (@"[A-Za-z_][A-Za-z0-9_]*", "alpha", new[] { (0, 5) }); +>> ForAll( MatchAll( "alpha", "[A-Za-z_][A-Za-z0-9_]*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:5}) + +# 279: yield return (@"^a(bc+|b[eh])g|.h$", "abh", new[] { (1, 3) }); +>> ForAll( MatchAll( "abh", "^a(bc+|b[eh])g|.h$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:1,E:3}) + +# 280: yield return (@"abcd", "abcd", new[] { (0, 4) }); +>> ForAll( MatchAll( "abcd", "abcd" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:4}) + +# 281: yield return (@"a(bc)d", "abcd", new[] { (0, 4) }); +>> ForAll( MatchAll( "abcd", "a(bc)d" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:4}) + +# 283: yield return (@"a+(b|c)*d+", "aabcdd", new[] { (0, 6) }); +>> ForAll( MatchAll( "aabcdd", "a+(b|c)*d+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:6}) + +# 284: yield return (@"^.+$", "vivi", new[] { (0, 4) }); +>> ForAll( MatchAll( "vivi", "^.+$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:4}) + +# 285: yield return (@"^(.+)$", "vivi", new[] { (0, 4) }); +>> ForAll( MatchAll( "vivi", "^(.+)$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:4}) + +# 286: yield return (@".*(/XXX).*", "/XXX", new[] { (0, 4) }); +>> ForAll( MatchAll( "/XXX", ".*(/XXX).*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:4}) + +# 287: yield return (@".*(/000).*", "/000", new[] { (0, 4) }); +>> ForAll( MatchAll( "/000", ".*(/000).*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:4}) + +# 288: yield return (@".*(\\000).*", "\000", new ValueTuple[] { }); +>> ForAll( MatchAll( "\000", ".*(\\000).*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 289: yield return (@"\\000", "\000", new ValueTuple[] { }); +>> ForAll( MatchAll( "\000", "\\000" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 290: yield return (@"(a*)*", "a", new[] { (0, 1), (1, 1) }); +>> ForAll( MatchAll( "a", "(a*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1},{B:1,E:1}) + +# 291: yield return (@"(a*)*", "x", new[] { (0, 0), (1, 1) }); +>> ForAll( MatchAll( "x", "(a*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1}) + +# 292: yield return (@"(a*)*", "aaaaaa", new[] { (0, 6), (6, 6) }); +>> ForAll( MatchAll( "aaaaaa", "(a*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:6},{B:6,E:6}) + +# 293: yield return (@"(a*)*", "aaaaaax", new[] { (0, 6), (6, 6), (7, 7) }); +>> ForAll( MatchAll( "aaaaaax", "(a*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:6},{B:6,E:6},{B:7,E:7}) + +# 294: yield return (@"(a*)+", "a", new[] { (0, 1), (1, 1) }); +>> ForAll( MatchAll( "a", "(a*)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1},{B:1,E:1}) + +# 295: yield return (@"(a*)+", "x", new[] { (0, 0), (1, 1) }); +>> ForAll( MatchAll( "x", "(a*)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1}) + +# 296: yield return (@"(a*)+", "aaaaaa", new[] { (0, 6), (6, 6) }); +>> ForAll( MatchAll( "aaaaaa", "(a*)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:6},{B:6,E:6}) + +# 297: yield return (@"(a*)+", "aaaaaax", new[] { (0, 6), (6, 6), (7, 7) }); +>> ForAll( MatchAll( "aaaaaax", "(a*)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:6},{B:6,E:6},{B:7,E:7}) + +# 298: yield return (@"(a+)*", "a", new[] { (0, 1), (1, 1) }); +>> ForAll( MatchAll( "a", "(a+)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1},{B:1,E:1}) + +# 299: yield return (@"(a+)*", "x", new[] { (0, 0), (1, 1) }); +>> ForAll( MatchAll( "x", "(a+)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1}) + +# 300: yield return (@"(a+)*", "aaaaaa", new[] { (0, 6), (6, 6) }); +>> ForAll( MatchAll( "aaaaaa", "(a+)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:6},{B:6,E:6}) + +# 301: yield return (@"(a+)*", "aaaaaax", new[] { (0, 6), (6, 6), (7, 7) }); +>> ForAll( MatchAll( "aaaaaax", "(a+)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:6},{B:6,E:6},{B:7,E:7}) + +# 302: yield return (@"(a+)+", "a", new[] { (0, 1) }); +>> ForAll( MatchAll( "a", "(a+)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1}) + +# 303: yield return (@"(a+)+", "x", new ValueTuple[] { }); +>> ForAll( MatchAll( "x", "(a+)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 304: yield return (@"(a+)+", "aaaaaa", new[] { (0, 6) }); +>> ForAll( MatchAll( "aaaaaa", "(a+)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:6}) + +# 305: yield return (@"(a+)+", "aaaaaax", new[] { (0, 6) }); +>> ForAll( MatchAll( "aaaaaax", "(a+)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:6}) + +# 306: yield return (@"([a]*)*", "a", new[] { (0, 1), (1, 1) }); +>> ForAll( MatchAll( "a", "([a]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1},{B:1,E:1}) + +# 307: yield return (@"([a]*)*", "x", new[] { (0, 0), (1, 1) }); +>> ForAll( MatchAll( "x", "([a]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1}) + +# 308: yield return (@"([a]*)*", "aaaaaa", new[] { (0, 6), (6, 6) }); +>> ForAll( MatchAll( "aaaaaa", "([a]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:6},{B:6,E:6}) + +# 309: yield return (@"([a]*)*", "aaaaaax", new[] { (0, 6), (6, 6), (7, 7) }); +>> ForAll( MatchAll( "aaaaaax", "([a]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:6},{B:6,E:6},{B:7,E:7}) + +# 310: yield return (@"([a]*)+", "a", new[] { (0, 1), (1, 1) }); +>> ForAll( MatchAll( "a", "([a]*)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1},{B:1,E:1}) + +# 311: yield return (@"([a]*)+", "x", new[] { (0, 0), (1, 1) }); +>> ForAll( MatchAll( "x", "([a]*)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1}) + +# 312: yield return (@"([a]*)+", "aaaaaa", new[] { (0, 6), (6, 6) }); +>> ForAll( MatchAll( "aaaaaa", "([a]*)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:6},{B:6,E:6}) + +# 313: yield return (@"([a]*)+", "aaaaaax", new[] { (0, 6), (6, 6), (7, 7) }); +>> ForAll( MatchAll( "aaaaaax", "([a]*)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:6},{B:6,E:6},{B:7,E:7}) + +# 314: yield return (@"([^b]*)*", "a", new[] { (0, 1), (1, 1) }); +>> ForAll( MatchAll( "a", "([^b]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1},{B:1,E:1}) + +# 315: yield return (@"([^b]*)*", "b", new[] { (0, 0), (1, 1) }); +>> ForAll( MatchAll( "b", "([^b]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1}) + +# 316: yield return (@"([^b]*)*", "aaaaaa", new[] { (0, 6), (6, 6) }); +>> ForAll( MatchAll( "aaaaaa", "([^b]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:6},{B:6,E:6}) + +# 317: yield return (@"([ab]*)*", "a", new[] { (0, 1), (1, 1) }); +>> ForAll( MatchAll( "a", "([ab]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1},{B:1,E:1}) + +# 318: yield return (@"([ab]*)*", "aaaaaa", new[] { (0, 6), (6, 6) }); +>> ForAll( MatchAll( "aaaaaa", "([ab]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:6},{B:6,E:6}) + +# 319: yield return (@"([ab]*)*", "ababab", new[] { (0, 6), (6, 6) }); +>> ForAll( MatchAll( "ababab", "([ab]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:6},{B:6,E:6}) + +# 320: yield return (@"([ab]*)*", "bababa", new[] { (0, 6), (6, 6) }); +>> ForAll( MatchAll( "bababa", "([ab]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:6},{B:6,E:6}) + +# 321: yield return (@"([ab]*)*", "b", new[] { (0, 1), (1, 1) }); +>> ForAll( MatchAll( "b", "([ab]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1},{B:1,E:1}) + +# 322: yield return (@"([ab]*)*", "bbbbbb", new[] { (0, 6), (6, 6) }); +>> ForAll( MatchAll( "bbbbbb", "([ab]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:6},{B:6,E:6}) + +# 323: yield return (@"([^a]*)*", "b", new[] { (0, 1), (1, 1) }); +>> ForAll( MatchAll( "b", "([^a]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1},{B:1,E:1}) + +# 324: yield return (@"([^a]*)*", "bbbbbb", new[] { (0, 6), (6, 6) }); +>> ForAll( MatchAll( "bbbbbb", "([^a]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:6},{B:6,E:6}) + +# 325: yield return (@"([^a]*)*", "aaaaaa", new[] { (0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6) }); +>> ForAll( MatchAll( "aaaaaa", "([^a]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3},{B:4,E:4},{B:5,E:5},{B:6,E:6}) + +# 326: yield return (@"([^ab]*)*", "ababab", new[] { (0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6) }); +>> ForAll( MatchAll( "ababab", "([^ab]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3},{B:4,E:4},{B:5,E:5},{B:6,E:6}) + +# 327: yield return (@"((..)|(.))", "", new ValueTuple[] { }); +>> ForAll( MatchAll( "", "((..)|(.))" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 328: yield return (@"((..)|(.))((..)|(.))", "", new ValueTuple[] { }); +>> ForAll( MatchAll( "", "((..)|(.))((..)|(.))" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 329: yield return (@"((..)|(.))((..)|(.))((..)|(.))", "", new ValueTuple[] { }); +>> ForAll( MatchAll( "", "((..)|(.))((..)|(.))((..)|(.))" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 330: yield return (@"((..)|(.)){1}", "", new ValueTuple[] { }); +>> ForAll( MatchAll( "", "((..)|(.)){1}" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 331: yield return (@"((..)|(.)){2}", "", new ValueTuple[] { }); +>> ForAll( MatchAll( "", "((..)|(.)){2}" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 332: yield return (@"((..)|(.)){3}", "", new ValueTuple[] { }); +>> ForAll( MatchAll( "", "((..)|(.)){3}" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 333: yield return (@"((..)|(.))*", "", new[] { (0, 0) }); +>> ForAll( MatchAll( "", "((..)|(.))*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0}) + +# 334: yield return (@"((..)|(.))((..)|(.))", "a", new ValueTuple[] { }); +>> ForAll( MatchAll( "a", "((..)|(.))((..)|(.))" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 335: yield return (@"((..)|(.))((..)|(.))((..)|(.))", "a", new ValueTuple[] { }); +>> ForAll( MatchAll( "a", "((..)|(.))((..)|(.))((..)|(.))" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 336: yield return (@"((..)|(.)){2}", "a", new ValueTuple[] { }); +>> ForAll( MatchAll( "a", "((..)|(.)){2}" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 337: yield return (@"((..)|(.)){3}", "a", new ValueTuple[] { }); +>> ForAll( MatchAll( "a", "((..)|(.)){3}" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 338: yield return (@"((..)|(.))((..)|(.))((..)|(.))", "aa", new ValueTuple[] { }); +>> ForAll( MatchAll( "aa", "((..)|(.))((..)|(.))((..)|(.))" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 339: yield return (@"((..)|(.)){3}", "aa", new ValueTuple[] { }); +>> ForAll( MatchAll( "aa", "((..)|(.)){3}" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 340: yield return (@"(a|ab|c|bcd){4,}(d*)", "ababcd", new ValueTuple[] { }); +>> ForAll( MatchAll( "ababcd", "(a|ab|c|bcd){4,}(d*)" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 341: yield return (@"(a|ab|c|bcd){4,10}(d*)", "ababcd", new ValueTuple[] { }); +>> ForAll( MatchAll( "ababcd", "(a|ab|c|bcd){4,10}(d*)" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 342: yield return (@"(ab|a|c|bcd){4,}(d*)", "ababcd", new ValueTuple[] { }); +>> ForAll( MatchAll( "ababcd", "(ab|a|c|bcd){4,}(d*)" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 343: yield return (@"(ab|a|c|bcd){4,10}(d*)", "ababcd", new ValueTuple[] { }); +>> ForAll( MatchAll( "ababcd", "(ab|a|c|bcd){4,10}(d*)" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 344: yield return (@"^abc", "abc", new[] { (0, 3) }); +>> ForAll( MatchAll( "abc", "^abc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 345: yield return (@"^abc", "zabc", new ValueTuple[] { }); +>> ForAll( MatchAll( "zabc", "^abc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 346: yield return (@"abc", "xxxxxab", new ValueTuple[] { }); +>> ForAll( MatchAll( "xxxxxab", "abc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 347: yield return (@"(?i)[^x]", "x", new ValueTuple[] { }); +>> ForAll( MatchAll( "x", "(?i)[^x]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 348: yield return (@"(?i)[^x]", "X", new ValueTuple[] { }); +>> ForAll( MatchAll( "X", "(?i)[^x]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 349: yield return (@"[[:word:]]", "_", new ValueTuple[] { }); +>> ForAll( MatchAll( "_", "[[:word:]]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 350: yield return (@"ab?|$", "az", new[] { (0, 1), (2, 2) }); +>> ForAll( MatchAll( "az", "ab?|$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1},{B:2,E:2}) + +# 351: yield return (@"^(.*?)(\n|\r\n?|$)", "ab\rcd", new[] { (0, 3) }); +>> ForAll( MatchAll( "ab\rcd", "^(.*?)(\n|\r\n?|$)" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 352: yield return (@"z*azb", "azb", new[] { (0, 3) }); +>> ForAll( MatchAll( "azb", "z*azb" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 353: yield return (@"(?i)\p{Ll}+", "\u039B\u0398\u0393\u0394\u03B1", new[] { (0, 5) }); +>> ForAll( MatchAll( UniChar(Hex2Dec("039B"))&UniChar(Hex2Dec("0398"))&UniChar(Hex2Dec("0393"))&UniChar(Hex2Dec("0394"))&UniChar(Hex2Dec("03B1")), "(?i)\p{Ll}+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:5}) + +# 354: yield return (@"1|2|3|4|5|6|7|8|9|10|int", "int", new[] { (0, 3) }); +>> ForAll( MatchAll( "int", "1|2|3|4|5|6|7|8|9|10|int" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 355: yield return (@"^a[[:^space:]]", "a ", new ValueTuple[] { }); +>> ForAll( MatchAll( "a ", "^a[[:^space:]]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 356: yield return (@"^a[[:^space:]]", "foo boo a ", new ValueTuple[] { }); +>> ForAll( MatchAll( "foo boo a ", "^a[[:^space:]]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 357: yield return (@"^-[a-z]", "r-f", new ValueTuple[] { }); +>> ForAll( MatchAll( "r-f", "^-[a-z]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 358: yield return (@"(ABC|CDA|BC)X", "CDAX", new[] { (0, 4) }); +>> ForAll( MatchAll( "CDAX", "(ABC|CDA|BC)X" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:4}) + +# 359: yield return (@"(aa$)?", "aaz", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); +>> ForAll( MatchAll( "aaz", "(aa$)?" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) + +# 360: yield return (@"ab??", "ab", new[] { (0, 1) }); +>> ForAll( MatchAll( "ab", "ab??" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1}) + +# 361: yield return (@".*abcd", "abcd", new[] { (0, 4) }); +>> ForAll( MatchAll( "abcd", ".*abcd" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:4}) + +# 362: yield return (@".*(?:abcd)+", "abcd", new[] { (0, 4) }); +>> ForAll( MatchAll( "abcd", ".*(?:abcd)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:4}) + +# 363: yield return (@".*(?:abcd)+", "abcdabcd", new[] { (0, 8) }); +>> ForAll( MatchAll( "abcdabcd", ".*(?:abcd)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:8}) + +# 364: yield return (@".*(?:abcd)+", "abcdxabcd", new[] { (0, 9) }); +>> ForAll( MatchAll( "abcdxabcd", ".*(?:abcd)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:9}) + +# 365: yield return (@".*x(?:abcd)+", "abcdxabcd", new[] { (0, 9) }); +>> ForAll( MatchAll( "abcdxabcd", ".*x(?:abcd)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:9}) + +# 366: yield return (@"[^abcd]*x(?:abcd)+", "abcdxabcd", new[] { (4, 9) }); +>> ForAll( MatchAll( "abcdxabcd", "[^abcd]*x(?:abcd)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:4,E:9}) + +# 367: yield return (@".", "\xD4\xC2\x65\x2B\x0E\xFE", new[] { (0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6) }); +>> ForAll( MatchAll( Char(Hex2Dec("D4"))&Char(Hex2Dec("C2"))&Char(Hex2Dec("65"))&Char(Hex2Dec("2B"))&Char(Hex2Dec("0E"))&Char(Hex2Dec("FE")), "." ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1},{B:1,E:2},{B:2,E:3},{B:3,E:4},{B:4,E:5},{B:5,E:6}) + +# 374: yield return (@"\p{Lu}+", "\u039B\u0398\u0393\u0394\u03B1", new[] { (0, 4) }); +>> ForAll( MatchAll( UniChar(Hex2Dec("039B"))&UniChar(Hex2Dec("0398"))&UniChar(Hex2Dec("0393"))&UniChar(Hex2Dec("0394"))&UniChar(Hex2Dec("03B1")), "\p{Lu}+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:4}) + +# 375: yield return (@"(?i)\p{Lu}+", "\u039B\u0398\u0393\u0394\u03B1", new[] { (0, 5) }); +>> ForAll( MatchAll( UniChar(Hex2Dec("039B"))&UniChar(Hex2Dec("0398"))&UniChar(Hex2Dec("0393"))&UniChar(Hex2Dec("0394"))&UniChar(Hex2Dec("03B1")), "(?i)\p{Lu}+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:5}) + +# 376: yield return (@"\p{L}+", "\u039B\u0398\u0393\u0394\u03B1", new[] { (0, 5) }); +>> ForAll( MatchAll( UniChar(Hex2Dec("039B"))&UniChar(Hex2Dec("0398"))&UniChar(Hex2Dec("0393"))&UniChar(Hex2Dec("0394"))&UniChar(Hex2Dec("03B1")), "\p{L}+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:5}) + +# 377: yield return (@"\p{Ll}+", "\u039B\u0398\u0393\u0394\u03B1", new[] { (4, 5) }); +>> ForAll( MatchAll( UniChar(Hex2Dec("039B"))&UniChar(Hex2Dec("0398"))&UniChar(Hex2Dec("0393"))&UniChar(Hex2Dec("0394"))&UniChar(Hex2Dec("03B1")), "\p{Ll}+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:4,E:5}) + +# 378: yield return (@"\w+", "d\u03B4d", new[] { (0, 3) }); +>> ForAll( MatchAll( "d"&UniChar(Hex2Dec("03B4d")), "\w+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:3}) + +# 379: yield return (@"\w+", "\u2961", new ValueTuple[] { }); +>> ForAll( MatchAll( UniChar(Hex2Dec("2961")), "\w+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 380: yield return (@"\W+", "\u2961", new[] { (0, 1) }); +>> ForAll( MatchAll( UniChar(Hex2Dec("2961")), "\W+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1}) + +# 381: yield return (@"\d+", "1\u0968\u09699", new[] { (0, 4) }); +>> ForAll( MatchAll( "1"&UniChar(Hex2Dec("0968"))&UniChar(Hex2Dec("09699")), "\d+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:4}) + +# 382: yield return (@"\d+", "\u2161", new ValueTuple[] { }); +>> ForAll( MatchAll( UniChar(Hex2Dec("2161")), "\d+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 383: yield return (@"\D+", "\u2161", new[] { (0, 1) }); +>> ForAll( MatchAll( UniChar(Hex2Dec("2161")), "\D+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1}) + +# 384: yield return (@"\s+", "\u1680", new[] { (0, 1) }); +>> ForAll( MatchAll( UniChar(Hex2Dec("1680")), "\s+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1}) + +# 385: yield return (@"\s+", "\u2603", new ValueTuple[] { }); +>> ForAll( MatchAll( UniChar(Hex2Dec("2603")), "\s+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 386: yield return (@"\S+", "\u2603", new[] { (0, 1) }); +>> ForAll( MatchAll( UniChar(Hex2Dec("2603")), "\S+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1}) + +# 387: yield return (@"\d\b", "6\u03B4", new ValueTuple[] { }); +>> ForAll( MatchAll( "6"&UniChar(Hex2Dec("03B4")), "\d\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + +# 388: yield return (@"\d\b", "6\u1680", new[] { (0, 1) }); +>> ForAll( MatchAll( "6"&UniChar(Hex2Dec("1680")), "\d\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1}) + +# 389: yield return (@"\d\B", "6\u03B4", new[] { (0, 1) }); +>> ForAll( MatchAll( "6"&UniChar(Hex2Dec("03B4")), "\d\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table({B:0,E:1}) + +# 390: yield return (@"\d\B", "6\u1680", new ValueTuple[] { }); +>> ForAll( MatchAll( "6"&UniChar(Hex2Dec("1680")), "\d\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) +Table() + diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Microsoft.PowerFx.Core.Tests.Shared.projitems b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Microsoft.PowerFx.Core.Tests.Shared.projitems index 5a1a0195bd..3c22fe5088 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Microsoft.PowerFx.Core.Tests.Shared.projitems +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Microsoft.PowerFx.Core.Tests.Shared.projitems @@ -38,16 +38,6 @@ - - ExpressionTestCases\%(Filename)%(Extension) - content\ExpressionTestCases - PreserveNewest - - - ExpressionTestCases\%(Filename)%(Extension) - contentFiles\any\$(TargetFrameworks)\ExpressionTestCases - PreserveNewest - ExpressionTestCases\NotYetReady\%(Filename)%(Extension) content\ExpressionTestCases\NotYetReady diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index 524433dffa..fed0d45019 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -153,12 +153,13 @@ private static bool ShouldSkipDotNetVersion(ExpressionTestCase testCase, string return false; } -#if false +#if true // Helper to run a single .txt [Fact] public void RunOne() { - var path = @"D:\repos\osp1\src\tests\Microsoft.PowerFx.Core.Tests\ExpressionTestCases\StronglyTypedEnum_TestEnums_PreV1.txt"; + // var path = @"C:\odm\retests\rust_fx.txt"; + var path = @"C:\repos\regex-min\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\Match_Limited.txt"; var line = 0; var runner = new InterpreterRunner(); From 601de22bc8f7d39b0ef5a2ca7fb30e54fc084d72 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Tue, 2 Jul 2024 12:22:31 -0700 Subject: [PATCH 03/61] Updates --- .../Localization/Strings.cs | 2 +- .../Texl/Builtins/Match.cs | 147 ++++++++----- src/strings/PowerFxResources.en-US.resx | 2 +- .../ExpressionTestCases/Match_Limited.txt | 203 +++++++++++++++++- ...rosoft.PowerFx.Core.Tests.Shared.projitems | 10 + .../FileExpressionEvaluationTests.cs | 2 +- 6 files changed, 308 insertions(+), 58 deletions(-) diff --git a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs index 1e9fc163a0..56719143de 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs @@ -730,7 +730,7 @@ internal static class TexlStrings public static ErrorResourceKey ErrInvalidRegExBadSingleQuoteNamedCapture = new ErrorResourceKey("ErrInvalidRegExBadSingleQuoteNamedCapture"); public static ErrorResourceKey ErrInvalidRegExBadEscape = new ErrorResourceKey("ErrInvalidRegExBadEscape"); public static ErrorResourceKey ErrInvalidRegExBadCharacterClassSubtraction = new ErrorResourceKey("ErrInvalidRegExBadCharacterClassSubtraction"); - public static ErrorResourceKey ErrInvalidRegExBadConditional = new ErrorResourceKey("ErrInvalidRegExBadBadConditional"); + public static ErrorResourceKey ErrInvalidRegExBadConditional = new ErrorResourceKey("ErrInvalidRegExBadConditional"); public static ErrorResourceKey ErrVariableRegEx = new ErrorResourceKey("ErrVariableRegEx"); public static ErrorResourceKey InfoRegExCaptureNameHidesPredefinedFullMatchField = new ErrorResourceKey("InfoRegExCaptureNameHidesPredefinedFullMatchField"); diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index 81ffa4ac83..bd405d8f98 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -88,82 +88,116 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp } string regularExpression = nodeValue; - fValid &= LimitRegularExpression(regExNode, regularExpression, errors); - fValid &= TryCreateReturnType(regExNode, regularExpression, errors, ref returnType); - return fValid; + return fValid && + (!context.Features.PowerFxV1CompatibilityRules || LimitRegularExpression(regExNode, regularExpression, errors)) && + TryCreateReturnType(regExNode, regularExpression, errors, ref returnType); } - // Disallow self referncing groups and consitently treat all "\[1-9][0-9]*" as a backreference. - // This avoids inconsistencies between .net and JavaScript regular expression behavior - // while maintaining Unicode definition of words, by avoiding the use of RegexOptions.ECMAScript. - // See https://learn.microsoft.com/en-us/dotnet/standard/base-types/regular-expression-options#ecmascript-matching-behavior + // Limit regular expressions to common features that are supported, with conssitent semantics, by both canonical .NET and XRegExp. + // It is better to disallow now and bring back with customer demand or as platforms add more support. + // + // Features that are disallowed: + // Capture groups + // Self-referncing groups, such as "(a\1)". + // Treat all escaped number sequences as a backreference number. + // Single quoted "(?'name'..." and "\k'name'". + // Balancing capture groups. + // Octal character codes (use Hex or Unicode instead). + // "\o" could be added in the future, but we should avoid "\0" which causes backreference confusion. + // Inline options + // Anywhere in the expression except the beginning. + // For subexpressions. + // Character classes + // Character class subtraction "[a-z-[m-n]]". + // Conditional alternation + // + // Features that aren't supported by canonical .NET will be blocked automatically when the regular expression is instantiated in TryCreateReturnType. + // + // We chose to use canonical .NET instead of RegexOptions.ECMAScript because we wanted the unicode definitions for words. + // See https://learn.microsoft.com/dotnet/standard/base-types/regular-expression-options#ecmascript-matching-behavior for more details private bool LimitRegularExpression(TexlNode regExNode, string regexPattern, IErrorContainer errors) { - // todo: - // group range - // scans the regular expression, counting capture groups and comparing with backreference numbers. + // Scans the regular expression for interesting constructs, ignoring other elements and constructs that are leagl, such as letters and numbers. + // Order of alternation is important. .NET regular expressions are greedy and will match the first of these that it can. + // Many subexpressions here take advantage of this, matching something that is valid, before falling through to check for something that is invalid. + // + // For example, consider testing "\\(\a)". This will match . + // will report an error and stop further processing. + // One might think that the "\a" could have matched , but it will match first because it is first in the RE. + // One might think that the "\(" could have matched , but the double backslashes will be consumed first, which is why it is important + // to gather all the matches in a linear scan from the beginning to the end. var groupPunctuationRE = new Regex( @" - (?\\(?:(?[1-9]\d*)|k<(?\w+)>)) | # valid backreference are accepted, others are an error - (?\\0[0-7]{0,3}) | - # any other escaped character is ignored, but must be paired so that '\\(' is seen as '\\' followed by '(' - (?\\(?:[bBtrvfnwWsSdD]|[pP]\{\w+\}|c[a-zA-Z]|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4})) | # missing are AaeGZz that are not supported with XRegExp, other common are u{} and o - (?\\[a-zA-Z_]) | - (?\\.) | # any other escaped character is ignored, but must be paired so that '\\(' is seen as '\\' followed by '(' and not '\' folloed by '\(' - - (?^\(\?[imns]+\)) | - (?\(\?<(\w+)>) | - (?\(\?:) | - (?\(\?(?:\w*-\w+|\w+)(?::|\))?) | - (?\(\?(?:<|')\w*-\w+(?:>|')?) | - (?\(\?'\w+'?) | - (?\(\?\(\?) | - - (?\() | - (?\)) | # parens that aren't escaped that could start/end a group, provided they are outside a character class - (?\[) | - (?\]) # character class start/end - ", RegexOptions.IgnorePatternWhitespace); - var groupNumStack = new Stack(); // int is the group number, -1 is used for non capturing groups - var groupNameDict = new Dictionary(); - var groupCounter = 0; // last group number defined - var openCharacterClass = false; // are we inside square brackets where parens do not need to be escaped? + # leading backslash + \\(?[1-9]\d*) | # numeric backreference + \\k<(?\w+)> | # named backreference + (?\\0[0-7]{0,3}) | # octal are not accepted (no XRegExp support, by design) + (?\\ + ([bBdDfnrsStvwW] | # standard regex character classes, missing from .NET are aAeGzZ (no XRegExp support), other common are u{} and o + [pP]\{\w+\} | # unicode character classes + c[a-zA-Z] | # Ctrl character classes + x[0-9a-fA-F]{2} | # hex character, must be exactly 2 hex digits + u[0-9a-fA-F]{4})) | # Unicode characters, must be exactly 4 hex digits + (?\\[a-zA-Z_]) | # reserving all other letters and underscore for future use (consistent with .NET) + (?\\.) | # any other escaped character is allowed, but must be paired so that '\\(' is seen as '\\' followed by '(' and not '\' folloed by '\(' + + # leading (? + \(\?<(?\w+)> | # named capture group + (?\(\?:) | # non-capture group, still need to track to match with closing + (?^\(\?[im]+\)) | # inline front of expression options we do support + (?\(\?(\w*-\w+|\w+)(:|\))?) | # inline options that we don't support, including disable of options (last ? portion makes for a better error message) + (?\(\?(<|')\w*-\w+(>|')?) | # .NET balancing captures are not supported (last ? portion makes for a better error message) + (?\(\?'\w+'?) | # single quoted capture names are not supported (last ? portion makes for a better error message) + (?\(\?\() | # .NET conditional alternations are not supported + + # basic open and close + (?\() | + (?\)) | + (?\[) | + (?\]) + ", RegexOptions.IgnorePatternWhitespace | RegexOptions.ExplicitCapture); + + var groupCounter = 0; // last group number defined + var groupNumStack = new Stack(); // stack of group numbers, -1 is used for non capturing groups + var groupNameDict = new Dictionary(); // mapping from group names to group numbers, membership means the name was defined + + var openCharacterClass = false; // are we defining a character class? foreach (Match groupMatch in groupPunctuationRE.Matches(regexPattern)) { - if (groupMatch.Groups["backRefNum"].Success) + if (groupMatch.Groups["goodBackRefNum"].Success) { - var backRefNum = int.Parse(groupMatch.Groups["backRefNum"].Value, CultureInfo.InvariantCulture); + var backRefNum = int.Parse(groupMatch.Groups["goodBackRefNum"].Value, CultureInfo.InvariantCulture); // group isn't defined, or not defined yet if (backRefNum > groupCounter) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefNotDefined, groupMatch.Groups["backRef"].Value); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefNotDefined, groupMatch.Value); return false; } // group is not closed and thus self referencing if (groupNumStack.Contains(backRefNum)) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefSelfReferencing, groupMatch.Groups["backRef"].Value); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefSelfReferencing, groupMatch.Value); return false; } } - else if (groupMatch.Groups["backRefName"].Success) + else if (groupMatch.Groups["goodBackRefName"].Success) { - var backRefName = groupMatch.Groups["backRefName"].Value; + var backRefName = groupMatch.Groups["goodBackRefName"].Value; // group isn't defined, or not defined yet - if (!groupNameDict.TryGetValue(groupMatch.Groups["backRefName"].Value, out var groupNum)) + if (!groupNameDict.TryGetValue(backRefName, out var groupNum)) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefNotDefined, groupMatch.Groups["backRef"].Value); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefNotDefined, groupMatch.Value); return false; } // group is not closed and thus self referencing if (groupNumStack.Contains(groupNum)) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefSelfReferencing, groupMatch.Groups["backRef"].Value); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefSelfReferencing, groupMatch.Value); return false; } } @@ -220,6 +254,7 @@ private bool LimitRegularExpression(TexlNode regExNode, string regexPattern, IEr } else if (groupMatch.Groups["closeCapture"].Success) { + // parens do not need to be escaped within square brackets if (!openCharacterClass) { groupNumStack.Pop(); @@ -229,23 +264,35 @@ private bool LimitRegularExpression(TexlNode regExNode, string regexPattern, IEr { if (openCharacterClass) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadCharacterClassSubtraction); - return false; - } + // character class subtraction "[a-z-[m-n]]" is not supported + if (regexPattern[groupMatch.Groups["openCharacterClass"].Index - 1] == '-') + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadCharacterClassSubtraction); + return false; + } - openCharacterClass = true; + // else ok, "[a[b]" is supported + } + else + { + openCharacterClass = true; + } } else if (groupMatch.Groups["closeCharacterClass"].Success) { - openCharacterClass = false; + // supports "[]]" which is valid but the closing square bracket must immediately follow the open + if (openCharacterClass && regexPattern[groupMatch.Groups["closeCharacterClass"].Index - 1] != '[') + { + openCharacterClass = false; + } } - else if (groupMatch.Groups["goodEescape"].Success || groupMatch.Groups["goodEscapeAlpha"].Success || groupMatch.Groups["goodOptions"].Success) + else if (groupMatch.Groups["goodEscape"].Success || groupMatch.Groups["goodEscapeAlpha"].Success || groupMatch.Groups["goodOptions"].Success) { // all is well, nothing to do } else { - throw new NotImplementedException("Internal error in LimitRegularExpression"); + throw new NotImplementedException("Unknown regular expression match"); } } diff --git a/src/strings/PowerFxResources.en-US.resx b/src/strings/PowerFxResources.en-US.resx index 78a094f9a7..b07993c2e4 100644 --- a/src/strings/PowerFxResources.en-US.resx +++ b/src/strings/PowerFxResources.en-US.resx @@ -4412,7 +4412,7 @@ Error message indicating that the regular expression has single quoted named capture. - Invalid regular expression: Conditionals are not supported; found "{0}". + Invalid regular expression: Conditional alternation is not supported; found "{0}". Error message indicating that the regular expression has conditionals. diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt index 9e7f20edf2..6bd27b8582 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt @@ -1,4 +1,4 @@ -#SETUP: RegEx +#SETUP: RegEx,PowerFxV1CompatibilityRules,SupportColumnNamesAsIdentifiers // For conssitent regular expressions across hosts, these tests check that we are // limiting .NET regular expresions to what we can also support in JavaScript with XRegExp @@ -75,13 +75,206 @@ Errors: Error 33-43: Invalid regular expression: Inline options must appear at t >> Match( "(hello world)", "(?)a") Errors: Error 24-35: Invalid regular expression: Balancing capture groups is not supported; found "(?".|Error 0-5: The function 'Match' has some invalid arguments. +>> Match( "(hello world)", "(?)a(?<-s>)b") +Errors: Error 24-41: Invalid regular expression: Balancing capture groups is not supported; found "(?<-s>".|Error 0-5: The function 'Match' has some invalid arguments. + // groups with single ticks ->> Match( "(hello wrold)", "(?'name'l)") +>> Match( "(hello world)", "(?'name'l)") Errors: Error 24-36: Invalid regular expression: Using single quoted named captures is not supported, use (?<...>) syntax instead; found "(?'name'".|Error 0-5: The function 'Match' has some invalid arguments. ->> Match( "(hello wrold)", "(?'s-e'l)") +>> Match( "(hello world)", "(?'s-e'l)") Errors: Error 24-35: Invalid regular expression: Balancing capture groups is not supported; found "(?'s-e'".|Error 0-5: The function 'Match' has some invalid arguments. ->> Fail -Fail +// conditional alternation + +// Console.WriteLine( Regex.Match( "1-23-456-7890", @"(?(\d{2}-)\d{2}-\d{2}|\d{3}-\d{2})" ).Value ); +>> Match( "1-23-456-7890", "(?(\d{2}-)\d{2}-\d{2}|\d{3}-\d{2})" ) +Errors: Error 24-60: Invalid regular expression: Conditional alternation is not supported; found "(?(".|Error 0-5: The function 'Match' has some invalid arguments. + +// Console.WriteLine( Regex.Match( "hello world", @"(e)(?(1)l|d)" ).Value ); +>> Match( "hello world", "(e)(?(1)l|d)" ) +Errors: Error 22-36: Invalid regular expression: Conditional alternation is not supported; found "(?(".|Error 0-5: The function 'Match' has some invalid arguments. + +// character class subtraction +>> Match( "[", "[[]" ) +{FullMatch:"[",StartMatch:1,SubMatches:Table()} + +>> Match( "]", "[]]" ) +{FullMatch:"]",StartMatch:1,SubMatches:Table()} + +>> Match( "a]", "[a]]" ) +{FullMatch:"a]",StartMatch:1,SubMatches:Table()} + +>> Match( "k", "[a-z-[b-c]]" ) +Errors: Error 12-25: Invalid regular expression: Character class subtraction is not supported.|Error 0-5: The function 'Match' has some invalid arguments. + +// regular expression parsing + +>> Match( "test\123bed", "\\(\a)" ) +Errors: Error 22-30: Invalid regular expression: Invalid escape code; found "\a".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test\123bed", "\\(\d)" ) +{FullMatch:"\1",StartMatch:5,SubMatches:Table({Value:"1"})} + +// character classes + +>> Match( "test", "\a" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\a".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "\A" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\A".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "$test atest test", "\btest" ) +{FullMatch:"test",StartMatch:2,SubMatches:Table()} + +>> Match( "$test atest test", "\Btest" ) +{FullMatch:"test",StartMatch:8,SubMatches:Table()} + +>> Match( "test", "\c" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\c".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "\C" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\C".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test123bed", "\d+" ) +{FullMatch:"123",StartMatch:5,SubMatches:Table()} + +>> Match( "test123bed", "\D+" ) +{FullMatch:"test",StartMatch:1,SubMatches:Table()} + +>> Match( "test", "\e" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\e".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "\E" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\E".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test"&Char(12)&"bed", "\f" ) +{FullMatch:" ",StartMatch:5,SubMatches:Table()} + +>> Match( "test", "\F" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\F".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "\g" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\g".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "\G" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\G".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "\h" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\h".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "\H" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\H".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "\i" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\i".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "\I" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\I".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "\j" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\j".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "\J" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\J".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "1234551234", "(?<1>\d)\k<1>" ) +{FullMatch:"55",StartMatch:5,SubMatches:Table({Value:"5"})} + +>> Match( "test", "\K" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\K".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "\l" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\l".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "\L" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\L".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "\m" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\m".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "\M" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\M".|Error 0-5: The function 'Match' has some invalid arguments. + +>> DropColumns( Match( "test" & Char(10) & "bed", "\n" ), FullMatch ) +{StartMatch:5,SubMatches:Table()} + +>> Match( "test", "\N" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\N".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "\o" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\o".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "\O" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\O".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "123test456", "\p{L}+" ) +{FullMatch:"test",StartMatch:4,SubMatches:Table()} + +>> Match( "foo123test456", "\P{L}+" ) +{FullMatch:"123",StartMatch:4,SubMatches:Table()} + +>> Match( "test", "\q" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\q".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "\Q" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\Q".|Error 0-5: The function 'Match' has some invalid arguments. + +>> DropColumns( Match( "test" & Char(13) & "bed", "\r" ), FullMatch ) +{StartMatch:5,SubMatches:Table()} + +>> Match( "test", "\R" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\R".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test bed", "\s+" ) +{FullMatch:" ",StartMatch:5,SubMatches:Table()} + +>> Match( " test ", "\S+" ) +{FullMatch:"test",StartMatch:4,SubMatches:Table()} + +>> Match( "test" & Char(9) & "bed", "\t" ) +{FullMatch:" ",StartMatch:5,SubMatches:Table()} + +>> Match( "test", "\T" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\T".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "\u0065" ) +{FullMatch:"e",StartMatch:2,SubMatches:Table()} + +>> Match( "test", "\U" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\U".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test" & Char(11) & "bed", "\v" ) +{FullMatch:" ",StartMatch:5,SubMatches:Table()} + +>> Match( "test", "\V" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\V".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "&*%test bed^%$", "\w+" ) +{FullMatch:"test",StartMatch:4,SubMatches:Table()} + +>> Match( "test%bed", "\W" ) +{FullMatch:"%",StartMatch:5,SubMatches:Table()} + +>> Match( "test", "\x65" ) +{FullMatch:"e",StartMatch:2,SubMatches:Table()} + +>> Match( "test", "\X" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\X".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "\y" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\y".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "\Y" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\Y".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "\z" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\z".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "\Z" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\Z".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "\_" ) +Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\_".|Error 0-5: The function 'Match' has some invalid arguments. + diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Microsoft.PowerFx.Core.Tests.Shared.projitems b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Microsoft.PowerFx.Core.Tests.Shared.projitems index 3c22fe5088..cc6c9fbbbe 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Microsoft.PowerFx.Core.Tests.Shared.projitems +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Microsoft.PowerFx.Core.Tests.Shared.projitems @@ -38,6 +38,16 @@ + + ExpressionTestCases\%(Filename)%(Extension) + content\ExpressionTestCases + PreserveNewest + + + ExpressionTestCases\%(Filename)%(Extension) + contentFiles\any\$(TargetFrameworks)\ExpressionTestCases + PreserveNewest + ExpressionTestCases\NotYetReady\%(Filename)%(Extension) content\ExpressionTestCases\NotYetReady diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index fed0d45019..f752115208 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -159,7 +159,7 @@ private static bool ShouldSkipDotNetVersion(ExpressionTestCase testCase, string public void RunOne() { // var path = @"C:\odm\retests\rust_fx.txt"; - var path = @"C:\repos\regex-min\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\Match_Limited.txt"; + var path = @"d:\repos\regex-min\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\Match_Limited.txt"; var line = 0; var runner = new InterpreterRunner(); From c36e21f3f670abcfc13fc0f6939cc19e91176f6d Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Tue, 2 Jul 2024 23:08:20 -0700 Subject: [PATCH 04/61] Updates --- .../Texl/Builtins/Match.cs | 105 +- src/strings/PowerFxResources.en-US.resx | 20 +- .../ExpressionTestCases/Match_Limited.txt | 197 ++- .../ExpressionTestCases/rust_fx.txt | 1534 ----------------- .../FileExpressionEvaluationTests.cs | 2 +- 5 files changed, 202 insertions(+), 1656 deletions(-) delete mode 100644 src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/rust_fx.txt diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index bd405d8f98..b6ad9e9169 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -165,7 +165,59 @@ private bool LimitRegularExpression(TexlNode regExNode, string regexPattern, IEr foreach (Match groupMatch in groupPunctuationRE.Matches(regexPattern)) { - if (groupMatch.Groups["goodBackRefNum"].Success) + // ordered from most common/good to least common/bad, for fewer tests + if (groupMatch.Groups["goodEscape"].Success || groupMatch.Groups["goodEscapeAlpha"].Success || groupMatch.Groups["goodOptions"].Success) + { + // all is well, nothing to do + } + else if (groupMatch.Groups["openCharacterClass"].Success) + { + if (openCharacterClass) + { + // character class subtraction "[a-z-[m-n]]" is not supported + if (regexPattern[groupMatch.Groups["openCharacterClass"].Index - 1] == '-') + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadCharacterClassSubtraction); + return false; + } + + // else ok, "[a[b]" is supported + } + else + { + openCharacterClass = true; + } + } + else if (groupMatch.Groups["closeCharacterClass"].Success) + { + // supports "[]]" which is valid but the closing square bracket must immediately follow the open + if (openCharacterClass && regexPattern[groupMatch.Groups["closeCharacterClass"].Index - 1] != '[') + { + openCharacterClass = false; + } + } + else if (groupMatch.Groups["openCapture"].Success || groupMatch.Groups["goodNonCapture"].Success || groupMatch.Groups["goodNamedCapture"].Success) + { + // parens do not need to be escaped within square brackets + if (!openCharacterClass) + { + // non capturing group still needs to match closing paren, but does not define a new group + groupNumStack.Push(groupMatch.Groups["goodNonCapture"].Success ? -1 : ++groupCounter); + if (groupMatch.Groups["goodNamedCapture"].Success) + { + groupNameDict.Add(groupMatch.Groups["goodNamedCapture"].Value, groupCounter); + } + } + } + else if (groupMatch.Groups["closeCapture"].Success) + { + // parens do not need to be escaped within square brackets + if (!openCharacterClass) + { + groupNumStack.Pop(); + } + } + else if (groupMatch.Groups["goodBackRefNum"].Success) { var backRefNum = int.Parse(groupMatch.Groups["goodBackRefNum"].Value, CultureInfo.InvariantCulture); @@ -239,57 +291,6 @@ private bool LimitRegularExpression(TexlNode regExNode, string regexPattern, IEr errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadEscape, groupMatch.Groups["badEscapeAlpha"].Value); return false; } - else if (groupMatch.Groups["openCapture"].Success || groupMatch.Groups["goodNonCapture"].Success || groupMatch.Groups["goodNamedCapture"].Success) - { - // parens do not need to be escaped within square brackets - if (!openCharacterClass) - { - // non capturing group still needs to match closing paren, but does not define a new group - groupNumStack.Push(groupMatch.Groups["goodNonCapture"].Success ? -1 : ++groupCounter); - if (groupMatch.Groups["goodNamedCapture"].Success) - { - groupNameDict.Add(groupMatch.Groups["goodNamedCapture"].Value, groupCounter); - } - } - } - else if (groupMatch.Groups["closeCapture"].Success) - { - // parens do not need to be escaped within square brackets - if (!openCharacterClass) - { - groupNumStack.Pop(); - } - } - else if (groupMatch.Groups["openCharacterClass"].Success) - { - if (openCharacterClass) - { - // character class subtraction "[a-z-[m-n]]" is not supported - if (regexPattern[groupMatch.Groups["openCharacterClass"].Index - 1] == '-') - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadCharacterClassSubtraction); - return false; - } - - // else ok, "[a[b]" is supported - } - else - { - openCharacterClass = true; - } - } - else if (groupMatch.Groups["closeCharacterClass"].Success) - { - // supports "[]]" which is valid but the closing square bracket must immediately follow the open - if (openCharacterClass && regexPattern[groupMatch.Groups["closeCharacterClass"].Index - 1] != '[') - { - openCharacterClass = false; - } - } - else if (groupMatch.Groups["goodEscape"].Success || groupMatch.Groups["goodEscapeAlpha"].Success || groupMatch.Groups["goodOptions"].Success) - { - // all is well, nothing to do - } else { throw new NotImplementedException("Unknown regular expression match"); diff --git a/src/strings/PowerFxResources.en-US.resx b/src/strings/PowerFxResources.en-US.resx index b07993c2e4..d53dcbce4f 100644 --- a/src/strings/PowerFxResources.en-US.resx +++ b/src/strings/PowerFxResources.en-US.resx @@ -4376,19 +4376,19 @@ Error message indicating that the regular expression entered by the user is invalid. - Invalid regular expression: Inline options must appear at the beginning of the regular expression; found "{0}" later. + Invalid regular expression: Inline options must appear at the beginning of the regular expression, found "{0}" later. Error message indicating that the regular expression has inline options not at the front. - Invalid regular expression: Inline options are limited to a combination of the letters [imns], cannot disable options, and cannot be used on a subexpression; found "{0}". + Invalid regular expression: Inline options are limited to a combination of the letters [im], cannot disable options, and cannot be used on a subexpression, found "{0}". Error message indicating that the regular expression has bad inline options. - Invalid regular expression: Octal \0 character codes are not supported, use hexadecimal \x or Unicode \u instead; found "{0}". + Invalid regular expression: Octal \0 character codes are not supported, use hexadecimal \x or Unicode \u instead, found "{0}". Error message indicating that the regular expression has octal characters. - Invalid regular expression: Invalid escape code; found "{0}". + Invalid regular expression: Invalid escape code, found "{0}". Error message indicating that the regular expression has an invalid alphanumeric escape code. @@ -4400,19 +4400,19 @@ Error message indicating that the regular expression capture group is not defined. - Invalid regular expression: Self-referencing capture groups are not supported; found "{0}". + Invalid regular expression: Self-referencing capture groups are not supported, found "{0}". Error message indicating that the regular expression has self-referencing capture groups. - Invalid regular expression: Balancing capture groups is not supported; found "{0}". + Invalid regular expression: Balancing capture groups is not supported, found "{0}". Error message indicating that the regular expression has balancing capture groups. - Invalid regular expression: Using single quoted named captures is not supported, use (?<...>) syntax instead; found "{0}". + Invalid regular expression: Using single quoted named captures is not supported, use (?<...>) syntax instead, found "{0}". Error message indicating that the regular expression has single quoted named capture. - Invalid regular expression: Conditional alternation is not supported; found "{0}". + Invalid regular expression: Conditional alternation is not supported, found "{0}". Error message indicating that the regular expression has conditionals. @@ -4501,7 +4501,7 @@ Error Message. - Type mismatch between source and target record types. Field name: {0} Expected {1}; Found {2}. + Type mismatch between source and target record types. Field name: {0} Expected {1}, found {2}. Error Message. @@ -4509,7 +4509,7 @@ Error Message. - Type mismatch between source and target types. Expected {0}; Found {1}. + Type mismatch between source and target types. Expected {0}, found {1}. Error Message. diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt index 6bd27b8582..22fefb3e48 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt @@ -1,11 +1,29 @@ #SETUP: RegEx,PowerFxV1CompatibilityRules,SupportColumnNamesAsIdentifiers -// For conssitent regular expressions across hosts, these tests check that we are -// limiting .NET regular expresions to what we can also support in JavaScript with XRegExp -// See https://learn.microsoft.com/en-us/dotnet/standard/base-types/regular-expression-options#ecmascript-matching-behavior -// We run without the RegexOptions.ECMASScript because we want Unicode letters for words - -// Unicode letters as word characters is allowed +// Limit regular expressions to common features that are supported, with conssitent semantics, by both canonical .NET and XRegExp. +// It is better to disallow now and bring back with customer demand or as platforms add more support. +// +// Features that are disallowed: +// Capture groups +// Self-referncing groups, such as "(a\1)". +// Treat all escaped number sequences as a backreference number. +// Single quoted "(?'name'..." and "\k'name'". +// Balancing capture groups. +// Octal character codes (use Hex or Unicode instead). +// "\o" could be added in the future, but we should avoid "\0" which causes backreference confusion. +// Inline options +// Anywhere in the expression except the beginning. +// For subexpressions. +// Character classes +// Character class subtraction "[a-z-[m-n]]". +// Conditional alternation +// +// Features that aren't supported by canonical .NET will be blocked automatically when the regular expression is instantiated in TryCreateReturnType. +// +// We chose to use canonical .NET instead of RegexOptions.ECMAScript because we wanted the unicode definitions for words. +// See https://learn.microsoft.com/dotnet/standard/base-types/regular-expression-options#ecmascript-matching-behavior for more details + +// Unicode letters as word characters are allowed >> Match( "the whole world", "\b(\w+\s*)+" ) {FullMatch:"the whole world",StartMatch:1,SubMatches:Table({Value:"world"})} @@ -22,9 +40,10 @@ // Self referncing groups are disallowed >> Match( "aa aaaa aaaaaa ", "((a+)(\1) ?)+" ) -Errors: Error 26-41: Invalid regular expression: Self-referencing capture groups are not supported; found "\1".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 26-41: Invalid regular expression: Self-referencing capture groups are not supported, found "\1".|Error 0-5: The function 'Match' has some invalid arguments. -// named self reference? +>> Match( "aa aaaa aaaaaa ", "(?(a+)(\k) ?)+" ) +Errors: Error 26-56: Invalid regular expression: Self-referencing capture groups are not supported, found "\k".|Error 0-5: The function 'Match' has some invalid arguments. // Backreferences without a group are disallowed @@ -34,12 +53,18 @@ Errors: Error 26-41: Invalid regular expression: Self-referencing capture groups >> Match( "hello howdy", "([hi]).*\2" ) Errors: Error 22-34: Invalid regular expression: Capture group "\2" not defined.|Error 0-5: The function 'Match' has some invalid arguments. +>> Match( "hello howdy", "(?[hi]).*\k" ) +{FullMatch:"hello h",StartMatch:1,SubMatches:Table({Value:"h"}),first:"h"} + +>> Match( "hello howdy", "(?[hi]).*\k" ) +Errors: Error 22-50: Invalid regular expression: Capture group "\k" not defined.|Error 0-5: The function 'Match' has some invalid arguments. + // Octal characters are not allowed >> Match( "as$df", "\044" ) -Errors: Error 16-22: Invalid regular expression: Octal \0 character codes are not supported, use hexadecimal \x or Unicode \u instead; found "\044".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 16-22: Invalid regular expression: Octal \0 character codes are not supported, use hexadecimal \x or Unicode \u instead, found "\044".|Error 0-5: The function 'Match' has some invalid arguments. -// options are allowed at the front of the regular expression only +// inline options >> Match( "hello"&Char(10)&"howdy", "o$" ) Blank() @@ -54,49 +79,64 @@ Blank() {FullMatch:"o",StartMatch:5,SubMatches:Table()} >> Match( "hello"&Char(10)&"howdy", "(?-m)o$" ) -Errors: Error 33-42: Invalid regular expression: Inline options are limited to a combination of the letters [imns], cannot disable options, and cannot be used on a subexpression; found "(?-m)".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 33-42: Invalid regular expression: Inline options are limited to a combination of the letters [im], cannot disable options, and cannot be used on a subexpression, found "(?-m)".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "hello"&Char(10)&"howdy", "(?i-m)o$" ) -Errors: Error 33-43: Invalid regular expression: Inline options are limited to a combination of the letters [imns], cannot disable options, and cannot be used on a subexpression; found "(?i-m)".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 33-43: Invalid regular expression: Inline options are limited to a combination of the letters [im], cannot disable options, and cannot be used on a subexpression, found "(?i-m)".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "hello"&Char(10)&"howdy", "^(?m)o$" ) -Errors: Error 33-42: Invalid regular expression: Inline options must appear at the beginning of the regular expression; found "(?m)" later.|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 33-42: Invalid regular expression: Inline options must appear at the beginning of the regular expression, found "(?m)" later.|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "hello"&Char(10)&"howdy", "^(?i-m)o$" ) -Errors: Error 33-44: Invalid regular expression: Inline options must appear at the beginning of the regular expression; found "(?i-m)" later.|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 33-44: Invalid regular expression: Inline options must appear at the beginning of the regular expression, found "(?i-m)" later.|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "hello"&Char(10)&"howdy", "^(?m:o$)" ) -Errors: Error 33-43: Invalid regular expression: Inline options must appear at the beginning of the regular expression; found "(?m:" later.|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 33-43: Invalid regular expression: Inline options must appear at the beginning of the regular expression, found "(?m:" later.|Error 0-5: The function 'Match' has some invalid arguments. + +// unsupported inline options + +>> Match( "hello world", "(?n)o") +Errors: Error 22-29: Invalid regular expression: Inline options are limited to a combination of the letters [im], cannot disable options, and cannot be used on a subexpression, found "(?n)".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "hello world", "(?s)o") +Errors: Error 22-29: Invalid regular expression: Inline options are limited to a combination of the letters [im], cannot disable options, and cannot be used on a subexpression, found "(?s)".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "hello world", "(?x)o") +Errors: Error 22-29: Invalid regular expression: Inline options are limited to a combination of the letters [im], cannot disable options, and cannot be used on a subexpression, found "(?x)".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "hello world", "(?A)o") +Errors: Error 22-29: Invalid regular expression: Inline options are limited to a combination of the letters [im], cannot disable options, and cannot be used on a subexpression, found "(?A)".|Error 0-5: The function 'Match' has some invalid arguments. // inline options overriding explicit options, conflicts? // balancing groups >> Match( "(hello world)", "(?)a") -Errors: Error 24-35: Invalid regular expression: Balancing capture groups is not supported; found "(?".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 24-35: Invalid regular expression: Balancing capture groups is not supported, found "(?".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "(hello world)", "(?)a(?<-s>)b") -Errors: Error 24-41: Invalid regular expression: Balancing capture groups is not supported; found "(?<-s>".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 24-41: Invalid regular expression: Balancing capture groups is not supported, found "(?<-s>".|Error 0-5: The function 'Match' has some invalid arguments. // groups with single ticks >> Match( "(hello world)", "(?'name'l)") -Errors: Error 24-36: Invalid regular expression: Using single quoted named captures is not supported, use (?<...>) syntax instead; found "(?'name'".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 24-36: Invalid regular expression: Using single quoted named captures is not supported, use (?<...>) syntax instead, found "(?'name'".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "(hello world)", "(?'s-e'l)") -Errors: Error 24-35: Invalid regular expression: Balancing capture groups is not supported; found "(?'s-e'".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 24-35: Invalid regular expression: Balancing capture groups is not supported, found "(?'s-e'".|Error 0-5: The function 'Match' has some invalid arguments. // conditional alternation // Console.WriteLine( Regex.Match( "1-23-456-7890", @"(?(\d{2}-)\d{2}-\d{2}|\d{3}-\d{2})" ).Value ); >> Match( "1-23-456-7890", "(?(\d{2}-)\d{2}-\d{2}|\d{3}-\d{2})" ) -Errors: Error 24-60: Invalid regular expression: Conditional alternation is not supported; found "(?(".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 24-60: Invalid regular expression: Conditional alternation is not supported, found "(?(".|Error 0-5: The function 'Match' has some invalid arguments. // Console.WriteLine( Regex.Match( "hello world", @"(e)(?(1)l|d)" ).Value ); >> Match( "hello world", "(e)(?(1)l|d)" ) -Errors: Error 22-36: Invalid regular expression: Conditional alternation is not supported; found "(?(".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 22-36: Invalid regular expression: Conditional alternation is not supported, found "(?(".|Error 0-5: The function 'Match' has some invalid arguments. // character class subtraction + >> Match( "[", "[[]" ) {FullMatch:"[",StartMatch:1,SubMatches:Table()} @@ -112,7 +152,7 @@ Errors: Error 12-25: Invalid regular expression: Character class subtraction is // regular expression parsing >> Match( "test\123bed", "\\(\a)" ) -Errors: Error 22-30: Invalid regular expression: Invalid escape code; found "\a".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 22-30: Invalid regular expression: Invalid escape code, found "\a".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test\123bed", "\\(\d)" ) {FullMatch:"\1",StartMatch:5,SubMatches:Table({Value:"1"})} @@ -120,10 +160,10 @@ Errors: Error 22-30: Invalid regular expression: Invalid escape code; found "\a" // character classes >> Match( "test", "\a" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\a".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\a".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test", "\A" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\A".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\A".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "$test atest test", "\btest" ) {FullMatch:"test",StartMatch:2,SubMatches:Table()} @@ -131,83 +171,83 @@ Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\A" >> Match( "$test atest test", "\Btest" ) {FullMatch:"test",StartMatch:8,SubMatches:Table()} ->> Match( "test", "\c" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\c".|Error 0-5: The function 'Match' has some invalid arguments. +>> DropColumns( Match( "test" & Char(10) & "bed", "\cj" ), FullMatch ) +{StartMatch:5,SubMatches:Table()} >> Match( "test", "\C" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\C".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\C".|Error 0-5: The function 'Match' has some invalid arguments. ->> Match( "test123bed", "\d+" ) +>> Match( "test123bed", "\d+" ) {FullMatch:"123",StartMatch:5,SubMatches:Table()} >> Match( "test123bed", "\D+" ) {FullMatch:"test",StartMatch:1,SubMatches:Table()} >> Match( "test", "\e" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\e".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\e".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test", "\E" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\E".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\E".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test"&Char(12)&"bed", "\f" ) {FullMatch:" ",StartMatch:5,SubMatches:Table()} >> Match( "test", "\F" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\F".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\F".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test", "\g" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\g".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\g".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test", "\G" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\G".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\G".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test", "\h" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\h".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\h".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test", "\H" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\H".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\H".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test", "\i" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\i".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\i".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test", "\I" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\I".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\I".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test", "\j" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\j".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\j".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test", "\J" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\J".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\J".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "1234551234", "(?<1>\d)\k<1>" ) {FullMatch:"55",StartMatch:5,SubMatches:Table({Value:"5"})} >> Match( "test", "\K" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\K".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\K".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test", "\l" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\l".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\l".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test", "\L" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\L".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\L".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test", "\m" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\m".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\m".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test", "\M" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\M".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\M".|Error 0-5: The function 'Match' has some invalid arguments. >> DropColumns( Match( "test" & Char(10) & "bed", "\n" ), FullMatch ) {StartMatch:5,SubMatches:Table()} >> Match( "test", "\N" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\N".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\N".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test", "\o" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\o".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\o".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test", "\O" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\O".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\O".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "123test456", "\p{L}+" ) {FullMatch:"test",StartMatch:4,SubMatches:Table()} @@ -216,16 +256,16 @@ Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\O" {FullMatch:"123",StartMatch:4,SubMatches:Table()} >> Match( "test", "\q" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\q".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\q".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test", "\Q" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\Q".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\Q".|Error 0-5: The function 'Match' has some invalid arguments. >> DropColumns( Match( "test" & Char(13) & "bed", "\r" ), FullMatch ) {StartMatch:5,SubMatches:Table()} >> Match( "test", "\R" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\R".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\R".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test bed", "\s+" ) {FullMatch:" ",StartMatch:5,SubMatches:Table()} @@ -237,19 +277,19 @@ Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\R" {FullMatch:" ",StartMatch:5,SubMatches:Table()} >> Match( "test", "\T" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\T".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\T".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test", "\u0065" ) {FullMatch:"e",StartMatch:2,SubMatches:Table()} >> Match( "test", "\U" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\U".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\U".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test" & Char(11) & "bed", "\v" ) {FullMatch:" ",StartMatch:5,SubMatches:Table()} >> Match( "test", "\V" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\V".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\V".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "&*%test bed^%$", "\w+" ) {FullMatch:"test",StartMatch:4,SubMatches:Table()} @@ -261,20 +301,59 @@ Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\V" {FullMatch:"e",StartMatch:2,SubMatches:Table()} >> Match( "test", "\X" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\X".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\X".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test", "\y" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\y".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\y".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test", "\Y" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\Y".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\Y".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test", "\z" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\z".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\z".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test", "\Z" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\Z".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\Z".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test", "\_" ) -Errors: Error 15-19: Invalid regular expression: Invalid escape code; found "\_".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\_".|Error 0-5: The function 'Match' has some invalid arguments. + +// Limits on character classes + +>> Match( "test", "\c@" ) +Errors: Error 15-20: Invalid regular expression: Invalid escape code, found "\c".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "\xF" ) +Errors: Error 15-20: Invalid regular expression: Invalid escape code, found "\x".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "eF", "\x65F" ) +{FullMatch:"eF",StartMatch:1,SubMatches:Table()} + +>> Match( "test", "\uF" ) +Errors: Error 15-20: Invalid regular expression: Invalid escape code, found "\u".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "\uFF" ) +Errors: Error 15-21: Invalid regular expression: Invalid escape code, found "\u".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "\uFFF" ) +Errors: Error 15-22: Invalid regular expression: Invalid escape code, found "\u".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "eF", "\u0065F" ) +{FullMatch:"eF",StartMatch:1,SubMatches:Table()} + +>> Match( "test", "\p{@}" ) +Errors: Error 15-22: Invalid regular expression: Invalid escape code, found "\p".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "\P{@}" ) +Errors: Error 15-22: Invalid regular expression: Invalid escape code, found "\P".|Error 0-5: The function 'Match' has some invalid arguments. + +// Escape is OK + +>> Match( "!@#$%^&*()[]{}+=-`~/><';:,.""", "\!\@\#\$\%\^\&\*\(\)\[\]\{\}\+\=\-\`\~\/\>\<\'\;\:\,\.\""" ) +{FullMatch:"!@#$%^&*()[]{}+=-`~/><';:,.""",StartMatch:1,SubMatches:Table()} + +// Comment is OK + +>> Match( "test", "(?# this is a test)st" ) +{FullMatch:"st",StartMatch:3,SubMatches:Table()} diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/rust_fx.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/rust_fx.txt deleted file mode 100644 index ac38138aa6..0000000000 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/rust_fx.txt +++ /dev/null @@ -1,1534 +0,0 @@ -#SETUP: RegEx - -# 1: yield return (@"^$", "", new[] { (0, 0) }); ->> ForAll( MatchAll( "", "^$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0}) - -# 2: yield return (@"^$^$^$", "", new[] { (0, 0) }); ->> ForAll( MatchAll( "", "^$^$^$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0}) - -# 3: yield return (@"^^^$$$", "", new[] { (0, 0) }); ->> ForAll( MatchAll( "", "^^^$$$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0}) - -# 4: yield return (@"$^", "", new[] { (0, 0) }); ->> ForAll( MatchAll( "", "$^" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0}) - -# 5: yield return (@"(?:^$)*", "a\nb\nc", new[] { (0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5) }); ->> ForAll( MatchAll( "a\nb\nc", "(?:^$)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3},{B:4,E:4},{B:5,E:5}) - -# 6: yield return (@"(?:$^)*", "a\nb\nc", new[] { (0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5) }); ->> ForAll( MatchAll( "a\nb\nc", "(?:$^)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3},{B:4,E:4},{B:5,E:5}) - -# 7: yield return (@"", "", new[] { (0, 0) }); ->> ForAll( MatchAll( "", "" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0}) - -# 8: yield return (@"", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); ->> ForAll( MatchAll( "abc", "" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) - -# 9: yield return (@"()", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); ->> ForAll( MatchAll( "abc", "()" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) - -# 10: yield return (@"()*", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); ->> ForAll( MatchAll( "abc", "()*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) - -# 11: yield return (@"()+", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); ->> ForAll( MatchAll( "abc", "()+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) - -# 12: yield return (@"()?", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); ->> ForAll( MatchAll( "abc", "()?" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) - -# 13: yield return (@"()()", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); ->> ForAll( MatchAll( "abc", "()()" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) - -# 14: yield return (@"()+|z", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); ->> ForAll( MatchAll( "abc", "()+|z" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) - -# 15: yield return (@"z|()+", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); ->> ForAll( MatchAll( "abc", "z|()+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) - -# 16: yield return (@"()+|b", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); ->> ForAll( MatchAll( "abc", "()+|b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) - -# 17: yield return (@"b|()+", "abc", new[] { (0, 0), (1, 2), (2, 2), (3, 3) }); ->> ForAll( MatchAll( "abc", "b|()+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:2},{B:2,E:2},{B:3,E:3}) - -# 18: yield return (@"|b", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); ->> ForAll( MatchAll( "abc", "|b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) - -# 19: yield return (@"b|", "abc", new[] { (0, 0), (1, 2), (2, 2), (3, 3) }); ->> ForAll( MatchAll( "abc", "b|" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:2},{B:2,E:2},{B:3,E:3}) - -# 20: yield return (@"|z", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); ->> ForAll( MatchAll( "abc", "|z" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) - -# 21: yield return (@"z|", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); ->> ForAll( MatchAll( "abc", "z|" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) - -# 22: yield return (@"|", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); ->> ForAll( MatchAll( "abc", "|" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) - -# 23: yield return (@"||", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); ->> ForAll( MatchAll( "abc", "||" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) - -# 24: yield return (@"||z", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); ->> ForAll( MatchAll( "abc", "||z" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) - -# 25: yield return (@"(?:)|b", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); ->> ForAll( MatchAll( "abc", "(?:)|b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) - -# 26: yield return (@"b|(?:)", "abc", new[] { (0, 0), (1, 2), (2, 2), (3, 3) }); ->> ForAll( MatchAll( "abc", "b|(?:)" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:2},{B:2,E:2},{B:3,E:3}) - -# 27: yield return (@"(?:|)", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); ->> ForAll( MatchAll( "abc", "(?:|)" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) - -# 28: yield return (@"(?:|)|z", "abc", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); ->> ForAll( MatchAll( "abc", "(?:|)|z" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) - -# 29: yield return (@"a(?:)|b", "abc", new[] { (0, 1), (1, 2) }); ->> ForAll( MatchAll( "abc", "a(?:)|b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1},{B:1,E:2}) - -# 30: yield return (@"a$", "a", new[] { (0, 1) }); ->> ForAll( MatchAll( "a", "a$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1}) - -# 31: yield return (@"(?m)^[a-z]+$", "abc\ndef\nxyz", new[] { (0, 3), (4, 7), (8, 11) }); ->> ForAll( MatchAll( "abc\ndef\nxyz", "(?m)^[a-z]+$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3},{B:4,E:7},{B:8,E:11}) - -# 32: yield return (@"(?m)^$", "abc\ndef\nxyz", new ValueTuple[] { }); ->> ForAll( MatchAll( "abc\ndef\nxyz", "(?m)^$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 33: yield return (@"(?m)^", "abc\ndef\nxyz", new[] { (0, 0), (4, 4), (8, 8) }); ->> ForAll( MatchAll( "abc\ndef\nxyz", "(?m)^" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:4,E:4},{B:8,E:8}) - -# 34: yield return (@"(?m)$", "abc\ndef\nxyz", new[] { (3, 3), (7, 7), (11, 11) }); ->> ForAll( MatchAll( "abc\ndef\nxyz", "(?m)$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:3,E:3},{B:7,E:7},{B:11,E:11}) - -# 35: yield return (@"(?m)^[a-z]", "abc\ndef\nxyz", new[] { (0, 1), (4, 5), (8, 9) }); ->> ForAll( MatchAll( "abc\ndef\nxyz", "(?m)^[a-z]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1},{B:4,E:5},{B:8,E:9}) - -# 36: yield return (@"(?m)[a-z]^", "abc\ndef\nxyz", new ValueTuple[] { }); ->> ForAll( MatchAll( "abc\ndef\nxyz", "(?m)[a-z]^" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 37: yield return (@"(?m)[a-z]$", "abc\ndef\nxyz", new[] { (2, 3), (6, 7), (10, 11) }); ->> ForAll( MatchAll( "abc\ndef\nxyz", "(?m)[a-z]$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:2,E:3},{B:6,E:7},{B:10,E:11}) - -# 38: yield return (@"(?m)$[a-z]", "abc\ndef\nxyz", new ValueTuple[] { }); ->> ForAll( MatchAll( "abc\ndef\nxyz", "(?m)$[a-z]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 39: yield return (@"(?m)^$", "", new[] { (0, 0) }); ->> ForAll( MatchAll( "", "(?m)^$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0}) - -# 40: yield return (@"(?m)(?:^$)*", "a\nb\nc", new[] { (0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5) }); ->> ForAll( MatchAll( "a\nb\nc", "(?m)(?:^$)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3},{B:4,E:4},{B:5,E:5}) - -# 41: yield return (@"(?m)(?:^|a)+", "a\naaa\n", new[] { (0, 0), (2, 2), (3, 5), (6, 6) }); ->> ForAll( MatchAll( "a\naaa\n", "(?m)(?:^|a)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:2,E:2},{B:3,E:5},{B:6,E:6}) - -# 42: yield return (@"(?m)(?:^|a)*", "a\naaa\n", new[] { (0, 0), (1, 1), (2, 2), (3, 5), (5, 5), (6, 6) }); ->> ForAll( MatchAll( "a\naaa\n", "(?m)(?:^|a)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:5},{B:5,E:5},{B:6,E:6}) - -# 43: yield return (@"(?m)(?:^[a-z])+", "abc\ndef\nxyz", new[] { (0, 1), (4, 5), (8, 9) }); ->> ForAll( MatchAll( "abc\ndef\nxyz", "(?m)(?:^[a-z])+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1},{B:4,E:5},{B:8,E:9}) - -# 44: yield return (@"(?m)(?:^[a-z]{3}\n?)+", "abc\ndef\nxyz", new[] { (0, 11) }); ->> ForAll( MatchAll( "abc\ndef\nxyz", "(?m)(?:^[a-z]{3}\n?)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:11}) - -# 45: yield return (@"(?m)(?:^[a-z]{3}\n?)*", "abc\ndef\nxyz", new[] { (0, 11), (11, 11) }); ->> ForAll( MatchAll( "abc\ndef\nxyz", "(?m)(?:^[a-z]{3}\n?)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:11},{B:11,E:11}) - -# 46: yield return (@"(?m)(?:\n?[a-z]{3}$)+", "abc\ndef\nxyz", new[] { (0, 11) }); ->> ForAll( MatchAll( "abc\ndef\nxyz", "(?m)(?:\n?[a-z]{3}$)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:11}) - -# 47: yield return (@"(?m)(?:\n?[a-z]{3}$)*", "abc\ndef\nxyz", new[] { (0, 11), (11, 11) }); ->> ForAll( MatchAll( "abc\ndef\nxyz", "(?m)(?:\n?[a-z]{3}$)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:11},{B:11,E:11}) - -# 48: yield return (@"(?m)^*", "\naa\n", new[] { (0, 0), (1, 1), (2, 2), (3, 3), (4, 4) }); ->> ForAll( MatchAll( "\naa\n", "(?m)^*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3},{B:4,E:4}) - -# 49: yield return (@"(?m)^+", "\naa\n", new[] { (0, 0), (1, 1), (4, 4) }); ->> ForAll( MatchAll( "\naa\n", "(?m)^+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1},{B:4,E:4}) - -# 50: yield return (@"(?m)$*", "\naa\n", new[] { (0, 0), (1, 1), (2, 2), (3, 3), (4, 4) }); ->> ForAll( MatchAll( "\naa\n", "(?m)$*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3},{B:4,E:4}) - -# 51: yield return (@"(?m)$+", "\naa\n", new[] { (0, 0), (3, 3), (4, 4) }); ->> ForAll( MatchAll( "\naa\n", "(?m)$+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:3,E:3},{B:4,E:4}) - -# 52: yield return (@"(?m)(?:$\n)+", "\n\naaa\n\n", new[] { (0, 2), (5, 7) }); ->> ForAll( MatchAll( "\n\naaa\n\n", "(?m)(?:$\n)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2},{B:5,E:7}) - -# 53: yield return (@"(?m)(?:$\n)*", "\n\naaa\n\n", new[] { (0, 2), (2, 2), (3, 3), (4, 4), (5, 7), (7, 7) }); ->> ForAll( MatchAll( "\n\naaa\n\n", "(?m)(?:$\n)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2},{B:2,E:2},{B:3,E:3},{B:4,E:4},{B:5,E:7},{B:7,E:7}) - -# 54: yield return (@"(?m)(?:$\n^)+", "\n\naaa\n\n", new[] { (0, 2), (5, 7) }); ->> ForAll( MatchAll( "\n\naaa\n\n", "(?m)(?:$\n^)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2},{B:5,E:7}) - -# 55: yield return (@"(?m)(?:^|$)+", "\n\naaa\n\n", new[] { (0, 0), (1, 1), (2, 2), (5, 5), (6, 6), (7, 7) }); ->> ForAll( MatchAll( "\n\naaa\n\n", "(?m)(?:^|$)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:5,E:5},{B:6,E:6},{B:7,E:7}) - -# 56: yield return (@"\b", "a b c", new[] { (0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5) }); ->> ForAll( MatchAll( "a b c", "\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3},{B:4,E:4},{B:5,E:5}) - -# 57: yield return (@"^a|b", "ba", new[] { (0, 1) }); ->> ForAll( MatchAll( "ba", "^a|b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1}) - -# 58: yield return (@"[0-9][0-9][0-9]000", "153.230000\n", new[] { (4, 10) }); ->> ForAll( MatchAll( "153.230000\n", "[0-9][0-9][0-9]000" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:4,E:10}) - -# 59: yield return (@"((?i)foo)|Bar", "foo Foo bar Bar", new[] { (0, 3), (4, 7), (12, 15) }); ->> ForAll( MatchAll( "foo Foo bar Bar", "((?i)foo)|Bar" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3},{B:4,E:7},{B:12,E:15}) - -# 60: yield return (@"()?01", "z?01", new[] { (2, 4) }); ->> ForAll( MatchAll( "z?01", "()?01" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:2,E:4}) - -# 61: yield return (@"\b", "", new ValueTuple[] { }); ->> ForAll( MatchAll( "", "\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 62: yield return (@"\b", "a", new[] { (0, 0), (1, 1) }); ->> ForAll( MatchAll( "a", "\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1}) - -# 63: yield return (@"\b", "ab", new[] { (0, 0), (2, 2) }); ->> ForAll( MatchAll( "ab", "\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:2,E:2}) - -# 64: yield return (@"^\b", "ab", new[] { (0, 0) }); ->> ForAll( MatchAll( "ab", "^\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0}) - -# 65: yield return (@"\b$", "ab", new[] { (2, 2) }); ->> ForAll( MatchAll( "ab", "\b$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:2,E:2}) - -# 66: yield return (@"^\b$", "ab", new ValueTuple[] { }); ->> ForAll( MatchAll( "ab", "^\b$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 67: yield return (@"\bbar\b", "nobar bar foo bar", new[] { (6, 9), (14, 17) }); ->> ForAll( MatchAll( "nobar bar foo bar", "\bbar\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:6,E:9},{B:14,E:17}) - -# 68: yield return (@"a\b", "faoa x", new[] { (3, 4) }); ->> ForAll( MatchAll( "faoa x", "a\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:3,E:4}) - -# 69: yield return (@"\bbar", "bar x", new[] { (0, 3) }); ->> ForAll( MatchAll( "bar x", "\bbar" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 70: yield return (@"\bbar", "foo\nbar x", new[] { (4, 7) }); ->> ForAll( MatchAll( "foo\nbar x", "\bbar" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:4,E:7}) - -# 71: yield return (@"bar\b", "foobar", new[] { (3, 6) }); ->> ForAll( MatchAll( "foobar", "bar\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:3,E:6}) - -# 72: yield return (@"bar\b", "foobar\nxxx", new[] { (3, 6) }); ->> ForAll( MatchAll( "foobar\nxxx", "bar\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:3,E:6}) - -# 73: yield return (@"(foo|bar|[A-Z])\b", "foo", new[] { (0, 3) }); ->> ForAll( MatchAll( "foo", "(foo|bar|[A-Z])\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 74: yield return (@"(foo|bar|[A-Z])\b", "foo\n", new[] { (0, 3) }); ->> ForAll( MatchAll( "foo\n", "(foo|bar|[A-Z])\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 75: yield return (@"\b(foo|bar|[A-Z])", "foo", new[] { (0, 3) }); ->> ForAll( MatchAll( "foo", "\b(foo|bar|[A-Z])" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 76: yield return (@"\b(foo|bar|[A-Z])\b", "X", new[] { (0, 1) }); ->> ForAll( MatchAll( "X", "\b(foo|bar|[A-Z])\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1}) - -# 77: yield return (@"\b(foo|bar|[A-Z])\b", "XY", new ValueTuple[] { }); ->> ForAll( MatchAll( "XY", "\b(foo|bar|[A-Z])\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 78: yield return (@"\b(foo|bar|[A-Z])\b", "bar", new[] { (0, 3) }); ->> ForAll( MatchAll( "bar", "\b(foo|bar|[A-Z])\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 79: yield return (@"\b(foo|bar|[A-Z])\b", "foo", new[] { (0, 3) }); ->> ForAll( MatchAll( "foo", "\b(foo|bar|[A-Z])\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 80: yield return (@"\b(foo|bar|[A-Z])\b", "foo\n", new[] { (0, 3) }); ->> ForAll( MatchAll( "foo\n", "\b(foo|bar|[A-Z])\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 81: yield return (@"\b(foo|bar|[A-Z])\b", "ffoo bbar N x", new[] { (10, 11) }); ->> ForAll( MatchAll( "ffoo bbar N x", "\b(foo|bar|[A-Z])\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:10,E:11}) - -# 82: yield return (@"\b(fo|foo)\b", "fo", new[] { (0, 2) }); ->> ForAll( MatchAll( "fo", "\b(fo|foo)\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2}) - -# 83: yield return (@"\b(fo|foo)\b", "foo", new[] { (0, 3) }); ->> ForAll( MatchAll( "foo", "\b(fo|foo)\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 84: yield return (@"\b\b", "", new ValueTuple[] { }); ->> ForAll( MatchAll( "", "\b\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 85: yield return (@"\b\b", "a", new[] { (0, 0), (1, 1) }); ->> ForAll( MatchAll( "a", "\b\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1}) - -# 86: yield return (@"\b$", "", new ValueTuple[] { }); ->> ForAll( MatchAll( "", "\b$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 87: yield return (@"\b$", "x", new[] { (1, 1) }); ->> ForAll( MatchAll( "x", "\b$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:1,E:1}) - -# 88: yield return (@"\b$", "y x", new[] { (3, 3) }); ->> ForAll( MatchAll( "y x", "\b$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:3,E:3}) - -# 89: yield return (@"\b.$", "x", new[] { (0, 1) }); ->> ForAll( MatchAll( "x", "\b.$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1}) - -# 90: yield return (@"^\b(fo|foo)\b", "fo", new[] { (0, 2) }); ->> ForAll( MatchAll( "fo", "^\b(fo|foo)\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2}) - -# 91: yield return (@"^\b(fo|foo)\b", "foo", new[] { (0, 3) }); ->> ForAll( MatchAll( "foo", "^\b(fo|foo)\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 92: yield return (@"^\b$", "", new ValueTuple[] { }); ->> ForAll( MatchAll( "", "^\b$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 93: yield return (@"^\b$", "x", new ValueTuple[] { }); ->> ForAll( MatchAll( "x", "^\b$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 94: yield return (@"^\b.$", "x", new[] { (0, 1) }); ->> ForAll( MatchAll( "x", "^\b.$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1}) - -# 95: yield return (@"^\b.\b$", "x", new[] { (0, 1) }); ->> ForAll( MatchAll( "x", "^\b.\b$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1}) - -# 96: yield return (@"^^^^^\b$$$$$", "", new ValueTuple[] { }); ->> ForAll( MatchAll( "", "^^^^^\b$$$$$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 97: yield return (@"^^^^^\b.$$$$$", "x", new[] { (0, 1) }); ->> ForAll( MatchAll( "x", "^^^^^\b.$$$$$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1}) - -# 98: yield return (@"^^^^^\b$$$$$", "x", new ValueTuple[] { }); ->> ForAll( MatchAll( "x", "^^^^^\b$$$$$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 99: yield return (@"^^^^^\b\b\b.\b\b\b$$$$$", "x", new[] { (0, 1) }); ->> ForAll( MatchAll( "x", "^^^^^\b\b\b.\b\b\b$$$$$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1}) - -# 100: yield return (@"\b.+\b", "$$abc$$", new[] { (2, 5) }); ->> ForAll( MatchAll( "$$abc$$", "\b.+\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:2,E:5}) - -# 101: yield return (@"\b", "a b c", new[] { (0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5) }); ->> ForAll( MatchAll( "a b c", "\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3},{B:4,E:4},{B:5,E:5}) - -# 102: yield return (@"\Bfoo\B", "n foo xfoox that", new[] { (7, 10) }); ->> ForAll( MatchAll( "n foo xfoox that", "\Bfoo\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:7,E:10}) - -# 103: yield return (@"a\B", "faoa x", new[] { (1, 2) }); ->> ForAll( MatchAll( "faoa x", "a\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:1,E:2}) - -# 104: yield return (@"\Bbar", "bar x", new ValueTuple[] { }); ->> ForAll( MatchAll( "bar x", "\Bbar" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 105: yield return (@"\Bbar", "foo\nbar x", new ValueTuple[] { }); ->> ForAll( MatchAll( "foo\nbar x", "\Bbar" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 106: yield return (@"bar\B", "foobar", new ValueTuple[] { }); ->> ForAll( MatchAll( "foobar", "bar\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 107: yield return (@"bar\B", "foobar\nxxx", new ValueTuple[] { }); ->> ForAll( MatchAll( "foobar\nxxx", "bar\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 108: yield return (@"(foo|bar|[A-Z])\B", "foox", new[] { (0, 3) }); ->> ForAll( MatchAll( "foox", "(foo|bar|[A-Z])\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 109: yield return (@"(foo|bar|[A-Z])\B", "foo\n", new ValueTuple[] { }); ->> ForAll( MatchAll( "foo\n", "(foo|bar|[A-Z])\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 110: yield return (@"\B", "", new[] { (0, 0) }); ->> ForAll( MatchAll( "", "\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0}) - -# 111: yield return (@"\B", "x", new ValueTuple[] { }); ->> ForAll( MatchAll( "x", "\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 112: yield return (@"\B(foo|bar|[A-Z])", "foo", new ValueTuple[] { }); ->> ForAll( MatchAll( "foo", "\B(foo|bar|[A-Z])" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 113: yield return (@"\B(foo|bar|[A-Z])\B", "xXy", new[] { (1, 2) }); ->> ForAll( MatchAll( "xXy", "\B(foo|bar|[A-Z])\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:1,E:2}) - -# 114: yield return (@"\B(foo|bar|[A-Z])\B", "XY", new ValueTuple[] { }); ->> ForAll( MatchAll( "XY", "\B(foo|bar|[A-Z])\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 115: yield return (@"\B(foo|bar|[A-Z])\B", "XYZ", new[] { (1, 2) }); ->> ForAll( MatchAll( "XYZ", "\B(foo|bar|[A-Z])\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:1,E:2}) - -# 116: yield return (@"\B(foo|bar|[A-Z])\B", "abara", new[] { (1, 4) }); ->> ForAll( MatchAll( "abara", "\B(foo|bar|[A-Z])\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:1,E:4}) - -# 117: yield return (@"\B(foo|bar|[A-Z])\B", "xfoo_", new[] { (1, 4) }); ->> ForAll( MatchAll( "xfoo_", "\B(foo|bar|[A-Z])\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:1,E:4}) - -# 118: yield return (@"\B(foo|bar|[A-Z])\B", "xfoo\n", new ValueTuple[] { }); ->> ForAll( MatchAll( "xfoo\n", "\B(foo|bar|[A-Z])\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 119: yield return (@"\B(foo|bar|[A-Z])\B", "foo bar vNX", new[] { (9, 10) }); ->> ForAll( MatchAll( "foo bar vNX", "\B(foo|bar|[A-Z])\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:9,E:10}) - -# 120: yield return (@"\B(fo|foo)\B", "xfoo", new[] { (1, 3) }); ->> ForAll( MatchAll( "xfoo", "\B(fo|foo)\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:1,E:3}) - -# 121: yield return (@"\B(foo|fo)\B", "xfooo", new[] { (1, 4) }); ->> ForAll( MatchAll( "xfooo", "\B(foo|fo)\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:1,E:4}) - -# 122: yield return (@"\B\B", "", new[] { (0, 0) }); ->> ForAll( MatchAll( "", "\B\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0}) - -# 123: yield return (@"\B\B", "x", new ValueTuple[] { }); ->> ForAll( MatchAll( "x", "\B\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 124: yield return (@"\B$", "", new[] { (0, 0) }); ->> ForAll( MatchAll( "", "\B$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0}) - -# 125: yield return (@"\B$", "x", new ValueTuple[] { }); ->> ForAll( MatchAll( "x", "\B$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 126: yield return (@"\B$", "y x", new ValueTuple[] { }); ->> ForAll( MatchAll( "y x", "\B$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 127: yield return (@"\B.$", "x", new ValueTuple[] { }); ->> ForAll( MatchAll( "x", "\B.$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 128: yield return (@"^\B(fo|foo)\B", "fo", new ValueTuple[] { }); ->> ForAll( MatchAll( "fo", "^\B(fo|foo)\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 129: yield return (@"^\B(fo|foo)\B", "foo", new ValueTuple[] { }); ->> ForAll( MatchAll( "foo", "^\B(fo|foo)\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 130: yield return (@"^\B", "", new[] { (0, 0) }); ->> ForAll( MatchAll( "", "^\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0}) - -# 131: yield return (@"^\B", "x", new ValueTuple[] { }); ->> ForAll( MatchAll( "x", "^\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 132: yield return (@"^\B\B", "", new[] { (0, 0) }); ->> ForAll( MatchAll( "", "^\B\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0}) - -# 133: yield return (@"^\B\B", "x", new ValueTuple[] { }); ->> ForAll( MatchAll( "x", "^\B\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 134: yield return (@"^\B$", "", new[] { (0, 0) }); ->> ForAll( MatchAll( "", "^\B$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0}) - -# 135: yield return (@"^\B$", "x", new ValueTuple[] { }); ->> ForAll( MatchAll( "x", "^\B$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 136: yield return (@"^\B.$", "x", new ValueTuple[] { }); ->> ForAll( MatchAll( "x", "^\B.$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 137: yield return (@"^\B.\B$", "x", new ValueTuple[] { }); ->> ForAll( MatchAll( "x", "^\B.\B$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 138: yield return (@"^^^^^\B$$$$$", "", new[] { (0, 0) }); ->> ForAll( MatchAll( "", "^^^^^\B$$$$$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0}) - -# 139: yield return (@"^^^^^\B.$$$$$", "x", new ValueTuple[] { }); ->> ForAll( MatchAll( "x", "^^^^^\B.$$$$$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 140: yield return (@"^^^^^\B$$$$$", "x", new ValueTuple[] { }); ->> ForAll( MatchAll( "x", "^^^^^\B$$$$$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 141: yield return (@"\bx\b", "\u00ABx", new[] { (1, 2) }); ->> ForAll( MatchAll( UniChar(Hex2Dec("00ABx")), "\bx\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:1,E:2}) - -# 142: yield return (@"\bx\b", "x\u00BB", new[] { (0, 1) }); ->> ForAll( MatchAll( "x"&UniChar(Hex2Dec("00BB")), "\bx\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1}) - -# 143: yield return (@"\bx\b", "\u00E1x\u00DF", new ValueTuple[] { }); ->> ForAll( MatchAll( UniChar(Hex2Dec("00E1x"))&UniChar(Hex2Dec("00DF")), "\bx\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 144: yield return (@"\Bx\B", "\u00E1x\u00DF", new[] { (1, 2) }); ->> ForAll( MatchAll( UniChar(Hex2Dec("00E1x"))&UniChar(Hex2Dec("00DF")), "\Bx\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:1,E:2}) - -# 145: yield return (@" \b", " \u03B4", new[] { (0, 1) }); ->> ForAll( MatchAll( " "&UniChar(Hex2Dec("03B4")), " \b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1}) - -# 146: yield return (@" \B", " \u03B4", new ValueTuple[] { }); ->> ForAll( MatchAll( " "&UniChar(Hex2Dec("03B4")), " \B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 147: yield return (@"\w+", "a\u03B4", new[] { (0, 2) }); ->> ForAll( MatchAll( "a"&UniChar(Hex2Dec("03B4")), "\w+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2}) - -# 148: yield return (@"\d+", "1\u0968\u09699", new[] { (0, 4) }); ->> ForAll( MatchAll( "1"&UniChar(Hex2Dec("0968"))&UniChar(Hex2Dec("09699")), "\d+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:4}) - -# 149: yield return (@"[^a]", "\u03B4", new[] { (0, 1) }); ->> ForAll( MatchAll( UniChar(Hex2Dec("03B4")), "[^a]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1}) - -# 150: yield return (@"a", "\xFFa", new ValueTuple[] { }); ->> ForAll( MatchAll( Char(Hex2Dec("FFa")), "a" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 151: yield return (@"a", "a", new[] { (0, 1) }); ->> ForAll( MatchAll( "a", "a" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1}) - -# 152: yield return (@"[-+]?[0-9]*\.?[0-9]+", "0.1", new[] { (0, 3) }); ->> ForAll( MatchAll( "0.1", "[-+]?[0-9]*\.?[0-9]+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 153: yield return (@"[-+]?[0-9]*\.?[0-9]+", "0.1.2", new[] { (0, 3), (3, 5) }); ->> ForAll( MatchAll( "0.1.2", "[-+]?[0-9]*\.?[0-9]+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3},{B:3,E:5}) - -# 154: yield return (@"[-+]?[0-9]*\.?[0-9]+", "a1.2", new[] { (1, 4) }); ->> ForAll( MatchAll( "a1.2", "[-+]?[0-9]*\.?[0-9]+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:1,E:4}) - -# 155: yield return (@"^[-+]?[0-9]*\.?[0-9]+$", "1.a", new ValueTuple[] { }); ->> ForAll( MatchAll( "1.a", "^[-+]?[0-9]*\.?[0-9]+$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 156: yield return (@"[^ac]", "acx", new[] { (2, 3) }); ->> ForAll( MatchAll( "acx", "[^ac]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:2,E:3}) - -# 157: yield return (@"[^a,]", "a,x", new[] { (2, 3) }); ->> ForAll( MatchAll( "a,x", "[^a,]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:2,E:3}) - -# 158: yield return (@"[^,]", ",,x", new[] { (2, 3) }); ->> ForAll( MatchAll( ",,x", "[^,]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:2,E:3}) - -# 159: yield return (@"((?:.*)*?)=", "a=b", new[] { (0, 2) }); ->> ForAll( MatchAll( "a=b", "((?:.*)*?)=" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2}) - -# 160: yield return (@"((?:.?)*?)=", "a=b", new[] { (0, 2) }); ->> ForAll( MatchAll( "a=b", "((?:.?)*?)=" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2}) - -# 161: yield return (@"((?:.*)+?)=", "a=b", new[] { (0, 2) }); ->> ForAll( MatchAll( "a=b", "((?:.*)+?)=" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2}) - -# 162: yield return (@"((?:.?)+?)=", "a=b", new[] { (0, 2) }); ->> ForAll( MatchAll( "a=b", "((?:.?)+?)=" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2}) - -# 163: yield return (@"((?:.*){1,}?)=", "a=b", new[] { (0, 2) }); ->> ForAll( MatchAll( "a=b", "((?:.*){1,}?)=" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2}) - -# 164: yield return (@"((?:.*){1,2}?)=", "a=b", new[] { (0, 2) }); ->> ForAll( MatchAll( "a=b", "((?:.*){1,2}?)=" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2}) - -# 165: yield return (@"((?:.*)*)=", "a=b", new[] { (0, 2) }); ->> ForAll( MatchAll( "a=b", "((?:.*)*)=" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2}) - -# 166: yield return (@"((?:.?)*)=", "a=b", new[] { (0, 2) }); ->> ForAll( MatchAll( "a=b", "((?:.?)*)=" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2}) - -# 167: yield return (@"((?:.*)+)=", "a=b", new[] { (0, 2) }); ->> ForAll( MatchAll( "a=b", "((?:.*)+)=" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2}) - -# 168: yield return (@"((?:.?)+)=", "a=b", new[] { (0, 2) }); ->> ForAll( MatchAll( "a=b", "((?:.?)+)=" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2}) - -# 169: yield return (@"((?:.*){1,})=", "a=b", new[] { (0, 2) }); ->> ForAll( MatchAll( "a=b", "((?:.*){1,})=" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2}) - -# 170: yield return (@"((?:.*){1,2})=", "a=b", new[] { (0, 2) }); ->> ForAll( MatchAll( "a=b", "((?:.*){1,2})=" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2}) - -# 171: yield return (@"abracadabra$", "abracadabracadabra", new[] { (7, 18) }); ->> ForAll( MatchAll( "abracadabracadabra", "abracadabra$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:7,E:18}) - -# 172: yield return (@"a...b", "abababbb", new[] { (2, 7) }); ->> ForAll( MatchAll( "abababbb", "a...b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:2,E:7}) - -# 173: yield return (@"XXXXXX", "..XXXXXX", new[] { (2, 8) }); ->> ForAll( MatchAll( "..XXXXXX", "XXXXXX" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:2,E:8}) - -# 174: yield return (@"\)", "()", new[] { (1, 2) }); ->> ForAll( MatchAll( "()", "\)" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:1,E:2}) - -# 175: yield return (@"a]", "a]a", new[] { (0, 2) }); ->> ForAll( MatchAll( "a]a", "a]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2}) - -# 176: yield return (@"\}", "}", new[] { (0, 1) }); ->> ForAll( MatchAll( "}", "\}" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1}) - -# 177: yield return (@"\]", "]", new[] { (0, 1) }); ->> ForAll( MatchAll( "]", "\]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1}) - -# 178: yield return (@"]", "]", new[] { (0, 1) }); ->> ForAll( MatchAll( "]", "]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1}) - -# 179: yield return (@"^a", "ax", new[] { (0, 1) }); ->> ForAll( MatchAll( "ax", "^a" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1}) - -# 180: yield return (@"\^a", "a^a", new[] { (1, 3) }); ->> ForAll( MatchAll( "a^a", "\^a" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:1,E:3}) - -# 181: yield return (@"a\^", "a^", new[] { (0, 2) }); ->> ForAll( MatchAll( "a^", "a\^" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2}) - -# 182: yield return (@"a$", "aa", new[] { (1, 2) }); ->> ForAll( MatchAll( "aa", "a$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:1,E:2}) - -# 183: yield return (@"a\$", "a$", new[] { (0, 2) }); ->> ForAll( MatchAll( "a$", "a\$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2}) - -# 184: yield return (@"^$", "", new[] { (0, 0) }); ->> ForAll( MatchAll( "", "^$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0}) - -# 185: yield return (@"$^", "", new[] { (0, 0) }); ->> ForAll( MatchAll( "", "$^" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0}) - -# 186: yield return (@"a($)", "aa", new[] { (1, 2) }); ->> ForAll( MatchAll( "aa", "a($)" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:1,E:2}) - -# 187: yield return (@"a*(^a)", "aa", new[] { (0, 1) }); ->> ForAll( MatchAll( "aa", "a*(^a)" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1}) - -# 188: yield return (@"(..)*(...)*", "a", new[] { (0, 0), (1, 1) }); ->> ForAll( MatchAll( "a", "(..)*(...)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1}) - -# 189: yield return (@"(..)*(...)*", "abcd", new[] { (0, 4), (4, 4) }); ->> ForAll( MatchAll( "abcd", "(..)*(...)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:4},{B:4,E:4}) - -# 190: yield return (@"(ab)c|abc", "abc", new[] { (0, 3) }); ->> ForAll( MatchAll( "abc", "(ab)c|abc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 191: yield return (@"a{0}b", "ab", new[] { (1, 2) }); ->> ForAll( MatchAll( "ab", "a{0}b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:1,E:2}) - -# 192: yield return (@"a*(a.|aa)", "aaaa", new[] { (0, 4) }); ->> ForAll( MatchAll( "aaaa", "a*(a.|aa)" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:4}) - -# 193: yield return (@"(a|b)?.*", "b", new[] { (0, 1), (1, 1) }); ->> ForAll( MatchAll( "b", "(a|b)?.*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1},{B:1,E:1}) - -# 194: yield return (@"(a|b)c|a(b|c)", "ac", new[] { (0, 2) }); ->> ForAll( MatchAll( "ac", "(a|b)c|a(b|c)" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2}) - -# 195: yield return (@"(a|b)*c|(a|ab)*c", "abc", new[] { (0, 3) }); ->> ForAll( MatchAll( "abc", "(a|b)*c|(a|ab)*c" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 196: yield return (@"(a|b)*c|(a|ab)*c", "xc", new[] { (1, 2) }); ->> ForAll( MatchAll( "xc", "(a|b)*c|(a|ab)*c" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:1,E:2}) - -# 197: yield return (@"a?(ab|ba)ab", "abab", new[] { (0, 4) }); ->> ForAll( MatchAll( "abab", "a?(ab|ba)ab" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:4}) - -# 198: yield return (@"a?(ac{0}b|ba)ab", "abab", new[] { (0, 4) }); ->> ForAll( MatchAll( "abab", "a?(ac{0}b|ba)ab" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:4}) - -# 199: yield return (@"ab|abab", "abbabab", new[] { (0, 2), (3, 5), (5, 7) }); ->> ForAll( MatchAll( "abbabab", "ab|abab" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2},{B:3,E:5},{B:5,E:7}) - -# 200: yield return (@"aba|bab|bba", "baaabbbaba", new[] { (5, 8) }); ->> ForAll( MatchAll( "baaabbbaba", "aba|bab|bba" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:5,E:8}) - -# 201: yield return (@"aba|bab", "baaabbbaba", new[] { (6, 9) }); ->> ForAll( MatchAll( "baaabbbaba", "aba|bab" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:6,E:9}) - -# 202: yield return (@"ab|a", "xabc", new[] { (1, 3) }); ->> ForAll( MatchAll( "xabc", "ab|a" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:1,E:3}) - -# 203: yield return (@"ab|a", "xxabc", new[] { (2, 4) }); ->> ForAll( MatchAll( "xxabc", "ab|a" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:2,E:4}) - -# 204: yield return (@"[^-]", "--a", new[] { (2, 3) }); ->> ForAll( MatchAll( "--a", "[^-]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:2,E:3}) - -# 205: yield return (@"[a-]*", "--a", new[] { (0, 3), (3, 3) }); ->> ForAll( MatchAll( "--a", "[a-]*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3},{B:3,E:3}) - -# 206: yield return (@"[a-m-]*", "--amoma--", new[] { (0, 4), (4, 4), (5, 9), (9, 9) }); ->> ForAll( MatchAll( "--amoma--", "[a-m-]*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:4},{B:4,E:4},{B:5,E:9},{B:9,E:9}) - -# 207: yield return (@"[\p{Lu}]", "A", new[] { (0, 1) }); ->> ForAll( MatchAll( "A", "[\p{Lu}]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1}) - -# 208: yield return (@"[\p{Ll}]+", "`az{", new[] { (1, 3) }); ->> ForAll( MatchAll( "`az{", "[\p{Ll}]+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:1,E:3}) - -# 209: yield return (@"[\p{Lu}]+", "@AZ[", new[] { (1, 3) }); ->> ForAll( MatchAll( "@AZ[", "[\p{Lu}]+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:1,E:3}) - -# 210: yield return (@"xxx", "xxx", new[] { (0, 3) }); ->> ForAll( MatchAll( "xxx", "xxx" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 211: yield return (@".*", "\u263A\u007F", new[] { (0, 2), (2, 2) }); ->> ForAll( MatchAll( UniChar(Hex2Dec("263A"))&UniChar(Hex2Dec("007F")), ".*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2},{B:2,E:2}) - -# 212: yield return (@"a*a*a*a*a*b", "aaaaaaaaab", new[] { (0, 10) }); ->> ForAll( MatchAll( "aaaaaaaaab", "a*a*a*a*a*b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:10}) - -# 213: yield return (@"^", "", new[] { (0, 0) }); ->> ForAll( MatchAll( "", "^" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0}) - -# 214: yield return (@"$", "", new[] { (0, 0) }); ->> ForAll( MatchAll( "", "$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0}) - -# 215: yield return (@"^$", "", new[] { (0, 0) }); ->> ForAll( MatchAll( "", "^$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0}) - -# 216: yield return (@"^a$", "a", new[] { (0, 1) }); ->> ForAll( MatchAll( "a", "^a$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1}) - -# 217: yield return (@"abc", "abc", new[] { (0, 3) }); ->> ForAll( MatchAll( "abc", "abc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 218: yield return (@"abc", "xabcy", new[] { (1, 4) }); ->> ForAll( MatchAll( "xabcy", "abc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:1,E:4}) - -# 219: yield return (@"abc", "ababc", new[] { (2, 5) }); ->> ForAll( MatchAll( "ababc", "abc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:2,E:5}) - -# 220: yield return (@"ab*c", "abc", new[] { (0, 3) }); ->> ForAll( MatchAll( "abc", "ab*c" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 221: yield return (@"ab*bc", "abc", new[] { (0, 3) }); ->> ForAll( MatchAll( "abc", "ab*bc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 222: yield return (@"ab*bc", "abbc", new[] { (0, 4) }); ->> ForAll( MatchAll( "abbc", "ab*bc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:4}) - -# 223: yield return (@"ab*bc", "abbbbc", new[] { (0, 6) }); ->> ForAll( MatchAll( "abbbbc", "ab*bc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:6}) - -# 224: yield return (@"ab+bc", "abbc", new[] { (0, 4) }); ->> ForAll( MatchAll( "abbc", "ab+bc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:4}) - -# 225: yield return (@"ab+bc", "abbbbc", new[] { (0, 6) }); ->> ForAll( MatchAll( "abbbbc", "ab+bc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:6}) - -# 226: yield return (@"ab?bc", "abbc", new[] { (0, 4) }); ->> ForAll( MatchAll( "abbc", "ab?bc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:4}) - -# 227: yield return (@"ab?bc", "abc", new[] { (0, 3) }); ->> ForAll( MatchAll( "abc", "ab?bc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 228: yield return (@"ab?c", "abc", new[] { (0, 3) }); ->> ForAll( MatchAll( "abc", "ab?c" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 229: yield return (@"^abc$", "abc", new[] { (0, 3) }); ->> ForAll( MatchAll( "abc", "^abc$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 230: yield return (@"^abc", "abcc", new[] { (0, 3) }); ->> ForAll( MatchAll( "abcc", "^abc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 231: yield return (@"abc$", "aabc", new[] { (1, 4) }); ->> ForAll( MatchAll( "aabc", "abc$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:1,E:4}) - -# 232: yield return (@"^", "abc", new[] { (0, 0) }); ->> ForAll( MatchAll( "abc", "^" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0}) - -# 233: yield return (@"$", "abc", new[] { (3, 3) }); ->> ForAll( MatchAll( "abc", "$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:3,E:3}) - -# 234: yield return (@"a.c", "abc", new[] { (0, 3) }); ->> ForAll( MatchAll( "abc", "a.c" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 235: yield return (@"a.c", "axc", new[] { (0, 3) }); ->> ForAll( MatchAll( "axc", "a.c" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 236: yield return (@"a.*c", "axyzc", new[] { (0, 5) }); ->> ForAll( MatchAll( "axyzc", "a.*c" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:5}) - -# 237: yield return (@"a[bc]d", "abd", new[] { (0, 3) }); ->> ForAll( MatchAll( "abd", "a[bc]d" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 238: yield return (@"a[b-d]e", "ace", new[] { (0, 3) }); ->> ForAll( MatchAll( "ace", "a[b-d]e" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 239: yield return (@"a[b-d]", "aac", new[] { (1, 3) }); ->> ForAll( MatchAll( "aac", "a[b-d]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:1,E:3}) - -# 240: yield return (@"a[-b]", "a-", new[] { (0, 2) }); ->> ForAll( MatchAll( "a-", "a[-b]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2}) - -# 241: yield return (@"a[b-]", "a-", new[] { (0, 2) }); ->> ForAll( MatchAll( "a-", "a[b-]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2}) - -# 242: yield return (@"a]", "a]", new[] { (0, 2) }); ->> ForAll( MatchAll( "a]", "a]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2}) - -# 243: yield return (@"a[]]b", "a]b", new[] { (0, 3) }); ->> ForAll( MatchAll( "a]b", "a[]]b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 244: yield return (@"a[^bc]d", "aed", new[] { (0, 3) }); ->> ForAll( MatchAll( "aed", "a[^bc]d" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 245: yield return (@"a[^-b]c", "adc", new[] { (0, 3) }); ->> ForAll( MatchAll( "adc", "a[^-b]c" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 246: yield return (@"a[^]b]c", "adc", new[] { (0, 3) }); ->> ForAll( MatchAll( "adc", "a[^]b]c" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 247: yield return (@"ab|cd", "abc", new[] { (0, 2) }); ->> ForAll( MatchAll( "abc", "ab|cd" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2}) - -# 248: yield return (@"ab|cd", "abcd", new[] { (0, 2), (2, 4) }); ->> ForAll( MatchAll( "abcd", "ab|cd" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2},{B:2,E:4}) - -# 249: yield return (@"a\(b", "a(b", new[] { (0, 3) }); ->> ForAll( MatchAll( "a(b", "a\(b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 250: yield return (@"a\(*b", "ab", new[] { (0, 2) }); ->> ForAll( MatchAll( "ab", "a\(*b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2}) - -# 251: yield return (@"a\(*b", "a((b", new[] { (0, 4) }); ->> ForAll( MatchAll( "a((b", "a\(*b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:4}) - -# 252: yield return (@"a+b+c", "aabbabc", new[] { (4, 7) }); ->> ForAll( MatchAll( "aabbabc", "a+b+c" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:4,E:7}) - -# 253: yield return (@"a*", "aaa", new[] { (0, 3), (3, 3) }); ->> ForAll( MatchAll( "aaa", "a*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3},{B:3,E:3}) - -# 254: yield return (@"(a*)*", "-", new[] { (0, 0), (1, 1) }); ->> ForAll( MatchAll( "-", "(a*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1}) - -# 255: yield return (@"(a*)+", "-", new[] { (0, 0), (1, 1) }); ->> ForAll( MatchAll( "-", "(a*)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1}) - -# 256: yield return (@"(a*|b)*", "-", new[] { (0, 0), (1, 1) }); ->> ForAll( MatchAll( "-", "(a*|b)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1}) - -# 257: yield return (@"(a+|b)*", "ab", new[] { (0, 2), (2, 2) }); ->> ForAll( MatchAll( "ab", "(a+|b)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2},{B:2,E:2}) - -# 258: yield return (@"(a+|b)+", "ab", new[] { (0, 2) }); ->> ForAll( MatchAll( "ab", "(a+|b)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2}) - -# 259: yield return (@"(a+|b)?", "ab", new[] { (0, 1), (1, 2), (2, 2) }); ->> ForAll( MatchAll( "ab", "(a+|b)?" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1},{B:1,E:2},{B:2,E:2}) - -# 260: yield return (@"[^ab]*", "cde", new[] { (0, 3), (3, 3) }); ->> ForAll( MatchAll( "cde", "[^ab]*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3},{B:3,E:3}) - -# 261: yield return (@"(^)*", "-", new[] { (0, 0), (1, 1) }); ->> ForAll( MatchAll( "-", "(^)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1}) - -# 262: yield return (@"a*", "", new[] { (0, 0) }); ->> ForAll( MatchAll( "", "a*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0}) - -# 263: yield return (@"([abc])*d", "abbbcd", new[] { (0, 6) }); ->> ForAll( MatchAll( "abbbcd", "([abc])*d" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:6}) - -# 264: yield return (@"([abc])*bcd", "abcd", new[] { (0, 4) }); ->> ForAll( MatchAll( "abcd", "([abc])*bcd" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:4}) - -# 265: yield return (@"a|b|c|d|e", "e", new[] { (0, 1) }); ->> ForAll( MatchAll( "e", "a|b|c|d|e" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1}) - -# 266: yield return (@"(a|b|c|d|e)f", "ef", new[] { (0, 2) }); ->> ForAll( MatchAll( "ef", "(a|b|c|d|e)f" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:2}) - -# 267: yield return (@"((a*|b))*", "-", new[] { (0, 0), (1, 1) }); ->> ForAll( MatchAll( "-", "((a*|b))*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1}) - -# 268: yield return (@"abcd*efg", "abcdefg", new[] { (0, 7) }); ->> ForAll( MatchAll( "abcdefg", "abcd*efg" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:7}) - -# 269: yield return (@"ab*", "xabyabbbz", new[] { (1, 3), (4, 8) }); ->> ForAll( MatchAll( "xabyabbbz", "ab*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:1,E:3},{B:4,E:8}) - -# 270: yield return (@"ab*", "xayabbbz", new[] { (1, 2), (3, 7) }); ->> ForAll( MatchAll( "xayabbbz", "ab*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:1,E:2},{B:3,E:7}) - -# 271: yield return (@"(ab|cd)e", "abcde", new[] { (2, 5) }); ->> ForAll( MatchAll( "abcde", "(ab|cd)e" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:2,E:5}) - -# 272: yield return (@"[abhgefdc]ij", "hij", new[] { (0, 3) }); ->> ForAll( MatchAll( "hij", "[abhgefdc]ij" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 273: yield return (@"(a|b)c*d", "abcd", new[] { (1, 4) }); ->> ForAll( MatchAll( "abcd", "(a|b)c*d" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:1,E:4}) - -# 274: yield return (@"(ab|ab*)bc", "abc", new[] { (0, 3) }); ->> ForAll( MatchAll( "abc", "(ab|ab*)bc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 275: yield return (@"a([bc]*)c*", "abc", new[] { (0, 3) }); ->> ForAll( MatchAll( "abc", "a([bc]*)c*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 276: yield return (@"a[bcd]*dcdcde", "adcdcde", new[] { (0, 7) }); ->> ForAll( MatchAll( "adcdcde", "a[bcd]*dcdcde" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:7}) - -# 277: yield return (@"(ab|a)b*c", "abc", new[] { (0, 3) }); ->> ForAll( MatchAll( "abc", "(ab|a)b*c" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 278: yield return (@"[A-Za-z_][A-Za-z0-9_]*", "alpha", new[] { (0, 5) }); ->> ForAll( MatchAll( "alpha", "[A-Za-z_][A-Za-z0-9_]*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:5}) - -# 279: yield return (@"^a(bc+|b[eh])g|.h$", "abh", new[] { (1, 3) }); ->> ForAll( MatchAll( "abh", "^a(bc+|b[eh])g|.h$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:1,E:3}) - -# 280: yield return (@"abcd", "abcd", new[] { (0, 4) }); ->> ForAll( MatchAll( "abcd", "abcd" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:4}) - -# 281: yield return (@"a(bc)d", "abcd", new[] { (0, 4) }); ->> ForAll( MatchAll( "abcd", "a(bc)d" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:4}) - -# 283: yield return (@"a+(b|c)*d+", "aabcdd", new[] { (0, 6) }); ->> ForAll( MatchAll( "aabcdd", "a+(b|c)*d+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:6}) - -# 284: yield return (@"^.+$", "vivi", new[] { (0, 4) }); ->> ForAll( MatchAll( "vivi", "^.+$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:4}) - -# 285: yield return (@"^(.+)$", "vivi", new[] { (0, 4) }); ->> ForAll( MatchAll( "vivi", "^(.+)$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:4}) - -# 286: yield return (@".*(/XXX).*", "/XXX", new[] { (0, 4) }); ->> ForAll( MatchAll( "/XXX", ".*(/XXX).*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:4}) - -# 287: yield return (@".*(/000).*", "/000", new[] { (0, 4) }); ->> ForAll( MatchAll( "/000", ".*(/000).*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:4}) - -# 288: yield return (@".*(\\000).*", "\000", new ValueTuple[] { }); ->> ForAll( MatchAll( "\000", ".*(\\000).*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 289: yield return (@"\\000", "\000", new ValueTuple[] { }); ->> ForAll( MatchAll( "\000", "\\000" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 290: yield return (@"(a*)*", "a", new[] { (0, 1), (1, 1) }); ->> ForAll( MatchAll( "a", "(a*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1},{B:1,E:1}) - -# 291: yield return (@"(a*)*", "x", new[] { (0, 0), (1, 1) }); ->> ForAll( MatchAll( "x", "(a*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1}) - -# 292: yield return (@"(a*)*", "aaaaaa", new[] { (0, 6), (6, 6) }); ->> ForAll( MatchAll( "aaaaaa", "(a*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:6},{B:6,E:6}) - -# 293: yield return (@"(a*)*", "aaaaaax", new[] { (0, 6), (6, 6), (7, 7) }); ->> ForAll( MatchAll( "aaaaaax", "(a*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:6},{B:6,E:6},{B:7,E:7}) - -# 294: yield return (@"(a*)+", "a", new[] { (0, 1), (1, 1) }); ->> ForAll( MatchAll( "a", "(a*)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1},{B:1,E:1}) - -# 295: yield return (@"(a*)+", "x", new[] { (0, 0), (1, 1) }); ->> ForAll( MatchAll( "x", "(a*)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1}) - -# 296: yield return (@"(a*)+", "aaaaaa", new[] { (0, 6), (6, 6) }); ->> ForAll( MatchAll( "aaaaaa", "(a*)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:6},{B:6,E:6}) - -# 297: yield return (@"(a*)+", "aaaaaax", new[] { (0, 6), (6, 6), (7, 7) }); ->> ForAll( MatchAll( "aaaaaax", "(a*)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:6},{B:6,E:6},{B:7,E:7}) - -# 298: yield return (@"(a+)*", "a", new[] { (0, 1), (1, 1) }); ->> ForAll( MatchAll( "a", "(a+)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1},{B:1,E:1}) - -# 299: yield return (@"(a+)*", "x", new[] { (0, 0), (1, 1) }); ->> ForAll( MatchAll( "x", "(a+)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1}) - -# 300: yield return (@"(a+)*", "aaaaaa", new[] { (0, 6), (6, 6) }); ->> ForAll( MatchAll( "aaaaaa", "(a+)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:6},{B:6,E:6}) - -# 301: yield return (@"(a+)*", "aaaaaax", new[] { (0, 6), (6, 6), (7, 7) }); ->> ForAll( MatchAll( "aaaaaax", "(a+)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:6},{B:6,E:6},{B:7,E:7}) - -# 302: yield return (@"(a+)+", "a", new[] { (0, 1) }); ->> ForAll( MatchAll( "a", "(a+)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1}) - -# 303: yield return (@"(a+)+", "x", new ValueTuple[] { }); ->> ForAll( MatchAll( "x", "(a+)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 304: yield return (@"(a+)+", "aaaaaa", new[] { (0, 6) }); ->> ForAll( MatchAll( "aaaaaa", "(a+)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:6}) - -# 305: yield return (@"(a+)+", "aaaaaax", new[] { (0, 6) }); ->> ForAll( MatchAll( "aaaaaax", "(a+)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:6}) - -# 306: yield return (@"([a]*)*", "a", new[] { (0, 1), (1, 1) }); ->> ForAll( MatchAll( "a", "([a]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1},{B:1,E:1}) - -# 307: yield return (@"([a]*)*", "x", new[] { (0, 0), (1, 1) }); ->> ForAll( MatchAll( "x", "([a]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1}) - -# 308: yield return (@"([a]*)*", "aaaaaa", new[] { (0, 6), (6, 6) }); ->> ForAll( MatchAll( "aaaaaa", "([a]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:6},{B:6,E:6}) - -# 309: yield return (@"([a]*)*", "aaaaaax", new[] { (0, 6), (6, 6), (7, 7) }); ->> ForAll( MatchAll( "aaaaaax", "([a]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:6},{B:6,E:6},{B:7,E:7}) - -# 310: yield return (@"([a]*)+", "a", new[] { (0, 1), (1, 1) }); ->> ForAll( MatchAll( "a", "([a]*)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1},{B:1,E:1}) - -# 311: yield return (@"([a]*)+", "x", new[] { (0, 0), (1, 1) }); ->> ForAll( MatchAll( "x", "([a]*)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1}) - -# 312: yield return (@"([a]*)+", "aaaaaa", new[] { (0, 6), (6, 6) }); ->> ForAll( MatchAll( "aaaaaa", "([a]*)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:6},{B:6,E:6}) - -# 313: yield return (@"([a]*)+", "aaaaaax", new[] { (0, 6), (6, 6), (7, 7) }); ->> ForAll( MatchAll( "aaaaaax", "([a]*)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:6},{B:6,E:6},{B:7,E:7}) - -# 314: yield return (@"([^b]*)*", "a", new[] { (0, 1), (1, 1) }); ->> ForAll( MatchAll( "a", "([^b]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1},{B:1,E:1}) - -# 315: yield return (@"([^b]*)*", "b", new[] { (0, 0), (1, 1) }); ->> ForAll( MatchAll( "b", "([^b]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1}) - -# 316: yield return (@"([^b]*)*", "aaaaaa", new[] { (0, 6), (6, 6) }); ->> ForAll( MatchAll( "aaaaaa", "([^b]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:6},{B:6,E:6}) - -# 317: yield return (@"([ab]*)*", "a", new[] { (0, 1), (1, 1) }); ->> ForAll( MatchAll( "a", "([ab]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1},{B:1,E:1}) - -# 318: yield return (@"([ab]*)*", "aaaaaa", new[] { (0, 6), (6, 6) }); ->> ForAll( MatchAll( "aaaaaa", "([ab]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:6},{B:6,E:6}) - -# 319: yield return (@"([ab]*)*", "ababab", new[] { (0, 6), (6, 6) }); ->> ForAll( MatchAll( "ababab", "([ab]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:6},{B:6,E:6}) - -# 320: yield return (@"([ab]*)*", "bababa", new[] { (0, 6), (6, 6) }); ->> ForAll( MatchAll( "bababa", "([ab]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:6},{B:6,E:6}) - -# 321: yield return (@"([ab]*)*", "b", new[] { (0, 1), (1, 1) }); ->> ForAll( MatchAll( "b", "([ab]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1},{B:1,E:1}) - -# 322: yield return (@"([ab]*)*", "bbbbbb", new[] { (0, 6), (6, 6) }); ->> ForAll( MatchAll( "bbbbbb", "([ab]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:6},{B:6,E:6}) - -# 323: yield return (@"([^a]*)*", "b", new[] { (0, 1), (1, 1) }); ->> ForAll( MatchAll( "b", "([^a]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1},{B:1,E:1}) - -# 324: yield return (@"([^a]*)*", "bbbbbb", new[] { (0, 6), (6, 6) }); ->> ForAll( MatchAll( "bbbbbb", "([^a]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:6},{B:6,E:6}) - -# 325: yield return (@"([^a]*)*", "aaaaaa", new[] { (0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6) }); ->> ForAll( MatchAll( "aaaaaa", "([^a]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3},{B:4,E:4},{B:5,E:5},{B:6,E:6}) - -# 326: yield return (@"([^ab]*)*", "ababab", new[] { (0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6) }); ->> ForAll( MatchAll( "ababab", "([^ab]*)*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3},{B:4,E:4},{B:5,E:5},{B:6,E:6}) - -# 327: yield return (@"((..)|(.))", "", new ValueTuple[] { }); ->> ForAll( MatchAll( "", "((..)|(.))" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 328: yield return (@"((..)|(.))((..)|(.))", "", new ValueTuple[] { }); ->> ForAll( MatchAll( "", "((..)|(.))((..)|(.))" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 329: yield return (@"((..)|(.))((..)|(.))((..)|(.))", "", new ValueTuple[] { }); ->> ForAll( MatchAll( "", "((..)|(.))((..)|(.))((..)|(.))" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 330: yield return (@"((..)|(.)){1}", "", new ValueTuple[] { }); ->> ForAll( MatchAll( "", "((..)|(.)){1}" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 331: yield return (@"((..)|(.)){2}", "", new ValueTuple[] { }); ->> ForAll( MatchAll( "", "((..)|(.)){2}" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 332: yield return (@"((..)|(.)){3}", "", new ValueTuple[] { }); ->> ForAll( MatchAll( "", "((..)|(.)){3}" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 333: yield return (@"((..)|(.))*", "", new[] { (0, 0) }); ->> ForAll( MatchAll( "", "((..)|(.))*" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0}) - -# 334: yield return (@"((..)|(.))((..)|(.))", "a", new ValueTuple[] { }); ->> ForAll( MatchAll( "a", "((..)|(.))((..)|(.))" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 335: yield return (@"((..)|(.))((..)|(.))((..)|(.))", "a", new ValueTuple[] { }); ->> ForAll( MatchAll( "a", "((..)|(.))((..)|(.))((..)|(.))" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 336: yield return (@"((..)|(.)){2}", "a", new ValueTuple[] { }); ->> ForAll( MatchAll( "a", "((..)|(.)){2}" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 337: yield return (@"((..)|(.)){3}", "a", new ValueTuple[] { }); ->> ForAll( MatchAll( "a", "((..)|(.)){3}" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 338: yield return (@"((..)|(.))((..)|(.))((..)|(.))", "aa", new ValueTuple[] { }); ->> ForAll( MatchAll( "aa", "((..)|(.))((..)|(.))((..)|(.))" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 339: yield return (@"((..)|(.)){3}", "aa", new ValueTuple[] { }); ->> ForAll( MatchAll( "aa", "((..)|(.)){3}" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 340: yield return (@"(a|ab|c|bcd){4,}(d*)", "ababcd", new ValueTuple[] { }); ->> ForAll( MatchAll( "ababcd", "(a|ab|c|bcd){4,}(d*)" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 341: yield return (@"(a|ab|c|bcd){4,10}(d*)", "ababcd", new ValueTuple[] { }); ->> ForAll( MatchAll( "ababcd", "(a|ab|c|bcd){4,10}(d*)" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 342: yield return (@"(ab|a|c|bcd){4,}(d*)", "ababcd", new ValueTuple[] { }); ->> ForAll( MatchAll( "ababcd", "(ab|a|c|bcd){4,}(d*)" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 343: yield return (@"(ab|a|c|bcd){4,10}(d*)", "ababcd", new ValueTuple[] { }); ->> ForAll( MatchAll( "ababcd", "(ab|a|c|bcd){4,10}(d*)" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 344: yield return (@"^abc", "abc", new[] { (0, 3) }); ->> ForAll( MatchAll( "abc", "^abc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 345: yield return (@"^abc", "zabc", new ValueTuple[] { }); ->> ForAll( MatchAll( "zabc", "^abc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 346: yield return (@"abc", "xxxxxab", new ValueTuple[] { }); ->> ForAll( MatchAll( "xxxxxab", "abc" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 347: yield return (@"(?i)[^x]", "x", new ValueTuple[] { }); ->> ForAll( MatchAll( "x", "(?i)[^x]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 348: yield return (@"(?i)[^x]", "X", new ValueTuple[] { }); ->> ForAll( MatchAll( "X", "(?i)[^x]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 349: yield return (@"[[:word:]]", "_", new ValueTuple[] { }); ->> ForAll( MatchAll( "_", "[[:word:]]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 350: yield return (@"ab?|$", "az", new[] { (0, 1), (2, 2) }); ->> ForAll( MatchAll( "az", "ab?|$" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1},{B:2,E:2}) - -# 351: yield return (@"^(.*?)(\n|\r\n?|$)", "ab\rcd", new[] { (0, 3) }); ->> ForAll( MatchAll( "ab\rcd", "^(.*?)(\n|\r\n?|$)" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 352: yield return (@"z*azb", "azb", new[] { (0, 3) }); ->> ForAll( MatchAll( "azb", "z*azb" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 353: yield return (@"(?i)\p{Ll}+", "\u039B\u0398\u0393\u0394\u03B1", new[] { (0, 5) }); ->> ForAll( MatchAll( UniChar(Hex2Dec("039B"))&UniChar(Hex2Dec("0398"))&UniChar(Hex2Dec("0393"))&UniChar(Hex2Dec("0394"))&UniChar(Hex2Dec("03B1")), "(?i)\p{Ll}+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:5}) - -# 354: yield return (@"1|2|3|4|5|6|7|8|9|10|int", "int", new[] { (0, 3) }); ->> ForAll( MatchAll( "int", "1|2|3|4|5|6|7|8|9|10|int" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 355: yield return (@"^a[[:^space:]]", "a ", new ValueTuple[] { }); ->> ForAll( MatchAll( "a ", "^a[[:^space:]]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 356: yield return (@"^a[[:^space:]]", "foo boo a ", new ValueTuple[] { }); ->> ForAll( MatchAll( "foo boo a ", "^a[[:^space:]]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 357: yield return (@"^-[a-z]", "r-f", new ValueTuple[] { }); ->> ForAll( MatchAll( "r-f", "^-[a-z]" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 358: yield return (@"(ABC|CDA|BC)X", "CDAX", new[] { (0, 4) }); ->> ForAll( MatchAll( "CDAX", "(ABC|CDA|BC)X" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:4}) - -# 359: yield return (@"(aa$)?", "aaz", new[] { (0, 0), (1, 1), (2, 2), (3, 3) }); ->> ForAll( MatchAll( "aaz", "(aa$)?" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:0},{B:1,E:1},{B:2,E:2},{B:3,E:3}) - -# 360: yield return (@"ab??", "ab", new[] { (0, 1) }); ->> ForAll( MatchAll( "ab", "ab??" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1}) - -# 361: yield return (@".*abcd", "abcd", new[] { (0, 4) }); ->> ForAll( MatchAll( "abcd", ".*abcd" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:4}) - -# 362: yield return (@".*(?:abcd)+", "abcd", new[] { (0, 4) }); ->> ForAll( MatchAll( "abcd", ".*(?:abcd)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:4}) - -# 363: yield return (@".*(?:abcd)+", "abcdabcd", new[] { (0, 8) }); ->> ForAll( MatchAll( "abcdabcd", ".*(?:abcd)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:8}) - -# 364: yield return (@".*(?:abcd)+", "abcdxabcd", new[] { (0, 9) }); ->> ForAll( MatchAll( "abcdxabcd", ".*(?:abcd)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:9}) - -# 365: yield return (@".*x(?:abcd)+", "abcdxabcd", new[] { (0, 9) }); ->> ForAll( MatchAll( "abcdxabcd", ".*x(?:abcd)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:9}) - -# 366: yield return (@"[^abcd]*x(?:abcd)+", "abcdxabcd", new[] { (4, 9) }); ->> ForAll( MatchAll( "abcdxabcd", "[^abcd]*x(?:abcd)+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:4,E:9}) - -# 367: yield return (@".", "\xD4\xC2\x65\x2B\x0E\xFE", new[] { (0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6) }); ->> ForAll( MatchAll( Char(Hex2Dec("D4"))&Char(Hex2Dec("C2"))&Char(Hex2Dec("65"))&Char(Hex2Dec("2B"))&Char(Hex2Dec("0E"))&Char(Hex2Dec("FE")), "." ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1},{B:1,E:2},{B:2,E:3},{B:3,E:4},{B:4,E:5},{B:5,E:6}) - -# 374: yield return (@"\p{Lu}+", "\u039B\u0398\u0393\u0394\u03B1", new[] { (0, 4) }); ->> ForAll( MatchAll( UniChar(Hex2Dec("039B"))&UniChar(Hex2Dec("0398"))&UniChar(Hex2Dec("0393"))&UniChar(Hex2Dec("0394"))&UniChar(Hex2Dec("03B1")), "\p{Lu}+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:4}) - -# 375: yield return (@"(?i)\p{Lu}+", "\u039B\u0398\u0393\u0394\u03B1", new[] { (0, 5) }); ->> ForAll( MatchAll( UniChar(Hex2Dec("039B"))&UniChar(Hex2Dec("0398"))&UniChar(Hex2Dec("0393"))&UniChar(Hex2Dec("0394"))&UniChar(Hex2Dec("03B1")), "(?i)\p{Lu}+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:5}) - -# 376: yield return (@"\p{L}+", "\u039B\u0398\u0393\u0394\u03B1", new[] { (0, 5) }); ->> ForAll( MatchAll( UniChar(Hex2Dec("039B"))&UniChar(Hex2Dec("0398"))&UniChar(Hex2Dec("0393"))&UniChar(Hex2Dec("0394"))&UniChar(Hex2Dec("03B1")), "\p{L}+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:5}) - -# 377: yield return (@"\p{Ll}+", "\u039B\u0398\u0393\u0394\u03B1", new[] { (4, 5) }); ->> ForAll( MatchAll( UniChar(Hex2Dec("039B"))&UniChar(Hex2Dec("0398"))&UniChar(Hex2Dec("0393"))&UniChar(Hex2Dec("0394"))&UniChar(Hex2Dec("03B1")), "\p{Ll}+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:4,E:5}) - -# 378: yield return (@"\w+", "d\u03B4d", new[] { (0, 3) }); ->> ForAll( MatchAll( "d"&UniChar(Hex2Dec("03B4d")), "\w+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:3}) - -# 379: yield return (@"\w+", "\u2961", new ValueTuple[] { }); ->> ForAll( MatchAll( UniChar(Hex2Dec("2961")), "\w+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 380: yield return (@"\W+", "\u2961", new[] { (0, 1) }); ->> ForAll( MatchAll( UniChar(Hex2Dec("2961")), "\W+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1}) - -# 381: yield return (@"\d+", "1\u0968\u09699", new[] { (0, 4) }); ->> ForAll( MatchAll( "1"&UniChar(Hex2Dec("0968"))&UniChar(Hex2Dec("09699")), "\d+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:4}) - -# 382: yield return (@"\d+", "\u2161", new ValueTuple[] { }); ->> ForAll( MatchAll( UniChar(Hex2Dec("2161")), "\d+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 383: yield return (@"\D+", "\u2161", new[] { (0, 1) }); ->> ForAll( MatchAll( UniChar(Hex2Dec("2161")), "\D+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1}) - -# 384: yield return (@"\s+", "\u1680", new[] { (0, 1) }); ->> ForAll( MatchAll( UniChar(Hex2Dec("1680")), "\s+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1}) - -# 385: yield return (@"\s+", "\u2603", new ValueTuple[] { }); ->> ForAll( MatchAll( UniChar(Hex2Dec("2603")), "\s+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 386: yield return (@"\S+", "\u2603", new[] { (0, 1) }); ->> ForAll( MatchAll( UniChar(Hex2Dec("2603")), "\S+" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1}) - -# 387: yield return (@"\d\b", "6\u03B4", new ValueTuple[] { }); ->> ForAll( MatchAll( "6"&UniChar(Hex2Dec("03B4")), "\d\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - -# 388: yield return (@"\d\b", "6\u1680", new[] { (0, 1) }); ->> ForAll( MatchAll( "6"&UniChar(Hex2Dec("1680")), "\d\b" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1}) - -# 389: yield return (@"\d\B", "6\u03B4", new[] { (0, 1) }); ->> ForAll( MatchAll( "6"&UniChar(Hex2Dec("03B4")), "\d\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table({B:0,E:1}) - -# 390: yield return (@"\d\B", "6\u1680", new ValueTuple[] { }); ->> ForAll( MatchAll( "6"&UniChar(Hex2Dec("1680")), "\d\B" ), {B:StartMatch-1, E:StartMatch+Len(FullMatch)-1} ) -Table() - diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index f752115208..6efb8e6281 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -159,7 +159,7 @@ private static bool ShouldSkipDotNetVersion(ExpressionTestCase testCase, string public void RunOne() { // var path = @"C:\odm\retests\rust_fx.txt"; - var path = @"d:\repos\regex-min\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\Match_Limited.txt"; + var path = @"c :\repos\regex-min\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\Match_Limited.txt"; var line = 0; var runner = new InterpreterRunner(); From 6347e5904166d367b6dae05872b22b7319d3366b Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Tue, 2 Jul 2024 23:22:23 -0700 Subject: [PATCH 05/61] Updates --- src/strings/PowerFxResources.en-US.resx | 4 ++-- .../FileExpressionEvaluationTests.cs | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/strings/PowerFxResources.en-US.resx b/src/strings/PowerFxResources.en-US.resx index d53dcbce4f..f164d0443d 100644 --- a/src/strings/PowerFxResources.en-US.resx +++ b/src/strings/PowerFxResources.en-US.resx @@ -4501,7 +4501,7 @@ Error Message. - Type mismatch between source and target record types. Field name: {0} Expected {1}, found {2}. + Type mismatch between source and target record types. Field name: {0} Expected {1}; found {2}. Error Message. @@ -4509,7 +4509,7 @@ Error Message. - Type mismatch between source and target types. Expected {0}, found {1}. + Type mismatch between source and target types. Expected {0}; found {1}. Error Message. diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index 6efb8e6281..524433dffa 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -153,13 +153,12 @@ private static bool ShouldSkipDotNetVersion(ExpressionTestCase testCase, string return false; } -#if true +#if false // Helper to run a single .txt [Fact] public void RunOne() { - // var path = @"C:\odm\retests\rust_fx.txt"; - var path = @"c :\repos\regex-min\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\Match_Limited.txt"; + var path = @"D:\repos\osp1\src\tests\Microsoft.PowerFx.Core.Tests\ExpressionTestCases\StronglyTypedEnum_TestEnums_PreV1.txt"; var line = 0; var runner = new InterpreterRunner(); From a2ab49fcfb11c26586df66845967af576989f5c8 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Tue, 2 Jul 2024 23:22:59 -0700 Subject: [PATCH 06/61] Update Microsoft.PowerFx.Core.Tests.Shared.projitems --- .../Microsoft.PowerFx.Core.Tests.Shared.projitems | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Microsoft.PowerFx.Core.Tests.Shared.projitems b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Microsoft.PowerFx.Core.Tests.Shared.projitems index cc6c9fbbbe..5de53d2999 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Microsoft.PowerFx.Core.Tests.Shared.projitems +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Microsoft.PowerFx.Core.Tests.Shared.projitems @@ -47,7 +47,7 @@ ExpressionTestCases\%(Filename)%(Extension) contentFiles\any\$(TargetFrameworks)\ExpressionTestCases PreserveNewest - + ExpressionTestCases\NotYetReady\%(Filename)%(Extension) content\ExpressionTestCases\NotYetReady @@ -72,4 +72,4 @@ - \ No newline at end of file + From 20d2fd3cafc7932ba64191432e3afa7556e13879 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Tue, 2 Jul 2024 23:23:38 -0700 Subject: [PATCH 07/61] Update Microsoft.PowerFx.Core.Tests.Shared.projitems From 765b291a3ae922f7c39c1bcb6189eb21ac93ca26 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Tue, 2 Jul 2024 23:24:38 -0700 Subject: [PATCH 08/61] Updates --- .../Microsoft.PowerFx.Core.Tests.Shared.projitems | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Microsoft.PowerFx.Core.Tests.Shared.projitems b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Microsoft.PowerFx.Core.Tests.Shared.projitems index cc6c9fbbbe..5a1a0195bd 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Microsoft.PowerFx.Core.Tests.Shared.projitems +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Microsoft.PowerFx.Core.Tests.Shared.projitems @@ -47,7 +47,7 @@ ExpressionTestCases\%(Filename)%(Extension) contentFiles\any\$(TargetFrameworks)\ExpressionTestCases PreserveNewest - + ExpressionTestCases\NotYetReady\%(Filename)%(Extension) content\ExpressionTestCases\NotYetReady From 9b33931c7956d03fe64353a1c5acd416e45b42f7 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Tue, 2 Jul 2024 23:27:11 -0700 Subject: [PATCH 09/61] Updates --- .../Microsoft.PowerFx.Core.Tests.Shared.projitems | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Microsoft.PowerFx.Core.Tests.Shared.projitems b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Microsoft.PowerFx.Core.Tests.Shared.projitems index 5de53d2999..5a1a0195bd 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Microsoft.PowerFx.Core.Tests.Shared.projitems +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Microsoft.PowerFx.Core.Tests.Shared.projitems @@ -72,4 +72,4 @@ - + \ No newline at end of file From d5463c8dc543c47a13a2e27f391a9dc84e4894ed Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Wed, 3 Jul 2024 07:13:34 -0700 Subject: [PATCH 10/61] Updates --- src/strings/PowerFxResources.en-US.resx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/strings/PowerFxResources.en-US.resx b/src/strings/PowerFxResources.en-US.resx index dd89993c8c..2c393a57a9 100644 --- a/src/strings/PowerFxResources.en-US.resx +++ b/src/strings/PowerFxResources.en-US.resx @@ -4497,7 +4497,7 @@ Error Message. - Type mismatch between source and target record types. Field name: {0} Expected {1}; found {2}. + Type mismatch between source and target record types. Field name: {0} Expected {1}; Found {2}. Error Message. @@ -4505,7 +4505,7 @@ Error Message. - Type mismatch between source and target types. Expected {0}; found {1}. + Type mismatch between source and target types. Expected {0}; Found {1}. Error Message. From 23166650a9cd241680b5d695cb1708a5b4ed2fa1 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Wed, 3 Jul 2024 15:22:30 -0700 Subject: [PATCH 11/61] Updates --- .../Localization/Strings.cs | 4 +- .../Texl/Builtins/Match.cs | 44 +++++++--- src/strings/PowerFxResources.en-US.resx | 8 ++ .../ExpressionTestCases/Match_Limited.txt | 84 ++++++++++++++++++- .../FileExpressionEvaluationTests.cs | 2 +- 5 files changed, 127 insertions(+), 15 deletions(-) diff --git a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs index 25f755c205..117b34642c 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs @@ -728,7 +728,9 @@ internal static class TexlStrings public static ErrorResourceKey ErrInvalidRegExBadSingleQuoteNamedCapture = new ErrorResourceKey("ErrInvalidRegExBadSingleQuoteNamedCapture"); public static ErrorResourceKey ErrInvalidRegExBadEscape = new ErrorResourceKey("ErrInvalidRegExBadEscape"); public static ErrorResourceKey ErrInvalidRegExBadCharacterClassSubtraction = new ErrorResourceKey("ErrInvalidRegExBadCharacterClassSubtraction"); - public static ErrorResourceKey ErrInvalidRegExBadConditional = new ErrorResourceKey("ErrInvalidRegExBadConditional"); + public static ErrorResourceKey ErrInvalidRegExBadConditional = new ErrorResourceKey("ErrInvalidRegExBadConditional"); + public static ErrorResourceKey ErrInvalidRegExBadBackRefUseNameInsteadOfNum = new ErrorResourceKey("ErrInvalidRegExBadBackRefUseNameInsteadOfNum"); + public static ErrorResourceKey ErrInvalidRegExBadBackRefNumberForName = new ErrorResourceKey("ErrInvalidRegExBadBackRefNumberForName"); public static ErrorResourceKey ErrVariableRegEx = new ErrorResourceKey("ErrVariableRegEx"); public static ErrorResourceKey InfoRegExCaptureNameHidesPredefinedFullMatchField = new ErrorResourceKey("InfoRegExCaptureNameHidesPredefinedFullMatchField"); diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index b6ad9e9169..4c9a49fc55 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -98,18 +98,21 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp // // Features that are disallowed: // Capture groups - // Self-referncing groups, such as "(a\1)". - // Treat all escaped number sequences as a backreference number. - // Single quoted "(?'name'..." and "\k'name'". - // Balancing capture groups. - // Octal character codes (use Hex or Unicode instead). + // Self-referncing groups, such as "(a\1)" (.NET different from XRegExp). + // Treat all escaped number sequences as a backreference number (.NET different from XRegExp). + // Single quoted "(?'name'..." and "\k'name'" (.NET only). + // Balancing capture groups (.NET only). + // Using named captures with back reference \number (.NET different from XRegExp). + // Using \k notation for numeric back references (.NET different from XRegExp). + // Octal character codes (.NET different from XRegExp) + // Uuse Hex or Unicode instead. // "\o" could be added in the future, but we should avoid "\0" which causes backreference confusion. // Inline options - // Anywhere in the expression except the beginning. - // For subexpressions. + // Anywhere in the expression except the beginning (.NET only). + // For subexpressions (.NET only). // Character classes - // Character class subtraction "[a-z-[m-n]]". - // Conditional alternation + // Character class subtraction "[a-z-[m-n]]" (.NET only). + // Conditional alternation (.NET only). // // Features that aren't supported by canonical .NET will be blocked automatically when the regular expression is instantiated in TryCreateReturnType. // @@ -158,7 +161,8 @@ private bool LimitRegularExpression(TexlNode regExNode, string regexPattern, IEr ", RegexOptions.IgnorePatternWhitespace | RegexOptions.ExplicitCapture); var groupCounter = 0; // last group number defined - var groupNumStack = new Stack(); // stack of group numbers, -1 is used for non capturing groups + var groupNumStack = new Stack(); // stack of open group numbers, -1 is used for non capturing groups + var groupNumHasName = new List(); // list of capture group numbers that are from a named capture group var groupNameDict = new Dictionary(); // mapping from group names to group numbers, membership means the name was defined var openCharacterClass = false; // are we defining a character class? @@ -206,6 +210,7 @@ private bool LimitRegularExpression(TexlNode regExNode, string regexPattern, IEr if (groupMatch.Groups["goodNamedCapture"].Success) { groupNameDict.Add(groupMatch.Groups["goodNamedCapture"].Value, groupCounter); + groupNumHasName.Add(groupCounter); } } } @@ -228,6 +233,13 @@ private bool LimitRegularExpression(TexlNode regExNode, string regexPattern, IEr return false; } + // group has a name, use that instead + if (groupNumHasName.Contains(backRefNum)) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefUseNameInsteadOfNum, groupMatch.Value); + return false; + } + // group is not closed and thus self referencing if (groupNumStack.Contains(backRefNum)) { @@ -242,8 +254,16 @@ private bool LimitRegularExpression(TexlNode regExNode, string regexPattern, IEr // group isn't defined, or not defined yet if (!groupNameDict.TryGetValue(backRefName, out var groupNum)) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefNotDefined, groupMatch.Value); - return false; + if (int.TryParse(backRefName, out groupNum)) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefNumberForName, groupMatch.Value); + return false; + } + else + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefNotDefined, groupMatch.Value); + return false; + } } // group is not closed and thus self referencing diff --git a/src/strings/PowerFxResources.en-US.resx b/src/strings/PowerFxResources.en-US.resx index 2c393a57a9..a47f27ee1d 100644 --- a/src/strings/PowerFxResources.en-US.resx +++ b/src/strings/PowerFxResources.en-US.resx @@ -4399,6 +4399,14 @@ Invalid regular expression: Self-referencing capture groups are not supported, found "{0}". Error message indicating that the regular expression has self-referencing capture groups. + + Invalid regular expression: Named capture groups need to be referenced with \k<name> and not by capture group number, found "{0}". + Error message indicating that the regular expression is using a number for a named capture. + + + Invalid regular expression: Numeric capture groups cannot be referenced with \k<number>, found "{0}". + Error message indicating that the regular expression is using a number for a named capture. + Invalid regular expression: Balancing capture groups is not supported, found "{0}". Error message indicating that the regular expression has balancing capture groups. diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt index 22fefb3e48..67160df82e 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt @@ -9,6 +9,8 @@ // Treat all escaped number sequences as a backreference number. // Single quoted "(?'name'..." and "\k'name'". // Balancing capture groups. +// Using named captures with back reference \number. +// Using \k notation for numeric back references. // Octal character codes (use Hex or Unicode instead). // "\o" could be added in the future, but we should avoid "\0" which causes backreference confusion. // Inline options @@ -50,15 +52,96 @@ Errors: Error 26-56: Invalid regular expression: Self-referencing capture groups >> Match( "hello howdy", "([hi]).*\1" ) {FullMatch:"hello h",StartMatch:1,SubMatches:Table({Value:"h"})} +>> Match( "hello howdy", "([hi]).*\k<1>" ) +Errors: Error 22-37: Invalid regular expression: Numeric capture groups cannot be referenced with \k, found "\k<1>".|Error 0-5: The function 'Match' has some invalid arguments. + >> Match( "hello howdy", "([hi]).*\2" ) Errors: Error 22-34: Invalid regular expression: Capture group "\2" not defined.|Error 0-5: The function 'Match' has some invalid arguments. +>> Match( "hello howdy", "([hi]).*\k<2>" ) +Errors: Error 22-37: Invalid regular expression: Numeric capture groups cannot be referenced with \k, found "\k<2>".|Error 0-5: The function 'Match' has some invalid arguments. + >> Match( "hello howdy", "(?[hi]).*\k" ) {FullMatch:"hello h",StartMatch:1,SubMatches:Table({Value:"h"}),first:"h"} +>> Match( "hello howdy", "(?[hi]).*\1" ) +Errors: Error 22-42: Invalid regular expression: Named capture groups need to be referenced with \k and not by capture group number, found "\1".|Error 0-5: The function 'Match' has some invalid arguments. + >> Match( "hello howdy", "(?[hi]).*\k" ) Errors: Error 22-50: Invalid regular expression: Capture group "\k" not defined.|Error 0-5: The function 'Match' has some invalid arguments. +>> Match( "hello howdy", "(?[hi]).*\2>" ) +Errors: Error 22-43: Invalid regular expression: Capture group "\2" not defined.|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "hello world", "(((((((((((l))))))))))).*\11") // 11 parens +{FullMatch:"llo worl",StartMatch:3,SubMatches:Table({Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"})} + +>> Match( "hello world", "(((((((((((l)))))))))).*\12") // unclosed 11th paren +Errors: Error 22-51: Invalid regular expression: Capture group "\12" not defined.|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "hello world", "(((((((((((l))))))))))).*\12") // 11 parens +Errors: Error 22-52: Invalid regular expression: Capture group "\12" not defined.|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "hello world", "(?(?(?(?(?(?(?(?(?(?(l))))))))))).*\11") // 11 parens +{FullMatch:"llo worl",StartMatch:3,SubMatches:Table({Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"}),a:"l",b:"l",c:"l",d:"l",e:"l",f:"l",g:"l",h:"l",i:"l",j:"l"} + +>> Match( "hello world", "(?(?(?(?(?(?(?(?(?(?(l))))))))))).*\k") // 11 parens +{FullMatch:"llo worl",StartMatch:3,SubMatches:Table({Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"}),a:"l",b:"l",c:"l",d:"l",e:"l",f:"l",g:"l",h:"l",i:"l",j:"l"} + +>> Match( "hello world", "(?(?(?(?(?(?(?(?(?(?(l)))))))))).*\12") // unclosed 11th paren +Errors: Error 22-91: Invalid regular expression: Capture group "\12" not defined.|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "hello world", "(?(?(?(?(?(?(?(?(?(?(l))))))))))).*\12") // 11 parens +Errors: Error 22-92: Invalid regular expression: Capture group "\12" not defined.|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "hello world", "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "(?l)" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & ".*\k" ) +{FullMatch:"llo worl",StartMatch:3,SubMatches:Table({Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"}),hundredone:"l"} + +>> Match( "hello world", "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "(?l" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & ".*\k" ) // missing paren +Errors: Error 341-342: Invalid regular expression.|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "hello world", "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "(?l)" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & ".*\100" ) +{FullMatch:"llo worl",StartMatch:3,SubMatches:Table({Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"}),hundredone:"l"} + +>> Match( "hello world", "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(?l)" & ".*\k" ) +{FullMatch:"llo worl",StartMatch:3,SubMatches:Table({Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:"l"}),hundredone:"l"} + +>> Match( "hello world", "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(?l)" & ".*\101" ) +Errors: Error 491-492: Invalid regular expression: Named capture groups need to be referenced with \k and not by capture group number, found "\101".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "hello world", "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(l)" & ".*\101" ) +{FullMatch:"llo worl",StartMatch:3,SubMatches:Table({Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:"l"})} + +>> Match( "hello world", "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(l)" & ".*\k<101>" ) +Errors: Error 478-479: Invalid regular expression: Numeric capture groups cannot be referenced with \k, found "\k<101>".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "hello world", "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(l)" & ".*\102" ) +Errors: Error 478-479: Invalid regular expression: Capture group "\102" not defined.|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "hello world", "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(l)" & ".*\k<102>" ) +Errors: Error 478-479: Invalid regular expression: Numeric capture groups cannot be referenced with \k, found "\k<102>".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "hello world", "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(l)" & ".*\81" ) +{FullMatch:"llo worl",StartMatch:3,SubMatches:Table({Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:"l"})} + +>> Match( "hello world", "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(l)" & ".*\82" ) +Errors: Error 388-389: Invalid regular expression: Capture group "\82" not defined.|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "hello world", "(((())(())(())(((((((())))))))))()(l)()\17") +{FullMatch:"l",StartMatch:3,SubMatches:Table({Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:"l"},{Value:""})} + +>> Match( "hello world", "(((())(())(())(((((((())))))))))()(l)()\18") +{FullMatch:"ll",StartMatch:3,SubMatches:Table({Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:"l"},{Value:""})} + +>> Match( "hello world", "(((())(())(())(((((((())))))))))()(l)()\19") +{FullMatch:"l",StartMatch:3,SubMatches:Table({Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:"l"},{Value:""})} + +>> Match( "hello world", "(((())(())(())(((((((())))))))))()(l)()\20") +Errors: Error 22-66: Invalid regular expression: Capture group "\20" not defined.|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "hello world", "(((())(())(())(((((((())))))))))()(?l)()\k") +{FullMatch:"ll",StartMatch:3,SubMatches:Table({Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:"l"}),letter:"l"} + // Octal characters are not allowed >> Match( "as$df", "\044" ) @@ -356,4 +439,3 @@ Errors: Error 15-22: Invalid regular expression: Invalid escape code, found "\P" >> Match( "test", "(?# this is a test)st" ) {FullMatch:"st",StartMatch:3,SubMatches:Table()} - diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index 524433dffa..acbe7594fc 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -158,7 +158,7 @@ private static bool ShouldSkipDotNetVersion(ExpressionTestCase testCase, string [Fact] public void RunOne() { - var path = @"D:\repos\osp1\src\tests\Microsoft.PowerFx.Core.Tests\ExpressionTestCases\StronglyTypedEnum_TestEnums_PreV1.txt"; + var path = @"D:\repos\regex-min\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\match_limited.txt"; var line = 0; var runner = new InterpreterRunner(); From e2e58ff28e893e993c0193b88b23c26f14f66ee0 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Thu, 4 Jul 2024 09:41:13 -0700 Subject: [PATCH 12/61] Updates --- .../Localization/Strings.cs | 1 + .../Texl/Builtins/Match.cs | 21 ++++++----- src/strings/PowerFxResources.en-US.resx | 4 +++ .../ExpressionTestCases/Match_Limited.txt | 35 +++++++++++++++---- .../FileExpressionEvaluationTests.cs | 2 +- 5 files changed, 48 insertions(+), 15 deletions(-) diff --git a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs index 117b34642c..d06b68e5cc 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs @@ -731,6 +731,7 @@ internal static class TexlStrings public static ErrorResourceKey ErrInvalidRegExBadConditional = new ErrorResourceKey("ErrInvalidRegExBadConditional"); public static ErrorResourceKey ErrInvalidRegExBadBackRefUseNameInsteadOfNum = new ErrorResourceKey("ErrInvalidRegExBadBackRefUseNameInsteadOfNum"); public static ErrorResourceKey ErrInvalidRegExBadBackRefNumberForName = new ErrorResourceKey("ErrInvalidRegExBadBackRefNumberForName"); + public static ErrorResourceKey ErrInvalidRegExBadNamedCaptureAlreadyExists = new ErrorResourceKey("ErrInvalidRegExBadNamedCaptureAlreadyExists"); public static ErrorResourceKey ErrVariableRegEx = new ErrorResourceKey("ErrVariableRegEx"); public static ErrorResourceKey InfoRegExCaptureNameHidesPredefinedFullMatchField = new ErrorResourceKey("InfoRegExCaptureNameHidesPredefinedFullMatchField"); diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index 4c9a49fc55..509b26cb03 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -89,11 +89,11 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp string regularExpression = nodeValue; return fValid && - (!context.Features.PowerFxV1CompatibilityRules || LimitRegularExpression(regExNode, regularExpression, errors)) && + (!context.Features.PowerFxV1CompatibilityRules || IsSupportedRegularExpression(regExNode, regularExpression, errors)) && TryCreateReturnType(regExNode, regularExpression, errors, ref returnType); } - // Limit regular expressions to common features that are supported, with conssitent semantics, by both canonical .NET and XRegExp. + // Limit regular expressions to common features that are supported, with consistent semantics, by both canonical .NET and XRegExp. // It is better to disallow now and bring back with customer demand or as platforms add more support. // // Features that are disallowed: @@ -118,9 +118,9 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp // // We chose to use canonical .NET instead of RegexOptions.ECMAScript because we wanted the unicode definitions for words. // See https://learn.microsoft.com/dotnet/standard/base-types/regular-expression-options#ecmascript-matching-behavior for more details - private bool LimitRegularExpression(TexlNode regExNode, string regexPattern, IErrorContainer errors) + private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPattern, IErrorContainer errors) { - // Scans the regular expression for interesting constructs, ignoring other elements and constructs that are leagl, such as letters and numbers. + // Scans the regular expression for interesting constructs, ignoring other elements and constructs that are legal, such as letters and numbers. // Order of alternation is important. .NET regular expressions are greedy and will match the first of these that it can. // Many subexpressions here take advantage of this, matching something that is valid, before falling through to check for something that is invalid. // @@ -162,8 +162,7 @@ private bool LimitRegularExpression(TexlNode regExNode, string regexPattern, IEr var groupCounter = 0; // last group number defined var groupNumStack = new Stack(); // stack of open group numbers, -1 is used for non capturing groups - var groupNumHasName = new List(); // list of capture group numbers that are from a named capture group - var groupNameDict = new Dictionary(); // mapping from group names to group numbers, membership means the name was defined + var groupNameDict = new Dictionary(); // mapping from group names to group numbers var openCharacterClass = false; // are we defining a character class? @@ -209,8 +208,13 @@ private bool LimitRegularExpression(TexlNode regExNode, string regexPattern, IEr groupNumStack.Push(groupMatch.Groups["goodNonCapture"].Success ? -1 : ++groupCounter); if (groupMatch.Groups["goodNamedCapture"].Success) { + if (groupNameDict.ContainsKey(groupMatch.Groups["goodNamedCapture"].Value)) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadNamedCaptureAlreadyExists, groupMatch.Value); + return false; + } + groupNameDict.Add(groupMatch.Groups["goodNamedCapture"].Value, groupCounter); - groupNumHasName.Add(groupCounter); } } } @@ -234,7 +238,7 @@ private bool LimitRegularExpression(TexlNode regExNode, string regexPattern, IEr } // group has a name, use that instead - if (groupNumHasName.Contains(backRefNum)) + if (groupNameDict.ContainsValue(backRefNum)) { errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefUseNameInsteadOfNum, groupMatch.Value); return false; @@ -313,6 +317,7 @@ private bool LimitRegularExpression(TexlNode regExNode, string regexPattern, IEr } else { + // This should never be hit. Good to have here in case one of the group names checked doesn't match the RE, running tests would hit this. throw new NotImplementedException("Unknown regular expression match"); } } diff --git a/src/strings/PowerFxResources.en-US.resx b/src/strings/PowerFxResources.en-US.resx index a47f27ee1d..04a0876dad 100644 --- a/src/strings/PowerFxResources.en-US.resx +++ b/src/strings/PowerFxResources.en-US.resx @@ -4407,6 +4407,10 @@ Invalid regular expression: Numeric capture groups cannot be referenced with \k<number>, found "{0}". Error message indicating that the regular expression is using a number for a named capture. + + Invalid regular expression: Named capture group "{0}" defined more than once. + Error message indicating that the regular expression is trying to define the same capture group more than once. + Invalid regular expression: Balancing capture groups is not supported, found "{0}". Error message indicating that the regular expression has balancing capture groups. diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt index 67160df82e..ecc5a4b761 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt @@ -1,6 +1,6 @@ #SETUP: RegEx,PowerFxV1CompatibilityRules,SupportColumnNamesAsIdentifiers -// Limit regular expressions to common features that are supported, with conssitent semantics, by both canonical .NET and XRegExp. +// Limit regular expressions to common features that are supported, with consistent semantics, by both canonical .NET and XRegExp. // It is better to disallow now and bring back with customer demand or as platforms add more support. // // Features that are disallowed: @@ -39,7 +39,7 @@ >> Match( "Müller", "^\w+$" ) {FullMatch:"Müller",StartMatch:1,SubMatches:Table()} -// Self referncing groups are disallowed +// Self referencing groups are disallowed >> Match( "aa aaaa aaaaaa ", "((a+)(\1) ?)+" ) Errors: Error 26-41: Invalid regular expression: Self-referencing capture groups are not supported, found "\1".|Error 0-5: The function 'Match' has some invalid arguments. @@ -251,6 +251,9 @@ Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\A" >> Match( "$test atest test", "\btest" ) {FullMatch:"test",StartMatch:2,SubMatches:Table()} +>> Match( "$test" & Char(8) & "test", "[\b]test" ) // \b acts differentely in a character class +{FullMatch:"test",StartMatch:6,SubMatches:Table()} + >> Match( "$test atest test", "\Btest" ) {FullMatch:"test",StartMatch:8,SubMatches:Table()} @@ -409,7 +412,7 @@ Errors: Error 15-20: Invalid regular expression: Invalid escape code, found "\c" >> Match( "test", "\xF" ) Errors: Error 15-20: Invalid regular expression: Invalid escape code, found "\x".|Error 0-5: The function 'Match' has some invalid arguments. ->> Match( "eF", "\x65F" ) +>> Match( "eF", "\x65F" ) // will only use the first two characters for the hex code and leave the F to match separately {FullMatch:"eF",StartMatch:1,SubMatches:Table()} >> Match( "test", "\uF" ) @@ -421,7 +424,7 @@ Errors: Error 15-21: Invalid regular expression: Invalid escape code, found "\u" >> Match( "test", "\uFFF" ) Errors: Error 15-22: Invalid regular expression: Invalid escape code, found "\u".|Error 0-5: The function 'Match' has some invalid arguments. ->> Match( "eF", "\u0065F" ) +>> Match( "eF", "\u0065F" ) // will only use the first four characters for the unicode and leave the F to match separately {FullMatch:"eF",StartMatch:1,SubMatches:Table()} >> Match( "test", "\p{@}" ) @@ -430,12 +433,32 @@ Errors: Error 15-22: Invalid regular expression: Invalid escape code, found "\p" >> Match( "test", "\P{@}" ) Errors: Error 15-22: Invalid regular expression: Invalid escape code, found "\P".|Error 0-5: The function 'Match' has some invalid arguments. -// Escape is OK +// Escape is OK for non alpha-numeric characters >> Match( "!@#$%^&*()[]{}+=-`~/><';:,.""", "\!\@\#\$\%\^\&\*\(\)\[\]\{\}\+\=\-\`\~\/\>\<\'\;\:\,\.\""" ) {FullMatch:"!@#$%^&*()[]{}+=-`~/><';:,.""",StartMatch:1,SubMatches:Table()} -// Comment is OK +// Inline comment is OK >> Match( "test", "(?# this is a test)st" ) {FullMatch:"st",StartMatch:3,SubMatches:Table()} + +// Can't define named capture group more than once + +>> Match( "test", "(?t).*(?t)" ) +{FullMatch:"test",StartMatch:1,SubMatches:Table({Value:"t"},{Value:"t"}),one:"t",two:"t"} + +>> Match( "test", "((?t)|(?t))" ) +{FullMatch:"t",StartMatch:1,SubMatches:Table({Value:"t"},{Value:"t"},{Value:""}),one:"t",two:""} + +>> Match( "test", "(?t).*(?t)" ) +Errors: Error 15-37: Invalid regular expression: Named capture group "(?" defined more than once.|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "((?t)|(?t))" ) +Errors: Error 15-38: Invalid regular expression: Named capture group "(?" defined more than once.|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "(?<1>t).*(?<2>t)" ) +{FullMatch:"test",StartMatch:1,SubMatches:Table({Value:"t"},{Value:"t"})} + +>> Match( "test", "(?<1>t).*(?<1>t)" ) +Errors: Error 15-33: Invalid regular expression: Named capture group "(?<1>" defined more than once.|Error 0-5: The function 'Match' has some invalid arguments. diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index acbe7594fc..9475e4fd97 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -153,7 +153,7 @@ private static bool ShouldSkipDotNetVersion(ExpressionTestCase testCase, string return false; } -#if false +#if true // Helper to run a single .txt [Fact] public void RunOne() From 6349dd99e6ae5b01f6252b5fa504cc75d2437c2d Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Thu, 4 Jul 2024 11:53:07 -0700 Subject: [PATCH 13/61] Updates --- .../Localization/Strings.cs | 2 + .../Texl/Builtins/Match.cs | 69 +++++++++++-------- src/strings/PowerFxResources.en-US.resx | 8 +++ .../ExpressionTestCases/Match_Limited.txt | 58 +++++++++++++--- 4 files changed, 99 insertions(+), 38 deletions(-) diff --git a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs index d06b68e5cc..111fefcaf9 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs @@ -732,6 +732,8 @@ internal static class TexlStrings public static ErrorResourceKey ErrInvalidRegExBadBackRefUseNameInsteadOfNum = new ErrorResourceKey("ErrInvalidRegExBadBackRefUseNameInsteadOfNum"); public static ErrorResourceKey ErrInvalidRegExBadBackRefNumberForName = new ErrorResourceKey("ErrInvalidRegExBadBackRefNumberForName"); public static ErrorResourceKey ErrInvalidRegExBadNamedCaptureAlreadyExists = new ErrorResourceKey("ErrInvalidRegExBadNamedCaptureAlreadyExists"); + public static ErrorResourceKey ErrInvalidRegExBadNamedCaptureName = new ErrorResourceKey("ErrInvalidRegExBadNamedCaptureName"); + public static ErrorResourceKey ErrInvalidRegExBadCharacterClassLiteralSquareBracket = new ErrorResourceKey("ErrInvalidRegExBadCharacterClassLiteralSquareBracket"); public static ErrorResourceKey ErrVariableRegEx = new ErrorResourceKey("ErrVariableRegEx"); public static ErrorResourceKey InfoRegExCaptureNameHidesPredefinedFullMatchField = new ErrorResourceKey("InfoRegExCaptureNameHidesPredefinedFullMatchField"); diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index 509b26cb03..97ed7cf0a1 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -131,32 +131,36 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter // to gather all the matches in a linear scan from the beginning to the end. var groupPunctuationRE = new Regex( @" - # leading backslash - \\(?[1-9]\d*) | # numeric backreference - \\k<(?\w+)> | # named backreference - (?\\0[0-7]{0,3}) | # octal are not accepted (no XRegExp support, by design) + # leading backslash, escape sequences + \\(?[1-9]\d*) | # numeric backreference + \\k<(?\w+)> | # named backreference + (?\\0[0-7]{0,3}) | # octal are not accepted (no XRegExp support, by design) (?\\ - ([bBdDfnrsStvwW] | # standard regex character classes, missing from .NET are aAeGzZ (no XRegExp support), other common are u{} and o - [pP]\{\w+\} | # unicode character classes - c[a-zA-Z] | # Ctrl character classes - x[0-9a-fA-F]{2} | # hex character, must be exactly 2 hex digits - u[0-9a-fA-F]{4})) | # Unicode characters, must be exactly 4 hex digits - (?\\[a-zA-Z_]) | # reserving all other letters and underscore for future use (consistent with .NET) - (?\\.) | # any other escaped character is allowed, but must be paired so that '\\(' is seen as '\\' followed by '(' and not '\' folloed by '\(' + ([bBdDfnrsStvwW] | # standard regex character classes, missing from .NET are aAeGzZ (no XRegExp support), other common are u{} and o + [pP]\{\w+\} | # unicode character classes + c[a-zA-Z] | # Ctrl character classes + x[0-9a-fA-F]{2} | # hex character, must be exactly 2 hex digits + u[0-9a-fA-F]{4})) | # Unicode characters, must be exactly 4 hex digits + (?\\[a-zA-Z_]) | # reserving all other letters and underscore for future use (consistent with .NET) + (?\\.) | # any other escaped character is allowed, but must be paired so that '\\(' is seen as '\\' followed by '(' and not '\' folloed by '\(' + # leading (?<, named captures + \(\?<(?[a-zA-Z][a-zA-Z\d]*)> | # named capture group, can only be letters and numbers and must start with a letter + (?\(\?<\w*-\w*>) | # .NET balancing captures are not supported + (?\(\?<[^>]*>) | # bad named capture name, didn't match goodNamedCapture + (?\(\?'[^']*') | # single quoted capture names are not supported + # leading (? - \(\?<(?\w+)> | # named capture group - (?\(\?:) | # non-capture group, still need to track to match with closing - (?^\(\?[im]+\)) | # inline front of expression options we do support - (?\(\?(\w*-\w+|\w+)(:|\))?) | # inline options that we don't support, including disable of options (last ? portion makes for a better error message) - (?\(\?(<|')\w*-\w+(>|')?) | # .NET balancing captures are not supported (last ? portion makes for a better error message) - (?\(\?'\w+'?) | # single quoted capture names are not supported (last ? portion makes for a better error message) - (?\(\?\() | # .NET conditional alternations are not supported + (?\(\?:) | # non-capture group, still need to track to match with closing + (?^\(\?[im]+\)) | # inline front of expression options we do support + (?\(\?(\w*-\w*|\w+)(:|\))?) | # inline options that we don't support, including disable of options (last ? portion makes for a better error message) + (?\(\?\() | # .NET conditional alternations are not supported # basic open and close - (?\() | - (?\)) | - (?\[) | + (?\[\]) | # disallow empty chararcter class (supported by XRegExp) and literal ] at front of character class (supported by .NET) + (?\() | + (?\)) | + (?\[) | (?\]) ", RegexOptions.IgnorePatternWhitespace | RegexOptions.ExplicitCapture); @@ -183,8 +187,11 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadCharacterClassSubtraction); return false; } - - // else ok, "[a[b]" is supported + else + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadCharacterClassLiteralSquareBracket); + return false; + } } else { @@ -193,11 +200,7 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter } else if (groupMatch.Groups["closeCharacterClass"].Success) { - // supports "[]]" which is valid but the closing square bracket must immediately follow the open - if (openCharacterClass && regexPattern[groupMatch.Groups["closeCharacterClass"].Index - 1] != '[') - { - openCharacterClass = false; - } + openCharacterClass = false; } else if (groupMatch.Groups["openCapture"].Success || groupMatch.Groups["goodNonCapture"].Success || groupMatch.Groups["goodNamedCapture"].Success) { @@ -277,6 +280,11 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter return false; } } + else if (groupMatch.Groups["badNamedCaptureName"].Success) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadNamedCaptureName, groupMatch.Groups["badNamedCaptureName"].Value); + return false; + } else if (groupMatch.Groups["badOctal"].Success) { errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadOctal, groupMatch.Groups["badOctal"].Value); @@ -310,6 +318,11 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadConditional, groupMatch.Groups["badConditional"].Value); return false; } + else if (groupMatch.Groups["badCharacterClassEmpty"].Success) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadCharacterClassLiteralSquareBracket, groupMatch.Groups["badCharacterClassEmpty"].Value); + return false; + } else if (groupMatch.Groups["badEscapeAlpha"].Success) { errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadEscape, groupMatch.Groups["badEscapeAlpha"].Value); diff --git a/src/strings/PowerFxResources.en-US.resx b/src/strings/PowerFxResources.en-US.resx index 04a0876dad..fb9df6d807 100644 --- a/src/strings/PowerFxResources.en-US.resx +++ b/src/strings/PowerFxResources.en-US.resx @@ -4411,6 +4411,14 @@ Invalid regular expression: Named capture group "{0}" defined more than once. Error message indicating that the regular expression is trying to define the same capture group more than once. + + Invalid regular expression: Named capture group name must be a combination of letters and digits and begin with a letter, found "{0}". + Error message indicating that the regular expression is trying to define the same capture group more than once. + + + Invalid regular expression: Square bracket character classes cannot be empty and cannot include unescaped literal open or close square brackets, escape with "\[" or "\]". + Error message indicating that the regular expression is trying to define the same capture group more than once. + Invalid regular expression: Balancing capture groups is not supported, found "{0}". Error message indicating that the regular expression has balancing capture groups. diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt index ecc5a4b761..47ed6d6d12 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt @@ -206,7 +206,7 @@ Errors: Error 24-41: Invalid regular expression: Balancing capture groups is not Errors: Error 24-36: Invalid regular expression: Using single quoted named captures is not supported, use (?<...>) syntax instead, found "(?'name'".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "(hello world)", "(?'s-e'l)") -Errors: Error 24-35: Invalid regular expression: Balancing capture groups is not supported, found "(?'s-e'".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 24-35: Invalid regular expression: Using single quoted named captures is not supported, use (?<...>) syntax instead, found "(?'s-e'".|Error 0-5: The function 'Match' has some invalid arguments. // conditional alternation @@ -218,17 +218,40 @@ Errors: Error 24-60: Invalid regular expression: Conditional alternation is not >> Match( "hello world", "(e)(?(1)l|d)" ) Errors: Error 22-36: Invalid regular expression: Conditional alternation is not supported, found "(?(".|Error 0-5: The function 'Match' has some invalid arguments. -// character class subtraction +// character class and literal square brackets + +>> Match( "a", "[]" ) +Errors: Error 12-16: Invalid regular expression: Square bracket character classes cannot be empty and cannot include unescaped literal open or close square brackets, escape with "\[" or "\]".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "[", "[[]" ) -{FullMatch:"[",StartMatch:1,SubMatches:Table()} +Errors: Error 12-17: Invalid regular expression: Square bracket character classes cannot be empty and cannot include unescaped literal open or close square brackets, escape with "\[" or "\]".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "]", "[]]" ) -{FullMatch:"]",StartMatch:1,SubMatches:Table()} +Errors: Error 12-17: Invalid regular expression: Square bracket character classes cannot be empty and cannot include unescaped literal open or close square brackets, escape with "\[" or "\]".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcdef]ghijk", "[\w]\w]" ) // second closing square bracket is allowed unescaped as it is outside a character class +{FullMatch:"ef]",StartMatch:5,SubMatches:Table()} >> Match( "a]", "[a]]" ) {FullMatch:"a]",StartMatch:1,SubMatches:Table()} +>> Match( "abcdef]ghijk", "[\w\]\w]" ) +{FullMatch:"a",StartMatch:1,SubMatches:Table()} + +>> Match( "[", "[\[]" ) +{FullMatch:"[",StartMatch:1,SubMatches:Table()} + +>> Match( "]", "[\]]" ) +{FullMatch:"]",StartMatch:1,SubMatches:Table()} + +>> Match( ">test[", "[\w\[\>]+" ) +{FullMatch:">test[",StartMatch:1,SubMatches:Table()} + +>> Match( ">test[", "[\w\]\>]+" ) +{FullMatch:">test",StartMatch:1,SubMatches:Table()} + +// character class subtraction + >> Match( "k", "[a-z-[b-c]]" ) Errors: Error 12-25: Invalid regular expression: Character class subtraction is not supported.|Error 0-5: The function 'Match' has some invalid arguments. @@ -305,8 +328,8 @@ Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\j" >> Match( "test", "\J" ) Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\J".|Error 0-5: The function 'Match' has some invalid arguments. ->> Match( "1234551234", "(?<1>\d)\k<1>" ) -{FullMatch:"55",StartMatch:5,SubMatches:Table({Value:"5"})} +>> Match( "1234551234", "(?\d)\k" ) +{FullMatch:"55",StartMatch:5,SubMatches:Table({Value:"5"}),first:"5"} >> Match( "test", "\K" ) Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\K".|Error 0-5: The function 'Match' has some invalid arguments. @@ -457,8 +480,23 @@ Errors: Error 15-37: Invalid regular expression: Named capture group "(?" d >> Match( "test", "((?t)|(?t))" ) Errors: Error 15-38: Invalid regular expression: Named capture group "(?" defined more than once.|Error 0-5: The function 'Match' has some invalid arguments. ->> Match( "test", "(?<1>t).*(?<2>t)" ) -{FullMatch:"test",StartMatch:1,SubMatches:Table({Value:"t"},{Value:"t"})} +// Bad named capture group names + +>> Match( "test", "(?s).*" ) +{FullMatch:"st",StartMatch:3,SubMatches:Table({Value:"s"}),a:"s"} + +>> Match( "test", "(?s).*" ) +{FullMatch:"st",StartMatch:3,SubMatches:Table({Value:"s"}),a1:"s"} + +>> Match( "test", "(?<1>s).*" ) +Errors: Error 15-26: Invalid regular expression: Named capture group name must be a combination of letters and digits and begin with a letter, found "(?<1>".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "(?<1a>s).*" ) +Errors: Error 15-27: Invalid regular expression: Named capture group name must be a combination of letters and digits and begin with a letter, found "(?<1a>".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "(?s).*" ) +Errors: Error 15-27: Invalid regular expression: Named capture group name must be a combination of letters and digits and begin with a letter, found "(?".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "(?s).*" ) +Errors: Error 15-27: Invalid regular expression: Named capture group name must be a combination of letters and digits and begin with a letter, found "(?".|Error 0-5: The function 'Match' has some invalid arguments. ->> Match( "test", "(?<1>t).*(?<1>t)" ) -Errors: Error 15-33: Invalid regular expression: Named capture group "(?<1>" defined more than once.|Error 0-5: The function 'Match' has some invalid arguments. From 510546839e1b57221e4695ac9f89ee76a9e22767 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Tue, 9 Jul 2024 21:03:32 -0700 Subject: [PATCH 14/61] Updates --- .../Localization/Strings.cs | 5 +- .../Texl/Builtins/Match.cs | 73 ++++---- src/strings/PowerFxResources.en-US.resx | 16 +- .../ExpressionTestCases/Culture_tr-TR.txt | 138 +++++++++++++++ .../ExpressionTestCases/Match_Limited.txt | 164 +++++++++++------- .../ExpressionTestHelpers/TestRunner.cs | 1 + .../TestRunnerTests/InternalSetup.cs | 20 +++ .../FileExpressionEvaluationTests.cs | 4 +- .../Helpers/AsyncVerify.cs | 5 + .../PowerFxEvaluationTests.cs | 5 + 10 files changed, 314 insertions(+), 117 deletions(-) create mode 100644 src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_tr-TR.txt diff --git a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs index 111fefcaf9..d3bd380499 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs @@ -724,16 +724,17 @@ internal static class TexlStrings public static ErrorResourceKey ErrInvalidRegExBadOctal = new ErrorResourceKey("ErrInvalidRegExBadOctal"); public static ErrorResourceKey ErrInvalidRegExBadBackRefSelfReferencing = new ErrorResourceKey("ErrInvalidRegExBadBackRefSelfReferencing"); public static ErrorResourceKey ErrInvalidRegExBadBackRefNotDefined = new ErrorResourceKey("ErrInvalidRegExBadBackRefNotDefined"); + public static ErrorResourceKey ErrInvalidRegExBadBackRefNumber = new ErrorResourceKey("ErrInvalidRegExBadBackRefNumber"); public static ErrorResourceKey ErrInvalidRegExBadBalancing = new ErrorResourceKey("ErrInvalidRegExBadBalancing"); public static ErrorResourceKey ErrInvalidRegExBadSingleQuoteNamedCapture = new ErrorResourceKey("ErrInvalidRegExBadSingleQuoteNamedCapture"); public static ErrorResourceKey ErrInvalidRegExBadEscape = new ErrorResourceKey("ErrInvalidRegExBadEscape"); public static ErrorResourceKey ErrInvalidRegExBadCharacterClassSubtraction = new ErrorResourceKey("ErrInvalidRegExBadCharacterClassSubtraction"); public static ErrorResourceKey ErrInvalidRegExBadConditional = new ErrorResourceKey("ErrInvalidRegExBadConditional"); - public static ErrorResourceKey ErrInvalidRegExBadBackRefUseNameInsteadOfNum = new ErrorResourceKey("ErrInvalidRegExBadBackRefUseNameInsteadOfNum"); - public static ErrorResourceKey ErrInvalidRegExBadBackRefNumberForName = new ErrorResourceKey("ErrInvalidRegExBadBackRefNumberForName"); public static ErrorResourceKey ErrInvalidRegExBadNamedCaptureAlreadyExists = new ErrorResourceKey("ErrInvalidRegExBadNamedCaptureAlreadyExists"); public static ErrorResourceKey ErrInvalidRegExBadNamedCaptureName = new ErrorResourceKey("ErrInvalidRegExBadNamedCaptureName"); public static ErrorResourceKey ErrInvalidRegExBadCharacterClassLiteralSquareBracket = new ErrorResourceKey("ErrInvalidRegExBadCharacterClassLiteralSquareBracket"); + public static ErrorResourceKey ErrInvalidRegExUnclosedCaptureGroups = new ErrorResourceKey("ErrInvalidRegExUnclosedCaptureGroups"); + public static ErrorResourceKey ErrInvalidRegExUnclosedCharacterClass = new ErrorResourceKey("ErrInvalidRegExUnclosedCharacterClass"); public static ErrorResourceKey ErrVariableRegEx = new ErrorResourceKey("ErrVariableRegEx"); public static ErrorResourceKey InfoRegExCaptureNameHidesPredefinedFullMatchField = new ErrorResourceKey("InfoRegExCaptureNameHidesPredefinedFullMatchField"); diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index 97ed7cf0a1..1aed3d185d 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -132,9 +132,9 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter var groupPunctuationRE = new Regex( @" # leading backslash, escape sequences - \\(?[1-9]\d*) | # numeric backreference \\k<(?\w+)> | # named backreference (?\\0[0-7]{0,3}) | # octal are not accepted (no XRegExp support, by design) + (?\\\d+) | # numeric backreference (?\\ ([bBdDfnrsStvwW] | # standard regex character classes, missing from .NET are aAeGzZ (no XRegExp support), other common are u{} and o [pP]\{\w+\} | # unicode character classes @@ -164,9 +164,8 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter (?\]) ", RegexOptions.IgnorePatternWhitespace | RegexOptions.ExplicitCapture); - var groupCounter = 0; // last group number defined - var groupNumStack = new Stack(); // stack of open group numbers, -1 is used for non capturing groups - var groupNameDict = new Dictionary(); // mapping from group names to group numbers + var groupStack = new Stack(); // stack of open group numbers, null is used for non capturing groups + var groupNames = new List(); // list of known group names var openCharacterClass = false; // are we defining a character class? @@ -208,16 +207,20 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter if (!openCharacterClass) { // non capturing group still needs to match closing paren, but does not define a new group - groupNumStack.Push(groupMatch.Groups["goodNonCapture"].Success ? -1 : ++groupCounter); if (groupMatch.Groups["goodNamedCapture"].Success) { - if (groupNameDict.ContainsKey(groupMatch.Groups["goodNamedCapture"].Value)) + groupStack.Push(groupMatch.Groups["goodNamedCapture"].Value); + if (groupNames.Contains(groupMatch.Groups["goodNamedCapture"].Value)) { errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadNamedCaptureAlreadyExists, groupMatch.Value); return false; } - groupNameDict.Add(groupMatch.Groups["goodNamedCapture"].Value, groupCounter); + groupNames.Add(groupMatch.Groups["goodNamedCapture"].Value); + } + else + { + groupStack.Push(null); } } } @@ -226,59 +229,31 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter // parens do not need to be escaped within square brackets if (!openCharacterClass) { - groupNumStack.Pop(); + groupStack.Pop(); } } - else if (groupMatch.Groups["goodBackRefNum"].Success) + else if (groupMatch.Groups["goodBackRefName"].Success) { - var backRefNum = int.Parse(groupMatch.Groups["goodBackRefNum"].Value, CultureInfo.InvariantCulture); + var backRefName = groupMatch.Groups["goodBackRefName"].Value; // group isn't defined, or not defined yet - if (backRefNum > groupCounter) + if (!groupNames.Contains(backRefName)) { errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefNotDefined, groupMatch.Value); return false; } - // group has a name, use that instead - if (groupNameDict.ContainsValue(backRefNum)) - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefUseNameInsteadOfNum, groupMatch.Value); - return false; - } - // group is not closed and thus self referencing - if (groupNumStack.Contains(backRefNum)) + if (groupStack.Contains(backRefName)) { errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefSelfReferencing, groupMatch.Value); return false; } } - else if (groupMatch.Groups["goodBackRefName"].Success) + else if (groupMatch.Groups["badBackRefNum"].Success) { - var backRefName = groupMatch.Groups["goodBackRefName"].Value; - - // group isn't defined, or not defined yet - if (!groupNameDict.TryGetValue(backRefName, out var groupNum)) - { - if (int.TryParse(backRefName, out groupNum)) - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefNumberForName, groupMatch.Value); - return false; - } - else - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefNotDefined, groupMatch.Value); - return false; - } - } - - // group is not closed and thus self referencing - if (groupNumStack.Contains(groupNum)) - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefSelfReferencing, groupMatch.Value); - return false; - } + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefNumber, groupMatch.Value); + return false; } else if (groupMatch.Groups["badNamedCaptureName"].Success) { @@ -335,6 +310,18 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter } } + if (groupStack.Count > 0) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExUnclosedCaptureGroups); + return false; + } + + if (openCharacterClass) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExUnclosedCharacterClass); + return false; + } + return true; } diff --git a/src/strings/PowerFxResources.en-US.resx b/src/strings/PowerFxResources.en-US.resx index fb9df6d807..eed2e49ffd 100644 --- a/src/strings/PowerFxResources.en-US.resx +++ b/src/strings/PowerFxResources.en-US.resx @@ -4399,13 +4399,17 @@ Invalid regular expression: Self-referencing capture groups are not supported, found "{0}". Error message indicating that the regular expression has self-referencing capture groups. - - Invalid regular expression: Named capture groups need to be referenced with \k<name> and not by capture group number, found "{0}". - Error message indicating that the regular expression is using a number for a named capture. + + Invalid regular expression: Numbered back references are not supported, use named back references with "(?<name>)" and "\k<name>" instead, found "{0}". + Error message indicating that the regular expression is using numeric capture groups. - - Invalid regular expression: Numeric capture groups cannot be referenced with \k<number>, found "{0}". - Error message indicating that the regular expression is using a number for a named capture. + + Invalid regular expression: Unclosed character class, too few closing square brackets. + Error message indicating that the regular expression has unclosed character classes. + + + Invalid regular expression: Unclosed groups, too few closing parenthesis. + Error message indicating that the regular expression has unclosed capture groups. Invalid regular expression: Named capture group "{0}" defined more than once. diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_tr-TR.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_tr-TR.txt new file mode 100644 index 0000000000..7994e644d9 --- /dev/null +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_tr-TR.txt @@ -0,0 +1,138 @@ +#SETUP: RegEx,CultureInfo("tr-TR"),PowerFxV1CompatibilityRules + +// Four types of letter I +// Dotted Dotless +// Upper İ U+0130 I U+0049 +// Lower i U+0069 ı U+0131 + +// Upper and Lower + +>> Language() +"tr-TR" + +>> "İ" = UniChar( Hex2Dec( "0130") ) +true + +>> "ı" = UniChar( Hex2Dec( "0131" ) ) +true + +>> Upper( "i" ) +"İ" + +>> Lower( "I" ) +"ı" + +>> Upper( "ı" ) +"I" + +>> Lower( "İ" ) +"i" + +>> Upper( "i" ) = UniChar( Hex2Dec( "0130") ) +true + +>> Lower( "I" ) = UniChar( Hex2Dec( "0131") ) +true + +>> Upper( "i" ) = "I" +false + +>> Lower( "I" ) = "i" +false + +>> Lower( "quit" ) = Lower( "QUIT" ) +false + +>> Lower( "quit" ) = Lower( "QUİT" ) +true + +>> Lower( "quıt" ) = Lower( "QUIT" ) +true + +>> Upper( "quit" ) = Upper( "QUIT" ) +false + +>> Upper( "quit" ) = Upper( "QUİT" ) +true + +>> Upper( "quıt" ) = Upper( "QUIT" ) +true + +>> Proper( "Iabc" ) +"Iabc" + +>> Proper( "iabc" ) +"İabc" + +>> Proper( "İabc" ) +"İabc" + +>> Proper( "ıabc" ) +"Iabc" + +>> Value( "123,456" ) +123.456 + +>> Value( "123,456", "en-US" ) +123456 + +>> Decimal( "123,456" ) +123.456 + +>> Decimal( "123,456", "en-US" ) +123456 + +>> Float( "123,456" ) +123.456 + +>> Float( "123,456", "en-US" ) +123456 + +>> Text( DateTime(2010,1,1,0,0,0,0), "mmm ddd yyyy" ) +"Oca Cum 2010" + +// Regular expressions, always uses invariant even though tr-TR is set + +// Results when using C# // Invariant tr-TR en-US + +>> IsMatch( "İ", "i", MatchOptions.IgnoreCase ) // false TRUE TRUE +false + +>> IsMatch( "i", "İ", MatchOptions.IgnoreCase ) // false TRUE TRUE +false + +>> IsMatch( "ı", "I", MatchOptions.IgnoreCase ) // false TRUE false +false + +>> IsMatch( "I", "ı", MatchOptions.IgnoreCase ) // false TRUE false +false + +>> IsMatch( "İ", "I", MatchOptions.IgnoreCase ) // false false TRUE +false + +>> IsMatch( "I", "İ", MatchOptions.IgnoreCase ) // false false TRUE +false + +>> IsMatch( "ı", "i", MatchOptions.IgnoreCase ) // false false false +false + +>> IsMatch( "i", "ı", MatchOptions.IgnoreCase ) // false false false +false + +>> IsMatch( "i", "I", MatchOptions.IgnoreCase ) // TRUE false TRUE +true + +>> IsMatch( "I", "i", MatchOptions.IgnoreCase ) // TRUE false TRUE +true + +>> IsMatch( "ı", "İ", MatchOptions.IgnoreCase ) // false false false +false + +>> IsMatch( "İ", "ı", MatchOptions.IgnoreCase ) // false false false +false + +>> Match( "hiIıİİıIhi", "\u0130+" ) +{FullMatch:"İİ",StartMatch:5,SubMatches:Table()} + +>> IsMatch( "Sıgh", "\u0131", MatchOptions.Contains ) +true diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt index 47ed6d6d12..efb14d967b 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt @@ -42,7 +42,7 @@ // Self referencing groups are disallowed >> Match( "aa aaaa aaaaaa ", "((a+)(\1) ?)+" ) -Errors: Error 26-41: Invalid regular expression: Self-referencing capture groups are not supported, found "\1".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 26-41: Invalid regular expression: Numbered back references are not supported, use named back references with "(?)" and "\k" instead, found "\1".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "aa aaaa aaaaaa ", "(?(a+)(\k) ?)+" ) Errors: Error 26-56: Invalid regular expression: Self-referencing capture groups are not supported, found "\k".|Error 0-5: The function 'Match' has some invalid arguments. @@ -50,95 +50,44 @@ Errors: Error 26-56: Invalid regular expression: Self-referencing capture groups // Backreferences without a group are disallowed >> Match( "hello howdy", "([hi]).*\1" ) -{FullMatch:"hello h",StartMatch:1,SubMatches:Table({Value:"h"})} +Errors: Error 22-34: Invalid regular expression: Numbered back references are not supported, use named back references with "(?)" and "\k" instead, found "\1".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "hello howdy", "([hi]).*\k<1>" ) -Errors: Error 22-37: Invalid regular expression: Numeric capture groups cannot be referenced with \k, found "\k<1>".|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "hello howdy", "([hi]).*\2" ) -Errors: Error 22-34: Invalid regular expression: Capture group "\2" not defined.|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "hello howdy", "([hi]).*\k<2>" ) -Errors: Error 22-37: Invalid regular expression: Numeric capture groups cannot be referenced with \k, found "\k<2>".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 22-37: Invalid regular expression: Capture group "\k<1>" not defined.|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "hello howdy", "(?[hi]).*\k" ) {FullMatch:"hello h",StartMatch:1,SubMatches:Table({Value:"h"}),first:"h"} >> Match( "hello howdy", "(?[hi]).*\1" ) -Errors: Error 22-42: Invalid regular expression: Named capture groups need to be referenced with \k and not by capture group number, found "\1".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 22-42: Invalid regular expression: Numbered back references are not supported, use named back references with "(?)" and "\k" instead, found "\1".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "hello howdy", "(?[hi]).*\k" ) Errors: Error 22-50: Invalid regular expression: Capture group "\k" not defined.|Error 0-5: The function 'Match' has some invalid arguments. ->> Match( "hello howdy", "(?[hi]).*\2>" ) -Errors: Error 22-43: Invalid regular expression: Capture group "\2" not defined.|Error 0-5: The function 'Match' has some invalid arguments. +>> Match( "hello world", "(((((((((((?l))))))))))).*\k") // 11 parens +{FullMatch:"llo worl",StartMatch:3,SubMatches:Table({Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"}),eleven:"l"} ->> Match( "hello world", "(((((((((((l))))))))))).*\11") // 11 parens -{FullMatch:"llo worl",StartMatch:3,SubMatches:Table({Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"})} +>> Match( "hello world", "(((((((((((?l)))))))))).*\k") // unclosed 11th paren +Errors: Error 22-67: Invalid regular expression: Unclosed groups, too few closing parenthesis.|Error 0-5: The function 'Match' has some invalid arguments. ->> Match( "hello world", "(((((((((((l)))))))))).*\12") // unclosed 11th paren -Errors: Error 22-51: Invalid regular expression: Capture group "\12" not defined.|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "hello world", "(((((((((((l))))))))))).*\12") // 11 parens -Errors: Error 22-52: Invalid regular expression: Capture group "\12" not defined.|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "hello world", "(?(?(?(?(?(?(?(?(?(?(l))))))))))).*\11") // 11 parens -{FullMatch:"llo worl",StartMatch:3,SubMatches:Table({Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"}),a:"l",b:"l",c:"l",d:"l",e:"l",f:"l",g:"l",h:"l",i:"l",j:"l"} +>> Match( "hello world", "(?((((((((((?l)))))))))).*\k") // unclosed 11th paren +Errors: Error 22-74: Invalid regular expression: Self-referencing capture groups are not supported, found "\k".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "hello world", "(?(?(?(?(?(?(?(?(?(?(l))))))))))).*\k") // 11 parens {FullMatch:"llo worl",StartMatch:3,SubMatches:Table({Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"}),a:"l",b:"l",c:"l",d:"l",e:"l",f:"l",g:"l",h:"l",i:"l",j:"l"} ->> Match( "hello world", "(?(?(?(?(?(?(?(?(?(?(l)))))))))).*\12") // unclosed 11th paren -Errors: Error 22-91: Invalid regular expression: Capture group "\12" not defined.|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "hello world", "(?(?(?(?(?(?(?(?(?(?(l))))))))))).*\12") // 11 parens -Errors: Error 22-92: Invalid regular expression: Capture group "\12" not defined.|Error 0-5: The function 'Match' has some invalid arguments. +>> Match( "hello world", "(?(?(?(?(?(?(?(?(?(?(l))))))))))).*\k") // 11 parens +{FullMatch:"llo worl",StartMatch:3,SubMatches:Table({Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"}),a:"l",b:"l",c:"l",d:"l",e:"l",f:"l",g:"l",h:"l",i:"l",j:"l"} >> Match( "hello world", "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "(?l)" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & ".*\k" ) {FullMatch:"llo worl",StartMatch:3,SubMatches:Table({Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"}),hundredone:"l"} >> Match( "hello world", "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "(?l" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & ".*\k" ) // missing paren -Errors: Error 341-342: Invalid regular expression.|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "hello world", "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "(?l)" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & ".*\100" ) -{FullMatch:"llo worl",StartMatch:3,SubMatches:Table({Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"}),hundredone:"l"} +Errors: Error 341-342: Invalid regular expression: Unclosed groups, too few closing parenthesis.|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "hello world", "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(?l)" & ".*\k" ) {FullMatch:"llo worl",StartMatch:3,SubMatches:Table({Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:"l"}),hundredone:"l"} ->> Match( "hello world", "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(?l)" & ".*\101" ) -Errors: Error 491-492: Invalid regular expression: Named capture groups need to be referenced with \k and not by capture group number, found "\101".|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "hello world", "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(l)" & ".*\101" ) -{FullMatch:"llo worl",StartMatch:3,SubMatches:Table({Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:"l"})} - ->> Match( "hello world", "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(l)" & ".*\k<101>" ) -Errors: Error 478-479: Invalid regular expression: Numeric capture groups cannot be referenced with \k, found "\k<101>".|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "hello world", "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(l)" & ".*\102" ) -Errors: Error 478-479: Invalid regular expression: Capture group "\102" not defined.|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "hello world", "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(l)" & ".*\k<102>" ) -Errors: Error 478-479: Invalid regular expression: Numeric capture groups cannot be referenced with \k, found "\k<102>".|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "hello world", "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(l)" & ".*\81" ) -{FullMatch:"llo worl",StartMatch:3,SubMatches:Table({Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:"l"})} - ->> Match( "hello world", "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(l)" & ".*\82" ) -Errors: Error 388-389: Invalid regular expression: Capture group "\82" not defined.|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "hello world", "(((())(())(())(((((((())))))))))()(l)()\17") -{FullMatch:"l",StartMatch:3,SubMatches:Table({Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:"l"},{Value:""})} - ->> Match( "hello world", "(((())(())(())(((((((())))))))))()(l)()\18") -{FullMatch:"ll",StartMatch:3,SubMatches:Table({Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:"l"},{Value:""})} - ->> Match( "hello world", "(((())(())(())(((((((())))))))))()(l)()\19") -{FullMatch:"l",StartMatch:3,SubMatches:Table({Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:"l"},{Value:""})} - ->> Match( "hello world", "(((())(())(())(((((((())))))))))()(l)()\20") -Errors: Error 22-66: Invalid regular expression: Capture group "\20" not defined.|Error 0-5: The function 'Match' has some invalid arguments. - >> Match( "hello world", "(((())(())(())(((((((())))))))))()(?l)()\k") {FullMatch:"ll",StartMatch:3,SubMatches:Table({Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:"l"}),letter:"l"} @@ -500,3 +449,90 @@ Errors: Error 15-27: Invalid regular expression: Named capture group name must b >> Match( "test", "(?s).*" ) Errors: Error 15-27: Invalid regular expression: Named capture group name must be a combination of letters and digits and begin with a letter, found "(?".|Error 0-5: The function 'Match' has some invalid arguments. +// Group name case sensitivity + +>> Match( "test", "(?t).*\k") +{FullMatch:"test",StartMatch:1,SubMatches:Table({Value:"t"}),a:"t"} + +>> Match( "test", "(?t).*\k") +Errors: Error 15-31: Invalid regular expression: Capture group "\k" not defined.|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "(?t).*\k") +Errors: Error 15-31: Invalid regular expression: Capture group "\k" not defined.|Error 0-5: The function 'Match' has some invalid arguments. + +// Remaining differences between .NET and XRegExp + +// .NET will match up to the final newline, XRegExp and JavaScript do not + +>> AddColumns( Match( "test" & Char(10), "^test$" ), len, Len(FullMatch) ) +{FullMatch:"test",StartMatch:1,SubMatches:Table(),len:4} + +>> AddColumns( Match( "test" & Char(10) & Char(10), "^test$" ), len, Len(FullMatch) ) +Blank() + +>> AddColumns( Match( "test" & Char(13), "^test$" ), len, Len(FullMatch) ) +Blank() + +>> AddColumns( Match( "test" & Char(13) & Char(10), "^test$" ), len, Len(FullMatch) ) +Blank() + +// .NET treats dot as [^\n], XRegExp and JavaScript use [^\n\r\u2028\u2029] + +>> DropColumns( Match( "te" & " " & "t", "te.t" ), FullMatch ) +{StartMatch:1,SubMatches:Table()} + +>> DropColumns( Match( "te" & Char(10) & "t", "te.t" ), FullMatch ) +Blank() + +>> DropColumns( Match( "te" & Char(13) & "t", "te.t" ), FullMatch ) +{StartMatch:1,SubMatches:Table()} + +>> DropColumns( Match( "te" & UniChar(Hex2Dec("2028")) & "t", "te.t" ), FullMatch ) +{StartMatch:1,SubMatches:Table()} + +>> DropColumns( Match( "te" & UniChar(Hex2Dec("2029")) & "t", "te.t" ), FullMatch ) +{StartMatch:1,SubMatches:Table()} + +// $ end anchor, multiline, and newline characters + +>> MatchAll( "a1" & Char(10) & "b2" & Char(10) & "c3", "\d$" ) +Table({FullMatch:"3",StartMatch:8,SubMatches:Table()}) + +>> MatchAll( "a1" & Char(10) & "b2" & Char(10) & "c3", "\d$", MatchOptions.Multiline ) +Table({FullMatch:"1",StartMatch:2,SubMatches:Table()},{FullMatch:"2",StartMatch:5,SubMatches:Table()},{FullMatch:"3",StartMatch:8,SubMatches:Table()}) + +>> MatchAll( "a1" & Char(13) & "b2" & Char(10) & "c3", "\d$" ) +Table({FullMatch:"3",StartMatch:8,SubMatches:Table()}) + +>> MatchAll( "a1" & Char(13) & "b2" & Char(13) & "c3", "\d$", MatchOptions.Multiline ) +Table({FullMatch:"3",StartMatch:8,SubMatches:Table()}) + +>> MatchAll( "a1" & Char(13)&Char(10) & "b2" & Char(13)&Char(10) & "c3", "\d$" ) +Table({FullMatch:"3",StartMatch:10,SubMatches:Table()}) + +>> MatchAll( "a1" & Char(13)&Char(10) & "b2" & Char(13)&Char(10) & "c3", "\d$", MatchOptions.Multiline ) +Table({FullMatch:"3",StartMatch:10,SubMatches:Table()}) + +// ^ beginning anchor, multiline, and newline characters + +>> MatchAll( "1a" & Char(10) & "2b" & Char(10) & "3c", "^\d" ) +Table({FullMatch:"1",StartMatch:1,SubMatches:Table()}) + +>> MatchAll( "1a" & Char(10) & "2b" & Char(10) & "3c", "^\d", MatchOptions.Multiline ) +Table({FullMatch:"1",StartMatch:1,SubMatches:Table()},{FullMatch:"2",StartMatch:4,SubMatches:Table()},{FullMatch:"3",StartMatch:7,SubMatches:Table()}) + +>> MatchAll( "1a" & Char(13) & "2b" & Char(10) & "3c", "^\d" ) +Table({FullMatch:"1",StartMatch:1,SubMatches:Table()}) + +>> MatchAll( "1a" & Char(13) & "2b" & Char(13) & "3c", "^\d", MatchOptions.Multiline ) +Table({FullMatch:"1",StartMatch:1,SubMatches:Table()}) + +>> MatchAll( "1a" & Char(13)&Char(10) & "2b" & Char(13)&Char(10) & "3c", "^\d" ) +Table({FullMatch:"1",StartMatch:1,SubMatches:Table()}) + +>> MatchAll( "1a" & Char(13)&Char(10) & "2b" & Char(13)&Char(10) & "3c", "^\d", MatchOptions.Multiline ) +Table({FullMatch:"1",StartMatch:1,SubMatches:Table()},{FullMatch:"2",StartMatch:5,SubMatches:Table()},{FullMatch:"3",StartMatch:9,SubMatches:Table()}) + +// Same for anchors in multi-line mode +>> fail +fail diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestHelpers/TestRunner.cs b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestHelpers/TestRunner.cs index ef33b4c3be..4a3a3f9e50 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestHelpers/TestRunner.cs +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestHelpers/TestRunner.cs @@ -102,6 +102,7 @@ public static Dictionary ParseSetupString(string setup) possible.Add("RegEx"); possible.Add("TimeZoneInfo"); possible.Add("TraceSetup"); + possible.Add("CultureInfo"); foreach (Match match in Regex.Matches(setup, @"(disable:)?(([\w]+|//)(\([^\)]*\))?)")) { diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/TestRunnerTests/InternalSetup.cs b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/TestRunnerTests/InternalSetup.cs index 353934ff6f..b39f3d8a1e 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/TestRunnerTests/InternalSetup.cs +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/TestRunnerTests/InternalSetup.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Reflection; using System.Text.RegularExpressions; @@ -20,6 +21,8 @@ internal class InternalSetup internal TimeZoneInfo TimeZoneInfo { get; set; } + internal CultureInfo CultureInfo { get; set; } + /// /// By default, we run expressions with a memory governor to enforce a limited amount of memory. /// When true, disable memory checks and allow expression to use as much memory as it needs. @@ -111,6 +114,23 @@ internal static InternalSetup Parse(string setupHandlerName, Features features, throw new ArgumentException("Invalid TimeZoneInfo setup!"); } } + else if (part.StartsWith("CultureInfo", StringComparison.OrdinalIgnoreCase)) + { + var m = new Regex(@"CultureInfo\(""(?[^)]+)""\)", RegexOptions.IgnoreCase).Match(part); + + if (m.Success) + { + var culture = m.Groups["culture"].Value; + + // This call will throw if the Language tag in invalid + iSetup.CultureInfo = new CultureInfo(culture); + parts.Remove(part); + } + else + { + throw new ArgumentException("Invalid TimeZoneInfo setup!"); + } + } } iSetup.HandlerNames = parts; diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index 9475e4fd97..172b06c227 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -154,11 +154,11 @@ private static bool ShouldSkipDotNetVersion(ExpressionTestCase testCase, string } #if true - // Helper to run a single .txt + // Helper to run a single .txt A [Fact] public void RunOne() { - var path = @"D:\repos\regex-min\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\match_limited.txt"; + var path = @"D:\repos\regex-min\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\culture_tr-TR.txt"; var line = 0; var runner = new InterpreterRunner(); diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/AsyncVerify.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/AsyncVerify.cs index 0cc4d0bfc2..2c91f9112d 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/AsyncVerify.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/AsyncVerify.cs @@ -83,6 +83,11 @@ public async Task EvalAsync(RecalcEngine engine, string expr, Inte rtConfig.AddService(setup.TimeZoneInfo); } + if (setup.CultureInfo != null) + { + rtConfig.AddService(setup.CultureInfo); + } + var task = engine.EvalAsync(expr, CancellationToken.None, options: setup.Flags.ToParserOptions(new CultureInfo("en-US")), runtimeConfig: rtConfig); var i = 0; diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/PowerFxEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/PowerFxEvaluationTests.cs index afa31bcb1f..a7994bc2ca 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/PowerFxEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/PowerFxEvaluationTests.cs @@ -958,6 +958,11 @@ protected override async Task RunAsyncInternal(string expr, string se runtimeConfig.AddService(iSetup.TimeZoneInfo); } + if (iSetup.CultureInfo != null) + { + runtimeConfig.AddService(iSetup.CultureInfo); + } + if (engine.TryGetByName("traceRecord", out _)) { var traceRecord = engine.GetValue("traceRecord"); From bbe578d5c462f8314fdcf5dcc3826e374afcf44a Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Tue, 9 Jul 2024 21:12:55 -0700 Subject: [PATCH 15/61] Updates --- src/tools/Repl/Program.cs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/tools/Repl/Program.cs b/src/tools/Repl/Program.cs index 37cabab2b6..63ee94d22a 100644 --- a/src/tools/Repl/Program.cs +++ b/src/tools/Repl/Program.cs @@ -44,6 +44,8 @@ public static class ConsoleRepl private static StandardFormatter _standardFormatter; + private static CultureInfo _cultureInfo = CultureInfo.CurrentCulture; + private static bool _reset; private static RecalcEngine ReplRecalcEngine() @@ -90,6 +92,7 @@ private static RecalcEngine ReplRecalcEngine() config.AddFunction(new Option2Function()); config.AddFunction(new Run1Function()); config.AddFunction(new Run2Function()); + config.AddFunction(new Language1Function()); var optionsSet = new OptionSet("Options", DisplayNameUtility.MakeUnique(options)); @@ -132,6 +135,10 @@ public MyRepl() this.ValueFormatter = _standardFormatter; this.HelpProvider = new MyHelpProvider(); + var bsp = new BasicServiceProvider(); + bsp.AddService(_cultureInfo); + this.InnerServices = bsp; + this.AllowSetDefinitions = true; this.EnableSampleUserObject(); this.AddPseudoFunction(new IRPseudoFunction()); @@ -407,6 +414,26 @@ public FormulaValue Execute(StringValue option, BooleanValue value) } } + // set the language + private class Language1Function : ReflectionFunction + { + public Language1Function() + : base("Language", FormulaType.Void, new[] { FormulaType.String }) + { + } + + public FormulaValue Execute(StringValue lang) + { + var cultureInfo = new CultureInfo(lang.Value); + + _cultureInfo = cultureInfo; + + _reset = true; + + return FormulaValue.NewVoid(); + } + } + private class MyHelpProvider : HelpProvider { #pragma warning disable CS0618 // Type or member is obsolete @@ -478,6 +505,8 @@ Use Option( Options.FormatTable, false ) to disable table formatting. Use Option() to see the list of all options with their current value. Use Help( ""Options"" ) for more information. +Use Language( ""en-US"" ) to set culture info. + Once a formula is defined or a variable's type is defined, it cannot be changed. Use Reset() to clear all formulas and variables. "; From 1c7262040be311af2ce7961708acaf5223c4c105 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Wed, 10 Jul 2024 00:43:14 -0700 Subject: [PATCH 16/61] update --- .../Public/Values/StringValue.cs | 5 -- .../Texl/Builtins/Match.cs | 13 ++-- .../Functions/LibraryOperators.cs | 23 ++++--- .../ExpressionTestCases/Culture_tr-TR.txt | 65 +++++++++++++++++-- .../ExpressionTestCases/Match_Limited.txt | 24 +++---- 5 files changed, 88 insertions(+), 42 deletions(-) diff --git a/src/libraries/Microsoft.PowerFx.Core/Public/Values/StringValue.cs b/src/libraries/Microsoft.PowerFx.Core/Public/Values/StringValue.cs index 2dabf96f14..e4ff4a41d8 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Public/Values/StringValue.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Public/Values/StringValue.cs @@ -36,11 +36,6 @@ public override void Visit(IValueVisitor visitor) visitor.Visit(this); } - internal StringValue ToLower() - { - return new StringValue(IRContext.NotInSource(FormulaType.String), Value.ToLowerInvariant()); - } - public override void ToExpression(StringBuilder sb, FormulaValueSerializerSettings settings) { sb.Append($"\"{CharacterUtils.ExcelEscapeString(Value)}\""); diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index 1aed3d185d..edbdaa3f85 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -98,14 +98,11 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp // // Features that are disallowed: // Capture groups + // Numbered capture groups, use named capture groups instead (.NET different from XRegExp). // Self-referncing groups, such as "(a\1)" (.NET different from XRegExp). - // Treat all escaped number sequences as a backreference number (.NET different from XRegExp). // Single quoted "(?'name'..." and "\k'name'" (.NET only). // Balancing capture groups (.NET only). - // Using named captures with back reference \number (.NET different from XRegExp). - // Using \k notation for numeric back references (.NET different from XRegExp). - // Octal character codes (.NET different from XRegExp) - // Uuse Hex or Unicode instead. + // Octal character codes, use \x or \u instead (.NET different from XRegExp) // "\o" could be added in the future, but we should avoid "\0" which causes backreference confusion. // Inline options // Anywhere in the expression except the beginning (.NET only). @@ -133,7 +130,7 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter @" # leading backslash, escape sequences \\k<(?\w+)> | # named backreference - (?\\0[0-7]{0,3}) | # octal are not accepted (no XRegExp support, by design) + (?\\0\d+) | # octal are not accepted (no XRegExp support, by design) (?\\\d+) | # numeric backreference (?\\ ([bBdDfnrsStvwW] | # standard regex character classes, missing from .NET are aAeGzZ (no XRegExp support), other common are u{} and o @@ -164,8 +161,8 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter (?\]) ", RegexOptions.IgnorePatternWhitespace | RegexOptions.ExplicitCapture); - var groupStack = new Stack(); // stack of open group numbers, null is used for non capturing groups - var groupNames = new List(); // list of known group names + var groupStack = new Stack(); // stack of open group numbers, null is used for non capturing groups, for detecting if a named group is closed + var groupNames = new List(); // list of seen group names var openCharacterClass = false; // are we defining a character class? diff --git a/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryOperators.cs b/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryOperators.cs index 0abd961927..db7bcabb78 100644 --- a/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryOperators.cs +++ b/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryOperators.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using System; +using System.Globalization; using System.Linq; using System.Text; using Microsoft.PowerFx.Core.IR; @@ -720,9 +721,9 @@ private static BooleanValue NotEqualPolymorphic(IRContext irContext, FormulaValu } // See in_SS in JScript membershipReplacementFunctions - public static Func StringInOperator(bool exact) + public static Func StringInOperator(bool exact) { - return (irContext, args) => + return (services, irContext, args) => { var left = args[0]; var right = args[1]; @@ -738,23 +739,25 @@ public static Func StringInOperator(boo var leftStr = (StringValue)left; var rightStr = (StringValue)right; - - return new BooleanValue(irContext, rightStr.Value.IndexOf(leftStr.Value, exact ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase) >= 0); + + return new BooleanValue(irContext, services.GetService().CompareInfo.IndexOf(rightStr.Value, leftStr.Value, exact ? CompareOptions.Ordinal : CompareOptions.IgnoreCase) >= 0); }; } // Left is a scalar. Right is a single-column table. // See in_ST() - public static Func InScalarTableOperator(bool exact) + public static Func InScalarTableOperator(bool exact) { - return (irContext, args) => + return (services, irContext, args) => { var left = args[0]; - var right = args[1]; - + var right = args[1]; + + var cultureInfo = services.GetService(); + if (!exact && left is StringValue strLhs) { - left = strLhs.ToLower(); + left = new StringValue(IRContext.NotInSource(FormulaType.String), cultureInfo.TextInfo.ToLower(strLhs.Value)); } var source = (TableValue)right; @@ -767,7 +770,7 @@ public static Func InScalarTableOperato if (!exact && rhs is StringValue strRhs) { - rhs = strRhs.ToLower(); + rhs = new StringValue(IRContext.NotInSource(FormulaType.String), cultureInfo.TextInfo.ToLower(strRhs.Value)); } if (RuntimeHelpers.AreEqual(left, rhs)) diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_tr-TR.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_tr-TR.txt index 7994e644d9..e4d03b268f 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_tr-TR.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_tr-TR.txt @@ -5,8 +5,6 @@ // Upper İ U+0130 I U+0049 // Lower i U+0069 ı U+0131 -// Upper and Lower - >> Language() "tr-TR" @@ -16,6 +14,8 @@ true >> "ı" = UniChar( Hex2Dec( "0131" ) ) true +// UPPER, LOWER, PROPER + >> Upper( "i" ) "İ" @@ -70,6 +70,8 @@ true >> Proper( "ıabc" ) "Iabc" +// VALUE, DECIMAL, FLOAT + >> Value( "123,456" ) 123.456 @@ -88,10 +90,63 @@ true >> Float( "123,456", "en-US" ) 123456 ->> Text( DateTime(2010,1,1,0,0,0,0), "mmm ddd yyyy" ) -"Oca Cum 2010" +// TEXT + +>> Text( DateTime(2010,1,1,14,0,0,0), "mmm ddd yyyy AM/PM" ) +"Oca Cum 2010 ÖS" + +>> Text( DateTime(2020,1,1,2,0,0,0), "mmmm dddd yyyy AM/PM" ) +"Ocak Çarşamba 2020 ÖÖ" + +>> Text( 123456789, "#,###.00" ) +"123456789,00000" + +>> Text( 123456789, "#.###,00" ) +"123.456.789,00" + +// IN AND EXACTIN + +>> "ı" in "SIGH" +true + +>> "İ" in "sigh" +true + +>> "ı" in "SİGH" +false + +>> "İ" in "sıgh" +false + +>> "ı" exactin "SIGH" +false + +>> "İ" exactin "sigh" +false + +>> "ı" exactin "SİGH" +false + +>> "İ" exactin "sıgh" +false + +>> "sİGh" in ["sigh","bcde"] +true + +>> "siGh" in ["SİGH","bcde"] +true + +>> "sIGH" in ["sigh","bcde"] +false + +>> "sıGH" in ["bcde","sIgh"] +true + +>> "SIgh" in ["bcde","sıgh"] +true -// Regular expressions, always uses invariant even though tr-TR is set +// REGULAR EXPRESSIONS +// Always uses invariant even though tr-TR is set, subject of // Results when using C# // Invariant tr-TR en-US diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt index efb14d967b..451b7902e6 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt @@ -5,20 +5,18 @@ // // Features that are disallowed: // Capture groups -// Self-referncing groups, such as "(a\1)". -// Treat all escaped number sequences as a backreference number. -// Single quoted "(?'name'..." and "\k'name'". -// Balancing capture groups. -// Using named captures with back reference \number. -// Using \k notation for numeric back references. -// Octal character codes (use Hex or Unicode instead). +// Numbered capture groups, use named capture groups instead (.NET different from XRegExp). +// Self-referncing groups, such as "(a\1)" (.NET different from XRegExp). +// Single quoted "(?'name'..." and "\k'name'" (.NET only). +// Balancing capture groups (.NET only). +// Octal character codes, use \x or \u instead (.NET different from XRegExp) // "\o" could be added in the future, but we should avoid "\0" which causes backreference confusion. // Inline options -// Anywhere in the expression except the beginning. -// For subexpressions. +// Anywhere in the expression except the beginning (.NET only). +// For subexpressions (.NET only). // Character classes -// Character class subtraction "[a-z-[m-n]]". -// Conditional alternation +// Character class subtraction "[a-z-[m-n]]" (.NET only). +// Conditional alternation (.NET only). // // Features that aren't supported by canonical .NET will be blocked automatically when the regular expression is instantiated in TryCreateReturnType. // @@ -533,6 +531,4 @@ Table({FullMatch:"1",StartMatch:1,SubMatches:Table()}) >> MatchAll( "1a" & Char(13)&Char(10) & "2b" & Char(13)&Char(10) & "3c", "^\d", MatchOptions.Multiline ) Table({FullMatch:"1",StartMatch:1,SubMatches:Table()},{FullMatch:"2",StartMatch:5,SubMatches:Table()},{FullMatch:"3",StartMatch:9,SubMatches:Table()}) -// Same for anchors in multi-line mode ->> fail -fail + From 428164df9fc6d3ebf40ec8e5e23e60fa7a67e8c4 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Wed, 10 Jul 2024 12:26:31 -0700 Subject: [PATCH 17/61] Updates --- .../Functions/LibraryTable.cs | 28 ++- .../ExpressionTestCases/Culture_en-US.txt | 178 ++++++++++++++++++ .../ExpressionTestCases/Culture_tr-TR.txt | 16 +- .../FileExpressionEvaluationTests.cs | 2 +- 4 files changed, 212 insertions(+), 12 deletions(-) create mode 100644 src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_en-US.txt diff --git a/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryTable.cs b/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryTable.cs index ad1f52d9e5..ee4c1e3d09 100644 --- a/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryTable.cs +++ b/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryTable.cs @@ -652,31 +652,31 @@ public static async ValueTask SortTable(EvalVisitor runner, EvalVi if (allNumbers) { - return SortValueType(pairs, irContext, compareToResultModifier); + return SortValueType(pairs, runner, irContext, compareToResultModifier); } else if (allDecimals) { - return SortValueType(pairs, irContext, compareToResultModifier); + return SortValueType(pairs, runner, irContext, compareToResultModifier); } else if (allStrings) { - return SortValueType(pairs, irContext, compareToResultModifier); + return SortValueType(pairs, runner, irContext, compareToResultModifier); } else if (allBooleans) { - return SortValueType(pairs, irContext, compareToResultModifier); + return SortValueType(pairs, runner, irContext, compareToResultModifier); } else if (allDatetimes) { - return SortValueType(pairs, irContext, compareToResultModifier); + return SortValueType(pairs, runner, irContext, compareToResultModifier); } else if (allDates) { - return SortValueType(pairs, irContext, compareToResultModifier); + return SortValueType(pairs, runner, irContext, compareToResultModifier); } else if (allTimes) { - return SortValueType(pairs, irContext, compareToResultModifier); + return SortValueType(pairs, runner, irContext, compareToResultModifier); } else if (allOptionSets) { @@ -1103,7 +1103,7 @@ private static FormulaValue DistinctValueType(List<(DValue row, For return new InMemoryTableValue(irContext, result); } - private static FormulaValue SortValueType(List<(DValue row, FormulaValue sortValue)> pairs, IRContext irContext, int compareToResultModifier) + private static FormulaValue SortValueType(List<(DValue row, FormulaValue sortValue)> pairs, EvalVisitor runner, IRContext irContext, int compareToResultModifier) where TPFxPrimitive : PrimitiveValue where TDotNetPrimitive : IComparable { @@ -1119,8 +1119,16 @@ private static FormulaValue SortValueType(List< } var n1 = a.sortValue as TPFxPrimitive; - var n2 = b.sortValue as TPFxPrimitive; - return n1.Value.CompareTo(n2.Value) * compareToResultModifier; + var n2 = b.sortValue as TPFxPrimitive; + CultureInfo culture; + if (n1.Value is string n1s && n2.Value is string n2s && (culture = runner.GetService()) != null) + { + return culture.CompareInfo.Compare(n1s, n2s) * compareToResultModifier; + } + else + { + return n1.Value.CompareTo(n2.Value) * compareToResultModifier; + } }); return new InMemoryTableValue(irContext, pairs.Select(pair => pair.row)); diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_en-US.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_en-US.txt new file mode 100644 index 0000000000..6f76a0805a --- /dev/null +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_en-US.txt @@ -0,0 +1,178 @@ +#SETUP: RegEx,CultureInfo("en-US"),PowerFxV1CompatibilityRules,ConsistentOneColumnTableResult + +// Four types of letter I +// Dotted Dotless +// Upper İ U+0130 I U+0049 +// Lower i U+0069 ı U+0131 + +>> Language() +"en-US" + +>> "İ" = UniChar( Hex2Dec( "0130") ) +true + +>> "ı" = UniChar( Hex2Dec( "0131" ) ) +true + +// UPPER, LOWER, PROPER + +>> Upper( "i" ) +"I" + +>> Lower( "I" ) +"i" + +>> Upper( "i" ) = "I" +true + +>> Lower( "I" ) = "i" +true + +>> Lower( "quit" ) = Lower( "QUIT" ) +true + +>> Lower( "quit" ) = Lower( "QUİT" ) +true + +>> Lower( "quıt" ) = Lower( "QUIT" ) +false + +>> Upper( "quit" ) = Upper( "QUIT" ) +true + +>> Proper( "Iabc" ) +"Iabc" + +>> Proper( "iabc" ) +"Iabc" + +// VALUE, DECIMAL, FLOAT + +>> Value( "123,456" ) +123456 + +>> Value( "123,456", "tr-TR" ) +123.456 + +>> Decimal( "123,456" ) +123456 + +>> Decimal( "123,456", "tr-TR" ) +123.456 + +>> Float( "123,456" ) +123456 + +>> Float( "123,456", "tr-TR" ) +123.456 + +// TEXT + +>> Text( DateTime(2010,1,1,14,0,0,0), "mmm ddd yyyy AM/PM" ) +"Jan Fri 2010 PM" + +>> Text( DateTime(2020,1,1,2,0,0,0), "mmmm dddd yyyy AM/PM" ) +"January Wednesday 2020 AM" + +>> Text( 123456789, "#,###.00" ) +"123,456,789.00" + +>> Text( 123456789, "#.###,00" ) +"123456789.00000" + +// IN AND EXACTIN + +>> "i" in "SIGH" +true + +>> "I" in "sigh" +true + +>> "i" exactin "SIGH" +false + +>> "I" exactin "sigh" +false + +>> "I" exactin "SIGH" +true + +>> "i" exactin "sigh" +true + +>> "sIGh" in ["sigh","bcde"] +true + +>> "siGh" in ["SIGH","bcde"] +true + +>> "sIGH" in ["sigh","bcde"] +true + +>> "siGH" in ["bcde","sIgh"] +true + +>> "SIgh" in ["bcde","sigh"] +true + +// SORT +// Relative order of i, I, ı, İ are different between en-US and tr-TR + +>> Sort( [ "Z", "İ", "z", "I", "J", "j", "ı", "a", "h", "i", "A", "H"], Value ) +Table({Value:"a"},{Value:"A"},{Value:"h"},{Value:"H"},{Value:"i"},{Value:"I"},{Value:"İ"},{Value:"ı"},{Value:"j"},{Value:"J"},{Value:"z"},{Value:"Z"}) + +>> SortByColumns( [ "Z", "İ", "z", "I", "J", "j", "ı", "a", "h", "i", "A", "H"], "Value" ) +Table({Value:"a"},{Value:"A"},{Value:"h"},{Value:"H"},{Value:"i"},{Value:"I"},{Value:"İ"},{Value:"ı"},{Value:"j"},{Value:"J"},{Value:"z"},{Value:"Z"}) + +>> Concat( Sort( Split( "j J k K l L m M n N o O p P r R s S t T u U v V y Y z Z Ç ç Ş ş Ü ü Ö ö İ ı Ğ ğ a A b B c C d D e E f F g G h H i I", " " ), Value ), Value, " " ) +"a A b B c C ç Ç d D e E f F g G ğ Ğ h H i I İ ı j J k K l L m M n N o O ö Ö p P r R s S ş Ş t T u U ü Ü v V y Y z Z" + +>> Concat( SortByColumns( Split( "d D e E f F g G h H i I j J k K l L m M n N o O p P r R s S t T u U v V y Y z Z Ç ç Ş ş Ü ü Ö ö İ ı Ğ ğ a A b B c C", " " ), "Value" ), Value, " " ) +"a A b B c C ç Ç d D e E f F g G ğ Ğ h H i I İ ı j J k K l L m M n N o O ö Ö p P r R s S ş Ş t T u U ü Ü v V y Y z Z" + +// REGULAR EXPRESSIONS +// Always uses invariant even though tr-TR is set, subject of + +// Results when using C# // Invariant tr-TR en-US + +>> IsMatch( "İ", "i", MatchOptions.IgnoreCase ) // false TRUE TRUE +false + +>> IsMatch( "i", "İ", MatchOptions.IgnoreCase ) // false TRUE TRUE +false + +>> IsMatch( "ı", "I", MatchOptions.IgnoreCase ) // false TRUE false +false + +>> IsMatch( "I", "ı", MatchOptions.IgnoreCase ) // false TRUE false +false + +>> IsMatch( "İ", "I", MatchOptions.IgnoreCase ) // false false TRUE +false + +>> IsMatch( "I", "İ", MatchOptions.IgnoreCase ) // false false TRUE +false + +>> IsMatch( "ı", "i", MatchOptions.IgnoreCase ) // false false false +false + +>> IsMatch( "i", "ı", MatchOptions.IgnoreCase ) // false false false +false + +>> IsMatch( "i", "I", MatchOptions.IgnoreCase ) // TRUE false TRUE +true + +>> IsMatch( "I", "i", MatchOptions.IgnoreCase ) // TRUE false TRUE +true + +>> IsMatch( "ı", "İ", MatchOptions.IgnoreCase ) // false false false +false + +>> IsMatch( "İ", "ı", MatchOptions.IgnoreCase ) // false false false +false + +>> Match( "hiIıİİıIhi", "\u0130+" ) +{FullMatch:"İİ",StartMatch:5,SubMatches:Table()} + +>> IsMatch( "Sıgh", "\u0131", MatchOptions.Contains ) +true diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_tr-TR.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_tr-TR.txt index e4d03b268f..17f3032f87 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_tr-TR.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_tr-TR.txt @@ -1,4 +1,4 @@ -#SETUP: RegEx,CultureInfo("tr-TR"),PowerFxV1CompatibilityRules +#SETUP: RegEx,CultureInfo("tr-TR"),PowerFxV1CompatibilityRules,ConsistentOneColumnTableResult // Four types of letter I // Dotted Dotless @@ -145,6 +145,20 @@ true >> "SIgh" in ["bcde","sıgh"] true +// SORT + +>> Sort( [ "Z", "İ", "z", "I", "J", "j", "ı", "a", "h", "i", "A", "H"], Value ) +Table({Value:"a"},{Value:"A"},{Value:"h"},{Value:"H"},{Value:"ı"},{Value:"I"},{Value:"i"},{Value:"İ"},{Value:"j"},{Value:"J"},{Value:"z"},{Value:"Z"}) + +>> SortByColumns( [ "Z", "İ", "z", "I", "J", "j", "ı", "a", "h", "i", "A", "H"], "Value" ) +Table({Value:"a"},{Value:"A"},{Value:"h"},{Value:"H"},{Value:"ı"},{Value:"I"},{Value:"i"},{Value:"İ"},{Value:"j"},{Value:"J"},{Value:"z"},{Value:"Z"}) + +>> Concat( Sort( Split( "j J k K l L m M n N o O p P r R s S t T u U v V y Y z Z Ç ç Ş ş Ü ü Ö ö İ ı Ğ ğ a A b B c C d D e E f F g G h H i I", " " ), Value ), Value, " " ) +"a A b B c C ç Ç d D e E f F g G ğ Ğ h H ı I i İ j J k K l L m M n N o O ö Ö p P r R s S ş Ş t T u U ü Ü v V y Y z Z" + +>> Concat( SortByColumns( Split( "d D e E f F g G h H i I j J k K l L m M n N o O p P r R s S t T u U v V y Y z Z Ç ç Ş ş Ü ü Ö ö İ ı Ğ ğ a A b B c C", " " ), "Value" ), Value, " " ) +"a A b B c C ç Ç d D e E f F g G ğ Ğ h H ı I i İ j J k K l L m M n N o O ö Ö p P r R s S ş Ş t T u U ü Ü v V y Y z Z" + // REGULAR EXPRESSIONS // Always uses invariant even though tr-TR is set, subject of diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index 172b06c227..e8a776baa0 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -158,7 +158,7 @@ private static bool ShouldSkipDotNetVersion(ExpressionTestCase testCase, string [Fact] public void RunOne() { - var path = @"D:\repos\regex-min\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\culture_tr-TR.txt"; + var path = @"D:\repos\regex-min\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\culture_en-US.txt"; var line = 0; var runner = new InterpreterRunner(); From 3693147befc9ab1a6be991ea0503822582a04a33 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Wed, 10 Jul 2024 12:32:25 -0700 Subject: [PATCH 18/61] Updates --- .../ExpressionTestCases/Culture_en-US.txt | 2 +- .../ExpressionTestCases/Culture_tr-TR.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_en-US.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_en-US.txt index 6f76a0805a..121dd01006 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_en-US.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_en-US.txt @@ -131,7 +131,7 @@ Table({Value:"a"},{Value:"A"},{Value:"h"},{Value:"H"},{Value:"i"},{Value:"I"},{V "a A b B c C ç Ç d D e E f F g G ğ Ğ h H i I İ ı j J k K l L m M n N o O ö Ö p P r R s S ş Ş t T u U ü Ü v V y Y z Z" // REGULAR EXPRESSIONS -// Always uses invariant even though tr-TR is set, subject of +// Always uses invariant even though tr-TR is set, subject of https://github.com/microsoft/Power-Fx/issues/2538 // Results when using C# // Invariant tr-TR en-US diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_tr-TR.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_tr-TR.txt index 17f3032f87..db3c8a756d 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_tr-TR.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_tr-TR.txt @@ -160,7 +160,7 @@ Table({Value:"a"},{Value:"A"},{Value:"h"},{Value:"H"},{Value:"ı"},{Value:"I"},{ "a A b B c C ç Ç d D e E f F g G ğ Ğ h H ı I i İ j J k K l L m M n N o O ö Ö p P r R s S ş Ş t T u U ü Ü v V y Y z Z" // REGULAR EXPRESSIONS -// Always uses invariant even though tr-TR is set, subject of +// Always uses invariant even though tr-TR is set, subject of https://github.com/microsoft/Power-Fx/issues/2538 // Results when using C# // Invariant tr-TR en-US From b79704d7260934951fabefe7cd7b8ed99aeafaa9 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Fri, 2 Aug 2024 23:14:16 -0700 Subject: [PATCH 19/61] Updates --- .../Functions/LibraryRegEx.cs | 55 +++++++++++++++++++ .../ExpressionTestCases/Match_Limited.txt | 19 +++++-- .../FileExpressionEvaluationTests.cs | 2 +- 3 files changed, 69 insertions(+), 7 deletions(-) diff --git a/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs b/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs index 9c9d51cd8b..b78fadaa08 100644 --- a/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs +++ b/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; @@ -199,6 +200,58 @@ internal abstract class RegexCommonImplementation : IAsyncTexlFunction protected abstract string RegexOptions { get; } + private string AlterNewlineMatching(string regex, RegexOptions options) + { + var openCharacterClass = false; // are we defining a character class? + var sb = new StringBuilder(); + + for (int i = 0; i < regex.Length; i++) + { + switch (regex[i]) + { + case '[': + openCharacterClass = true; + break; + case ']': + openCharacterClass = false; + break; + case '\\': + sb.Append("\\"); + i++; + break; + case '.': + if (!openCharacterClass) + { + sb.Append(@"[^\n\r\u2028\u2029]"); + continue; + } + + break; + case '^': + if (!openCharacterClass && (options & System.Text.RegularExpressions.RegexOptions.Multiline) != 0) + { + sb.Append(@"(?<=\A|[\n\r\u2028\u2029])"); + continue; + } + + break; + + case '$': + if (!openCharacterClass && (options & System.Text.RegularExpressions.RegexOptions.Multiline) != 0) + { + sb.Append(@"(?=\z|[\n\r\u2028\u2029])"); + continue; + } + + break; + } + + sb.Append(regex[i]); + } + + return sb.ToString(); + } + public Task InvokeAsync(FormulaValue[] args, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -265,6 +318,8 @@ public Task InvokeAsync(FormulaValue[] args, CancellationToken can regularExpression += "$"; } + regularExpression = AlterNewlineMatching(regularExpression, regOptions); + try { return Task.FromResult(InvokeRegexFunction(inputString, regularExpression, regOptions)); diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt index 451b7902e6..c33ff05026 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt @@ -483,13 +483,13 @@ Blank() Blank() >> DropColumns( Match( "te" & Char(13) & "t", "te.t" ), FullMatch ) -{StartMatch:1,SubMatches:Table()} +Blank() >> DropColumns( Match( "te" & UniChar(Hex2Dec("2028")) & "t", "te.t" ), FullMatch ) -{StartMatch:1,SubMatches:Table()} +Blank() >> DropColumns( Match( "te" & UniChar(Hex2Dec("2029")) & "t", "te.t" ), FullMatch ) -{StartMatch:1,SubMatches:Table()} +Blank() // $ end anchor, multiline, and newline characters @@ -503,13 +503,13 @@ Table({FullMatch:"1",StartMatch:2,SubMatches:Table()},{FullMatch:"2",StartMatch: Table({FullMatch:"3",StartMatch:8,SubMatches:Table()}) >> MatchAll( "a1" & Char(13) & "b2" & Char(13) & "c3", "\d$", MatchOptions.Multiline ) -Table({FullMatch:"3",StartMatch:8,SubMatches:Table()}) +Table({FullMatch:"1",StartMatch:2,SubMatches:Table()},{FullMatch:"2",StartMatch:5,SubMatches:Table()},{FullMatch:"3",StartMatch:8,SubMatches:Table()}) >> MatchAll( "a1" & Char(13)&Char(10) & "b2" & Char(13)&Char(10) & "c3", "\d$" ) Table({FullMatch:"3",StartMatch:10,SubMatches:Table()}) >> MatchAll( "a1" & Char(13)&Char(10) & "b2" & Char(13)&Char(10) & "c3", "\d$", MatchOptions.Multiline ) -Table({FullMatch:"3",StartMatch:10,SubMatches:Table()}) +Table({FullMatch:"1",StartMatch:2,SubMatches:Table()},{FullMatch:"2",StartMatch:6,SubMatches:Table()},{FullMatch:"3",StartMatch:10,SubMatches:Table()}) // ^ beginning anchor, multiline, and newline characters @@ -523,7 +523,7 @@ Table({FullMatch:"1",StartMatch:1,SubMatches:Table()},{FullMatch:"2",StartMatch: Table({FullMatch:"1",StartMatch:1,SubMatches:Table()}) >> MatchAll( "1a" & Char(13) & "2b" & Char(13) & "3c", "^\d", MatchOptions.Multiline ) -Table({FullMatch:"1",StartMatch:1,SubMatches:Table()}) +Table({FullMatch:"1",StartMatch:1,SubMatches:Table()},{FullMatch:"2",StartMatch:4,SubMatches:Table()},{FullMatch:"3",StartMatch:7,SubMatches:Table()}) >> MatchAll( "1a" & Char(13)&Char(10) & "2b" & Char(13)&Char(10) & "3c", "^\d" ) Table({FullMatch:"1",StartMatch:1,SubMatches:Table()}) @@ -531,4 +531,11 @@ Table({FullMatch:"1",StartMatch:1,SubMatches:Table()}) >> MatchAll( "1a" & Char(13)&Char(10) & "2b" & Char(13)&Char(10) & "3c", "^\d", MatchOptions.Multiline ) Table({FullMatch:"1",StartMatch:1,SubMatches:Table()},{FullMatch:"2",StartMatch:5,SubMatches:Table()},{FullMatch:"3",StartMatch:9,SubMatches:Table()}) +>> ForAll( MatchAll( " + a + b + c + ", "^.+$", MatchOptions.Multiline), { Match: FullMatch, Len: Len(FullMatch) } ) +Table({Len:2,Match:" a"},{Len:2,Match:" b"},{Len:2,Match:" c"},{Len:1,Match:" "}) + diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index e8a776baa0..35ccae5667 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -153,7 +153,7 @@ private static bool ShouldSkipDotNetVersion(ExpressionTestCase testCase, string return false; } -#if true +#if false // Helper to run a single .txt A [Fact] public void RunOne() From 15541fc8ae2112cfab6205e0eab56392c24adf31 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Mon, 12 Aug 2024 09:45:41 -0700 Subject: [PATCH 20/61] Updates --- .../Localization/Strings.cs | 10 +- .../Texl/Builtins/Match.cs | 335 ++++++++++++------ .../Types/Enums/BuiltInEnums.cs | 5 +- .../Functions/LibraryRegEx.cs | 17 +- src/strings/PowerFxResources.en-US.resx | 32 +- .../ExpressionTestCases/Match_Limited.txt | 49 ++- .../FileExpressionEvaluationTests.cs | 2 +- 7 files changed, 315 insertions(+), 135 deletions(-) diff --git a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs index d3bd380499..f678a7c300 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs @@ -719,24 +719,28 @@ internal static class TexlStrings public static ErrorResourceKey ErrDecimalRequiresPowerFxV1 = new ErrorResourceKey("ErrDecimalNeedsPowerFxV1"); public static ErrorResourceKey ErrInvalidRegEx = new ErrorResourceKey("ErrInvalidRegEx"); - public static ErrorResourceKey ErrInvalidRegExBadOptions = new ErrorResourceKey("ErrInvalidRegExBadOptions"); - public static ErrorResourceKey ErrInvalidRegExBadOptionsNotAtFront = new ErrorResourceKey("ErrInvalidRegExBadOptionsNotAtFront"); + public static ErrorResourceKey ErrInvalidRegExBadInlineOptions = new ErrorResourceKey("ErrInvalidRegExBadInlineOptions"); + public static ErrorResourceKey ErrInvalidRegExInlineOptionNotAtStart = new ErrorResourceKey("ErrInvalidRegExInlineOptionNotAtStart"); public static ErrorResourceKey ErrInvalidRegExBadOctal = new ErrorResourceKey("ErrInvalidRegExBadOctal"); + public static ErrorResourceKey ErrInvalidRegExBadCurly = new ErrorResourceKey("ErrInvalidRegExBadCurly"); + public static ErrorResourceKey ErrInvalidRegExRepeatInCharClass = new ErrorResourceKey("ErrInvalidRegExRepeatInCharClass"); + public static ErrorResourceKey ErrInvalidRegExBadQuantifier = new ErrorResourceKey("ErrInvalidRegExBadQuantifier"); public static ErrorResourceKey ErrInvalidRegExBadBackRefSelfReferencing = new ErrorResourceKey("ErrInvalidRegExBadBackRefSelfReferencing"); public static ErrorResourceKey ErrInvalidRegExBadBackRefNotDefined = new ErrorResourceKey("ErrInvalidRegExBadBackRefNotDefined"); public static ErrorResourceKey ErrInvalidRegExBadBackRefNumber = new ErrorResourceKey("ErrInvalidRegExBadBackRefNumber"); public static ErrorResourceKey ErrInvalidRegExBadBalancing = new ErrorResourceKey("ErrInvalidRegExBadBalancing"); public static ErrorResourceKey ErrInvalidRegExBadSingleQuoteNamedCapture = new ErrorResourceKey("ErrInvalidRegExBadSingleQuoteNamedCapture"); public static ErrorResourceKey ErrInvalidRegExBadEscape = new ErrorResourceKey("ErrInvalidRegExBadEscape"); - public static ErrorResourceKey ErrInvalidRegExBadCharacterClassSubtraction = new ErrorResourceKey("ErrInvalidRegExBadCharacterClassSubtraction"); public static ErrorResourceKey ErrInvalidRegExBadConditional = new ErrorResourceKey("ErrInvalidRegExBadConditional"); public static ErrorResourceKey ErrInvalidRegExBadNamedCaptureAlreadyExists = new ErrorResourceKey("ErrInvalidRegExBadNamedCaptureAlreadyExists"); public static ErrorResourceKey ErrInvalidRegExBadNamedCaptureName = new ErrorResourceKey("ErrInvalidRegExBadNamedCaptureName"); public static ErrorResourceKey ErrInvalidRegExBadCharacterClassLiteralSquareBracket = new ErrorResourceKey("ErrInvalidRegExBadCharacterClassLiteralSquareBracket"); public static ErrorResourceKey ErrInvalidRegExUnclosedCaptureGroups = new ErrorResourceKey("ErrInvalidRegExUnclosedCaptureGroups"); + public static ErrorResourceKey ErrInvalidRegExUnopenedCaptureGroups = new ErrorResourceKey("ErrInvalidRegExUnopenedCaptureGroups"); public static ErrorResourceKey ErrInvalidRegExUnclosedCharacterClass = new ErrorResourceKey("ErrInvalidRegExUnclosedCharacterClass"); public static ErrorResourceKey ErrVariableRegEx = new ErrorResourceKey("ErrVariableRegEx"); + public static ErrorResourceKey ErrVariableRegExOptions = new ErrorResourceKey("ErrVariableRegExOptions"); public static ErrorResourceKey InfoRegExCaptureNameHidesPredefinedFullMatchField = new ErrorResourceKey("InfoRegExCaptureNameHidesPredefinedFullMatchField"); public static ErrorResourceKey InfoRegExCaptureNameHidesPredefinedSubMatchesField = new ErrorResourceKey("InfoRegExCaptureNameHidesPredefinedSubMatchesField"); public static ErrorResourceKey InfoRegExCaptureNameHidesPredefinedStartMatchField = new ErrorResourceKey("InfoRegExCaptureNameHidesPredefinedStartMatchField"); diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index edbdaa3f85..d965dd78e2 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -5,6 +5,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Globalization; +using System.Text; using System.Text.RegularExpressions; using Microsoft.PowerFx.Core.App.ErrorContainers; using Microsoft.PowerFx.Core.Binding; @@ -80,16 +81,23 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp bool fValid = base.CheckTypes(context, args, argTypes, errors, out returnType, out nodeToCoercedTypeMap); Contracts.Assert(returnType.IsRecord || returnType.IsTable); TexlNode regExNode = args[1]; + string regularExpressionOptions = string.Empty; - if ((argTypes[1].Kind != DKind.String && argTypes[1].Kind != DKind.OptionSetValue) || !BinderUtils.TryGetConstantValue(context, regExNode, out var nodeValue)) + if ((argTypes[1].Kind != DKind.String && argTypes[1].Kind != DKind.OptionSetValue) || !BinderUtils.TryGetConstantValue(context, regExNode, out var regularExpression)) { errors.EnsureError(regExNode, TexlStrings.ErrVariableRegEx); return false; } - string regularExpression = nodeValue; + if (context.Features.PowerFxV1CompatibilityRules && args.Length == 3 && + ((argTypes[2].Kind != DKind.String && argTypes[2].Kind != DKind.OptionSetValue) || !BinderUtils.TryGetConstantValue(context, regExNode, out regularExpressionOptions))) + { + errors.EnsureError(regExNode, TexlStrings.ErrVariableRegExOptions); + return false; + } + return fValid && - (!context.Features.PowerFxV1CompatibilityRules || IsSupportedRegularExpression(regExNode, regularExpression, errors)) && + (!context.Features.PowerFxV1CompatibilityRules || IsSupportedRegularExpression(regExNode, regularExpression, regularExpressionOptions, errors)) && TryCreateReturnType(regExNode, regularExpression, errors, ref returnType); } @@ -115,7 +123,7 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp // // We chose to use canonical .NET instead of RegexOptions.ECMAScript because we wanted the unicode definitions for words. // See https://learn.microsoft.com/dotnet/standard/base-types/regular-expression-options#ecmascript-matching-behavior for more details - private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPattern, IErrorContainer errors) + private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPattern, string regexOptions, IErrorContainer errors) { // Scans the regular expression for interesting constructs, ignoring other elements and constructs that are legal, such as letters and numbers. // Order of alternation is important. .NET regular expressions are greedy and will match the first of these that it can. @@ -130,10 +138,10 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter @" # leading backslash, escape sequences \\k<(?\w+)> | # named backreference - (?\\0\d+) | # octal are not accepted (no XRegExp support, by design) - (?\\\d+) | # numeric backreference + (?\\0\d*) | # octal are not accepted (no XRegExp support, by design) + \\(?\d+) | # numeric backreference (?\\ - ([bBdDfnrsStvwW] | # standard regex character classes, missing from .NET are aAeGzZ (no XRegExp support), other common are u{} and o + ([bBdDfnrsStwW] | # standard regex character classes, missing from .NET are aAeGzZv (no XRegExp support), other common are u{} and o [pP]\{\w+\} | # unicode character classes c[a-zA-Z] | # Ctrl character classes x[0-9a-fA-F]{2} | # hex character, must be exactly 2 hex digits @@ -147,163 +155,272 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter (?\(\?<[^>]*>) | # bad named capture name, didn't match goodNamedCapture (?\(\?'[^']*') | # single quoted capture names are not supported - # leading (? - (?\(\?:) | # non-capture group, still need to track to match with closing - (?^\(\?[im]+\)) | # inline front of expression options we do support - (?\(\?(\w*-\w*|\w+)(:|\))?) | # inline options that we don't support, including disable of options (last ? portion makes for a better error message) + # leading (?, misc + (?\(\?:) | # non-capture group, still need to track to match with closing paren + \A\(\?(?[imsx]+)\) | + (?\(\?\#[^\)]*\)) | # inline comment + (?\(\?(=|!|<=|\(\?(\w+|\w*-\w+)[\:\)]?) | # inline options, including disable of options (?\(\?\() | # .NET conditional alternations are not supported + (?\([\?\+\*\|]) | # everything else unsupported that could start with a (, includes atomic groups, recursion, subroutines, branch reset, and future features + + # leading ?\*\+, quantifiers + (?[\?\*\+]\??) | # greedy and lazy quantifiers + (?[\?\*\+][\+\*]) | # possessive and useless quantifiers - # basic open and close + # leading {, limited quantifiers + (?{\d+(,\d*)?}(\?|\+|\*)) | # possessive and useless quantifiers + (?{\d+(,\d*)?}) | # standard limited quantifiers + (?[{}]) | # more constrained, blocks {,3} and Java/Rust semantics that does not treat this as a literal + + # open and close regions (?\[\]) | # disallow empty chararcter class (supported by XRegExp) and literal ] at front of character class (supported by .NET) (?\() | (?\)) | (?\[) | - (?\]) + (?\]) | + (?\#) | + (?[\r\n]) | + (?.) ", RegexOptions.IgnorePatternWhitespace | RegexOptions.ExplicitCapture); - var groupStack = new Stack(); // stack of open group numbers, null is used for non capturing groups, for detecting if a named group is closed + int groupNumber = 0; + var groupStack = new Stack(); // stack of open groups, null is used for non capturing groups, for detecting if a named group is closed var groupNames = new List(); // list of seen group names + var openComment = false; // there is an open end-of-line pound comment, only in freeFormMode + var freeSpacing = regexOptions.Contains("x"); // can also be set with inline mode modifier + var numberedCpature = regexOptions.Contains("N"); var openCharacterClass = false; // are we defining a character class? + List characterClassRepeat = new List(); foreach (Match groupMatch in groupPunctuationRE.Matches(regexPattern)) { - // ordered from most common/good to least common/bad, for fewer tests - if (groupMatch.Groups["goodEscape"].Success || groupMatch.Groups["goodEscapeAlpha"].Success || groupMatch.Groups["goodOptions"].Success) + if (groupMatch.Groups["newline"].Success) + { + openComment = false; + } + else if (groupMatch.Groups["poundComment"].Success) { - // all is well, nothing to do + openComment = freeSpacing; } - else if (groupMatch.Groups["openCharacterClass"].Success) + else if (!openComment) { - if (openCharacterClass) + // ordered from most common/good to least common/bad, for fewer tests + if (groupMatch.Groups["goodEscape"].Success || groupMatch.Groups["goodEscapeAlpha"].Success || + groupMatch.Groups["goodLookaround"].Success || groupMatch.Groups["goodInlineComment"].Success || + groupMatch.Groups["goodLimited"].Success) + { + // all is well, nothing to do + } + else if (groupMatch.Groups["openCharacterClass"].Success) { - // character class subtraction "[a-z-[m-n]]" is not supported - if (regexPattern[groupMatch.Groups["openCharacterClass"].Index - 1] == '-') + if (openCharacterClass) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadCharacterClassSubtraction); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadCharacterClassLiteralSquareBracket); return false; } else { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadCharacterClassLiteralSquareBracket); - return false; + openCharacterClass = true; + characterClassRepeat = new List(); } } - else + else if (groupMatch.Groups["closeCharacterClass"].Success) { - openCharacterClass = true; + openCharacterClass = false; } - } - else if (groupMatch.Groups["closeCharacterClass"].Success) - { - openCharacterClass = false; - } - else if (groupMatch.Groups["openCapture"].Success || groupMatch.Groups["goodNonCapture"].Success || groupMatch.Groups["goodNamedCapture"].Success) - { - // parens do not need to be escaped within square brackets - if (!openCharacterClass) + else if (groupMatch.Groups["goodNamedCapture"].Success) { - // non capturing group still needs to match closing paren, but does not define a new group - if (groupMatch.Groups["goodNamedCapture"].Success) + // parens do not need to be escaped within square brackets + if (!openCharacterClass) { - groupStack.Push(groupMatch.Groups["goodNamedCapture"].Value); + if (numberedCpature) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExMixingNamedAndNumberedCaptures, groupMatch.Value); + return false; + } + if (groupNames.Contains(groupMatch.Groups["goodNamedCapture"].Value)) { errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadNamedCaptureAlreadyExists, groupMatch.Value); return false; } + groupStack.Push(groupMatch.Groups["goodNamedCapture"].Value); groupNames.Add(groupMatch.Groups["goodNamedCapture"].Value); } - else + } + else if (groupMatch.Groups["goodNonCapture"].Success) + { + // parens do not need to be escaped within square brackets + if (!openCharacterClass) { groupStack.Push(null); } } - } - else if (groupMatch.Groups["closeCapture"].Success) - { - // parens do not need to be escaped within square brackets - if (!openCharacterClass) + else if (groupMatch.Groups["openCapture"].Success) { - groupStack.Pop(); + // parens do not need to be escaped within square brackets + if (!openCharacterClass) + { + if (!numberedCpature) + { + var groupName = (++groupNumber).ToString(CultureInfo.InvariantCulture); + + groupStack.Push(groupName); + groupNames.Add(groupName); + } + } } - } - else if (groupMatch.Groups["goodBackRefName"].Success) - { - var backRefName = groupMatch.Groups["goodBackRefName"].Value; + else if (groupMatch.Groups["closeCapture"].Success) + { + // parens do not need to be escaped within square brackets + if (!openCharacterClass) + { + if (groupStack.Count == 0) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExUnopenedCaptureGroups); + return false; + } + else + { + groupStack.Pop(); + } + } + } + else if (groupMatch.Groups["goodBackRefName"].Success) + { + var backRefName = groupMatch.Groups["goodBackRefName"].Value; - // group isn't defined, or not defined yet - if (!groupNames.Contains(backRefName)) + if (numberedCpature) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExMixingNamedAndNumberedCaptures, groupMatch.Value); + return false; + } + + // group isn't defined, or not defined yet + if (!groupNames.Contains(backRefName)) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefNotDefined, groupMatch.Value); + return false; + } + + // group is not closed and thus self referencing + if (groupStack.Contains(backRefName)) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefSelfReferencing, groupMatch.Value); + return false; + } + } + else if (groupMatch.Groups["goodBackRefNumber"].Success) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefNotDefined, groupMatch.Value); + var backRefNumber = groupMatch.Groups["goodBackRefNumber"].Value; + + if (!numberedCpature) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExNumberedCaptureDisabled, groupMatch.Value); + return false; + } + + // group isn't defined, or not defined yet + if (!groupNames.Contains(backRefNumber)) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefNotDefined, groupMatch.Value); + return false; + } + + // group is not closed and thus self referencing + if (groupStack.Contains(backRefNumber)) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefSelfReferencing, groupMatch.Value); + return false; + } + } + else if (groupMatch.Groups["goodInlineOptions"].Success) + { + if (groupMatch.Groups["goodInlineOptions"].Value.Contains("x")) + { + freeSpacing = true; + } + } + else if (groupMatch.Groups["goodQuantifiers"].Success || groupMatch.Groups["remainingChars"].Success) + { + if (openCharacterClass) + { + foreach (char singleChar in groupMatch.Value) + { + if (characterClassRepeat.Contains(singleChar)) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExRepeatInCharClass, singleChar); + } + else + { + characterClassRepeat.Add(singleChar); + } + } + } + } + else if (groupMatch.Groups["badBackRefNum"].Success) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefNumber, groupMatch.Value); return false; } - - // group is not closed and thus self referencing - if (groupStack.Contains(backRefName)) + else if (groupMatch.Groups["badNamedCaptureName"].Success) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefSelfReferencing, groupMatch.Value); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadNamedCaptureName, groupMatch.Groups["badNamedCaptureName"].Value); return false; } - } - else if (groupMatch.Groups["badBackRefNum"].Success) - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefNumber, groupMatch.Value); - return false; - } - else if (groupMatch.Groups["badNamedCaptureName"].Success) - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadNamedCaptureName, groupMatch.Groups["badNamedCaptureName"].Value); - return false; - } - else if (groupMatch.Groups["badOctal"].Success) - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadOctal, groupMatch.Groups["badOctal"].Value); - return false; - } - else if (groupMatch.Groups["badBalancing"].Success) - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBalancing, groupMatch.Groups["badBalancing"].Value); - return false; - } - else if (groupMatch.Groups["badOptions"].Success) - { - if (groupMatch.Groups["badOptions"].Index > 0) + else if (groupMatch.Groups["badOctal"].Success) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadOptionsNotAtFront, groupMatch.Groups["badOptions"].Value); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadOctal, groupMatch.Groups["badOctal"].Value); + return false; + } + else if (groupMatch.Groups["badBalancing"].Success) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBalancing, groupMatch.Groups["badBalancing"].Value); + return false; + } + else if (groupMatch.Groups["badInlineOptions"].Success) + { + errors.EnsureError(regExNode, groupMatch.Groups["badInlineOptions"].Index > 0 ? TexlStrings.ErrInvalidRegExInlineOptionNotAtStart : TexlStrings.ErrInvalidRegExBadInlineOptions, groupMatch.Groups["badInlineOptions"].Value); + return false; + } + else if (groupMatch.Groups["badSingleQuoteNamedCapture"].Success) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadSingleQuoteNamedCapture, groupMatch.Groups["badSingleQuoteNamedCapture"].Value); + return false; + } + else if (groupMatch.Groups["badConditional"].Success) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadConditional, groupMatch.Groups["badConditional"].Value); + return false; + } + else if (groupMatch.Groups["badCharacterClassEmpty"].Success) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadCharacterClassLiteralSquareBracket, groupMatch.Groups["badCharacterClassEmpty"].Value); + return false; + } + else if (groupMatch.Groups["badEscapeAlpha"].Success) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadEscape, groupMatch.Groups["badEscapeAlpha"].Value); + return false; + } + else if (groupMatch.Groups["badQuantifier"].Success) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadQuantifier, groupMatch.Groups["badQuantifier"].Value); + return false; + } + else if (groupMatch.Groups["badCurly"].Success) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadCurly, groupMatch.Groups["badCurly"].Value); + return false; } else { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadOptions, groupMatch.Groups["badOptions"].Value); + // This should never be hit. Good to have here in case one of the group names checked doesn't match the RE, in which case running tests would hit this. + throw new NotImplementedException("Unknown regular expression match"); } - - return false; - } - else if (groupMatch.Groups["badSingleQuoteNamedCapture"].Success) - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadSingleQuoteNamedCapture, groupMatch.Groups["badSingleQuoteNamedCapture"].Value); - return false; - } - else if (groupMatch.Groups["badConditional"].Success) - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadConditional, groupMatch.Groups["badConditional"].Value); - return false; - } - else if (groupMatch.Groups["badCharacterClassEmpty"].Success) - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadCharacterClassLiteralSquareBracket, groupMatch.Groups["badCharacterClassEmpty"].Value); - return false; - } - else if (groupMatch.Groups["badEscapeAlpha"].Success) - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadEscape, groupMatch.Groups["badEscapeAlpha"].Value); - return false; - } - else - { - // This should never be hit. Good to have here in case one of the group names checked doesn't match the RE, running tests would hit this. - throw new NotImplementedException("Unknown regular expression match"); } } diff --git a/src/libraries/Microsoft.PowerFx.Core/Types/Enums/BuiltInEnums.cs b/src/libraries/Microsoft.PowerFx.Core/Types/Enums/BuiltInEnums.cs index 1974d0dedf..c5865af126 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Types/Enums/BuiltInEnums.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Types/Enums/BuiltInEnums.cs @@ -86,7 +86,10 @@ internal static class BuiltInEnums { "Complete", "^c$" }, { "Contains", "c" }, { "IgnoreCase", "i" }, - { "Multiline", "m" } + { "Multiline", "m" }, + { "FreeSpacing", "x" }, + { "DotAll", "s" }, + { "NumberedCapture", "N" } }, canConcatenateStronglyTyped: true); diff --git a/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs b/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs index b78fadaa08..20665ef686 100644 --- a/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs +++ b/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs @@ -203,6 +203,7 @@ internal abstract class RegexCommonImplementation : IAsyncTexlFunction private string AlterNewlineMatching(string regex, RegexOptions options) { var openCharacterClass = false; // are we defining a character class? + var freeFormMode = (options & System.Text.RegularExpressions.RegexOptions.IgnorePatternWhitespace) != 0 || Regex.IsMatch(regex, @"\(\?[A-Za-wyz]*x"); var sb = new StringBuilder(); for (int i = 0; i < regex.Length; i++) @@ -214,6 +215,16 @@ private string AlterNewlineMatching(string regex, RegexOptions options) break; case ']': openCharacterClass = false; + break; + case '#': + if (freeFormMode) + { + for (i++; i < regex.Length && regex[i] != '\r' && regex[i] != '\n'; i++) + { + // skip the comment characters until the next newline, in case it includes [ ] + } + } + break; case '\\': sb.Append("\\"); @@ -222,7 +233,7 @@ private string AlterNewlineMatching(string regex, RegexOptions options) case '.': if (!openCharacterClass) { - sb.Append(@"[^\n\r\u2028\u2029]"); + sb.Append(@"[^\n\r]"); continue; } @@ -230,7 +241,7 @@ private string AlterNewlineMatching(string regex, RegexOptions options) case '^': if (!openCharacterClass && (options & System.Text.RegularExpressions.RegexOptions.Multiline) != 0) { - sb.Append(@"(?<=\A|[\n\r\u2028\u2029])"); + sb.Append(@"(?<=\A|\r\n|\n|\r)"); continue; } @@ -239,7 +250,7 @@ private string AlterNewlineMatching(string regex, RegexOptions options) case '$': if (!openCharacterClass && (options & System.Text.RegularExpressions.RegexOptions.Multiline) != 0) { - sb.Append(@"(?=\z|[\n\r\u2028\u2029])"); + sb.Append(@"(?=\z|\r\n|\n|\r)"); continue; } diff --git a/src/strings/PowerFxResources.en-US.resx b/src/strings/PowerFxResources.en-US.resx index eed2e49ffd..c16a63007c 100644 --- a/src/strings/PowerFxResources.en-US.resx +++ b/src/strings/PowerFxResources.en-US.resx @@ -4375,22 +4375,26 @@ Invalid regular expression: Inline options must appear at the beginning of the regular expression, found "{0}" later. Error message indicating that the regular expression has inline options not at the front. - - Invalid regular expression: Inline options are limited to a combination of the letters [im], cannot disable options, and cannot be used on a subexpression, found "{0}". + + Invalid regular expression: Inline options are limited to a combination of the letters [imsx], cannot disable options, and cannot be used on a subexpression, found "{0}". Error message indicating that the regular expression has bad inline options. Invalid regular expression: Octal \0 character codes are not supported, use hexadecimal \x or Unicode \u instead, found "{0}". Error message indicating that the regular expression has octal characters. + + Invalid regular expression: Literal curly braces must be escaped with a backslash, for example \{ or \}, found "{0}". + Error message indicating that the regular expression has literla curly braces. + + + Invalid regular expression: Possessive quantifiers are not supported, found "{0}". + Error message indicating that the regular expression does not support possessive quantifiers. + Invalid regular expression: Invalid escape code, found "{0}". Error message indicating that the regular expression has an invalid alphanumeric escape code. - - Invalid regular expression: Character class subtraction is not supported. - Error message indicating that the regular expression does not support character class subtraction. - Invalid regular expression: Capture group "{0}" not defined. Error message indicating that the regular expression capture group is not defined. @@ -4411,6 +4415,10 @@ Invalid regular expression: Unclosed groups, too few closing parenthesis. Error message indicating that the regular expression has unclosed capture groups. + + Invalid regular expression: Unopened groups, too few opening parenthesis. + Error message indicating that the regular expression has unclosed capture groups. + Invalid regular expression: Named capture group "{0}" defined more than once. Error message indicating that the regular expression is trying to define the same capture group more than once. @@ -4419,6 +4427,14 @@ Invalid regular expression: Named capture group name must be a combination of letters and digits and begin with a letter, found "{0}". Error message indicating that the regular expression is trying to define the same capture group more than once. + + Invalid regular expression: Inline options must appear at the beginning of the regular expression, found "{0}" later. + Error message indicating that the regular expression has inline options not at the front. + + + Invalid regular expression: Character appears more than once in character class, found "{0}". + Error message indicating that the regular expression has repeated characters in a character class definition. + Invalid regular expression: Square bracket character classes cannot be empty and cannot include unescaped literal open or close square brackets, escape with "\[" or "\]". Error message indicating that the regular expression is trying to define the same capture group more than once. @@ -4439,6 +4455,10 @@ Regular expressions must be constant values. Error Message. + + Regular expression options must be constant values. + Error Message. + The value passed to the '{0}' function cannot be changed. Error message shown to the user if they try to use a mutation function (such as Patch / Collect) with a value that cannot be mutated. diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt index c33ff05026..79b1c31d7d 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt @@ -108,11 +108,25 @@ Blank() >> Match( "hello"&Char(10)&"howdy", "(?m)o$" ) {FullMatch:"o",StartMatch:5,SubMatches:Table()} +>> Match( "hello"&Char(10)&"howdy", "(?s)hello.howdy" ) +{FullMatch:"o",StartMatch:5,SubMatches:Table()} + +>> Match( "hello"&Char(13)&"howdy", "(?s)hello.howdy" ) +{FullMatch:"o",StartMatch:5,SubMatches:Table()} + +>> Match( "hello"&Char(13)&Char(10)&"howdy", "(?s)hello.howdy" ) +{FullMatch:"o",StartMatch:5,SubMatches:Table()} + +>> Match( "hello howdy", "(?x) hello \s howdy # comment" ) +{FullMatch:"o",StartMatch:5,SubMatches:Table()} + +// unsupported inline options + >> Match( "hello"&Char(10)&"howdy", "(?-m)o$" ) -Errors: Error 33-42: Invalid regular expression: Inline options are limited to a combination of the letters [im], cannot disable options, and cannot be used on a subexpression, found "(?-m)".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 33-42: Invalid regular expression: Inline options are limited to a combination of the letters [imsx], cannot disable options, and cannot be used on a subexpression, found "(?-m)".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "hello"&Char(10)&"howdy", "(?i-m)o$" ) -Errors: Error 33-43: Invalid regular expression: Inline options are limited to a combination of the letters [im], cannot disable options, and cannot be used on a subexpression, found "(?i-m)".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 33-43: Invalid regular expression: Inline options are limited to a combination of the letters [imsx], cannot disable options, and cannot be used on a subexpression, found "(?i-m)".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "hello"&Char(10)&"howdy", "^(?m)o$" ) Errors: Error 33-42: Invalid regular expression: Inline options must appear at the beginning of the regular expression, found "(?m)" later.|Error 0-5: The function 'Match' has some invalid arguments. @@ -123,19 +137,29 @@ Errors: Error 33-44: Invalid regular expression: Inline options must appear at t >> Match( "hello"&Char(10)&"howdy", "^(?m:o$)" ) Errors: Error 33-43: Invalid regular expression: Inline options must appear at the beginning of the regular expression, found "(?m:" later.|Error 0-5: The function 'Match' has some invalid arguments. -// unsupported inline options - >> Match( "hello world", "(?n)o") -Errors: Error 22-29: Invalid regular expression: Inline options are limited to a combination of the letters [im], cannot disable options, and cannot be used on a subexpression, found "(?n)".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 22-29: Invalid regular expression: Inline options are limited to a combination of the letters [imsx], cannot disable options, and cannot be used on a subexpression, found "(?n)".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "hello world", "(?s)o") -Errors: Error 22-29: Invalid regular expression: Inline options are limited to a combination of the letters [im], cannot disable options, and cannot be used on a subexpression, found "(?s)".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 22-29: Invalid regular expression: Inline options are limited to a combination of the letters [imsx], cannot disable options, and cannot be used on a subexpression, found "(?s)".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "hello world", "(?x)o") -Errors: Error 22-29: Invalid regular expression: Inline options are limited to a combination of the letters [im], cannot disable options, and cannot be used on a subexpression, found "(?x)".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 22-29: Invalid regular expression: Inline options are limited to a combination of the letters [imsx], cannot disable options, and cannot be used on a subexpression, found "(?x)".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "hello world", "(?A)o") -Errors: Error 22-29: Invalid regular expression: Inline options are limited to a combination of the letters [im], cannot disable options, and cannot be used on a subexpression, found "(?A)".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 22-29: Invalid regular expression: Inline options are limited to a combination of the letters [imsx], cannot disable options, and cannot be used on a subexpression, found "(?A)".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match ("hello world", "(?^)o") // PCRE2 +Errors + +>> Match ("hello world", "(?xx)o") // PCRE2 +Errors + +>> Match ("hello world", "(?J)o") // PCRE2 +Errors + +>> Match ("hello world", "(?U)o") // PCRE2 +Errors // inline options overriding explicit options, conflicts? @@ -200,7 +224,7 @@ Errors: Error 12-17: Invalid regular expression: Square bracket character classe // character class subtraction >> Match( "k", "[a-z-[b-c]]" ) -Errors: Error 12-25: Invalid regular expression: Character class subtraction is not supported.|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 12-25: Invalid regular expression: Square bracket character classes cannot be empty and cannot include unescaped literal open or close square brackets, escape with "\[" or "\]". // regular expression parsing @@ -342,7 +366,7 @@ Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\T" Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\U".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test" & Char(11) & "bed", "\v" ) -{FullMatch:" ",StartMatch:5,SubMatches:Table()} +Error 34-38: Invalid regular expression: Invalid escape code, found "\v".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test", "\V" ) Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\V".|Error 0-5: The function 'Match' has some invalid arguments. @@ -486,10 +510,10 @@ Blank() Blank() >> DropColumns( Match( "te" & UniChar(Hex2Dec("2028")) & "t", "te.t" ), FullMatch ) -Blank() +{StartMatch:1,SubMatches:Table()} >> DropColumns( Match( "te" & UniChar(Hex2Dec("2029")) & "t", "te.t" ), FullMatch ) -Blank() +{StartMatch:1,SubMatches:Table()} // $ end anchor, multiline, and newline characters @@ -539,3 +563,4 @@ Table({FullMatch:"1",StartMatch:1,SubMatches:Table()},{FullMatch:"2",StartMatch: Table({Len:2,Match:" a"},{Len:2,Match:" b"},{Len:2,Match:" c"},{Len:1,Match:" "}) + diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index 35ccae5667..beede7d534 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -24,7 +24,7 @@ public FileExpressionEvaluationTests(ITestOutputHelper output) } // File expression tests are run multiple times for the different ways a host can use Power Fx. - // + // ab // 1. Features.PowerFxV1 without NumberIsFloat - the main way that most hosts will use Power Fx. // 2. Feautres.PowerFxV1 with NumberIsFloat - for hosts that wish to use floating point instead of Decimal. // 3. Default Canvas features with NumberIsFloat - the current default for Canvas apps. Canvas From 0d0c88c768123eb813a9cc74466fd1fbf42cb767 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Tue, 13 Aug 2024 00:11:37 -0700 Subject: [PATCH 21/61] Updates --- .../Localization/Strings.cs | 5 + .../Texl/Builtins/Match.cs | 188 ++++++++++-------- .../Types/Enums/BuiltInEnums.cs | 2 +- .../Functions/LibraryRegEx.cs | 52 ++--- src/strings/PowerFxResources.en-US.resx | 24 ++- .../ExpressionTestCases/Match_Limited.txt | 56 ++++-- .../FileExpressionEvaluationTests.cs | 6 +- 7 files changed, 200 insertions(+), 133 deletions(-) diff --git a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs index f678a7c300..cf52619da2 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs @@ -723,7 +723,9 @@ internal static class TexlStrings public static ErrorResourceKey ErrInvalidRegExInlineOptionNotAtStart = new ErrorResourceKey("ErrInvalidRegExInlineOptionNotAtStart"); public static ErrorResourceKey ErrInvalidRegExBadOctal = new ErrorResourceKey("ErrInvalidRegExBadOctal"); public static ErrorResourceKey ErrInvalidRegExBadCurly = new ErrorResourceKey("ErrInvalidRegExBadCurly"); + public static ErrorResourceKey ErrInvalidRegExBadParen = new ErrorResourceKey("ErrInvalidRegExBadParen"); public static ErrorResourceKey ErrInvalidRegExRepeatInCharClass = new ErrorResourceKey("ErrInvalidRegExRepeatInCharClass"); + public static ErrorResourceKey ErrInvalidRegExRepeatedInlineOption = new ErrorResourceKey("ErrInvalidRegExRepeatedInlineOption"); public static ErrorResourceKey ErrInvalidRegExBadQuantifier = new ErrorResourceKey("ErrInvalidRegExBadQuantifier"); public static ErrorResourceKey ErrInvalidRegExBadBackRefSelfReferencing = new ErrorResourceKey("ErrInvalidRegExBadBackRefSelfReferencing"); public static ErrorResourceKey ErrInvalidRegExBadBackRefNotDefined = new ErrorResourceKey("ErrInvalidRegExBadBackRefNotDefined"); @@ -738,6 +740,9 @@ internal static class TexlStrings public static ErrorResourceKey ErrInvalidRegExUnclosedCaptureGroups = new ErrorResourceKey("ErrInvalidRegExUnclosedCaptureGroups"); public static ErrorResourceKey ErrInvalidRegExUnopenedCaptureGroups = new ErrorResourceKey("ErrInvalidRegExUnopenedCaptureGroups"); public static ErrorResourceKey ErrInvalidRegExUnclosedCharacterClass = new ErrorResourceKey("ErrInvalidRegExUnclosedCharacterClass"); + public static ErrorResourceKey ErrInvalidRegExMixingNamedAndNumberedCaptures = new ErrorResourceKey("ErrInvalidRegExMixingNamedAndNumberedCaptures"); + public static ErrorResourceKey ErrInvalidRegExNumberedCapturesDisabled = new ErrorResourceKey("ErrInvalidRegExNumberedCapturesDisabled"); + public static ErrorResourceKey ErrInvalidRegExBadUnsupportedCharacterClassSubtraction = new ErrorResourceKey("ErrInvalidRegExBadUnsupportedCharacterClassSubtraction"); public static ErrorResourceKey ErrVariableRegEx = new ErrorResourceKey("ErrVariableRegEx"); public static ErrorResourceKey ErrVariableRegExOptions = new ErrorResourceKey("ErrVariableRegExOptions"); diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index d965dd78e2..469a8114e1 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -5,6 +5,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Globalization; +using System.Linq; using System.Text; using System.Text.RegularExpressions; using Microsoft.PowerFx.Core.App.ErrorContainers; @@ -134,12 +135,12 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter // One might think that the "\a" could have matched , but it will match first because it is first in the RE. // One might think that the "\(" could have matched , but the double backslashes will be consumed first, which is why it is important // to gather all the matches in a linear scan from the beginning to the end. - var groupPunctuationRE = new Regex( + var tokenRE = new Regex( @" # leading backslash, escape sequences \\k<(?\w+)> | # named backreference (?\\0\d*) | # octal are not accepted (no XRegExp support, by design) - \\(?\d+) | # numeric backreference + \\(?\d+) | # numeric backreference, must be enabled with MatchOptions.NumberedCaptures (?\\ ([bBdDfnrsStwW] | # standard regex character classes, missing from .NET are aAeGzZv (no XRegExp support), other common are u{} and o [pP]\{\w+\} | # unicode character classes @@ -160,7 +161,7 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter \A\(\?(?[imsx]+)\) | (?\(\?\#[^\)]*\)) | # inline comment (?\(\?(=|!|<=|\(\?(\w+|\w*-\w+)[\:\)]?) | # inline options, including disable of options + (?\(\?(\w+|\w*-\w+)[\:\)]) | # inline options, including disable of options (?\(\?\() | # .NET conditional alternations are not supported (?\([\?\+\*\|]) | # everything else unsupported that could start with a (, includes atomic groups, recursion, subroutines, branch reset, and future features @@ -179,46 +180,53 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter (?\)) | (?\[) | (?\]) | - (?\#) | - (?[\r\n]) | - (?.) + (?\#) | # used in free spacing mode (to detect start of comment), ignored otherwise + (?[\r\n]) | # used in free spacing mode (to detect end of comment), ignored otherwise + (?.) # used in free spacing mode (to detect repeats), ignored otherwise ", RegexOptions.IgnorePatternWhitespace | RegexOptions.ExplicitCapture); - int groupNumber = 0; - var groupStack = new Stack(); // stack of open groups, null is used for non capturing groups, for detecting if a named group is closed - var groupNames = new List(); // list of seen group names - var openComment = false; // there is an open end-of-line pound comment, only in freeFormMode - var freeSpacing = regexOptions.Contains("x"); // can also be set with inline mode modifier - var numberedCpature = regexOptions.Contains("N"); + int captureNumber = 0; // last numbered capture encountered + var captureStack = new Stack(); // stack of all open capture groups, including null for non capturing groups, for detecting if a named group is closed + var captureNames = new List(); // list of seen named groups, does not included numbered groups or non capture groups + var openComment = false; // there is an open end-of-line pound comment, only in freeFormMode + var freeSpacing = regexOptions.Contains("x"); // can also be set with inline mode modifier + var numberedCpature = regexOptions.Contains("N"); // can only be set here, no inline mode modifier + var openCharacterClass = false; // are we defining a character class? + List characterClassRepeat = new List(); // encountered character class characters, to detect repeats - var openCharacterClass = false; // are we defining a character class? - List characterClassRepeat = new List(); - - foreach (Match groupMatch in groupPunctuationRE.Matches(regexPattern)) + foreach (Match token in tokenRE.Matches(regexPattern)) { - if (groupMatch.Groups["newline"].Success) + if (token.Groups["newline"].Success) { openComment = false; } - else if (groupMatch.Groups["poundComment"].Success) + else if (token.Groups["poundComment"].Success) { openComment = freeSpacing; } else if (!openComment) { // ordered from most common/good to least common/bad, for fewer tests - if (groupMatch.Groups["goodEscape"].Success || groupMatch.Groups["goodEscapeAlpha"].Success || - groupMatch.Groups["goodLookaround"].Success || groupMatch.Groups["goodInlineComment"].Success || - groupMatch.Groups["goodLimited"].Success) + if (token.Groups["goodEscape"].Success || token.Groups["goodEscapeAlpha"].Success || + token.Groups["goodLookaround"].Success || token.Groups["goodInlineComment"].Success || + token.Groups["goodLimited"].Success) { // all is well, nothing to do } - else if (groupMatch.Groups["openCharacterClass"].Success) + else if (token.Groups["openCharacterClass"].Success) { if (openCharacterClass) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadCharacterClassLiteralSquareBracket); - return false; + if (token.Index > 0 && regexPattern[token.Index - 1] == '-') + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadUnsupportedCharacterClassSubtraction, token.Index >= regexPattern.Length - 5 ? regexPattern.Substring(token.Index - 1) : regexPattern.Substring(token.Index - 1, 6) + "..."); + return false; + } + else + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadCharacterClassLiteralSquareBracket); + return false; + } } else { @@ -226,205 +234,215 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter characterClassRepeat = new List(); } } - else if (groupMatch.Groups["closeCharacterClass"].Success) + else if (token.Groups["closeCharacterClass"].Success) { openCharacterClass = false; } - else if (groupMatch.Groups["goodNamedCapture"].Success) + else if (token.Groups["goodNamedCapture"].Success) { // parens do not need to be escaped within square brackets if (!openCharacterClass) { if (numberedCpature) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExMixingNamedAndNumberedCaptures, groupMatch.Value); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExMixingNamedAndNumberedCaptures, token.Value); return false; } - if (groupNames.Contains(groupMatch.Groups["goodNamedCapture"].Value)) + if (captureNames.Contains(token.Groups["goodNamedCapture"].Value)) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadNamedCaptureAlreadyExists, groupMatch.Value); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadNamedCaptureAlreadyExists, token.Value); return false; } - groupStack.Push(groupMatch.Groups["goodNamedCapture"].Value); - groupNames.Add(groupMatch.Groups["goodNamedCapture"].Value); + captureStack.Push(token.Groups["goodNamedCapture"].Value); + captureNames.Add(token.Groups["goodNamedCapture"].Value); } } - else if (groupMatch.Groups["goodNonCapture"].Success) + else if (token.Groups["goodNonCapture"].Success) { // parens do not need to be escaped within square brackets if (!openCharacterClass) { - groupStack.Push(null); + captureStack.Push(null); } } - else if (groupMatch.Groups["openCapture"].Success) + else if (token.Groups["openCapture"].Success) { // parens do not need to be escaped within square brackets if (!openCharacterClass) { if (!numberedCpature) { - var groupName = (++groupNumber).ToString(CultureInfo.InvariantCulture); - - groupStack.Push(groupName); - groupNames.Add(groupName); + captureNumber++; + captureStack.Push(captureNumber.ToString(CultureInfo.InvariantCulture)); } } } - else if (groupMatch.Groups["closeCapture"].Success) + else if (token.Groups["closeCapture"].Success) { // parens do not need to be escaped within square brackets if (!openCharacterClass) { - if (groupStack.Count == 0) + if (captureStack.Count == 0) { errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExUnopenedCaptureGroups); return false; } else { - groupStack.Pop(); + captureStack.Pop(); } } } - else if (groupMatch.Groups["goodBackRefName"].Success) + else if (token.Groups["goodBackRefName"].Success) { - var backRefName = groupMatch.Groups["goodBackRefName"].Value; + var backRefName = token.Groups["goodBackRefName"].Value; if (numberedCpature) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExMixingNamedAndNumberedCaptures, groupMatch.Value); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExMixingNamedAndNumberedCaptures, token.Value); return false; } // group isn't defined, or not defined yet - if (!groupNames.Contains(backRefName)) + if (!captureNames.Contains(backRefName)) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefNotDefined, groupMatch.Value); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefNotDefined, token.Value); return false; } // group is not closed and thus self referencing - if (groupStack.Contains(backRefName)) + if (captureStack.Contains(backRefName)) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefSelfReferencing, groupMatch.Value); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefSelfReferencing, token.Value); return false; } } - else if (groupMatch.Groups["goodBackRefNumber"].Success) + else if (token.Groups["goodBackRefNumber"].Success) { - var backRefNumber = groupMatch.Groups["goodBackRefNumber"].Value; + var backRefNumber = Convert.ToInt32(token.Groups["goodBackRefNumber"].Value, CultureInfo.InvariantCulture); if (!numberedCpature) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExNumberedCaptureDisabled, groupMatch.Value); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExNumberedCapturesDisabled, token.Value); return false; } - // group isn't defined, or not defined yet - if (!groupNames.Contains(backRefNumber)) + // back ref number has not yet been defined + if (backRefNumber < 1 || backRefNumber > captureNumber) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefNotDefined, groupMatch.Value); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefNotDefined, token.Value); return false; } // group is not closed and thus self referencing - if (groupStack.Contains(backRefNumber)) + if (captureStack.Contains(token.Groups["goodBackRefNumber"].Value)) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefSelfReferencing, groupMatch.Value); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefSelfReferencing, token.Value); return false; } } - else if (groupMatch.Groups["goodInlineOptions"].Success) + else if (token.Groups["goodInlineOptions"].Success) { - if (groupMatch.Groups["goodInlineOptions"].Value.Contains("x")) + if (Regex.IsMatch(token.Groups["goodInlineOptions"].Value, @"(?.).*\k")) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExRepeatedInlineOption, token.Value); + return false; + } + + if (token.Groups["goodInlineOptions"].Value.Contains("x")) { freeSpacing = true; } } - else if (groupMatch.Groups["goodQuantifiers"].Success || groupMatch.Groups["remainingChars"].Success) + else if (token.Groups["goodQuantifiers"].Success || token.Groups["remainingChars"].Success) { if (openCharacterClass) { - foreach (char singleChar in groupMatch.Value) + foreach (char singleChar in token.Value) { if (characterClassRepeat.Contains(singleChar)) { errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExRepeatInCharClass, singleChar); + return false; } - else + else if (singleChar != '-') { characterClassRepeat.Add(singleChar); } } } } - else if (groupMatch.Groups["badBackRefNum"].Success) + else if (token.Groups["badBackRefNum"].Success) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefNumber, token.Value); + return false; + } + else if (token.Groups["badNamedCaptureName"].Success) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefNumber, groupMatch.Value); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadNamedCaptureName, token.Groups["badNamedCaptureName"].Value); return false; } - else if (groupMatch.Groups["badNamedCaptureName"].Success) + else if (token.Groups["badOctal"].Success) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadNamedCaptureName, groupMatch.Groups["badNamedCaptureName"].Value); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadOctal, token.Groups["badOctal"].Value); return false; } - else if (groupMatch.Groups["badOctal"].Success) + else if (token.Groups["badBalancing"].Success) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadOctal, groupMatch.Groups["badOctal"].Value); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBalancing, token.Groups["badBalancing"].Value); return false; } - else if (groupMatch.Groups["badBalancing"].Success) + else if (token.Groups["badInlineOptions"].Success) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBalancing, groupMatch.Groups["badBalancing"].Value); + errors.EnsureError(regExNode, token.Groups["badInlineOptions"].Index > 0 ? TexlStrings.ErrInvalidRegExInlineOptionNotAtStart : TexlStrings.ErrInvalidRegExBadInlineOptions, token.Groups["badInlineOptions"].Value); return false; } - else if (groupMatch.Groups["badInlineOptions"].Success) + else if (token.Groups["badSingleQuoteNamedCapture"].Success) { - errors.EnsureError(regExNode, groupMatch.Groups["badInlineOptions"].Index > 0 ? TexlStrings.ErrInvalidRegExInlineOptionNotAtStart : TexlStrings.ErrInvalidRegExBadInlineOptions, groupMatch.Groups["badInlineOptions"].Value); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadSingleQuoteNamedCapture, token.Groups["badSingleQuoteNamedCapture"].Value); return false; } - else if (groupMatch.Groups["badSingleQuoteNamedCapture"].Success) + else if (token.Groups["badConditional"].Success) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadSingleQuoteNamedCapture, groupMatch.Groups["badSingleQuoteNamedCapture"].Value); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadConditional, token.Groups["badConditional"].Value); return false; } - else if (groupMatch.Groups["badConditional"].Success) + else if (token.Groups["badCharacterClassEmpty"].Success) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadConditional, groupMatch.Groups["badConditional"].Value); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadCharacterClassLiteralSquareBracket, token.Groups["badCharacterClassEmpty"].Value); return false; } - else if (groupMatch.Groups["badCharacterClassEmpty"].Success) + else if (token.Groups["badEscapeAlpha"].Success) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadCharacterClassLiteralSquareBracket, groupMatch.Groups["badCharacterClassEmpty"].Value); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadEscape, token.Groups["badEscapeAlpha"].Value); return false; } - else if (groupMatch.Groups["badEscapeAlpha"].Success) + else if (token.Groups["badQuantifier"].Success) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadEscape, groupMatch.Groups["badEscapeAlpha"].Value); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadQuantifier, token.Groups["badQuantifier"].Value); return false; } - else if (groupMatch.Groups["badQuantifier"].Success) + else if (token.Groups["badCurly"].Success) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadQuantifier, groupMatch.Groups["badQuantifier"].Value); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadCurly, token.Groups["badCurly"].Value); return false; } - else if (groupMatch.Groups["badCurly"].Success) + else if (token.Groups["badParen"].Success) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadCurly, groupMatch.Groups["badCurly"].Value); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadParen, token.Index >= regexPattern.Length - 5 ? regexPattern.Substring(token.Index) : regexPattern.Substring(token.Index, 5) + "..."); return false; } else { - // This should never be hit. Good to have here in case one of the group names checked doesn't match the RE, in which case running tests would hit this. + // This should never be hit. Here in case one of the names checked doesn't match the RE, in which case running tests would hit this. throw new NotImplementedException("Unknown regular expression match"); } } } - if (groupStack.Count > 0) + if (captureStack.Count > 0) { errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExUnclosedCaptureGroups); return false; diff --git a/src/libraries/Microsoft.PowerFx.Core/Types/Enums/BuiltInEnums.cs b/src/libraries/Microsoft.PowerFx.Core/Types/Enums/BuiltInEnums.cs index c5865af126..8e4066c0ad 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Types/Enums/BuiltInEnums.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Types/Enums/BuiltInEnums.cs @@ -89,7 +89,7 @@ internal static class BuiltInEnums { "Multiline", "m" }, { "FreeSpacing", "x" }, { "DotAll", "s" }, - { "NumberedCapture", "N" } + { "NumberedCaptures", "N" } }, canConcatenateStronglyTyped: true); diff --git a/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs b/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs index 20665ef686..b3e43078bf 100644 --- a/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs +++ b/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs @@ -203,8 +203,10 @@ internal abstract class RegexCommonImplementation : IAsyncTexlFunction private string AlterNewlineMatching(string regex, RegexOptions options) { var openCharacterClass = false; // are we defining a character class? - var freeFormMode = (options & System.Text.RegularExpressions.RegexOptions.IgnorePatternWhitespace) != 0 || Regex.IsMatch(regex, @"\(\?[A-Za-wyz]*x"); - var sb = new StringBuilder(); + var freeSpacing = (options & System.Text.RegularExpressions.RegexOptions.IgnorePatternWhitespace) != 0 || Regex.IsMatch(regex, @"^\(\?[A-Za-z-[x]]*x"); + var multiline = (options & System.Text.RegularExpressions.RegexOptions.Multiline) != 0 || Regex.IsMatch(regex, @"^\(\?[A-Za-a-[m]]*m"); + var dotAll = (options & System.Text.RegularExpressions.RegexOptions.Singleline) != 0 || Regex.IsMatch(regex, @"^\(\?[A-Za-z-[s]]*s"); + var alteredRegex = new StringBuilder(); for (int i = 0; i < regex.Length; i++) { @@ -212,55 +214,57 @@ private string AlterNewlineMatching(string regex, RegexOptions options) { case '[': openCharacterClass = true; + alteredRegex.Append('['); break; + case ']': openCharacterClass = false; + alteredRegex.Append(']'); break; + case '#': - if (freeFormMode) + if (freeSpacing) { for (i++; i < regex.Length && regex[i] != '\r' && regex[i] != '\n'; i++) { // skip the comment characters until the next newline, in case it includes [ ] } } + else + { + alteredRegex.Append('#'); + } break; + case '\\': - sb.Append("\\"); - i++; - break; - case '.': - if (!openCharacterClass) + alteredRegex.Append("\\"); + if (++i < regex.Length) { - sb.Append(@"[^\n\r]"); - continue; + alteredRegex.Append(regex[i]); } break; - case '^': - if (!openCharacterClass && (options & System.Text.RegularExpressions.RegexOptions.Multiline) != 0) - { - sb.Append(@"(?<=\A|\r\n|\n|\r)"); - continue; - } + case '.': + alteredRegex.Append(!openCharacterClass && !dotAll ? @"[^\n\r]" : "."); + break; + + case '^': + alteredRegex.Append(!openCharacterClass && multiline ? @"(?<=\A|\r\n|\n|\r)" : "^"); break; case '$': - if (!openCharacterClass && (options & System.Text.RegularExpressions.RegexOptions.Multiline) != 0) - { - sb.Append(@"(?=\z|\r\n|\n|\r)"); - continue; - } + alteredRegex.Append(!openCharacterClass && multiline ? @"(?=\z|\r\n|\n|\r)" : "$"); + break; + default: + alteredRegex.Append(regex[i]); break; } - - sb.Append(regex[i]); } - return sb.ToString(); + return alteredRegex.ToString(); } public Task InvokeAsync(FormulaValue[] args, CancellationToken cancellationToken) diff --git a/src/strings/PowerFxResources.en-US.resx b/src/strings/PowerFxResources.en-US.resx index c16a63007c..34b16e8964 100644 --- a/src/strings/PowerFxResources.en-US.resx +++ b/src/strings/PowerFxResources.en-US.resx @@ -4385,7 +4385,15 @@ Invalid regular expression: Literal curly braces must be escaped with a backslash, for example \{ or \}, found "{0}". - Error message indicating that the regular expression has literla curly braces. + Error message indicating that the regular expression has literal curly braces. + + + Invalid regular expression: Unsupported special group, found "{0}". + Error message indicating that the regular expression that starts with a paren. + + + Invalid regular expression: Repeated inline option, found "{0}". + Error message indicating that the regular expression includes more than one of the same option. Invalid regular expression: Possessive quantifiers are not supported, found "{0}". @@ -4432,7 +4440,7 @@ Error message indicating that the regular expression has inline options not at the front. - Invalid regular expression: Character appears more than once in character class, found "{0}". + Invalid regular expression: Character appears more than once in character class, found repeated "{0}". Error message indicating that the regular expression has repeated characters in a character class definition. @@ -4451,6 +4459,18 @@ Invalid regular expression: Conditional alternation is not supported, found "{0}". Error message indicating that the regular expression has conditionals. + + Invalid regular expression: Named captures cannot be used with MatchOptions.NumberedCaptures enabled, found "{0}". + Error message indicating that the regular expression is mixing named and numbered captures. + + + Invalid regular expression: Use named captures with "(?<name>" and "\k<name>" or enable MatchOptions.NumberedCaptures, found "{0}". + Error message indicating that the regular expression is not enabled for numbered captures. + + + Invalid regular expression: Character class subtraction is not supported, found "{0}". + Error message indicating that the regular expression is using character class subtraction and it is not supported. + Regular expressions must be constant values. Error Message. diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt index 79b1c31d7d..c3c472facb 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt @@ -40,7 +40,7 @@ // Self referencing groups are disallowed >> Match( "aa aaaa aaaaaa ", "((a+)(\1) ?)+" ) -Errors: Error 26-41: Invalid regular expression: Numbered back references are not supported, use named back references with "(?)" and "\k" instead, found "\1".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 26-41: Invalid regular expression: Use named captures with "(?" and "\k" or enable MatchOptions.NumberedCaptures, found "\1".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "aa aaaa aaaaaa ", "(?(a+)(\k) ?)+" ) Errors: Error 26-56: Invalid regular expression: Self-referencing capture groups are not supported, found "\k".|Error 0-5: The function 'Match' has some invalid arguments. @@ -48,7 +48,7 @@ Errors: Error 26-56: Invalid regular expression: Self-referencing capture groups // Backreferences without a group are disallowed >> Match( "hello howdy", "([hi]).*\1" ) -Errors: Error 22-34: Invalid regular expression: Numbered back references are not supported, use named back references with "(?)" and "\k" instead, found "\1".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 22-34: Invalid regular expression: Use named captures with "(?" and "\k" or enable MatchOptions.NumberedCaptures, found "\1".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "hello howdy", "([hi]).*\k<1>" ) Errors: Error 22-37: Invalid regular expression: Capture group "\k<1>" not defined.|Error 0-5: The function 'Match' has some invalid arguments. @@ -57,7 +57,7 @@ Errors: Error 22-37: Invalid regular expression: Capture group "\k<1>" not defin {FullMatch:"hello h",StartMatch:1,SubMatches:Table({Value:"h"}),first:"h"} >> Match( "hello howdy", "(?[hi]).*\1" ) -Errors: Error 22-42: Invalid regular expression: Numbered back references are not supported, use named back references with "(?)" and "\k" instead, found "\1".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 22-42: Invalid regular expression: Use named captures with "(?" and "\k" or enable MatchOptions.NumberedCaptures, found "\1".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "hello howdy", "(?[hi]).*\k" ) Errors: Error 22-50: Invalid regular expression: Capture group "\k" not defined.|Error 0-5: The function 'Match' has some invalid arguments. @@ -108,17 +108,17 @@ Blank() >> Match( "hello"&Char(10)&"howdy", "(?m)o$" ) {FullMatch:"o",StartMatch:5,SubMatches:Table()} ->> Match( "hello"&Char(10)&"howdy", "(?s)hello.howdy" ) -{FullMatch:"o",StartMatch:5,SubMatches:Table()} +>> With( Match( "hello"&Char(10)&"howdy", "(?s)hello.howdy" ), {StartMatch: StartMatch, LengthMatch: Len(FullMatch)} ) +{LengthMatch:11,StartMatch:1} ->> Match( "hello"&Char(13)&"howdy", "(?s)hello.howdy" ) -{FullMatch:"o",StartMatch:5,SubMatches:Table()} +>> With( Match( "hello"&Char(13)&"howdy", "(?s)hello.howdy" ), {StartMatch: StartMatch, LengthMatch: Len(FullMatch)} ) +{LengthMatch:11,StartMatch:1} >> Match( "hello"&Char(13)&Char(10)&"howdy", "(?s)hello.howdy" ) -{FullMatch:"o",StartMatch:5,SubMatches:Table()} +Blank() ->> Match( "hello howdy", "(?x) hello \s howdy # comment" ) -{FullMatch:"o",StartMatch:5,SubMatches:Table()} +>> Match( "hello, howdy", "(?x) llo , \s how # comment" ) +{FullMatch:"llo, how",StartMatch:3,SubMatches:Table()} // unsupported inline options @@ -141,25 +141,25 @@ Errors: Error 33-43: Invalid regular expression: Inline options must appear at t Errors: Error 22-29: Invalid regular expression: Inline options are limited to a combination of the letters [imsx], cannot disable options, and cannot be used on a subexpression, found "(?n)".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "hello world", "(?s)o") -Errors: Error 22-29: Invalid regular expression: Inline options are limited to a combination of the letters [imsx], cannot disable options, and cannot be used on a subexpression, found "(?s)".|Error 0-5: The function 'Match' has some invalid arguments. +{FullMatch:"o",StartMatch:5,SubMatches:Table()} >> Match( "hello world", "(?x)o") -Errors: Error 22-29: Invalid regular expression: Inline options are limited to a combination of the letters [imsx], cannot disable options, and cannot be used on a subexpression, found "(?x)".|Error 0-5: The function 'Match' has some invalid arguments. +{FullMatch:"o",StartMatch:5,SubMatches:Table()} >> Match( "hello world", "(?A)o") Errors: Error 22-29: Invalid regular expression: Inline options are limited to a combination of the letters [imsx], cannot disable options, and cannot be used on a subexpression, found "(?A)".|Error 0-5: The function 'Match' has some invalid arguments. >> Match ("hello world", "(?^)o") // PCRE2 -Errors +Errors: Error 22-29: Invalid regular expression: Unsupported special group, found "(?^)o".|Error 0-5: The function 'Match' has some invalid arguments. >> Match ("hello world", "(?xx)o") // PCRE2 -Errors +Errors: Error 22-30: Invalid regular expression: Repeated inline option, found "(?xx)".|Error 0-5: The function 'Match' has some invalid arguments. >> Match ("hello world", "(?J)o") // PCRE2 -Errors +Errors: Error 22-29: Invalid regular expression: Inline options are limited to a combination of the letters [imsx], cannot disable options, and cannot be used on a subexpression, found "(?J)".|Error 0-5: The function 'Match' has some invalid arguments. >> Match ("hello world", "(?U)o") // PCRE2 -Errors +Errors: Error 22-29: Invalid regular expression: Inline options are limited to a combination of the letters [imsx], cannot disable options, and cannot be used on a subexpression, found "(?U)".|Error 0-5: The function 'Match' has some invalid arguments. // inline options overriding explicit options, conflicts? @@ -224,7 +224,7 @@ Errors: Error 12-17: Invalid regular expression: Square bracket character classe // character class subtraction >> Match( "k", "[a-z-[b-c]]" ) -Errors: Error 12-25: Invalid regular expression: Square bracket character classes cannot be empty and cannot include unescaped literal open or close square brackets, escape with "\[" or "\]". +Errors: Error 12-25: Invalid regular expression: Character class subtraction is not supported, found "-[b-c]...".|Error 0-5: The function 'Match' has some invalid arguments. // regular expression parsing @@ -366,7 +366,7 @@ Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\T" Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\U".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test" & Char(11) & "bed", "\v" ) -Error 34-38: Invalid regular expression: Invalid escape code, found "\v".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 34-38: Invalid regular expression: Invalid escape code, found "\v".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test", "\V" ) Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\V".|Error 0-5: The function 'Match' has some invalid arguments. @@ -562,5 +562,25 @@ Table({FullMatch:"1",StartMatch:1,SubMatches:Table()},{FullMatch:"2",StartMatch: ", "^.+$", MatchOptions.Multiline), { Match: FullMatch, Len: Len(FullMatch) } ) Table({Len:2,Match:" a"},{Len:2,Match:" b"},{Len:2,Match:" c"},{Len:1,Match:" "}) +// repeated characters in character class, used by intersection and future character class features, also would catch POSIX cases if wasn't already blocked by nested square brackets + +>> Match( "hello", "[a-z&&[k-m]]" ) +Errors: Error 16-30: Invalid regular expression: Character appears more than once in character class, found repeated "&".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "hello", "[a-z&&k-m]" ) +Errors: Error 16-28: Invalid regular expression: Character appears more than once in character class, found repeated "&".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "hello", "[a-hh-z]" ) +Errors: Error 16-26: Invalid regular expression: Character appears more than once in character class, found repeated "h".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "HellO", "[[:lower:]]" ) +Errors: Error 16-29: Invalid regular expression: Square bracket character classes cannot be empty and cannot include unescaped literal open or close square brackets, escape with "\[" or "\]".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "hello", "[[:s:]]" ) +Errors: Error 16-25: Invalid regular expression: Square bracket character classes cannot be empty and cannot include unescaped literal open or close square brackets, escape with "\[" or "\]".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "hello", "[[=x=]]" ) +Errors: Error 16-25: Invalid regular expression: Square bracket character classes cannot be empty and cannot include unescaped literal open or close square brackets, escape with "\[" or "\]".|Error 0-5: The function 'Match' has some invalid arguments. + diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index beede7d534..fcd3ecada7 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -24,7 +24,7 @@ public FileExpressionEvaluationTests(ITestOutputHelper output) } // File expression tests are run multiple times for the different ways a host can use Power Fx. - // ab + // abcdefge // 1. Features.PowerFxV1 without NumberIsFloat - the main way that most hosts will use Power Fx. // 2. Feautres.PowerFxV1 with NumberIsFloat - for hosts that wish to use floating point instead of Decimal. // 3. Default Canvas features with NumberIsFloat - the current default for Canvas apps. Canvas @@ -153,12 +153,12 @@ private static bool ShouldSkipDotNetVersion(ExpressionTestCase testCase, string return false; } -#if false +#if true // Helper to run a single .txt A [Fact] public void RunOne() { - var path = @"D:\repos\regex-min\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\culture_en-US.txt"; + var path = @"D:\repos\regex-min\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\match_limited.txt"; var line = 0; var runner = new InterpreterRunner(); From e18f2fe0e297daeef49afc180b5b298279be3ac0 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Tue, 13 Aug 2024 15:17:03 -0700 Subject: [PATCH 22/61] Updates --- .../Localization/Strings.cs | 1 + .../Texl/Builtins/Match.cs | 45 +++-- .../Functions/LibraryRegEx.cs | 26 ++- src/strings/PowerFxResources.en-US.resx | 4 + .../ExpressionTestCases/Culture_en-US.txt | 4 +- .../ExpressionTestCases/Culture_tr-TR.txt | 4 +- .../ExpressionTestCases/Match.txt | 49 +---- .../ExpressionTestCases/Match_Limited.txt | 181 +++++++++++------- .../ExpressionTestCases/Match_V1Compat.txt | 35 ++++ .../Match_V1CompatDisabled.txt | 38 ++++ .../FileExpressionEvaluationTests.cs | 6 +- 11 files changed, 252 insertions(+), 141 deletions(-) create mode 100644 src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_V1Compat.txt create mode 100644 src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_V1CompatDisabled.txt diff --git a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs index cf52619da2..9919629992 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs @@ -743,6 +743,7 @@ internal static class TexlStrings public static ErrorResourceKey ErrInvalidRegExMixingNamedAndNumberedCaptures = new ErrorResourceKey("ErrInvalidRegExMixingNamedAndNumberedCaptures"); public static ErrorResourceKey ErrInvalidRegExNumberedCapturesDisabled = new ErrorResourceKey("ErrInvalidRegExNumberedCapturesDisabled"); public static ErrorResourceKey ErrInvalidRegExBadUnsupportedCharacterClassSubtraction = new ErrorResourceKey("ErrInvalidRegExBadUnsupportedCharacterClassSubtraction"); + public static ErrorResourceKey ErrInvalidRegExOpenParenInComment = new ErrorResourceKey("ErrInvalidRegExOpenParenInComment"); public static ErrorResourceKey ErrVariableRegEx = new ErrorResourceKey("ErrVariableRegEx"); public static ErrorResourceKey ErrVariableRegExOptions = new ErrorResourceKey("ErrVariableRegExOptions"); diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index 469a8114e1..9682ba5279 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -81,8 +81,9 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp bool fValid = base.CheckTypes(context, args, argTypes, errors, out returnType, out nodeToCoercedTypeMap); Contracts.Assert(returnType.IsRecord || returnType.IsTable); - TexlNode regExNode = args[1]; + string regularExpressionOptions = string.Empty; + var regExNode = args[1]; if ((argTypes[1].Kind != DKind.String && argTypes[1].Kind != DKind.OptionSetValue) || !BinderUtils.TryGetConstantValue(context, regExNode, out var regularExpression)) { @@ -91,15 +92,20 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp } if (context.Features.PowerFxV1CompatibilityRules && args.Length == 3 && - ((argTypes[2].Kind != DKind.String && argTypes[2].Kind != DKind.OptionSetValue) || !BinderUtils.TryGetConstantValue(context, regExNode, out regularExpressionOptions))) + ((argTypes[2].Kind != DKind.String && argTypes[2].Kind != DKind.OptionSetValue) || !BinderUtils.TryGetConstantValue(context, args[2], out regularExpressionOptions))) { - errors.EnsureError(regExNode, TexlStrings.ErrVariableRegExOptions); + errors.EnsureError(args[2], TexlStrings.ErrVariableRegExOptions); return false; } + if (!context.Features.PowerFxV1CompatibilityRules) + { + regularExpressionOptions += "N"; + } + return fValid && (!context.Features.PowerFxV1CompatibilityRules || IsSupportedRegularExpression(regExNode, regularExpression, regularExpressionOptions, errors)) && - TryCreateReturnType(regExNode, regularExpression, errors, ref returnType); + TryCreateReturnType(regExNode, regularExpression, regularExpressionOptions, errors, ref returnType); } // Limit regular expressions to common features that are supported, with consistent semantics, by both canonical .NET and XRegExp. @@ -158,7 +164,7 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter # leading (?, misc (?\(\?:) | # non-capture group, still need to track to match with closing paren - \A\(\?(?[imsx]+)\) | + \A\(\?(?[imsx]+)\) | # inline options (?\(\?\#[^\)]*\)) | # inline comment (?\(\?(=|!|<=|\(\?(\w+|\w*-\w+)[\:\)]) | # inline options, including disable of options @@ -208,8 +214,7 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter { // ordered from most common/good to least common/bad, for fewer tests if (token.Groups["goodEscape"].Success || token.Groups["goodEscapeAlpha"].Success || - token.Groups["goodLookaround"].Success || token.Groups["goodInlineComment"].Success || - token.Groups["goodLimited"].Success) + token.Groups["goodLookaround"].Success || token.Groups["goodLimited"].Success) { // all is well, nothing to do } @@ -272,11 +277,15 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter // parens do not need to be escaped within square brackets if (!openCharacterClass) { - if (!numberedCpature) + if (numberedCpature) { captureNumber++; captureStack.Push(captureNumber.ToString(CultureInfo.InvariantCulture)); } + else + { + captureStack.Push(null); + } } } else if (token.Groups["closeCapture"].Success) @@ -374,6 +383,14 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter } } } + else if (token.Groups["goodInlineComment"].Success) + { + if (token.Groups["goodInlineComment"].Value.Substring(1).Contains("(")) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExOpenParenInComment, token.Groups["goodInlineComment"].Value); + return false; + } + } else if (token.Groups["badBackRefNum"].Success) { errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefNumber, token.Value); @@ -458,7 +475,7 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter } // Creates a typed result: [Match:s, Captures:*[Value:s], NamedCaptures:r[:s]] - private bool TryCreateReturnType(TexlNode regExNode, string regexPattern, IErrorContainer errors, ref DType returnType) + private bool TryCreateReturnType(TexlNode regExNode, string regexPattern, string regexOptions, IErrorContainer errors, ref DType returnType) { Contracts.AssertValue(regexPattern); string prefixedRegexPattern = this._cachePrefix + regexPattern; @@ -489,7 +506,13 @@ private bool TryCreateReturnType(TexlNode regExNode, string regexPattern, IError try { - var regex = new Regex(regexPattern); + var regexDotNetOptions = RegexOptions.None; + if (regexOptions.Contains("x")) + { + regexDotNetOptions |= RegexOptions.IgnorePatternWhitespace; + } + + var regex = new Regex(regexPattern, regexDotNetOptions); List propertyNames = new List(); bool fullMatchHidden = false, subMatchesHidden = false, startMatchHidden = false; @@ -523,7 +546,7 @@ private bool TryCreateReturnType(TexlNode regExNode, string regexPattern, IError propertyNames.Add(new TypedName(DType.String, ColumnName_FullMatch)); } - if (!subMatchesHidden) + if (!subMatchesHidden && regexOptions.Contains("N")) { propertyNames.Add(new TypedName(DType.CreateTable(new TypedName(DType.String, ColumnName_Value)), ColumnName_SubMatches)); } diff --git a/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs b/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs index b3e43078bf..42f83406e6 100644 --- a/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs +++ b/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs @@ -93,10 +93,10 @@ protected override FormulaValue InvokeRegexFunction(string input, string regex, if (!m.Success) { - return new BlankValue(IRContext.NotInSource(new KnownRecordType(GetRecordTypeFromRegularExpression(regex)))); + return new BlankValue(IRContext.NotInSource(new KnownRecordType(GetRecordTypeFromRegularExpression(regex, options)))); } - return GetRecordFromMatch(rex, m); + return GetRecordFromMatch(rex, m, options); } } @@ -119,14 +119,14 @@ protected override FormulaValue InvokeRegexFunction(string input, string regex, foreach (Match m in mc) { - records.Add(GetRecordFromMatch(rex, m)); + records.Add(GetRecordFromMatch(rex, m, options)); } - return TableValue.NewTable(new KnownRecordType(GetRecordTypeFromRegularExpression(regex)), records.ToArray()); + return TableValue.NewTable(new KnownRecordType(GetRecordTypeFromRegularExpression(regex, options)), records.ToArray()); } } - private static RecordValue GetRecordFromMatch(Regex rex, Match m) + private static RecordValue GetRecordFromMatch(Regex rex, Match m, RegexOptions options) { Dictionary fields = new () { @@ -161,7 +161,7 @@ private static RecordValue GetRecordFromMatch(Regex rex, Match m) } } - if (!fields.ContainsKey(SUBMATCHES)) + if (!fields.ContainsKey(SUBMATCHES) && (options & RegexOptions.ExplicitCapture) == 0) { fields.Add(SUBMATCHES, new NamedValue(SUBMATCHES, TableValue.NewSingleColumnTable(subMatches.Select(s => StringValue.New(s)).ToArray()))); } @@ -169,14 +169,17 @@ private static RecordValue GetRecordFromMatch(Regex rex, Match m) return RecordValue.NewRecordFromFields(fields.Values); } - private static DType GetRecordTypeFromRegularExpression(string regularExpression) + private static DType GetRecordTypeFromRegularExpression(string regularExpression, RegexOptions regularExpressionOptions) { Dictionary propertyNames = new (); Regex rex = new Regex(regularExpression); propertyNames.Add(FULLMATCH, new TypedName(DType.String, new DName(FULLMATCH))); propertyNames.Add(STARTMATCH, new TypedName(DType.Number, new DName(STARTMATCH))); - propertyNames.Add(SUBMATCHES, new TypedName(DType.CreateTable(new TypedName(DType.String, new DName(TexlFunction.ColumnName_ValueStr))), new DName(SUBMATCHES))); + if ((regularExpressionOptions & RegexOptions.ExplicitCapture) == 0) + { + propertyNames.Add(SUBMATCHES, new TypedName(DType.CreateTable(new TypedName(DType.String, new DName(TexlFunction.ColumnName_ValueStr))), new DName(SUBMATCHES))); + } foreach (string groupName in rex.GetGroupNames()) { @@ -311,7 +314,7 @@ public Task InvokeAsync(FormulaValue[] args, CancellationToken can matchOptions = RegexOptions; } - RegexOptions regOptions = System.Text.RegularExpressions.RegexOptions.CultureInvariant; + RegexOptions regOptions = System.Text.RegularExpressions.RegexOptions.CultureInvariant; if (matchOptions.Contains("i")) { @@ -333,6 +336,11 @@ public Task InvokeAsync(FormulaValue[] args, CancellationToken can regularExpression += "$"; } + if (!matchOptions.Contains("N")) + { + regOptions |= System.Text.RegularExpressions.RegexOptions.ExplicitCapture; + } + regularExpression = AlterNewlineMatching(regularExpression, regOptions); try diff --git a/src/strings/PowerFxResources.en-US.resx b/src/strings/PowerFxResources.en-US.resx index 34b16e8964..9542f5a70e 100644 --- a/src/strings/PowerFxResources.en-US.resx +++ b/src/strings/PowerFxResources.en-US.resx @@ -4471,6 +4471,10 @@ Invalid regular expression: Character class subtraction is not supported, found "{0}". Error message indicating that the regular expression is using character class subtraction and it is not supported. + + Invalid regular expression: Inline comments cannot include open parenthesis, found in "{0}". + Error message indicating that the regular expression has an open paren in an inline comment. + Regular expressions must be constant values. Error Message. diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_en-US.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_en-US.txt index 121dd01006..4713ac5bd7 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_en-US.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_en-US.txt @@ -171,8 +171,8 @@ false >> IsMatch( "İ", "ı", MatchOptions.IgnoreCase ) // false false false false ->> Match( "hiIıİİıIhi", "\u0130+" ) -{FullMatch:"İİ",StartMatch:5,SubMatches:Table()} +>> ShowColumns( Match( "hiIıİİıIhi", "\u0130+" ), FullMatch, StartMatch ) +{FullMatch:"İİ",StartMatch:5} >> IsMatch( "Sıgh", "\u0131", MatchOptions.Contains ) true diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_tr-TR.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_tr-TR.txt index db3c8a756d..15ec85f741 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_tr-TR.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_tr-TR.txt @@ -200,8 +200,8 @@ false >> IsMatch( "İ", "ı", MatchOptions.IgnoreCase ) // false false false false ->> Match( "hiIıİİıIhi", "\u0130+" ) -{FullMatch:"İİ",StartMatch:5,SubMatches:Table()} +>> ShowColumns( Match( "hiIıİİıIhi", "\u0130+" ), FullMatch, StartMatch ) +{FullMatch:"İİ",StartMatch:5} >> IsMatch( "Sıgh", "\u0131", MatchOptions.Contains ) true diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match.txt index f88891561c..3d823bf024 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match.txt @@ -1,14 +1,11 @@ #SETUP: RegEx ->> Match("Hello", "\w").FullMatch -"H" - ->> Match("Hello", "\w") -{FullMatch:"H",StartMatch:1,SubMatches:Table()} - >> Match("Hello", "(?\w)") {FullMatch:"H",StartMatch:1,SubMatches:"H"} +>> Match("Hello", "\w").FullMatch +"H" + >> Match("Hello", "\w").StartMatch 1 @@ -24,9 +21,6 @@ Blank() >> Match("Hello", "llo", MatchOptions.Complete).StartMatch Blank() ->> Match("Hello", "llo", MatchOptions.Complete).SubMatches -Blank() - >> Match("Bob Jones ", "<(?" & Match.Email & ")>").email "bob.jones@contoso.com" @@ -42,9 +36,6 @@ Blank() >> Match( "Bob Jones ", "<(?" & Match.Email & ")>").StartMatch 11 ->> Concat(ForAll(Match( "Bob Jones ", "<(?" & Match.Email & ")>").SubMatches, With({x:Value}, x)), Value, ", ") -"bob.jones@contoso.com" - >> Match("Hello", "(?\w)l(?\w)").FullMatch "ell" @@ -57,30 +48,12 @@ Blank() >> Match("Hello", "(?\w)l(?\w)").p2 "l" ->> Index(Match("Hello", "(?\w)l(?\w)").SubMatches, 1).Value -"e" - ->> Index(Match("Hello", "(?\w)l(?\w)").SubMatches, 2).Value -"l" - ->> Concat(ForAll(Match("Hello", "(?\w)l(?\w)").SubMatches, With({x:Value}, x)), Value, ", ") -"e, l" - >> With(Match("PT2H1M39S", "PT(?:(?\d+)H)?(?:(?\d+)M)?(?:(?\d+)S)?"), Time(Value(hours), Value(minutes), Value(seconds))) Time(2,1,39,0) ->> Match("Hello", "(?\w)l(?\w)").SubMatches -Table({Value:"e"},{Value:"l"}) - >> Match("Joe 164" & Char(10) & "Sam 208" & Char(10), "(\w+)\s(\d+)", MatchOptions.Complete) Blank() ->> Match("Joe 164" & Char(10) & "Sam 208" & Char(10), "(\w+)\s(\d+)", MatchOptions.Complete & MatchOptions.Multiline) -{FullMatch:"Joe 164",StartMatch:1,SubMatches:Table({Value:"Joe"},{Value:"164"})} - ->> Match("JohnDoe@microsoft.com", Match.Email) -{FullMatch:"JohnDoe@microsoft.com",StartMatch:1,SubMatches:Table()} - >> Match(Blank(), ".") Blank() @@ -90,18 +63,14 @@ Errors: Error 15-22: Regular expressions must be constant values.|Error 0-5: The >> Match("28", 28) Errors: Error 12-14: Regular expressions must be constant values.|Error 0-5: The function 'Match' has some invalid arguments. +>> Match("28", "28", Blank()) +Errors: Error 12-14: Regular expressions options must be constant values.|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match("28", "28", 28) +Errors: Error 12-14: Regular expressions options must be constant values.|Error 0-5: The function 'Match' has some invalid arguments. + >> Match(1/0, "Hi") Error({Kind:ErrorKind.Div0}) >> Match("Hello", Right("llo", 3)).FullMatch Errors: Error 15-30: Regular expressions must be constant values.|Error 0-5: The function 'Match' has some invalid arguments.|Error 31-41: Name isn't valid. 'FullMatch' isn't recognized. - ->> Match("(555) 123-4567", "^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$") -{FullMatch:"(555) 123-4567",StartMatch:1,SubMatches:Table()} - ->> Match("Hello", "Hello", MatchOptions.IgnoreCase) -{FullMatch:"Hello",StartMatch:1,SubMatches:Table()} - ->> Match("Hi", "Hi", MatchOptions.Multiline) -{FullMatch:"Hi",StartMatch:1,SubMatches:Table()} - diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt index c3c472facb..0dcff1dfad 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt @@ -26,16 +26,16 @@ // Unicode letters as word characters are allowed >> Match( "the whole world", "\b(\w+\s*)+" ) -{FullMatch:"the whole world",StartMatch:1,SubMatches:Table({Value:"world"})} +{FullMatch:"the whole world",StartMatch:1} >> Match( "целый мир", "\b(\w+\s*)+" ) -{FullMatch:"целый мир",StartMatch:1,SubMatches:Table({Value:"мир"})} +{FullMatch:"целый мир",StartMatch:1} >> Match( "el niño", "\b(\w+\s*)+" ) -{FullMatch:"el niño",StartMatch:1,SubMatches:Table({Value:"niño"})} +{FullMatch:"el niño",StartMatch:1} >> Match( "Müller", "^\w+$" ) -{FullMatch:"Müller",StartMatch:1,SubMatches:Table()} +{FullMatch:"Müller",StartMatch:1} // Self referencing groups are disallowed @@ -54,16 +54,28 @@ Errors: Error 22-34: Invalid regular expression: Use named captures with "(?" not defined.|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "hello howdy", "(?[hi]).*\k" ) -{FullMatch:"hello h",StartMatch:1,SubMatches:Table({Value:"h"}),first:"h"} +{FullMatch:"hello h",StartMatch:1,first:"h"} + +>> Match( "hello howdy", "(?[hi]).*\k", MatchOptions.NumberedCaptures ) +Errors: Error 22-49: Invalid regular expression: Named captures cannot be used with MatchOptions.NumberedCaptures enabled, found "(?".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "hello howdy", "(?[hi]).*\1" ) Errors: Error 22-42: Invalid regular expression: Use named captures with "(?" and "\k" or enable MatchOptions.NumberedCaptures, found "\1".|Error 0-5: The function 'Match' has some invalid arguments. +>> Match( "hello howdy", "([hi]).*\1", MatchOptions.NumberedCaptures ) +{FullMatch:"hello h",StartMatch:1,SubMatches:Table({Value:"h"})} + >> Match( "hello howdy", "(?[hi]).*\k" ) Errors: Error 22-50: Invalid regular expression: Capture group "\k" not defined.|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "hello world", "(((((((((((?l))))))))))).*\k") // 11 parens -{FullMatch:"llo worl",StartMatch:3,SubMatches:Table({Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"}),eleven:"l"} +{FullMatch:"llo worl",StartMatch:3,eleven:"l"} + +>> Match( "hello world", "(((((((((((l))))))))))).*\11") // 11 parens +Errors: Error 22-52: Invalid regular expression: Use named captures with "(?" and "\k" or enable MatchOptions.NumberedCaptures, found "\11".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "hello world", "(((((((((((l))))))))))).*\11", MatchOptions.NumberedCaptures) // 11 parens +{FullMatch:"llo worl",StartMatch:3,SubMatches:Table({Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"})} >> Match( "hello world", "(((((((((((?l)))))))))).*\k") // unclosed 11th paren Errors: Error 22-67: Invalid regular expression: Unclosed groups, too few closing parenthesis.|Error 0-5: The function 'Match' has some invalid arguments. @@ -72,22 +84,43 @@ Errors: Error 22-67: Invalid regular expression: Unclosed groups, too few closin Errors: Error 22-74: Invalid regular expression: Self-referencing capture groups are not supported, found "\k".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "hello world", "(?(?(?(?(?(?(?(?(?(?(l))))))))))).*\k") // 11 parens -{FullMatch:"llo worl",StartMatch:3,SubMatches:Table({Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"}),a:"l",b:"l",c:"l",d:"l",e:"l",f:"l",g:"l",h:"l",i:"l",j:"l"} +{FullMatch:"llo worl",StartMatch:3,a:"l",b:"l",c:"l",d:"l",e:"l",f:"l",g:"l",h:"l",i:"l",j:"l"} >> Match( "hello world", "(?(?(?(?(?(?(?(?(?(?(l))))))))))).*\k") // 11 parens -{FullMatch:"llo worl",StartMatch:3,SubMatches:Table({Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"}),a:"l",b:"l",c:"l",d:"l",e:"l",f:"l",g:"l",h:"l",i:"l",j:"l"} +{FullMatch:"llo worl",StartMatch:3,a:"l",b:"l",c:"l",d:"l",e:"l",f:"l",g:"l",h:"l",i:"l",j:"l"} + +>> Match( "hello world", "(((((((((((l))))))))))).*\1") // 11 parens +Errors: Error 22-51: Invalid regular expression: Use named captures with "(?" and "\k" or enable MatchOptions.NumberedCaptures, found "\1".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "hello world", "(((((((((((l))))))))))).*\1", MatchOptions.NumberedCaptures) // 11 parens +{FullMatch:"llo worl",StartMatch:3,SubMatches:Table({Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"})} >> Match( "hello world", "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "(?l)" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & ".*\k" ) -{FullMatch:"llo worl",StartMatch:3,SubMatches:Table({Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"}),hundredone:"l"} +{FullMatch:"llo worl",StartMatch:3,hundredone:"l"} + +>> Match( "hello world", "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "(l)" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & ".*\101", MatchOptions.NumberedCaptures ) +{FullMatch:"llo worl",StartMatch:3,SubMatches:Table({Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"})} >> Match( "hello world", "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "(?l" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & ".*\k" ) // missing paren Errors: Error 341-342: Invalid regular expression: Unclosed groups, too few closing parenthesis.|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "hello world", "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(?l)" & ".*\k" ) -{FullMatch:"llo worl",StartMatch:3,SubMatches:Table({Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:"l"}),hundredone:"l"} +{FullMatch:"llo worl",StartMatch:3,hundredone:"l"} >> Match( "hello world", "(((())(())(())(((((((())))))))))()(?l)()\k") -{FullMatch:"ll",StartMatch:3,SubMatches:Table({Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:"l"}),letter:"l"} +{FullMatch:"ll",StartMatch:3,letter:"l"} + +>> Match( "hello world", "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(?l)" & ".*\k", MatchOptions.NumberedCaptures ) +Errors: Error 491-492: Invalid regular expression: Named captures cannot be used with MatchOptions.NumberedCaptures enabled, found "(?".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "hello world", "(((())(())(())(((((((())))))))))()(?l)()\k", MatchOptions.NumberedCaptures) +Errors: Error 22-82: Invalid regular expression: Named captures cannot be used with MatchOptions.NumberedCaptures enabled, found "(?".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "hello world", "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(l)" & ".*\101", MatchOptions.NumberedCaptures ) +{FullMatch:"llo worl",StartMatch:3,SubMatches:Table({Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:"l"})} + +>> Match( "hello world", "(((())(())(())(((((((())))))))))()(l)()\18", MatchOptions.NumberedCaptures) +{FullMatch:"ll",StartMatch:3,SubMatches:Table({Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:"l"},{Value:""})} // Octal characters are not allowed @@ -100,13 +133,13 @@ Errors: Error 16-22: Invalid regular expression: Octal \0 character codes are no Blank() >> Match( "hello"&Char(10)&"howdy", "o$", MatchOptions.Multiline ) -{FullMatch:"o",StartMatch:5,SubMatches:Table()} +{FullMatch:"o",StartMatch:5} >> Match( "hello"&Char(10)&"howdy", "(?im)o$" ) -{FullMatch:"o",StartMatch:5,SubMatches:Table()} +{FullMatch:"o",StartMatch:5} >> Match( "hello"&Char(10)&"howdy", "(?m)o$" ) -{FullMatch:"o",StartMatch:5,SubMatches:Table()} +{FullMatch:"o",StartMatch:5} >> With( Match( "hello"&Char(10)&"howdy", "(?s)hello.howdy" ), {StartMatch: StartMatch, LengthMatch: Len(FullMatch)} ) {LengthMatch:11,StartMatch:1} @@ -118,7 +151,7 @@ Blank() Blank() >> Match( "hello, howdy", "(?x) llo , \s how # comment" ) -{FullMatch:"llo, how",StartMatch:3,SubMatches:Table()} +{FullMatch:"llo, how",StartMatch:3} // unsupported inline options @@ -141,10 +174,10 @@ Errors: Error 33-43: Invalid regular expression: Inline options must appear at t Errors: Error 22-29: Invalid regular expression: Inline options are limited to a combination of the letters [imsx], cannot disable options, and cannot be used on a subexpression, found "(?n)".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "hello world", "(?s)o") -{FullMatch:"o",StartMatch:5,SubMatches:Table()} +{FullMatch:"o",StartMatch:5} >> Match( "hello world", "(?x)o") -{FullMatch:"o",StartMatch:5,SubMatches:Table()} +{FullMatch:"o",StartMatch:5} >> Match( "hello world", "(?A)o") Errors: Error 22-29: Invalid regular expression: Inline options are limited to a combination of the letters [imsx], cannot disable options, and cannot be used on a subexpression, found "(?A)".|Error 0-5: The function 'Match' has some invalid arguments. @@ -201,25 +234,25 @@ Errors: Error 12-17: Invalid regular expression: Square bracket character classe Errors: Error 12-17: Invalid regular expression: Square bracket character classes cannot be empty and cannot include unescaped literal open or close square brackets, escape with "\[" or "\]".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "abcdef]ghijk", "[\w]\w]" ) // second closing square bracket is allowed unescaped as it is outside a character class -{FullMatch:"ef]",StartMatch:5,SubMatches:Table()} +{FullMatch:"ef]",StartMatch:5} >> Match( "a]", "[a]]" ) -{FullMatch:"a]",StartMatch:1,SubMatches:Table()} +{FullMatch:"a]",StartMatch:1} ->> Match( "abcdef]ghijk", "[\w\]\w]" ) -{FullMatch:"a",StartMatch:1,SubMatches:Table()} +>> Match( "abcdef]ghijk", "[\w\]\w]" ) // escaped closing square bracket +{FullMatch:"a",StartMatch:1} >> Match( "[", "[\[]" ) -{FullMatch:"[",StartMatch:1,SubMatches:Table()} +{FullMatch:"[",StartMatch:1} >> Match( "]", "[\]]" ) -{FullMatch:"]",StartMatch:1,SubMatches:Table()} +{FullMatch:"]",StartMatch:1} >> Match( ">test[", "[\w\[\>]+" ) -{FullMatch:">test[",StartMatch:1,SubMatches:Table()} +{FullMatch:">test[",StartMatch:1} >> Match( ">test[", "[\w\]\>]+" ) -{FullMatch:">test",StartMatch:1,SubMatches:Table()} +{FullMatch:">test",StartMatch:1} // character class subtraction @@ -232,7 +265,7 @@ Errors: Error 12-25: Invalid regular expression: Character class subtraction is Errors: Error 22-30: Invalid regular expression: Invalid escape code, found "\a".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test\123bed", "\\(\d)" ) -{FullMatch:"\1",StartMatch:5,SubMatches:Table({Value:"1"})} +{FullMatch:"\1",StartMatch:5} // character classes @@ -243,25 +276,25 @@ Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\a" Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\A".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "$test atest test", "\btest" ) -{FullMatch:"test",StartMatch:2,SubMatches:Table()} +{FullMatch:"test",StartMatch:2} >> Match( "$test" & Char(8) & "test", "[\b]test" ) // \b acts differentely in a character class -{FullMatch:"test",StartMatch:6,SubMatches:Table()} +{FullMatch:"test",StartMatch:6} >> Match( "$test atest test", "\Btest" ) -{FullMatch:"test",StartMatch:8,SubMatches:Table()} +{FullMatch:"test",StartMatch:8} >> DropColumns( Match( "test" & Char(10) & "bed", "\cj" ), FullMatch ) -{StartMatch:5,SubMatches:Table()} +{StartMatch:5} >> Match( "test", "\C" ) Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\C".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test123bed", "\d+" ) -{FullMatch:"123",StartMatch:5,SubMatches:Table()} +{FullMatch:"123",StartMatch:5} >> Match( "test123bed", "\D+" ) -{FullMatch:"test",StartMatch:1,SubMatches:Table()} +{FullMatch:"test",StartMatch:1} >> Match( "test", "\e" ) Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\e".|Error 0-5: The function 'Match' has some invalid arguments. @@ -270,7 +303,7 @@ Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\e" Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\E".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test"&Char(12)&"bed", "\f" ) -{FullMatch:" ",StartMatch:5,SubMatches:Table()} +{FullMatch:" ",StartMatch:5} >> Match( "test", "\F" ) Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\F".|Error 0-5: The function 'Match' has some invalid arguments. @@ -300,7 +333,7 @@ Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\j" Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\J".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "1234551234", "(?\d)\k" ) -{FullMatch:"55",StartMatch:5,SubMatches:Table({Value:"5"}),first:"5"} +{FullMatch:"55",StartMatch:5,first:"5"} >> Match( "test", "\K" ) Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\K".|Error 0-5: The function 'Match' has some invalid arguments. @@ -318,7 +351,7 @@ Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\m" Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\M".|Error 0-5: The function 'Match' has some invalid arguments. >> DropColumns( Match( "test" & Char(10) & "bed", "\n" ), FullMatch ) -{StartMatch:5,SubMatches:Table()} +{StartMatch:5} >> Match( "test", "\N" ) Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\N".|Error 0-5: The function 'Match' has some invalid arguments. @@ -330,10 +363,10 @@ Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\o" Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\O".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "123test456", "\p{L}+" ) -{FullMatch:"test",StartMatch:4,SubMatches:Table()} +{FullMatch:"test",StartMatch:4} >> Match( "foo123test456", "\P{L}+" ) -{FullMatch:"123",StartMatch:4,SubMatches:Table()} +{FullMatch:"123",StartMatch:4} >> Match( "test", "\q" ) Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\q".|Error 0-5: The function 'Match' has some invalid arguments. @@ -342,25 +375,25 @@ Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\q" Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\Q".|Error 0-5: The function 'Match' has some invalid arguments. >> DropColumns( Match( "test" & Char(13) & "bed", "\r" ), FullMatch ) -{StartMatch:5,SubMatches:Table()} +{StartMatch:5} >> Match( "test", "\R" ) Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\R".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test bed", "\s+" ) -{FullMatch:" ",StartMatch:5,SubMatches:Table()} +{FullMatch:" ",StartMatch:5} >> Match( " test ", "\S+" ) -{FullMatch:"test",StartMatch:4,SubMatches:Table()} +{FullMatch:"test",StartMatch:4} >> Match( "test" & Char(9) & "bed", "\t" ) -{FullMatch:" ",StartMatch:5,SubMatches:Table()} +{FullMatch:" ",StartMatch:5} >> Match( "test", "\T" ) Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\T".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test", "\u0065" ) -{FullMatch:"e",StartMatch:2,SubMatches:Table()} +{FullMatch:"e",StartMatch:2} >> Match( "test", "\U" ) Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\U".|Error 0-5: The function 'Match' has some invalid arguments. @@ -372,13 +405,13 @@ Errors: Error 34-38: Invalid regular expression: Invalid escape code, found "\v" Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\V".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "&*%test bed^%$", "\w+" ) -{FullMatch:"test",StartMatch:4,SubMatches:Table()} +{FullMatch:"test",StartMatch:4} >> Match( "test%bed", "\W" ) -{FullMatch:"%",StartMatch:5,SubMatches:Table()} +{FullMatch:"%",StartMatch:5} >> Match( "test", "\x65" ) -{FullMatch:"e",StartMatch:2,SubMatches:Table()} +{FullMatch:"e",StartMatch:2} >> Match( "test", "\X" ) Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\X".|Error 0-5: The function 'Match' has some invalid arguments. @@ -407,7 +440,7 @@ Errors: Error 15-20: Invalid regular expression: Invalid escape code, found "\c" Errors: Error 15-20: Invalid regular expression: Invalid escape code, found "\x".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "eF", "\x65F" ) // will only use the first two characters for the hex code and leave the F to match separately -{FullMatch:"eF",StartMatch:1,SubMatches:Table()} +{FullMatch:"eF",StartMatch:1} >> Match( "test", "\uF" ) Errors: Error 15-20: Invalid regular expression: Invalid escape code, found "\u".|Error 0-5: The function 'Match' has some invalid arguments. @@ -419,7 +452,7 @@ Errors: Error 15-21: Invalid regular expression: Invalid escape code, found "\u" Errors: Error 15-22: Invalid regular expression: Invalid escape code, found "\u".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "eF", "\u0065F" ) // will only use the first four characters for the unicode and leave the F to match separately -{FullMatch:"eF",StartMatch:1,SubMatches:Table()} +{FullMatch:"eF",StartMatch:1} >> Match( "test", "\p{@}" ) Errors: Error 15-22: Invalid regular expression: Invalid escape code, found "\p".|Error 0-5: The function 'Match' has some invalid arguments. @@ -430,20 +463,23 @@ Errors: Error 15-22: Invalid regular expression: Invalid escape code, found "\P" // Escape is OK for non alpha-numeric characters >> Match( "!@#$%^&*()[]{}+=-`~/><';:,.""", "\!\@\#\$\%\^\&\*\(\)\[\]\{\}\+\=\-\`\~\/\>\<\'\;\:\,\.\""" ) -{FullMatch:"!@#$%^&*()[]{}+=-`~/><';:,.""",StartMatch:1,SubMatches:Table()} +{FullMatch:"!@#$%^&*()[]{}+=-`~/><';:,.""",StartMatch:1} -// Inline comment is OK +// Inline comments >> Match( "test", "(?# this is a test)st" ) -{FullMatch:"st",StartMatch:3,SubMatches:Table()} +{FullMatch:"st",StartMatch:3} + +>> Match( "test", "(?# this is a test ( with an open paren)st" ) +Errors: Error 15-59: Invalid regular expression: Inline comments cannot include open parenthesis, found in "(?# this is a test ( with an open paren)".|Error 0-5: The function 'Match' has some invalid arguments. // Can't define named capture group more than once >> Match( "test", "(?t).*(?t)" ) -{FullMatch:"test",StartMatch:1,SubMatches:Table({Value:"t"},{Value:"t"}),one:"t",two:"t"} +{FullMatch:"test",StartMatch:1,one:"t",two:"t"} >> Match( "test", "((?t)|(?t))" ) -{FullMatch:"t",StartMatch:1,SubMatches:Table({Value:"t"},{Value:"t"},{Value:""}),one:"t",two:""} +{FullMatch:"t",StartMatch:1,one:"t",two:""} >> Match( "test", "(?t).*(?t)" ) Errors: Error 15-37: Invalid regular expression: Named capture group "(?" defined more than once.|Error 0-5: The function 'Match' has some invalid arguments. @@ -454,10 +490,10 @@ Errors: Error 15-38: Invalid regular expression: Named capture group "(?" d // Bad named capture group names >> Match( "test", "(?s).*" ) -{FullMatch:"st",StartMatch:3,SubMatches:Table({Value:"s"}),a:"s"} +{FullMatch:"st",StartMatch:3,a:"s"} >> Match( "test", "(?s).*" ) -{FullMatch:"st",StartMatch:3,SubMatches:Table({Value:"s"}),a1:"s"} +{FullMatch:"st",StartMatch:3,a1:"s"} >> Match( "test", "(?<1>s).*" ) Errors: Error 15-26: Invalid regular expression: Named capture group name must be a combination of letters and digits and begin with a letter, found "(?<1>".|Error 0-5: The function 'Match' has some invalid arguments. @@ -474,7 +510,7 @@ Errors: Error 15-27: Invalid regular expression: Named capture group name must b // Group name case sensitivity >> Match( "test", "(?t).*\k") -{FullMatch:"test",StartMatch:1,SubMatches:Table({Value:"t"}),a:"t"} +{FullMatch:"test",StartMatch:1,a:"t"} >> Match( "test", "(?t).*\k") Errors: Error 15-31: Invalid regular expression: Capture group "\k" not defined.|Error 0-5: The function 'Match' has some invalid arguments. @@ -487,7 +523,7 @@ Errors: Error 15-31: Invalid regular expression: Capture group "\k" not defin // .NET will match up to the final newline, XRegExp and JavaScript do not >> AddColumns( Match( "test" & Char(10), "^test$" ), len, Len(FullMatch) ) -{FullMatch:"test",StartMatch:1,SubMatches:Table(),len:4} +{FullMatch:"test",StartMatch:1,len:4} >> AddColumns( Match( "test" & Char(10) & Char(10), "^test$" ), len, Len(FullMatch) ) Blank() @@ -501,7 +537,7 @@ Blank() // .NET treats dot as [^\n], XRegExp and JavaScript use [^\n\r\u2028\u2029] >> DropColumns( Match( "te" & " " & "t", "te.t" ), FullMatch ) -{StartMatch:1,SubMatches:Table()} +{StartMatch:1} >> DropColumns( Match( "te" & Char(10) & "t", "te.t" ), FullMatch ) Blank() @@ -510,50 +546,50 @@ Blank() Blank() >> DropColumns( Match( "te" & UniChar(Hex2Dec("2028")) & "t", "te.t" ), FullMatch ) -{StartMatch:1,SubMatches:Table()} +{StartMatch:1} >> DropColumns( Match( "te" & UniChar(Hex2Dec("2029")) & "t", "te.t" ), FullMatch ) -{StartMatch:1,SubMatches:Table()} +{StartMatch:1} // $ end anchor, multiline, and newline characters >> MatchAll( "a1" & Char(10) & "b2" & Char(10) & "c3", "\d$" ) -Table({FullMatch:"3",StartMatch:8,SubMatches:Table()}) +Table({FullMatch:"3",StartMatch:8}) >> MatchAll( "a1" & Char(10) & "b2" & Char(10) & "c3", "\d$", MatchOptions.Multiline ) -Table({FullMatch:"1",StartMatch:2,SubMatches:Table()},{FullMatch:"2",StartMatch:5,SubMatches:Table()},{FullMatch:"3",StartMatch:8,SubMatches:Table()}) +Table({FullMatch:"1",StartMatch:2},{FullMatch:"2",StartMatch:5},{FullMatch:"3",StartMatch:8}) >> MatchAll( "a1" & Char(13) & "b2" & Char(10) & "c3", "\d$" ) -Table({FullMatch:"3",StartMatch:8,SubMatches:Table()}) +Table({FullMatch:"3",StartMatch:8}) >> MatchAll( "a1" & Char(13) & "b2" & Char(13) & "c3", "\d$", MatchOptions.Multiline ) -Table({FullMatch:"1",StartMatch:2,SubMatches:Table()},{FullMatch:"2",StartMatch:5,SubMatches:Table()},{FullMatch:"3",StartMatch:8,SubMatches:Table()}) +Table({FullMatch:"1",StartMatch:2},{FullMatch:"2",StartMatch:5},{FullMatch:"3",StartMatch:8}) >> MatchAll( "a1" & Char(13)&Char(10) & "b2" & Char(13)&Char(10) & "c3", "\d$" ) -Table({FullMatch:"3",StartMatch:10,SubMatches:Table()}) +Table({FullMatch:"3",StartMatch:10}) >> MatchAll( "a1" & Char(13)&Char(10) & "b2" & Char(13)&Char(10) & "c3", "\d$", MatchOptions.Multiline ) -Table({FullMatch:"1",StartMatch:2,SubMatches:Table()},{FullMatch:"2",StartMatch:6,SubMatches:Table()},{FullMatch:"3",StartMatch:10,SubMatches:Table()}) +Table({FullMatch:"1",StartMatch:2},{FullMatch:"2",StartMatch:6},{FullMatch:"3",StartMatch:10}) // ^ beginning anchor, multiline, and newline characters >> MatchAll( "1a" & Char(10) & "2b" & Char(10) & "3c", "^\d" ) -Table({FullMatch:"1",StartMatch:1,SubMatches:Table()}) +Table({FullMatch:"1",StartMatch:1}) >> MatchAll( "1a" & Char(10) & "2b" & Char(10) & "3c", "^\d", MatchOptions.Multiline ) -Table({FullMatch:"1",StartMatch:1,SubMatches:Table()},{FullMatch:"2",StartMatch:4,SubMatches:Table()},{FullMatch:"3",StartMatch:7,SubMatches:Table()}) +Table({FullMatch:"1",StartMatch:1},{FullMatch:"2",StartMatch:4},{FullMatch:"3",StartMatch:7}) >> MatchAll( "1a" & Char(13) & "2b" & Char(10) & "3c", "^\d" ) -Table({FullMatch:"1",StartMatch:1,SubMatches:Table()}) +Table({FullMatch:"1",StartMatch:1}) >> MatchAll( "1a" & Char(13) & "2b" & Char(13) & "3c", "^\d", MatchOptions.Multiline ) -Table({FullMatch:"1",StartMatch:1,SubMatches:Table()},{FullMatch:"2",StartMatch:4,SubMatches:Table()},{FullMatch:"3",StartMatch:7,SubMatches:Table()}) +Table({FullMatch:"1",StartMatch:1},{FullMatch:"2",StartMatch:4},{FullMatch:"3",StartMatch:7}) >> MatchAll( "1a" & Char(13)&Char(10) & "2b" & Char(13)&Char(10) & "3c", "^\d" ) -Table({FullMatch:"1",StartMatch:1,SubMatches:Table()}) +Table({FullMatch:"1",StartMatch:1}) >> MatchAll( "1a" & Char(13)&Char(10) & "2b" & Char(13)&Char(10) & "3c", "^\d", MatchOptions.Multiline ) -Table({FullMatch:"1",StartMatch:1,SubMatches:Table()},{FullMatch:"2",StartMatch:5,SubMatches:Table()},{FullMatch:"3",StartMatch:9,SubMatches:Table()}) +Table({FullMatch:"1",StartMatch:1},{FullMatch:"2",StartMatch:5},{FullMatch:"3",StartMatch:9}) >> ForAll( MatchAll( " a @@ -581,6 +617,3 @@ Errors: Error 16-25: Invalid regular expression: Square bracket character classe >> Match( "hello", "[[=x=]]" ) Errors: Error 16-25: Invalid regular expression: Square bracket character classes cannot be empty and cannot include unescaped literal open or close square brackets, escape with "\[" or "\]".|Error 0-5: The function 'Match' has some invalid arguments. - - - diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_V1Compat.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_V1Compat.txt new file mode 100644 index 0000000000..869f6b5a31 --- /dev/null +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_V1Compat.txt @@ -0,0 +1,35 @@ +#SETUP: RegEx,PowerFxV1CompatibilityRules + +>> Match("Hello", "\w") +{FullMatch:"H",StartMatch:1} + +>> Index(Match("Hello", "(\w)l(\w)", MatchOptions.NumberedCaptures).SubMatches, 1).Value +"e" + +>> Index(Match("Hello", "(\w)l(\w)", MatchOptions.NumberedCaptures).SubMatches, 2).Value +"l" + +>> Concat(ForAll(Match("Hello", "(\w)l(\w)", MatchOptions.NumberedCaptures).SubMatches, With({x:Value}, x)), Value, ", ") +"e, l" + +>> Match("Hello", "(\w)l(\w)", MatchOptions.NumberedCaptures).SubMatches +Table({Value:"e"},{Value:"l"}) + +>> Match("Joe 164" & Char(10) & "Sam 208" & Char(10), "(\w+)\s(\d+)", MatchOptions.Complete) +Blank() + +>> Match("Joe 164" & Char(10) & "Sam 208" & Char(10), "(\w+)\s(\d+)", MatchOptions.Complete & MatchOptions.Multiline & MatchOptions.NumberedCaptures) +{FullMatch:"Joe 164",StartMatch:1,SubMatches:Table({Value:"Joe"},{Value:"164"})} + +>> Match("JohnDoe@microsoft.com", Match.Email) +{FullMatch:"JohnDoe@microsoft.com",StartMatch:1} + +>> Match("(555) 123-4567", "^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$") +{FullMatch:"(555) 123-4567",StartMatch:1} + +>> Match("Hello", "Hello", MatchOptions.IgnoreCase) +{FullMatch:"Hello",StartMatch:1} + +>> Match("Hi", "Hi", MatchOptions.Multiline) +{FullMatch:"Hi",StartMatch:1} + diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_V1CompatDisabled.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_V1CompatDisabled.txt new file mode 100644 index 0000000000..e877cc9153 --- /dev/null +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_V1CompatDisabled.txt @@ -0,0 +1,38 @@ +#SETUP: RegEx + +>> Match("Hello", "\w") +{FullMatch:"H",StartMatch:1,SubMatches:Table()} + +>> Match("Hello", "llo", MatchOptions.Complete).SubMatches +Blank() + +>> Concat(ForAll(Match( "Bob Jones ", "<(?" & Match.Email & ")>").SubMatches, With({x:Value}, x)), Value, ", ") +"bob.jones@contoso.com" + +>> Index(Match("Hello", "(?\w)l(?\w)").SubMatches, 1).Value +"e" + +>> Index(Match("Hello", "(?\w)l(?\w)").SubMatches, 2).Value +"l" + +>> Concat(ForAll(Match("Hello", "(?\w)l(?\w)").SubMatches, With({x:Value}, x)), Value, ", ") +"e, l" + +>> Match("Hello", "(?\w)l(?\w)").SubMatches +Table({Value:"e"},{Value:"l"}) + +>> Match("Joe 164" & Char(10) & "Sam 208" & Char(10), "(\w+)\s(\d+)", MatchOptions.Complete & MatchOptions.Multiline) +{FullMatch:"Joe 164",StartMatch:1,SubMatches:Table({Value:"Joe"},{Value:"164"})} + +>> Match("JohnDoe@microsoft.com", Match.Email) +{FullMatch:"JohnDoe@microsoft.com",StartMatch:1,SubMatches:Table()} + +>> Match("(555) 123-4567", "^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$") +{FullMatch:"(555) 123-4567",StartMatch:1,SubMatches:Table()} + +>> Match("Hello", "Hello", MatchOptions.IgnoreCase) +{FullMatch:"Hello",StartMatch:1,SubMatches:Table()} + +>> Match("Hi", "Hi", MatchOptions.Multiline) +{FullMatch:"Hi",StartMatch:1,SubMatches:Table()} + diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index fcd3ecada7..cca1e4430e 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -24,7 +24,7 @@ public FileExpressionEvaluationTests(ITestOutputHelper output) } // File expression tests are run multiple times for the different ways a host can use Power Fx. - // abcdefge + // abcdefged // 1. Features.PowerFxV1 without NumberIsFloat - the main way that most hosts will use Power Fx. // 2. Feautres.PowerFxV1 with NumberIsFloat - for hosts that wish to use floating point instead of Decimal. // 3. Default Canvas features with NumberIsFloat - the current default for Canvas apps. Canvas @@ -158,7 +158,7 @@ private static bool ShouldSkipDotNetVersion(ExpressionTestCase testCase, string [Fact] public void RunOne() { - var path = @"D:\repos\regex-min\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\match_limited.txt"; + var path = @"c:\repos\regex-min\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\match_limited.txt"; var line = 0; var runner = new InterpreterRunner(); @@ -175,7 +175,7 @@ public void RunOne() var result = testRunner.RunTests(); if (result.Fail > 0) { - Assert.True(false, result.Output); + Assert.Fail(result.Output); } else { From a06654e3b92ae8b0c03bdf668e0501c15b9c1827 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Tue, 13 Aug 2024 17:23:04 -0700 Subject: [PATCH 23/61] Updates --- .../ExpressionTestCases/Culture_en-US.txt | 2 +- .../ExpressionTestCases/Culture_tr-TR.txt | 2 +- .../ExpressionTestCases/IsMatch.txt | 4 -- .../ExpressionTestCases/IsMatch_V1Compat.txt | 12 +++++ .../IsMatch_V1CompatDisabled.txt | 5 +++ .../ExpressionTestCases/Match.txt | 6 --- .../ExpressionTestCases/MatchAll.txt | 21 --------- .../MatchAll_StronglyTypedEnumsDisabled.txt | 4 +- .../ExpressionTestCases/MatchAll_V1Compat.txt | 44 +++++++++++++++++++ .../MatchAll_V1CompatDisabled.txt | 22 ++++++++++ .../Match_StronglyTypedEnumsDisabled.txt | 4 +- .../ExpressionTestCases/Match_V1Compat.txt | 5 +++ .../Match_V1CompatDisabled.txt | 2 +- .../StronglyTypedEnum_BuiltInEnums.txt | 28 ++++++------ .../FileExpressionEvaluationTests.cs | 2 +- 15 files changed, 110 insertions(+), 53 deletions(-) create mode 100644 src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1Compat.txt create mode 100644 src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1CompatDisabled.txt create mode 100644 src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/MatchAll_V1Compat.txt create mode 100644 src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/MatchAll_V1CompatDisabled.txt diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_en-US.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_en-US.txt index 4713ac5bd7..16d45f724d 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_en-US.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_en-US.txt @@ -1,4 +1,4 @@ -#SETUP: RegEx,CultureInfo("en-US"),PowerFxV1CompatibilityRules,ConsistentOneColumnTableResult +#SETUP: RegEx,CultureInfo("en-US"),PowerFxV1CompatibilityRules,ConsistentOneColumnTableResult,SupportColumnNamesAsIdentifiers // Four types of letter I // Dotted Dotless diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_tr-TR.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_tr-TR.txt index 15ec85f741..233cf95a9f 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_tr-TR.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_tr-TR.txt @@ -1,4 +1,4 @@ -#SETUP: RegEx,CultureInfo("tr-TR"),PowerFxV1CompatibilityRules,ConsistentOneColumnTableResult +#SETUP: RegEx,CultureInfo("tr-TR"),PowerFxV1CompatibilityRules,ConsistentOneColumnTableResult,SupportColumnNamesAsIdentifiers // Four types of letter I // Dotted Dotless diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch.txt index b35d34775f..80b5545fbe 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch.txt @@ -76,10 +76,6 @@ false >> IsMatch("Foo", "J(") Error({Kind:ErrorKind.BadRegex}) -// Dangerous Regex, will timeout (should take >2h on a fast CPU) ->> IsMatch("ababababababababababababababababababababababababababababababababababa", "^((ab)*)+$") -Error({Kind:ErrorKind.Timeout}) - >> IsMatch( "28", Concat( [2,8], Value ) ) Errors: Error 15-37: Regular expressions must be constant values. diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1Compat.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1Compat.txt new file mode 100644 index 0000000000..9178634dde --- /dev/null +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1Compat.txt @@ -0,0 +1,12 @@ +#SETUP: RegEx,PowerFxV1CompatibilityRules + +// Dangerous Regex, will timeout (should take >2h on a fast CPU) +>> IsMatch("ababababababababababababababababababababababababababababababababababa", "^((ab)*)+$", MatchOptions.NumberedCaptures) +Error({Kind:ErrorKind.Timeout}) + +// but will finish quickly without catches +>> IsMatch("ababababababababababababababababababababababababababababababababababa", "^((ab)*)+$") +false + +>> IsMatch("ababababababababababababababababababababababababababababababababababa", "^((ab)*)+$") +false diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1CompatDisabled.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1CompatDisabled.txt new file mode 100644 index 0000000000..49556968a0 --- /dev/null +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1CompatDisabled.txt @@ -0,0 +1,5 @@ +#SETUP: RegEx,disable:PowerFxV1CompatibilityRules + +// Dangerous Regex, will timeout (should take >2h on a fast CPU) +>> IsMatch("ababababababababababababababababababababababababababababababababababa", "^((ab)*)+$") +Error({Kind:ErrorKind.Timeout}) diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match.txt index 3d823bf024..6ebac4d255 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match.txt @@ -63,12 +63,6 @@ Errors: Error 15-22: Regular expressions must be constant values.|Error 0-5: The >> Match("28", 28) Errors: Error 12-14: Regular expressions must be constant values.|Error 0-5: The function 'Match' has some invalid arguments. ->> Match("28", "28", Blank()) -Errors: Error 12-14: Regular expressions options must be constant values.|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match("28", "28", 28) -Errors: Error 12-14: Regular expressions options must be constant values.|Error 0-5: The function 'Match' has some invalid arguments. - >> Match(1/0, "Hi") Error({Kind:ErrorKind.Div0}) diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/MatchAll.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/MatchAll.txt index 915d86714a..f4351e34c6 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/MatchAll.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/MatchAll.txt @@ -1,23 +1,8 @@ #SETUP: RegEx ->> MatchAll("Hello", "\w") -Table({FullMatch:"H",StartMatch:1,SubMatches:Table()},{FullMatch:"e",StartMatch:2,SubMatches:Table()},{FullMatch:"l",StartMatch:3,SubMatches:Table()},{FullMatch:"l",StartMatch:4,SubMatches:Table()},{FullMatch:"o",StartMatch:5,SubMatches:Table()}) - >> MatchAll("Hello", "llo", MatchOptions.Complete) Table() ->> MatchAll("Bob Jones ", "<(?" & Match.Email & ")>") -Table({FullMatch:"",StartMatch:11,SubMatches:Table({Value:"bob.jones@contoso.com"}),email:"bob.jones@contoso.com"}) - ->> MatchAll("PT2H1M39S", "PT(?:(?\d+)H)?(?:(?\d+)M)?(?:(?\d+)S)?") -Table({FullMatch:"PT2H1M39S",StartMatch:1,SubMatches:Table({Value:"2"},{Value:"1"},{Value:"39"}),hours:"2",minutes:"1",seconds:"39"}) - ->> MatchAll("Hello", "(?\w)l(?\w)") -Table({FullMatch:"ell",StartMatch:2,SubMatches:Table({Value:"e"},{Value:"l"}),p1:"e",p2:"l"}) - ->> MatchAll("Joe 164" & Char(10) & "Sam 208" & Char(10), "(\w+)\s(\d+)", MatchOptions.Complete & MatchOptions.Multiline) -Table({FullMatch:"Joe 164",StartMatch:1,SubMatches:Table({Value:"Joe"},{Value:"164"})},{FullMatch:"Sam 208",StartMatch:9,SubMatches:Table({Value:"Sam"},{Value:"208"})}) - >> MatchAll(Blank(), ".") Table() @@ -26,9 +11,3 @@ Errors: Error 18-25: Regular expressions must be constant values.|Error 0-8: The >> MatchAll(1/0, "Hi") Error({Kind:ErrorKind.Div0}) - ->> MatchAll("Hello", "Hello", MatchOptions.IgnoreCase) -Table({FullMatch:"Hello",StartMatch:1,SubMatches:Table()}) - ->> MatchAll("Hi", "Hi", MatchOptions.Multiline) -Table({FullMatch:"Hi",StartMatch:1,SubMatches:Table()}) diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/MatchAll_StronglyTypedEnumsDisabled.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/MatchAll_StronglyTypedEnumsDisabled.txt index 5cad17fbe4..1019bfa06f 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/MatchAll_StronglyTypedEnumsDisabled.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/MatchAll_StronglyTypedEnumsDisabled.txt @@ -1,4 +1,4 @@ #SETUP: RegEx,disable:StronglyTypedBuiltinEnums ->> MatchAll("Hello", "Hello", "") -Table({FullMatch:"Hello",StartMatch:1,SubMatches:Table()}) +>> First( MatchAll("Hello", "Hello", "") ).FullMatch +"Hello" diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/MatchAll_V1Compat.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/MatchAll_V1Compat.txt new file mode 100644 index 0000000000..e6aa64fb22 --- /dev/null +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/MatchAll_V1Compat.txt @@ -0,0 +1,44 @@ +#SETUP: RegEx,PowerFxV1CompatibilityRules + +>> MatchAll("Hello", "\w") +Table({FullMatch:"H",StartMatch:1},{FullMatch:"e",StartMatch:2},{FullMatch:"l",StartMatch:3},{FullMatch:"l",StartMatch:4},{FullMatch:"o",StartMatch:5}) + +>> MatchAll("Hello", "llo", MatchOptions.Complete) +Table() + +>> MatchAll("Bob Jones ", "<(?" & Match.Email & ")>") +Table({FullMatch:"",StartMatch:11,email:"bob.jones@contoso.com"}) + +>> MatchAll("PT2H1M39S", "PT(?:(?\d+)H)?(?:(?\d+)M)?(?:(?\d+)S)?") +Table({FullMatch:"PT2H1M39S",StartMatch:1,hours:"2",minutes:"1",seconds:"39"}) + +>> MatchAll("Hello", "(?\w)l(?\w)") +Table({FullMatch:"ell",StartMatch:2,p1:"e",p2:"l"}) + +>> MatchAll("Hello", "(\w)l(\w)") +Table({FullMatch:"ell",StartMatch:2}) + +>> MatchAll("Hello", "(\w)l(\w)", MatchOptions.NumberedCaptures) +Table({FullMatch:"ell",StartMatch:2,SubMatches:Table({Value:"e"},{Value:"l"})}) + +>> MatchAll("Joe 164" & Char(10) & "Sam 208" & Char(10), "(\w+)\s(\d+)", MatchOptions.Complete & MatchOptions.Multiline & MatchOptions.NumberedCaptures) +Table({FullMatch:"Joe 164",StartMatch:1,SubMatches:Table({Value:"Joe"},{Value:"164"})},{FullMatch:"Sam 208",StartMatch:9,SubMatches:Table({Value:"Sam"},{Value:"208"})}) + +>> MatchAll(Blank(), ".") +Table() + +>> MatchAll(Blank(), Blank()) +Errors: Error 18-25: Regular expressions must be constant values.|Error 0-8: The function 'MatchAll' has some invalid arguments. + +>> MatchAll(1/0, "Hi") +Error({Kind:ErrorKind.Div0}) + +>> MatchAll("Hello", "Hello", MatchOptions.IgnoreCase) +Table({FullMatch:"Hello",StartMatch:1}) + +>> MatchAll("Hi", "Hi", MatchOptions.Multiline) +Table({FullMatch:"Hi",StartMatch:1}) + +>> MatchAll("28", "28", Blank()) +Errors: Error 21-28: Regular expression options must be constant values.|Error 0-8: The function 'MatchAll' has some invalid arguments. + diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/MatchAll_V1CompatDisabled.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/MatchAll_V1CompatDisabled.txt new file mode 100644 index 0000000000..aa08769eb0 --- /dev/null +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/MatchAll_V1CompatDisabled.txt @@ -0,0 +1,22 @@ +#SETUP: RegEx,disable:PowerFxV1CompatibilityRules + +>> MatchAll("Hello", "\w") +Table({FullMatch:"H",StartMatch:1,SubMatches:Table()},{FullMatch:"e",StartMatch:2,SubMatches:Table()},{FullMatch:"l",StartMatch:3,SubMatches:Table()},{FullMatch:"l",StartMatch:4,SubMatches:Table()},{FullMatch:"o",StartMatch:5,SubMatches:Table()}) + +>> MatchAll("Bob Jones ", "<(?" & Match.Email & ")>") +Table({FullMatch:"",StartMatch:11,SubMatches:Table({Value:"bob.jones@contoso.com"}),email:"bob.jones@contoso.com"}) + +>> MatchAll("PT2H1M39S", "PT(?:(?\d+)H)?(?:(?\d+)M)?(?:(?\d+)S)?") +Table({FullMatch:"PT2H1M39S",StartMatch:1,SubMatches:Table({Value:"2"},{Value:"1"},{Value:"39"}),hours:"2",minutes:"1",seconds:"39"}) + +>> MatchAll("Hello", "(?\w)l(?\w)") +Table({FullMatch:"ell",StartMatch:2,SubMatches:Table({Value:"e"},{Value:"l"}),p1:"e",p2:"l"}) + +>> MatchAll("Joe 164" & Char(10) & "Sam 208" & Char(10), "(\w+)\s(\d+)", MatchOptions.Complete & MatchOptions.Multiline) +Table({FullMatch:"Joe 164",StartMatch:1,SubMatches:Table({Value:"Joe"},{Value:"164"})},{FullMatch:"Sam 208",StartMatch:9,SubMatches:Table({Value:"Sam"},{Value:"208"})}) + +>> MatchAll("Hello", "Hello", MatchOptions.IgnoreCase) +Table({FullMatch:"Hello",StartMatch:1,SubMatches:Table()}) + +>> MatchAll("Hi", "Hi", MatchOptions.Multiline) +Table({FullMatch:"Hi",StartMatch:1,SubMatches:Table()}) diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_StronglyTypedEnumsDisabled.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_StronglyTypedEnumsDisabled.txt index ab1e431f60..91cff38391 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_StronglyTypedEnumsDisabled.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_StronglyTypedEnumsDisabled.txt @@ -1,4 +1,4 @@ #SETUP: RegEx,disable:StronglyTypedBuiltinEnums ->> Match("Hello", "Hello", "") -{FullMatch:"Hello",StartMatch:1,SubMatches:Table()} +>> Match("Hello", "Hello", "").FullMatch +"Hello" diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_V1Compat.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_V1Compat.txt index 869f6b5a31..a23ceb1110 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_V1Compat.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_V1Compat.txt @@ -33,3 +33,8 @@ Blank() >> Match("Hi", "Hi", MatchOptions.Multiline) {FullMatch:"Hi",StartMatch:1} +>> Match("28", "28", Blank()) +Errors: Error 18-25: Regular expression options must be constant values.|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match("28", "28", 28) +Errors: Error 18-20: Regular expression options must be constant values.|Error 0-5: The function 'Match' has some invalid arguments. diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_V1CompatDisabled.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_V1CompatDisabled.txt index e877cc9153..0228c842ff 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_V1CompatDisabled.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_V1CompatDisabled.txt @@ -1,4 +1,4 @@ -#SETUP: RegEx +#SETUP: RegEx,disable:PowerFxV1CompatibilityRules >> Match("Hello", "\w") {FullMatch:"H",StartMatch:1,SubMatches:Table()} diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/StronglyTypedEnum_BuiltInEnums.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/StronglyTypedEnum_BuiltInEnums.txt index 6b0b9cc17d..f9924ec662 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/StronglyTypedEnum_BuiltInEnums.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/StronglyTypedEnum_BuiltInEnums.txt @@ -49,7 +49,7 @@ Table({Value:1},{Value:2},{Value:3}) >> Match( "info@contoso.com", Match.Email ) -{FullMatch:"info@contoso.com",StartMatch:1,SubMatches:Table()} +{FullMatch:"info@contoso.com",StartMatch:1} >> JSON( [1,2,3], JSONFormat.FlattenValueTables ) "[1,2,3]" @@ -418,10 +418,10 @@ Errors: Error 0-7: The function 'Boolean' has some invalid arguments. // Match (and friends) allows coercion from the backing kind for the regular expression >> Match( "a3d4", Match.Digit ) -{FullMatch:"3",StartMatch:2,SubMatches:Table()} +{FullMatch:"3",StartMatch:2} >> Match( "a3d4", "\d") -{FullMatch:"3",StartMatch:2,SubMatches:Table()} +{FullMatch:"3",StartMatch:2} >> IsMatch( "a3d4", Match.Digit ) false @@ -430,10 +430,10 @@ false false >> MatchAll( "a3d4", Match.Digit ) -Table({FullMatch:"3",StartMatch:2,SubMatches:Table()},{FullMatch:"4",StartMatch:4,SubMatches:Table()}) +Table({FullMatch:"3",StartMatch:2},{FullMatch:"4",StartMatch:4}) >> MatchAll( "a3d4", "\d") -Table({FullMatch:"3",StartMatch:2,SubMatches:Table()},{FullMatch:"4",StartMatch:4,SubMatches:Table()}) +Table({FullMatch:"3",StartMatch:2},{FullMatch:"4",StartMatch:4}) >> Match.Digit = "\d" true @@ -531,7 +531,7 @@ Errors: Error 34-35: Invalid argument type (Text). Expecting a Enum (JSONFormat) // Since the Match supports CanCoerceBackingKind, any concatenation combination is supported >> Match( "334", Match.Digit & Match.Digit & JSONFormat.IndentFour ) -{FullMatch:"334",StartMatch:1,SubMatches:Table()} +{FullMatch:"334",StartMatch:1} // Concatenation can be allowed between members of the option set and still retain strong typing with IExternalOptionSet.CanConcatenateStronglyTyped @@ -553,16 +553,16 @@ Errors: Error 15-18: Invalid argument type (Text). Expecting a Enum (JSONFormat) // Concatenation can be allowed with text strings and still retain strong typing with IExternalOptionSet.CanCoerceBackingKind >> Match( "33this is ok", Concatenate( Match.Digit, Match.Digit, "this is ok" ) ) -{FullMatch:"33this is ok",StartMatch:1,SubMatches:Table()} +{FullMatch:"33this is ok",StartMatch:1} >> Match( "33this is ok", Match.Digit & Match.Digit & "this is ok" ) -{FullMatch:"33this is ok",StartMatch:1,SubMatches:Table()} +{FullMatch:"33this is ok",StartMatch:1} >> Match( "33this is ok", "\d\dthis is ok" ) -{FullMatch:"33this is ok",StartMatch:1,SubMatches:Table()} +{FullMatch:"33this is ok",StartMatch:1} >> Match( "33this is ok", "\d" & "\d" & "this is ok" ) -{FullMatch:"33this is ok",StartMatch:1,SubMatches:Table()} +{FullMatch:"33this is ok",StartMatch:1} // Strongly typed concatenated results can be compared @@ -617,16 +617,16 @@ true // >> Match( "a34d", Match.Digit & "\d" ) -{FullMatch:"34",StartMatch:2,SubMatches:Table()} +{FullMatch:"34",StartMatch:2} >> Match( "a34d", "\d" & Match.Digit ) -{FullMatch:"34",StartMatch:2,SubMatches:Table()} +{FullMatch:"34",StartMatch:2} >> Match( "a34d", Concatenate( Match.Digit, "\d" ) ) -{FullMatch:"34",StartMatch:2,SubMatches:Table()} +{FullMatch:"34",StartMatch:2} >> Match( "a34d", Concatenate( "\d", Match.Digit ) ) -{FullMatch:"34",StartMatch:2,SubMatches:Table()} +{FullMatch:"34",StartMatch:2} >> Text(Match.Digit) & Text(SortOrder.Ascending) "\dascending" diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index cca1e4430e..73e67289ed 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -24,7 +24,7 @@ public FileExpressionEvaluationTests(ITestOutputHelper output) } // File expression tests are run multiple times for the different ways a host can use Power Fx. - // abcdefged + // abcdefgedeergy // 1. Features.PowerFxV1 without NumberIsFloat - the main way that most hosts will use Power Fx. // 2. Feautres.PowerFxV1 with NumberIsFloat - for hosts that wish to use floating point instead of Decimal. // 3. Default Canvas features with NumberIsFloat - the current default for Canvas apps. Canvas From 08d89e06a29d9343f5d8e11067cf50c698b78033 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Wed, 14 Aug 2024 01:12:18 -0700 Subject: [PATCH 24/61] Updates --- .../Texl/Builtins/Match.cs | 1 + .../ExpressionTestCases/IsMatch_V1Compat.txt | 4 +- .../IsMatch_V1CompatDisabled.txt | 2 +- .../StronglyTypedEnum_BuiltInEnums_PreV1.txt | 68 +++++++++---------- .../FileExpressionEvaluationTests.cs | 2 +- .../IsMatch_V1CompatDisabled_Overrides.txt | 8 +++ .../MatchAll_V1CompatDisabled_Overrides.txt | 26 +++++++ .../Match_V1CompatDisabled_Overrides.txt | 39 +++++++++++ 8 files changed, 112 insertions(+), 38 deletions(-) create mode 100644 src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/InterpreterExpressionTestCases/IsMatch_V1CompatDisabled_Overrides.txt create mode 100644 src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/InterpreterExpressionTestCases/MatchAll_V1CompatDisabled_Overrides.txt create mode 100644 src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/InterpreterExpressionTestCases/Match_V1CompatDisabled_Overrides.txt diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index 9682ba5279..64fb36902e 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -100,6 +100,7 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp if (!context.Features.PowerFxV1CompatibilityRules) { + // only used for the following analysis and type creation, not modified in the IR regularExpressionOptions += "N"; } diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1Compat.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1Compat.txt index 9178634dde..386a6987b4 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1Compat.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1Compat.txt @@ -1,10 +1,10 @@ #SETUP: RegEx,PowerFxV1CompatibilityRules -// Dangerous Regex, will timeout (should take >2h on a fast CPU) +// Dangerous Regex, will timeout (should take >2h on a fast CPU) - but only with Pre-V1 or MatchOptions.NumberedCaptures >> IsMatch("ababababababababababababababababababababababababababababababababababa", "^((ab)*)+$", MatchOptions.NumberedCaptures) Error({Kind:ErrorKind.Timeout}) -// but will finish quickly without catches +// but will finish quickly without captures >> IsMatch("ababababababababababababababababababababababababababababababababababa", "^((ab)*)+$") false diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1CompatDisabled.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1CompatDisabled.txt index 49556968a0..de3d563c0b 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1CompatDisabled.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1CompatDisabled.txt @@ -1,5 +1,5 @@ #SETUP: RegEx,disable:PowerFxV1CompatibilityRules -// Dangerous Regex, will timeout (should take >2h on a fast CPU) +// Dangerous Regex, will timeout (should take >2h on a fast CPU) - but only with Pre-V1 or MatchOptions.NumberedCaptures >> IsMatch("ababababababababababababababababababababababababababababababababababa", "^((ab)*)+$") Error({Kind:ErrorKind.Timeout}) diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/StronglyTypedEnum_BuiltInEnums_PreV1.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/StronglyTypedEnum_BuiltInEnums_PreV1.txt index 6413bf7f79..4410bce8c3 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/StronglyTypedEnum_BuiltInEnums_PreV1.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/StronglyTypedEnum_BuiltInEnums_PreV1.txt @@ -50,8 +50,8 @@ >> Sort( [1,2,3], SortOrder.Descending ) Table({Value:1},{Value:2},{Value:3}) ->> Match( "info@contoso.com", Match.Email ) -{FullMatch:"info@contoso.com",StartMatch:1,SubMatches:Table()} +>> Match( "info@contoso.com", Match.Email ).FullMatch +"info@contoso.com" >> JSON( [1,2,3], JSONFormat.FlattenValueTables ) "[1,2,3]" @@ -88,8 +88,8 @@ Blank() >> Match( "hi", JSONFormat.IndentFour ) Blank() ->> Match( "hi", "h.*", JSONFormat.IndentFour ) -{FullMatch:"hi",StartMatch:1,SubMatches:Table()} +>> Match( "hi", "h.*", JSONFormat.IndentFour ).FullMatch +"hi" >> Match( "hi", Match.Email, JSONFormat.IndentFour ) Blank() @@ -106,8 +106,8 @@ false >> MatchAll( "hi", JSONFormat.IndentFour ) Table() ->> MatchAll( "hi", "h.*", JSONFormat.IndentFour ) -Table({FullMatch:"hi",StartMatch:1,SubMatches:Table()}) +>> MatchAll( "hi", "h.*", JSONFormat.IndentFour ).FullMatch +"hi" >> MatchAll( "hi", Match.Email, JSONFormat.IndentFour ) Table() @@ -169,8 +169,8 @@ Table({Value:3},{Value:2},{Value:1}) >> JSON( [1,2,3], "_" ) "[1,2,3]" ->> Match( "howdy", "h", "c" ) -{FullMatch:"h",StartMatch:1,SubMatches:Table()} +>> Match( "howdy", "h", "c" ).FullMatch +"h" >> IsMatch("Foo", 17) Errors: Error 15-17: Regular expressions must be constant values. @@ -374,11 +374,11 @@ Error({Kind:ErrorKind.InvalidArgument}) // Match (and friends) allows coercion from the backing kind for the regular expression ->> Match( "a3d4", Match.Digit ) -{FullMatch:"3",StartMatch:2,SubMatches:Table()} +>> Match( "a3d4", Match.Digit ).FullMatch +"3" ->> Match( "a3d4", "\d") -{FullMatch:"3",StartMatch:2,SubMatches:Table()} +>> Match( "a3d4", "\d").FullMatch +"3" >> IsMatch( "a3d4", Match.Digit ) false @@ -386,11 +386,11 @@ false >> IsMatch( "a3d4", "\d") false ->> MatchAll( "a3d4", Match.Digit ) -Table({FullMatch:"3",StartMatch:2,SubMatches:Table()},{FullMatch:"4",StartMatch:4,SubMatches:Table()}) +>> ForAll( MatchAll( "a3d4", Match.Digit ), {fm:FullMatch} ) +Tale({fm:"3"},{fm:"4"}) ->> MatchAll( "a3d4", "\d") -Table({FullMatch:"3",StartMatch:2,SubMatches:Table()},{FullMatch:"4",StartMatch:4,SubMatches:Table()}) +>> ForAll( MatchAll( "a3d4", "\d"), {fm:FullMatch} ) +Table({fm:"3"},{fm:"4"}) >> Match.Digit = "\d" true @@ -484,8 +484,8 @@ Table({Value:1},{Value:2},{Value:3}) "[{""Value"":1},{""Value"":2},{""Value"":3}]" // Since the Match supports CanCoerceBackingKind, any concatenation combination is supported ->> Match( "334", Match.Digit & Match.Digit & JSONFormat.IndentFour ) -{FullMatch:"334",StartMatch:1,SubMatches:Table()} +>> Match( "334", Match.Digit & Match.Digit & JSONFormat.IndentFour ).FullMatch +"334" // Concatenation can be allowed between members of hte option set and still retain strong typing with IExternalOptionSet.CanConcatenateStronglyTyped @@ -506,17 +506,17 @@ Table({Value:1},{Value:2},{Value:3}) // Concatenation can be allowed with text strings and still retain strong typing with IExternalOptionSet.CanCoerceBackingKind ->> Match( "33this is ok", Concatenate( Match.Digit, Match.Digit, "this is ok" ) ) -{FullMatch:"33this is ok",StartMatch:1,SubMatches:Table()} +>> Match( "33this is ok", Concatenate( Match.Digit, Match.Digit, "this is ok" ) ).FullMatch +"33this is ok" ->> Match( "33this is ok", Match.Digit & Match.Digit & "this is ok" ) -{FullMatch:"33this is ok",StartMatch:1,SubMatches:Table()} +>> Match( "33this is ok", Match.Digit & Match.Digit & "this is ok" ).FullMatch +"33this is ok" ->> Match( "33this is ok", "\d\dthis is ok" ) -{FullMatch:"33this is ok",StartMatch:1,SubMatches:Table()} +>> Match( "33this is ok", "\d\dthis is ok" ).FullMatch +"33this is ok" ->> Match( "33this is ok", "\d" & "\d" & "this is ok" ) -{FullMatch:"33this is ok",StartMatch:1,SubMatches:Table()} +>> Match( "33this is ok", "\d" & "\d" & "this is ok" ).FullMatch +"33this is ok" // Strongly typed concatenated results can be compared @@ -572,17 +572,17 @@ true // 14. CanConcatenateStronglyTyped & CanCoerceFromBackingKind - An important combination, used by Match, allows strings and enums to be mixed // ->> Match( "a34d", Match.Digit & "\d" ) -{FullMatch:"34",StartMatch:2,SubMatches:Table()} +>> Match( "a34d", Match.Digit & "\d" ).FullMatch +"34" ->> Match( "a34d", "\d" & Match.Digit ) -{FullMatch:"34",StartMatch:2,SubMatches:Table()} +>> Match( "a34d", "\d" & Match.Digit ).FullMatch +"34" ->> Match( "a34d", Concatenate( Match.Digit, "\d" ) ) -{FullMatch:"34",StartMatch:2,SubMatches:Table()} +>> Match( "a34d", Concatenate( Match.Digit, "\d" ) ).FullMatch +"34" ->> Match( "a34d", Concatenate( "\d", Match.Digit ) ) -{FullMatch:"34",StartMatch:2,SubMatches:Table()} +>> Match( "a34d", Concatenate( "\d", Match.Digit ) ).FullMatch +"34" >> Text(Match.Digit) & Text(SortOrder.Ascending) "\dascending" diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index 73e67289ed..5075284868 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -24,7 +24,7 @@ public FileExpressionEvaluationTests(ITestOutputHelper output) } // File expression tests are run multiple times for the different ways a host can use Power Fx. - // abcdefgedeergy + // abcdefgedeergyor // 1. Features.PowerFxV1 without NumberIsFloat - the main way that most hosts will use Power Fx. // 2. Feautres.PowerFxV1 with NumberIsFloat - for hosts that wish to use floating point instead of Decimal. // 3. Default Canvas features with NumberIsFloat - the current default for Canvas apps. Canvas diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/InterpreterExpressionTestCases/IsMatch_V1CompatDisabled_Overrides.txt b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/InterpreterExpressionTestCases/IsMatch_V1CompatDisabled_Overrides.txt new file mode 100644 index 0000000000..27dbcab74a --- /dev/null +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/InterpreterExpressionTestCases/IsMatch_V1CompatDisabled_Overrides.txt @@ -0,0 +1,8 @@ +#override: IsMatch_V1CompatDisabled.txt +#SETUP: RegEx,disable:PowerFxV1CompatibilityRules + +// The C# interpeter doesn't have a non-V1 implementation of the Match functions, so SubMatches will not appear in these results + +// Dangerous Regex, will timeout (should take >2h on a fast CPU) - but only with Pre-V1 or MatchOptions.NumberedCaptures +>> IsMatch("ababababababababababababababababababababababababababababababababababa", "^((ab)*)+$") +false \ No newline at end of file diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/InterpreterExpressionTestCases/MatchAll_V1CompatDisabled_Overrides.txt b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/InterpreterExpressionTestCases/MatchAll_V1CompatDisabled_Overrides.txt new file mode 100644 index 0000000000..1c2d6e9aa1 --- /dev/null +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/InterpreterExpressionTestCases/MatchAll_V1CompatDisabled_Overrides.txt @@ -0,0 +1,26 @@ +#override: MatchAll_V1CompatDisabled.txt +#SETUP: RegEx,disable:PowerFxV1CompatibilityRules + +// The C# interpeter doesn't have a non-V1 implementation of the Match functions, so SubMatches will not appear in these results + +>> MatchAll("Hello", "\w") +Table({FullMatch:"H",StartMatch:1},{FullMatch:"e",StartMatch:2},{FullMatch:"l",StartMatch:3},{FullMatch:"l",StartMatch:4},{FullMatch:"o",StartMatch:5}) + +>> MatchAll("Bob Jones ", "<(?" & Match.Email & ")>") +Table({FullMatch:"",StartMatch:11,email:"bob.jones@contoso.com"}) + +>> MatchAll("PT2H1M39S", "PT(?:(?\d+)H)?(?:(?\d+)M)?(?:(?\d+)S)?") +Table({FullMatch:"PT2H1M39S",StartMatch:1,hours:"2",minutes:"1",seconds:"39"}) + +>> MatchAll("Hello", "(?\w)l(?\w)") +Table({FullMatch:"ell",StartMatch:2,p1:"e",p2:"l"}) + +>> MatchAll("Joe 164" & Char(10) & "Sam 208" & Char(10), "(\w+)\s(\d+)", MatchOptions.Complete & MatchOptions.Multiline) +Table({FullMatch:"Joe 164",StartMatch:1},{FullMatch:"Sam 208",StartMatch:9}) + +>> MatchAll("Hello", "Hello", MatchOptions.IgnoreCase) +Table({FullMatch:"Hello",StartMatch:1}) + +>> MatchAll("Hi", "Hi", MatchOptions.Multiline) +Table({FullMatch:"Hi",StartMatch:1}) + diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/InterpreterExpressionTestCases/Match_V1CompatDisabled_Overrides.txt b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/InterpreterExpressionTestCases/Match_V1CompatDisabled_Overrides.txt new file mode 100644 index 0000000000..fd00013f7b --- /dev/null +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/InterpreterExpressionTestCases/Match_V1CompatDisabled_Overrides.txt @@ -0,0 +1,39 @@ +#override: Match_V1CompatDisabled.txt +#SETUP: RegEx,disable:PowerFxV1CompatibilityRules + +// The C# interpeter doesn't have a non-V1 implementation of the Match functions, so SubMatches will not appear in these results + +>> Match("Hello", "\w") +{FullMatch:"H",StartMatch:1} + +// The following tests return Blank() because SubMatches is correctly handled by the front end (because V1 is disabled), but the interpreter doesn't handle it propery (because V1 is enabled) + +>> Concat(ForAll(Match( "Bob Jones ", "<(?" & Match.Email & ")>").SubMatches, With({x:Value}, x)), Value, ", ") +Blank() + +>> Index(Match("Hello", "(?\w)l(?\w)").SubMatches, 1).Value +Blank() + +>> Index(Match("Hello", "(?\w)l(?\w)").SubMatches, 2).Value +Blank() + +>> Concat(ForAll(Match("Hello", "(?\w)l(?\w)").SubMatches, With({x:Value}, x)), Value, ", ") +Blank() + +>> Match("Hello", "(?\w)l(?\w)").SubMatches +Blank() + +>> Match("Joe 164" & Char(10) & "Sam 208" & Char(10), "(\w+)\s(\d+)", MatchOptions.Complete & MatchOptions.Multiline) +{FullMatch:"Joe 164",StartMatch:1} + +>> Match("JohnDoe@microsoft.com", Match.Email) +{FullMatch:"JohnDoe@microsoft.com",StartMatch:1} + +>> Match("(555) 123-4567", "^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$") +{FullMatch:"(555) 123-4567",StartMatch:1} + +>> Match("Hello", "Hello", MatchOptions.IgnoreCase) +{FullMatch:"Hello",StartMatch:1} + +>> Match("Hi", "Hi", MatchOptions.Multiline) +{FullMatch:"Hi",StartMatch:1} From 442bf73a2fd3f7a96ad9b15f4d9c71942fc49fe6 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Thu, 15 Aug 2024 13:56:04 -0700 Subject: [PATCH 25/61] updates --- .../Texl/Builtins/IsMatch.cs | 61 ------------------- .../Texl/Builtins/Match.cs | 43 ++++++++++--- .../ExpressionTestCases/IsMatch.txt | 7 +-- .../ExpressionTestCases/IsMatch_V1Compat.txt | 3 + .../IsMatch_V1CompatDisabled.txt | 3 + .../MatchAll_StronglyTypedEnumsDisabled.txt | 4 +- .../ExpressionTestCases/Match_V1Compat.txt | 10 +-- .../StronglyTypedEnum_BuiltInEnums_PreV1.txt | 6 +- .../FileExpressionEvaluationTests.cs | 6 +- 9 files changed, 57 insertions(+), 86 deletions(-) delete mode 100644 src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/IsMatch.cs diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/IsMatch.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/IsMatch.cs deleted file mode 100644 index 06d037ad9e..0000000000 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/IsMatch.cs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -using System.Collections.Generic; -using Microsoft.PowerFx.Core.App.ErrorContainers; -using Microsoft.PowerFx.Core.Binding; -using Microsoft.PowerFx.Core.Functions; -using Microsoft.PowerFx.Core.Localization; -using Microsoft.PowerFx.Core.Types; -using Microsoft.PowerFx.Core.Types.Enums; -using Microsoft.PowerFx.Core.Utils; -using Microsoft.PowerFx.Syntax; - -#pragma warning disable SA1649 // File name should match first type name - -namespace Microsoft.PowerFx.Core.Texl.Builtins -{ - // IsMatch(text:s, format:s) - // Checks if the input text is of the correct format. - internal sealed class IsMatchFunction : BuiltinFunction - { - public override bool UseParentScopeForArgumentSuggestions => true; - - public override bool IsSelfContained => true; - - public override bool HasPreciseErrors => true; - - public IsMatchFunction() - : base("IsMatch", TexlStrings.AboutIsMatch, FunctionCategories.Text, DType.Boolean, 0, 2, 3, DType.String, BuiltInEnums.MatchEnum.FormulaType._type, BuiltInEnums.MatchOptionsEnum.FormulaType._type) - { - } - - public override IEnumerable GetRequiredEnumNames() - { - return new List() { LanguageConstants.MatchEnumString, LanguageConstants.MatchOptionsEnumString }; - } - - public override IEnumerable GetSignatures() - { - yield return new[] { TexlStrings.IsMatchArg1, TexlStrings.IsMatchArg2 }; - yield return new[] { TexlStrings.IsMatchArg1, TexlStrings.IsMatchArg2, TexlStrings.IsMatchArg3 }; - } - - public override void CheckSemantics(TexlBinding binding, TexlNode[] args, DType[] argTypes, IErrorContainer errors) - { - if ((argTypes[1].Kind != DKind.String && argTypes[1].Kind != DKind.OptionSetValue) || !binding.IsConstant(args[1])) - { - errors.EnsureError(args[1], TexlStrings.ErrVariableRegEx); - } - } - - public override bool HasSuggestionsForParam(int index) - { - Contracts.Assert(index >= 0); - - return index <= 2; - } - } -} - -#pragma warning restore SA1649 // File name should match first type name diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index 64fb36902e..45d2ec60d2 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -23,6 +23,21 @@ namespace Microsoft.PowerFx.Core.Texl.Builtins { + // IsMatch(text:s, regular_expression:s, [options:s]) + internal class IsMatchFunction : BaseMatchFunction + { + public IsMatchFunction() + : base("IsMatch", TexlStrings.AboutIsMatch, DType.Boolean) + { + } + + public override IEnumerable GetSignatures() + { + yield return new[] { TexlStrings.IsMatchArg1, TexlStrings.IsMatchArg2 }; + yield return new[] { TexlStrings.IsMatchArg1, TexlStrings.IsMatchArg2, TexlStrings.IsMatchArg3 }; + } + } + // Match(text:s, regular_expression:s, [options:s]) internal class MatchFunction : BaseMatchFunction { @@ -51,12 +66,19 @@ internal class BaseMatchFunction : BuiltinFunction public override bool SupportsParamCoercion => true; - public BaseMatchFunction(string functionName, TexlStrings.StringGetter aboutGetter, DType returnType, RegexTypeCache regexCache) + public override bool UseParentScopeForArgumentSuggestions => true; + + // public override bool HasPreciseErrors => true; + + public BaseMatchFunction(string functionName, TexlStrings.StringGetter aboutGetter, DType returnType, RegexTypeCache regexCache = null) : base(functionName, aboutGetter, FunctionCategories.Text, returnType, 0, 2, 3, DType.String, BuiltInEnums.MatchEnum.FormulaType._type, BuiltInEnums.MatchOptionsEnum.FormulaType._type) { - _cachePrefix = returnType.IsTable ? "tbl_" : "rec_"; - _regexTypeCache = regexCache.Cache; - _regexCacheSize = regexCache.CacheSize; + if (regexCache != null) + { + _cachePrefix = returnType.IsTable ? "tbl_" : "rec_"; + _regexTypeCache = regexCache.Cache; + _regexCacheSize = regexCache.CacheSize; + } } public override IEnumerable GetSignatures() @@ -68,7 +90,14 @@ public BaseMatchFunction(string functionName, TexlStrings.StringGetter aboutGett public override IEnumerable GetRequiredEnumNames() { return new List() { LanguageConstants.MatchEnumString, LanguageConstants.MatchOptionsEnumString }; - } + } + + public override bool HasSuggestionsForParam(int index) + { + Contracts.Assert(index >= 0); + + return index <= 2; + } public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DType[] argTypes, IErrorContainer errors, out DType returnType, out Dictionary nodeToCoercedTypeMap) { @@ -80,7 +109,7 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp Contracts.AssertValue(errors); bool fValid = base.CheckTypes(context, args, argTypes, errors, out returnType, out nodeToCoercedTypeMap); - Contracts.Assert(returnType.IsRecord || returnType.IsTable); + Contracts.Assert(returnType.IsRecord || returnType.IsTable || returnType == DType.Boolean); string regularExpressionOptions = string.Empty; var regExNode = args[1]; @@ -106,7 +135,7 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp return fValid && (!context.Features.PowerFxV1CompatibilityRules || IsSupportedRegularExpression(regExNode, regularExpression, regularExpressionOptions, errors)) && - TryCreateReturnType(regExNode, regularExpression, regularExpressionOptions, errors, ref returnType); + (returnType == DType.Boolean || TryCreateReturnType(regExNode, regularExpression, regularExpressionOptions, errors, ref returnType)); } // Limit regular expressions to common features that are supported, with consistent semantics, by both canonical .NET and XRegExp. diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch.txt index 80b5545fbe..24d1d1bf01 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch.txt @@ -73,9 +73,6 @@ false >> IsMatch("!@#$%^&*()-=_+<>,.:;\'{}[]\|?/~` Ð 1234567890", "\p{L}") false ->> IsMatch("Foo", "J(") -Error({Kind:ErrorKind.BadRegex}) - >> IsMatch( "28", Concat( [2,8], Value ) ) Errors: Error 15-37: Regular expressions must be constant values. @@ -95,10 +92,10 @@ true false >> IsMatch("""Hello world""", Char(34) & "Hello", MatchOptions.Contains) -true +Errors: Error 36-37: Regular expressions must be constant values.|Error 0-7: The function 'IsMatch' has some invalid arguments. >> IsMatch("Hello 123 world", $"Hello {Sqrt(1)}{Sqrt(4)}{Sqrt(9)} world") -true +Errors: Error 27-69: Regular expressions must be constant values.|Error 0-7: The function 'IsMatch' has some invalid arguments. >> IsMatch("Hello", "Hello", MatchOptions.IgnoreCase) true diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1Compat.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1Compat.txt index 386a6987b4..9d49badae0 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1Compat.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1Compat.txt @@ -10,3 +10,6 @@ false >> IsMatch("ababababababababababababababababababababababababababababababababababa", "^((ab)*)+$") false + +>> IsMatch("Foo", "J(") +Errors: Error 15-19: Invalid regular expression: Unclosed groups, too few closing parenthesis.|Error 0-7: The function 'IsMatch' has some invalid arguments. diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1CompatDisabled.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1CompatDisabled.txt index de3d563c0b..3bf5c9ecd2 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1CompatDisabled.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1CompatDisabled.txt @@ -3,3 +3,6 @@ // Dangerous Regex, will timeout (should take >2h on a fast CPU) - but only with Pre-V1 or MatchOptions.NumberedCaptures >> IsMatch("ababababababababababababababababababababababababababababababababababa", "^((ab)*)+$") Error({Kind:ErrorKind.Timeout}) + +>> IsMatch("Foo", "J(") +Error({Kind:ErrorKind.BadRegex}) diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/MatchAll_StronglyTypedEnumsDisabled.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/MatchAll_StronglyTypedEnumsDisabled.txt index 1019bfa06f..4269439fea 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/MatchAll_StronglyTypedEnumsDisabled.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/MatchAll_StronglyTypedEnumsDisabled.txt @@ -1,4 +1,4 @@ #SETUP: RegEx,disable:StronglyTypedBuiltinEnums ->> First( MatchAll("Hello", "Hello", "") ).FullMatch -"Hello" +>> ForAll( MatchAll("Helloofammasdfooerf", "(?\w)\k", ""), {fm:FullMatch} ) +Table({fm:"ll"},{fm:"oo"},{fm:"mm"},{fm:"oo"}) diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_V1Compat.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_V1Compat.txt index a23ceb1110..552ff9cc2e 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_V1Compat.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_V1Compat.txt @@ -3,22 +3,22 @@ >> Match("Hello", "\w") {FullMatch:"H",StartMatch:1} ->> Index(Match("Hello", "(\w)l(\w)", MatchOptions.NumberedCaptures).SubMatches, 1).Value +>> Index(Match("Hello", "(\w)l(\w)", MatchOptions.NumberedSubMatches).SubMatches, 1).Value "e" ->> Index(Match("Hello", "(\w)l(\w)", MatchOptions.NumberedCaptures).SubMatches, 2).Value +>> Index(Match("Hello", "(\w)l(\w)", MatchOptions.NumberedSubMatches).SubMatches, 2).Value "l" ->> Concat(ForAll(Match("Hello", "(\w)l(\w)", MatchOptions.NumberedCaptures).SubMatches, With({x:Value}, x)), Value, ", ") +>> Concat(ForAll(Match("Hello", "(\w)l(\w)", MatchOptions.NumberedSubMatches).SubMatches, With({x:Value}, x)), Value, ", ") "e, l" ->> Match("Hello", "(\w)l(\w)", MatchOptions.NumberedCaptures).SubMatches +>> Match("Hello", "(\w)l(\w)", MatchOptions.NumberedSubMatches).SubMatches Table({Value:"e"},{Value:"l"}) >> Match("Joe 164" & Char(10) & "Sam 208" & Char(10), "(\w+)\s(\d+)", MatchOptions.Complete) Blank() ->> Match("Joe 164" & Char(10) & "Sam 208" & Char(10), "(\w+)\s(\d+)", MatchOptions.Complete & MatchOptions.Multiline & MatchOptions.NumberedCaptures) +>> Match("Joe 164" & Char(10) & "Sam 208" & Char(10), "(\w+)\s(\d+)", MatchOptions.Complete & MatchOptions.Multiline & MatchOptions.NumberedSubMatches) {FullMatch:"Joe 164",StartMatch:1,SubMatches:Table({Value:"Joe"},{Value:"164"})} >> Match("JohnDoe@microsoft.com", Match.Email) diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/StronglyTypedEnum_BuiltInEnums_PreV1.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/StronglyTypedEnum_BuiltInEnums_PreV1.txt index 4410bce8c3..ad4f6e79af 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/StronglyTypedEnum_BuiltInEnums_PreV1.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/StronglyTypedEnum_BuiltInEnums_PreV1.txt @@ -106,8 +106,8 @@ false >> MatchAll( "hi", JSONFormat.IndentFour ) Table() ->> MatchAll( "hi", "h.*", JSONFormat.IndentFour ).FullMatch -"hi" +>> ForAll( MatchAll( "hiha", "h", JSONFormat.IndentFour ), {fm:FullMatch, sm:StartMatch} ) +Table({fm:"h",sm:1},{fm:"h",sm:3}) >> MatchAll( "hi", Match.Email, JSONFormat.IndentFour ) Table() @@ -387,7 +387,7 @@ false false >> ForAll( MatchAll( "a3d4", Match.Digit ), {fm:FullMatch} ) -Tale({fm:"3"},{fm:"4"}) +Table({fm:"3"},{fm:"4"}) >> ForAll( MatchAll( "a3d4", "\d"), {fm:FullMatch} ) Table({fm:"3"},{fm:"4"}) diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index 5075284868..c316ef9157 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -24,7 +24,7 @@ public FileExpressionEvaluationTests(ITestOutputHelper output) } // File expression tests are run multiple times for the different ways a host can use Power Fx. - // abcdefgedeergyor + // ab // 1. Features.PowerFxV1 without NumberIsFloat - the main way that most hosts will use Power Fx. // 2. Feautres.PowerFxV1 with NumberIsFloat - for hosts that wish to use floating point instead of Decimal. // 3. Default Canvas features with NumberIsFloat - the current default for Canvas apps. Canvas @@ -154,11 +154,11 @@ private static bool ShouldSkipDotNetVersion(ExpressionTestCase testCase, string } #if true - // Helper to run a single .txt A + // Helper to run a single .txt [Fact] public void RunOne() { - var path = @"c:\repos\regex-min\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\match_limited.txt"; + var path = @"d:\repos\regex-min\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\match_limited.txt"; var line = 0; var runner = new InterpreterRunner(); From dfa1e152f570f386281c71d29d1a0a75a3272c95 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Thu, 15 Aug 2024 13:56:24 -0700 Subject: [PATCH 26/61] Updates 2 --- .../Localization/Strings.cs | 4 +-- .../Types/Enums/BuiltInEnums.cs | 2 +- src/strings/PowerFxResources.en-US.resx | 8 ++--- .../ExpressionTestCases/MatchAll_V1Compat.txt | 4 +-- .../ExpressionTestCases/Match_Limited.txt | 34 +++++++++---------- .../IsMatch_V1CompatDisabled_Overrides.txt | 2 +- 6 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs index 9919629992..363e78ec38 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs @@ -740,8 +740,8 @@ internal static class TexlStrings public static ErrorResourceKey ErrInvalidRegExUnclosedCaptureGroups = new ErrorResourceKey("ErrInvalidRegExUnclosedCaptureGroups"); public static ErrorResourceKey ErrInvalidRegExUnopenedCaptureGroups = new ErrorResourceKey("ErrInvalidRegExUnopenedCaptureGroups"); public static ErrorResourceKey ErrInvalidRegExUnclosedCharacterClass = new ErrorResourceKey("ErrInvalidRegExUnclosedCharacterClass"); - public static ErrorResourceKey ErrInvalidRegExMixingNamedAndNumberedCaptures = new ErrorResourceKey("ErrInvalidRegExMixingNamedAndNumberedCaptures"); - public static ErrorResourceKey ErrInvalidRegExNumberedCapturesDisabled = new ErrorResourceKey("ErrInvalidRegExNumberedCapturesDisabled"); + public static ErrorResourceKey ErrInvalidRegExMixingNamedAndNumberedSubMatches = new ErrorResourceKey("ErrInvalidRegExMixingNamedAndNumberedSubMatches"); + public static ErrorResourceKey ErrInvalidRegExNumberedSubMatchesDisabled = new ErrorResourceKey("ErrInvalidRegExNumberedSubMatchesDisabled"); public static ErrorResourceKey ErrInvalidRegExBadUnsupportedCharacterClassSubtraction = new ErrorResourceKey("ErrInvalidRegExBadUnsupportedCharacterClassSubtraction"); public static ErrorResourceKey ErrInvalidRegExOpenParenInComment = new ErrorResourceKey("ErrInvalidRegExOpenParenInComment"); diff --git a/src/libraries/Microsoft.PowerFx.Core/Types/Enums/BuiltInEnums.cs b/src/libraries/Microsoft.PowerFx.Core/Types/Enums/BuiltInEnums.cs index 8e4066c0ad..a895f37eab 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Types/Enums/BuiltInEnums.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Types/Enums/BuiltInEnums.cs @@ -89,7 +89,7 @@ internal static class BuiltInEnums { "Multiline", "m" }, { "FreeSpacing", "x" }, { "DotAll", "s" }, - { "NumberedCaptures", "N" } + { "NumberedSubMatches", "N" } }, canConcatenateStronglyTyped: true); diff --git a/src/strings/PowerFxResources.en-US.resx b/src/strings/PowerFxResources.en-US.resx index 9542f5a70e..0992f7bfcd 100644 --- a/src/strings/PowerFxResources.en-US.resx +++ b/src/strings/PowerFxResources.en-US.resx @@ -4459,12 +4459,12 @@ Invalid regular expression: Conditional alternation is not supported, found "{0}". Error message indicating that the regular expression has conditionals. - - Invalid regular expression: Named captures cannot be used with MatchOptions.NumberedCaptures enabled, found "{0}". + + Invalid regular expression: Named captures cannot be used with MatchOptions.NumberedSubMatches enabled, found "{0}". Error message indicating that the regular expression is mixing named and numbered captures. - - Invalid regular expression: Use named captures with "(?<name>" and "\k<name>" or enable MatchOptions.NumberedCaptures, found "{0}". + + Invalid regular expression: Use named captures with "(?<name>" and "\k<name>" or enable MatchOptions.NumberedSubMatches, found "{0}". Error message indicating that the regular expression is not enabled for numbered captures. diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/MatchAll_V1Compat.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/MatchAll_V1Compat.txt index e6aa64fb22..11ba6766b9 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/MatchAll_V1Compat.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/MatchAll_V1Compat.txt @@ -18,10 +18,10 @@ Table({FullMatch:"ell",StartMatch:2,p1:"e",p2:"l"}) >> MatchAll("Hello", "(\w)l(\w)") Table({FullMatch:"ell",StartMatch:2}) ->> MatchAll("Hello", "(\w)l(\w)", MatchOptions.NumberedCaptures) +>> MatchAll("Hello", "(\w)l(\w)", MatchOptions.NumberedSubMatches) Table({FullMatch:"ell",StartMatch:2,SubMatches:Table({Value:"e"},{Value:"l"})}) ->> MatchAll("Joe 164" & Char(10) & "Sam 208" & Char(10), "(\w+)\s(\d+)", MatchOptions.Complete & MatchOptions.Multiline & MatchOptions.NumberedCaptures) +>> MatchAll("Joe 164" & Char(10) & "Sam 208" & Char(10), "(\w+)\s(\d+)", MatchOptions.Complete & MatchOptions.Multiline & MatchOptions.NumberedSubMatches) Table({FullMatch:"Joe 164",StartMatch:1,SubMatches:Table({Value:"Joe"},{Value:"164"})},{FullMatch:"Sam 208",StartMatch:9,SubMatches:Table({Value:"Sam"},{Value:"208"})}) >> MatchAll(Blank(), ".") diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt index 0dcff1dfad..c85bf4dffe 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt @@ -40,7 +40,7 @@ // Self referencing groups are disallowed >> Match( "aa aaaa aaaaaa ", "((a+)(\1) ?)+" ) -Errors: Error 26-41: Invalid regular expression: Use named captures with "(?" and "\k" or enable MatchOptions.NumberedCaptures, found "\1".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 26-41: Invalid regular expression: Use named captures with "(?" and "\k" or enable MatchOptions.NumberedSubMatches, found "\1".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "aa aaaa aaaaaa ", "(?(a+)(\k) ?)+" ) Errors: Error 26-56: Invalid regular expression: Self-referencing capture groups are not supported, found "\k".|Error 0-5: The function 'Match' has some invalid arguments. @@ -48,7 +48,7 @@ Errors: Error 26-56: Invalid regular expression: Self-referencing capture groups // Backreferences without a group are disallowed >> Match( "hello howdy", "([hi]).*\1" ) -Errors: Error 22-34: Invalid regular expression: Use named captures with "(?" and "\k" or enable MatchOptions.NumberedCaptures, found "\1".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 22-34: Invalid regular expression: Use named captures with "(?" and "\k" or enable MatchOptions.NumberedSubMatches, found "\1".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "hello howdy", "([hi]).*\k<1>" ) Errors: Error 22-37: Invalid regular expression: Capture group "\k<1>" not defined.|Error 0-5: The function 'Match' has some invalid arguments. @@ -56,13 +56,13 @@ Errors: Error 22-37: Invalid regular expression: Capture group "\k<1>" not defin >> Match( "hello howdy", "(?[hi]).*\k" ) {FullMatch:"hello h",StartMatch:1,first:"h"} ->> Match( "hello howdy", "(?[hi]).*\k", MatchOptions.NumberedCaptures ) -Errors: Error 22-49: Invalid regular expression: Named captures cannot be used with MatchOptions.NumberedCaptures enabled, found "(?".|Error 0-5: The function 'Match' has some invalid arguments. +>> Match( "hello howdy", "(?[hi]).*\k", MatchOptions.NumberedSubMatches ) +Errors: Error 22-49: Invalid regular expression: Named captures cannot be used with MatchOptions.NumberedSubMatches enabled, found "(?".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "hello howdy", "(?[hi]).*\1" ) -Errors: Error 22-42: Invalid regular expression: Use named captures with "(?" and "\k" or enable MatchOptions.NumberedCaptures, found "\1".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 22-42: Invalid regular expression: Use named captures with "(?" and "\k" or enable MatchOptions.NumberedSubMatches, found "\1".|Error 0-5: The function 'Match' has some invalid arguments. ->> Match( "hello howdy", "([hi]).*\1", MatchOptions.NumberedCaptures ) +>> Match( "hello howdy", "([hi]).*\1", MatchOptions.NumberedSubMatches ) {FullMatch:"hello h",StartMatch:1,SubMatches:Table({Value:"h"})} >> Match( "hello howdy", "(?[hi]).*\k" ) @@ -72,9 +72,9 @@ Errors: Error 22-50: Invalid regular expression: Capture group "\k" not {FullMatch:"llo worl",StartMatch:3,eleven:"l"} >> Match( "hello world", "(((((((((((l))))))))))).*\11") // 11 parens -Errors: Error 22-52: Invalid regular expression: Use named captures with "(?" and "\k" or enable MatchOptions.NumberedCaptures, found "\11".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 22-52: Invalid regular expression: Use named captures with "(?" and "\k" or enable MatchOptions.NumberedSubMatches, found "\11".|Error 0-5: The function 'Match' has some invalid arguments. ->> Match( "hello world", "(((((((((((l))))))))))).*\11", MatchOptions.NumberedCaptures) // 11 parens +>> Match( "hello world", "(((((((((((l))))))))))).*\11", MatchOptions.NumberedSubMatches) // 11 parens {FullMatch:"llo worl",StartMatch:3,SubMatches:Table({Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"})} >> Match( "hello world", "(((((((((((?l)))))))))).*\k") // unclosed 11th paren @@ -90,15 +90,15 @@ Errors: Error 22-74: Invalid regular expression: Self-referencing capture groups {FullMatch:"llo worl",StartMatch:3,a:"l",b:"l",c:"l",d:"l",e:"l",f:"l",g:"l",h:"l",i:"l",j:"l"} >> Match( "hello world", "(((((((((((l))))))))))).*\1") // 11 parens -Errors: Error 22-51: Invalid regular expression: Use named captures with "(?" and "\k" or enable MatchOptions.NumberedCaptures, found "\1".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 22-51: Invalid regular expression: Use named captures with "(?" and "\k" or enable MatchOptions.NumberedSubMatches, found "\1".|Error 0-5: The function 'Match' has some invalid arguments. ->> Match( "hello world", "(((((((((((l))))))))))).*\1", MatchOptions.NumberedCaptures) // 11 parens +>> Match( "hello world", "(((((((((((l))))))))))).*\1", MatchOptions.NumberedSubMatches) // 11 parens {FullMatch:"llo worl",StartMatch:3,SubMatches:Table({Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"})} >> Match( "hello world", "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "(?l)" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & ".*\k" ) {FullMatch:"llo worl",StartMatch:3,hundredone:"l"} ->> Match( "hello world", "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "(l)" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & ".*\101", MatchOptions.NumberedCaptures ) +>> Match( "hello world", "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "(l)" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & ".*\101", MatchOptions.NumberedSubMatches ) {FullMatch:"llo worl",StartMatch:3,SubMatches:Table({Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"},{Value:"l"})} >> Match( "hello world", "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "((((((((((" & "(?l" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & "))))))))))" & ".*\k" ) // missing paren @@ -110,16 +110,16 @@ Errors: Error 341-342: Invalid regular expression: Unclosed groups, too few clos >> Match( "hello world", "(((())(())(())(((((((())))))))))()(?l)()\k") {FullMatch:"ll",StartMatch:3,letter:"l"} ->> Match( "hello world", "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(?l)" & ".*\k", MatchOptions.NumberedCaptures ) -Errors: Error 491-492: Invalid regular expression: Named captures cannot be used with MatchOptions.NumberedCaptures enabled, found "(?".|Error 0-5: The function 'Match' has some invalid arguments. +>> Match( "hello world", "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(?l)" & ".*\k", MatchOptions.NumberedSubMatches ) +Errors: Error 491-492: Invalid regular expression: Named captures cannot be used with MatchOptions.NumberedSubMatches enabled, found "(?".|Error 0-5: The function 'Match' has some invalid arguments. ->> Match( "hello world", "(((())(())(())(((((((())))))))))()(?l)()\k", MatchOptions.NumberedCaptures) -Errors: Error 22-82: Invalid regular expression: Named captures cannot be used with MatchOptions.NumberedCaptures enabled, found "(?".|Error 0-5: The function 'Match' has some invalid arguments. +>> Match( "hello world", "(((())(())(())(((((((())))))))))()(?l)()\k", MatchOptions.NumberedSubMatches) +Errors: Error 22-82: Invalid regular expression: Named captures cannot be used with MatchOptions.NumberedSubMatches enabled, found "(?".|Error 0-5: The function 'Match' has some invalid arguments. ->> Match( "hello world", "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(l)" & ".*\101", MatchOptions.NumberedCaptures ) +>> Match( "hello world", "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)(z*)" & "(l)" & ".*\101", MatchOptions.NumberedSubMatches ) {FullMatch:"llo worl",StartMatch:3,SubMatches:Table({Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:"l"})} ->> Match( "hello world", "(((())(())(())(((((((())))))))))()(l)()\18", MatchOptions.NumberedCaptures) +>> Match( "hello world", "(((())(())(())(((((((())))))))))()(l)()\18", MatchOptions.NumberedSubMatches) {FullMatch:"ll",StartMatch:3,SubMatches:Table({Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:"l"},{Value:""})} // Octal characters are not allowed diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/InterpreterExpressionTestCases/IsMatch_V1CompatDisabled_Overrides.txt b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/InterpreterExpressionTestCases/IsMatch_V1CompatDisabled_Overrides.txt index 27dbcab74a..e993cc1469 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/InterpreterExpressionTestCases/IsMatch_V1CompatDisabled_Overrides.txt +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/InterpreterExpressionTestCases/IsMatch_V1CompatDisabled_Overrides.txt @@ -3,6 +3,6 @@ // The C# interpeter doesn't have a non-V1 implementation of the Match functions, so SubMatches will not appear in these results -// Dangerous Regex, will timeout (should take >2h on a fast CPU) - but only with Pre-V1 or MatchOptions.NumberedCaptures +// Dangerous Regex, will timeout (should take >2h on a fast CPU) - but only with Pre-V1 or MatchOptions.NumberedSubMatches >> IsMatch("ababababababababababababababababababababababababababababababababababa", "^((ab)*)+$") false \ No newline at end of file From 9d7ba42ab968413a3d7a8275a1652bde35fae972 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Thu, 15 Aug 2024 13:56:44 -0700 Subject: [PATCH 27/61] Updates 3 --- .../Microsoft.PowerFx.Core/Texl/Builtins/Match.cs | 8 ++++---- .../ExpressionTestCases/IsMatch_V1Compat.txt | 4 ++-- .../ExpressionTestCases/IsMatch_V1CompatDisabled.txt | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index 45d2ec60d2..d422088461 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -176,7 +176,7 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter # leading backslash, escape sequences \\k<(?\w+)> | # named backreference (?\\0\d*) | # octal are not accepted (no XRegExp support, by design) - \\(?\d+) | # numeric backreference, must be enabled with MatchOptions.NumberedCaptures + \\(?\d+) | # numeric backreference, must be enabled with MatchOptions.NumberedSubMatches (?\\ ([bBdDfnrsStwW] | # standard regex character classes, missing from .NET are aAeGzZv (no XRegExp support), other common are u{} and o [pP]\{\w+\} | # unicode character classes @@ -280,7 +280,7 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter { if (numberedCpature) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExMixingNamedAndNumberedCaptures, token.Value); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExMixingNamedAndNumberedSubMatches, token.Value); return false; } @@ -340,7 +340,7 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter if (numberedCpature) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExMixingNamedAndNumberedCaptures, token.Value); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExMixingNamedAndNumberedSubMatches, token.Value); return false; } @@ -364,7 +364,7 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter if (!numberedCpature) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExNumberedCapturesDisabled, token.Value); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExNumberedSubMatchesDisabled, token.Value); return false; } diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1Compat.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1Compat.txt index 9d49badae0..3ef6a9af28 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1Compat.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1Compat.txt @@ -1,7 +1,7 @@ #SETUP: RegEx,PowerFxV1CompatibilityRules -// Dangerous Regex, will timeout (should take >2h on a fast CPU) - but only with Pre-V1 or MatchOptions.NumberedCaptures ->> IsMatch("ababababababababababababababababababababababababababababababababababa", "^((ab)*)+$", MatchOptions.NumberedCaptures) +// Dangerous Regex, will timeout (should take >2h on a fast CPU) - but only with Pre-V1 or MatchOptions.NumberedSubMatches +>> IsMatch("ababababababababababababababababababababababababababababababababababa", "^((ab)*)+$", MatchOptions.NumberedSubMatches) Error({Kind:ErrorKind.Timeout}) // but will finish quickly without captures diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1CompatDisabled.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1CompatDisabled.txt index 3bf5c9ecd2..d791baebc6 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1CompatDisabled.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1CompatDisabled.txt @@ -1,6 +1,6 @@ #SETUP: RegEx,disable:PowerFxV1CompatibilityRules -// Dangerous Regex, will timeout (should take >2h on a fast CPU) - but only with Pre-V1 or MatchOptions.NumberedCaptures +// Dangerous Regex, will timeout (should take >2h on a fast CPU) - but only with Pre-V1 or MatchOptions.NumberedSubMatches >> IsMatch("ababababababababababababababababababababababababababababababababababa", "^((ab)*)+$") Error({Kind:ErrorKind.Timeout}) From d51e047f0a6efa21d1790f07bb4c44add8a4dcd2 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Thu, 15 Aug 2024 17:49:20 -0700 Subject: [PATCH 28/61] Updates --- .../Texl/Builtins/Match.cs | 28 +- .../Functions/LibraryRegEx.cs | 15 +- .../ExpressionTestCases/Match_Limited.txt | 242 +++++++++++++++++- .../FileExpressionEvaluationTests.cs | 4 +- 4 files changed, 265 insertions(+), 24 deletions(-) diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index d422088461..ff44c8704c 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -27,7 +27,7 @@ namespace Microsoft.PowerFx.Core.Texl.Builtins internal class IsMatchFunction : BaseMatchFunction { public IsMatchFunction() - : base("IsMatch", TexlStrings.AboutIsMatch, DType.Boolean) + : base("IsMatch", TexlStrings.AboutIsMatch, DType.Boolean, null) { } @@ -41,8 +41,8 @@ public IsMatchFunction() // Match(text:s, regular_expression:s, [options:s]) internal class MatchFunction : BaseMatchFunction { - public MatchFunction(RegexTypeCache regexCache) - : base("Match", TexlStrings.AboutMatch, DType.EmptyRecord, regexCache) + public MatchFunction(RegexTypeCache regexTypeCache) + : base("Match", TexlStrings.AboutMatch, DType.EmptyRecord, regexTypeCache) { } } @@ -50,8 +50,8 @@ public MatchFunction(RegexTypeCache regexCache) // MatchAll(text:s, regular_expression:s, [options:s]) internal class MatchAllFunction : BaseMatchFunction { - public MatchAllFunction(RegexTypeCache regexCache) - : base("MatchAll", TexlStrings.AboutMatchAll, DType.EmptyTable, regexCache) + public MatchAllFunction(RegexTypeCache regexTypeCache) + : base("MatchAll", TexlStrings.AboutMatchAll, DType.EmptyTable, regexTypeCache) { } } @@ -68,16 +68,14 @@ internal class BaseMatchFunction : BuiltinFunction public override bool UseParentScopeForArgumentSuggestions => true; - // public override bool HasPreciseErrors => true; - - public BaseMatchFunction(string functionName, TexlStrings.StringGetter aboutGetter, DType returnType, RegexTypeCache regexCache = null) + public BaseMatchFunction(string functionName, TexlStrings.StringGetter aboutGetter, DType returnType, RegexTypeCache regexTypeCache) : base(functionName, aboutGetter, FunctionCategories.Text, returnType, 0, 2, 3, DType.String, BuiltInEnums.MatchEnum.FormulaType._type, BuiltInEnums.MatchOptionsEnum.FormulaType._type) { - if (regexCache != null) + if (regexTypeCache != null) { _cachePrefix = returnType.IsTable ? "tbl_" : "rec_"; - _regexTypeCache = regexCache.Cache; - _regexCacheSize = regexCache.CacheSize; + _regexTypeCache = regexTypeCache.Cache; + _regexCacheSize = regexTypeCache.CacheSize; } } @@ -206,8 +204,8 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter (?[\?\*\+][\+\*]) | # possessive and useless quantifiers # leading {, limited quantifiers - (?{\d+(,\d*)?}(\?|\+|\*)) | # possessive and useless quantifiers - (?{\d+(,\d*)?}) | # standard limited quantifiers + (?{\d+(,\d*)?}\??) | # standard limited quantifiers + (?{\d+(,\d*)?}[\+|\*]) | # possessive and useless quantifiers (?[{}]) | # more constrained, blocks {,3} and Java/Rust semantics that does not treat this as a literal # open and close regions @@ -466,7 +464,7 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadEscape, token.Groups["badEscapeAlpha"].Value); return false; } - else if (token.Groups["badQuantifier"].Success) + else if (token.Groups["badQuantifier"].Success || token.Groups["badLimited"].Success) { errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadQuantifier, token.Groups["badQuantifier"].Value); return false; @@ -484,7 +482,7 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter else { // This should never be hit. Here in case one of the names checked doesn't match the RE, in which case running tests would hit this. - throw new NotImplementedException("Unknown regular expression match"); + throw new NotImplementedException("Unknown regular expression match: " + token.Value); } } } diff --git a/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs b/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs index 42f83406e6..e219283745 100644 --- a/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs +++ b/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs @@ -207,7 +207,7 @@ private string AlterNewlineMatching(string regex, RegexOptions options) { var openCharacterClass = false; // are we defining a character class? var freeSpacing = (options & System.Text.RegularExpressions.RegexOptions.IgnorePatternWhitespace) != 0 || Regex.IsMatch(regex, @"^\(\?[A-Za-z-[x]]*x"); - var multiline = (options & System.Text.RegularExpressions.RegexOptions.Multiline) != 0 || Regex.IsMatch(regex, @"^\(\?[A-Za-a-[m]]*m"); + var multiline = (options & System.Text.RegularExpressions.RegexOptions.Multiline) != 0 || Regex.IsMatch(regex, @"^\(\?[A-Za-z-[m]]*m"); var dotAll = (options & System.Text.RegularExpressions.RegexOptions.Singleline) != 0 || Regex.IsMatch(regex, @"^\(\?[A-Za-z-[s]]*s"); var alteredRegex = new StringBuilder(); @@ -250,15 +250,15 @@ private string AlterNewlineMatching(string regex, RegexOptions options) break; case '.': - alteredRegex.Append(!openCharacterClass && !dotAll ? @"[^\n\r]" : "."); + alteredRegex.Append(!openCharacterClass && !dotAll ? @"[^\r\n]" : "."); break; case '^': - alteredRegex.Append(!openCharacterClass && multiline ? @"(?<=\A|\r\n|\n|\r)" : "^"); + alteredRegex.Append(!openCharacterClass && multiline ? @"(?<=\A|\r\n|\r|\n)" : "^"); break; case '$': - alteredRegex.Append(!openCharacterClass && multiline ? @"(?=\z|\r\n|\n|\r)" : "$"); + alteredRegex.Append(openCharacterClass ? "$" : (multiline ? @"(?=\z|\r\n|\r|\n)" : @"(?=\z|\r\n\z|\r\z|\n\z)")); break; default: @@ -336,7 +336,12 @@ public Task InvokeAsync(FormulaValue[] args, CancellationToken can regularExpression += "$"; } - if (!matchOptions.Contains("N")) + if (matchOptions.Contains("s")) + { + regOptions |= System.Text.RegularExpressions.RegexOptions.Singleline; + } + + if (!matchOptions.Contains("N")) // lack of NumberedSubMatches turns on ExplicitCapture for higher performance { regOptions |= System.Text.RegularExpressions.RegexOptions.ExplicitCapture; } diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt index c85bf4dffe..447f3960cc 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt @@ -529,10 +529,10 @@ Errors: Error 15-31: Invalid regular expression: Capture group "\k" not defin Blank() >> AddColumns( Match( "test" & Char(13), "^test$" ), len, Len(FullMatch) ) -Blank() +{FullMatch:"test",StartMatch:1,len:4} >> AddColumns( Match( "test" & Char(13) & Char(10), "^test$" ), len, Len(FullMatch) ) -Blank() +{FullMatch:"test",StartMatch:1,len:4} // .NET treats dot as [^\n], XRegExp and JavaScript use [^\n\r\u2028\u2029] @@ -551,6 +551,40 @@ Blank() >> DropColumns( Match( "te" & UniChar(Hex2Dec("2029")) & "t", "te.t" ), FullMatch ) {StartMatch:1} +// Inline DotAll + +>> DropColumns( Match( "te" & " " & "t", "(?s)te.t" ), FullMatch ) +{StartMatch:1} + +>> DropColumns( Match( "te" & Char(10) & "t", "(?s)te.t" ), FullMatch ) +{StartMatch:1} + +>> DropColumns( Match( "te" & Char(13) & "t", "(?s)te.t" ), FullMatch ) +{StartMatch:1} + +>> DropColumns( Match( "te" & UniChar(Hex2Dec("2028")) & "t", "(?s)te.t" ), FullMatch ) +{StartMatch:1} + +>> DropColumns( Match( "te" & UniChar(Hex2Dec("2029")) & "t", "(?s)te.t" ), FullMatch ) +{StartMatch:1} + +// Option DotAll + +>> DropColumns( Match( "te" & " " & "t", "te.t", MatchOptions.DotAll ), FullMatch ) +{StartMatch:1} + +>> DropColumns( Match( "te" & Char(10) & "t", "te.t", MatchOptions.DotAll ), FullMatch ) +{StartMatch:1} + +>> DropColumns( Match( "te" & Char(13) & "t", "te.t", MatchOptions.DotAll ), FullMatch ) +{StartMatch:1} + +>> DropColumns( Match( "te" & UniChar(Hex2Dec("2028")) & "t", "te.t", MatchOptions.DotAll ), FullMatch ) +{StartMatch:1} + +>> DropColumns( Match( "te" & UniChar(Hex2Dec("2029")) & "t", "te.t", MatchOptions.DotAll ), FullMatch ) +{StartMatch:1} + // $ end anchor, multiline, and newline characters >> MatchAll( "a1" & Char(10) & "b2" & Char(10) & "c3", "\d$" ) @@ -617,3 +651,207 @@ Errors: Error 16-25: Invalid regular expression: Square bracket character classe >> Match( "hello", "[[=x=]]" ) Errors: Error 16-25: Invalid regular expression: Square bracket character classes cannot be empty and cannot include unescaped literal open or close square brackets, escape with "\[" or "\]".|Error 0-5: The function 'Match' has some invalid arguments. + +// spaces + +>> IsMatch( "h" & "a" & "d", "h\sd") // control +false + +>> IsMatch( "h" & UniChar(Hex2Dec("0020")) & "d", "h\sd") // " " +true + +>> IsMatch( "h" & UniChar(Hex2Dec("000d")) & "d", "h\sd") // \r +true + +>> IsMatch( "h" & UniChar(Hex2Dec("000c")) & "d", "h\sd") // \f +true + +>> IsMatch( "h" & UniChar(Hex2Dec("000a")) & "d", "h\sd") // \n +true + +>> IsMatch( "h" & UniChar(Hex2Dec("0009")) & "d", "h\sd") // \t +true + +>> IsMatch( "h" & UniChar(Hex2Dec("000b")) & "d", "h\sd") // \v +true + +>> IsMatch( "h" & UniChar(Hex2Dec("0085")) & "d", "h\sd") // \x85, not in ECMAScript +true + +>> IsMatch( "h" & UniChar(Hex2Dec("1680")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("2000")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("2001")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("2002")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("2003")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("2004")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("2005")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("2006")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("2007")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("2008")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("2009")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("200a")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("202f")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("205f")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("3000")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("2028")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("2029")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("feff")) & "d", "h\sd") // ECMAScript +false + +>> IsMatch( "h" & UniChar(Hex2Dec("00a0")) & "d", "h\sd") +true + +// non-space + +>> IsMatch( "h" & "a" & "d", "h\Sd") // control +true + +>> IsMatch( "h" & UniChar(Hex2Dec("0020")) & "d", "h\Sd") // " " +false + +>> IsMatch( "h" & UniChar(Hex2Dec("000d")) & "d", "h\Sd") // \r +false + +>> IsMatch( "h" & UniChar(Hex2Dec("000c")) & "d", "h\Sd") // \f +false + +>> IsMatch( "h" & UniChar(Hex2Dec("000a")) & "d", "h\Sd") // \n +false + +>> IsMatch( "h" & UniChar(Hex2Dec("0009")) & "d", "h\Sd") // \t +false + +>> IsMatch( "h" & UniChar(Hex2Dec("000b")) & "d", "h\Sd") // \v +false + +>> IsMatch( "h" & UniChar(Hex2Dec("0085")) & "d", "h\Sd") // \x85, not in ECMAScript +false + +>> IsMatch( "h" & UniChar(Hex2Dec("1680")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("2000")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("2001")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("2002")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("2003")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("2004")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("2005")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("2006")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("2007")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("2008")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("2009")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("200a")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("202f")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("205f")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("3000")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("2028")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("2029")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("feff")) & "d", "h\Sd") // ECMAScript +true + +>> IsMatch( "h" & UniChar(Hex2Dec("00a0")) & "d", "h\Sd") +false + +// greedy and lazy quantifiers + +>> Match( "#abcdef#", "\w+" ).FullMatch +"abcdef" + +>> Match( "abcdef", "\w+?" ).FullMatch +"a" + +>> Match( "abcdef", "\w*" ).FullMatch +"abcdef" + +>> Match( "abcdef", "\w*?" ).FullMatch +"" + +>> Match( "abcdef", "\w?" ).FullMatch +"a" + +>> Match( "abcdef", "\w??" ).FullMatch +"" + +>> Match( "abcdef", "\w{2}" ).FullMatch +"ab" + +>> Match( "abcdef", "\w{2}?" ).FullMatch +"ab" + +>> Match( "abcdef", "\w{2,}" ).FullMatch +"abcdef" + +>> Match( "abcdef", "\w{2,}?" ).FullMatch +"ab" + +>> Match( "abcdef", "\w{2,4}" ).FullMatch +"abcd" + +>> Match( "abcdef", "\w{2,4}?" ).FullMatch +"ab" diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index c316ef9157..8a1ce9e9c3 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -24,7 +24,7 @@ public FileExpressionEvaluationTests(ITestOutputHelper output) } // File expression tests are run multiple times for the different ways a host can use Power Fx. - // ab + // // 1. Features.PowerFxV1 without NumberIsFloat - the main way that most hosts will use Power Fx. // 2. Feautres.PowerFxV1 with NumberIsFloat - for hosts that wish to use floating point instead of Decimal. // 3. Default Canvas features with NumberIsFloat - the current default for Canvas apps. Canvas @@ -153,7 +153,7 @@ private static bool ShouldSkipDotNetVersion(ExpressionTestCase testCase, string return false; } -#if true +#if false // Helper to run a single .txt [Fact] public void RunOne() From e309223d7c2e257dfe2f64ba9d468545413a1569 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Thu, 22 Aug 2024 01:21:03 -0700 Subject: [PATCH 29/61] Updates --- .../Localization/Strings.cs | 2 + .../Texl/Builtins/Match.cs | 41 +- .../Functions/LibraryRegEx.cs | 312 ++++++------ src/strings/PowerFxResources.en-US.resx | 8 + .../ExpressionTestCases/IsMatch_V1Compat.txt | 11 - .../IsMatch_V1CompatDisabled.txt | 4 - .../ExpressionTestCases/Match_Limited.txt | 128 ++++- .../FileExpressionEvaluationTests.cs | 14 + .../Helpers/LibraryRegEx_Compare.cs | 124 +++++ .../Helpers/LibraryRegEx_NodeJS.cs | 446 ++++++++++++++++++ .../Helpers/LibraryRegEx_PCRE2.cs | 276 +++++++++++ .../PowerFxEvaluationTests.cs | 10 +- .../RegExTests.cs | 33 ++ src/tools/Repl/Program.cs | 24 +- src/tools/Repl/Repl.csproj | 1 + 15 files changed, 1235 insertions(+), 199 deletions(-) create mode 100644 src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_Compare.cs create mode 100644 src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs create mode 100644 src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs diff --git a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs index 363e78ec38..387396ad1f 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs @@ -723,7 +723,9 @@ internal static class TexlStrings public static ErrorResourceKey ErrInvalidRegExInlineOptionNotAtStart = new ErrorResourceKey("ErrInvalidRegExInlineOptionNotAtStart"); public static ErrorResourceKey ErrInvalidRegExBadOctal = new ErrorResourceKey("ErrInvalidRegExBadOctal"); public static ErrorResourceKey ErrInvalidRegExBadCurly = new ErrorResourceKey("ErrInvalidRegExBadCurly"); + public static ErrorResourceKey ErrInvalidRegExBadSquare = new ErrorResourceKey("ErrInvalidRegExBadSquare"); public static ErrorResourceKey ErrInvalidRegExBadParen = new ErrorResourceKey("ErrInvalidRegExBadParen"); + public static ErrorResourceKey ErrInvalidRegExBadEscapeWithinCharacterClass = new ErrorResourceKey("ErrInvalidRegExBadEscapeWithinCharacterClass"); public static ErrorResourceKey ErrInvalidRegExRepeatInCharClass = new ErrorResourceKey("ErrInvalidRegExRepeatInCharClass"); public static ErrorResourceKey ErrInvalidRegExRepeatedInlineOption = new ErrorResourceKey("ErrInvalidRegExRepeatedInlineOption"); public static ErrorResourceKey ErrInvalidRegExBadQuantifier = new ErrorResourceKey("ErrInvalidRegExBadQuantifier"); diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index ff44c8704c..aa879af6f0 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -173,16 +173,17 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter @" # leading backslash, escape sequences \\k<(?\w+)> | # named backreference - (?\\0\d*) | # octal are not accepted (no XRegExp support, by design) + (?\\0\d*) | # \0 and octal are not accepted, amiguous and not needed (use \x instead) \\(?\d+) | # numeric backreference, must be enabled with MatchOptions.NumberedSubMatches - (?\\ - ([bBdDfnrsStwW] | # standard regex character classes, missing from .NET are aAeGzZv (no XRegExp support), other common are u{} and o - [pP]\{\w+\} | # unicode character classes - c[a-zA-Z] | # Ctrl character classes - x[0-9a-fA-F]{2} | # hex character, must be exactly 2 hex digits + (?\\ + ([dfnrstw] | # standard regex character classes, missing from .NET are aAeGzZv (no XRegExp support), other common are u{} and o + [pP]\{\w+\} | # unicode character classes + [\^\$\\\.\*\+\?\(\)\[\]\{\}\|\/] | # acceptable escaped characters with Unicode aware ECMAScript + c[a-zA-Z] | # Ctrl character classes + x[0-9a-fA-F]{2} | # hex character, must be exactly 2 hex digits u[0-9a-fA-F]{4})) | # Unicode characters, must be exactly 4 hex digits - (?\\[a-zA-Z_]) | # reserving all other letters and underscore for future use (consistent with .NET) - (?\\.) | # any other escaped character is allowed, but must be paired so that '\\(' is seen as '\\' followed by '(' and not '\' folloed by '\(' + (?\\[bBWDS]) | # acceptable outside a character class, but not within + (?\\.) | # all other escaped characters are invalid and reserved for future use # leading (?<, named captures \(\?<(?[a-zA-Z][a-zA-Z\d]*)> | # named capture group, can only be letters and numbers and must start with a letter @@ -241,11 +242,19 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter else if (!openComment) { // ordered from most common/good to least common/bad, for fewer tests - if (token.Groups["goodEscape"].Success || token.Groups["goodEscapeAlpha"].Success || + if (token.Groups["goodEscape"].Success || token.Groups["goodLookaround"].Success || token.Groups["goodLimited"].Success) { // all is well, nothing to do } + else if (token.Groups["goodEscapeOutside"].Success) + { + if (openCharacterClass) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadEscapeWithinCharacterClass, token.Index >= regexPattern.Length - 5 ? regexPattern.Substring(token.Index - 1) : regexPattern.Substring(token.Index - 1, 6) + "..."); + return false; + } + } else if (token.Groups["openCharacterClass"].Success) { if (openCharacterClass) @@ -269,7 +278,15 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter } else if (token.Groups["closeCharacterClass"].Success) { - openCharacterClass = false; + if (openCharacterClass) + { + openCharacterClass = false; + } + else + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadSquare, token.Index >= regexPattern.Length - 5 ? regexPattern.Substring(token.Index - 1) : regexPattern.Substring(token.Index - 1, 6) + "..."); + return false; + } } else if (token.Groups["goodNamedCapture"].Success) { @@ -459,9 +476,9 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadCharacterClassLiteralSquareBracket, token.Groups["badCharacterClassEmpty"].Value); return false; } - else if (token.Groups["badEscapeAlpha"].Success) + else if (token.Groups["badEscape"].Success) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadEscape, token.Groups["badEscapeAlpha"].Value); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadEscape, token.Groups["badEscape"].Value); return false; } else if (token.Groups["badQuantifier"].Success || token.Groups["badLimited"].Success) diff --git a/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs b/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs index e219283745..909fc636a4 100644 --- a/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs +++ b/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs @@ -21,14 +21,6 @@ internal static partial class Library { // https://learn.microsoft.com/en-us/power-platform/power-fx/reference/function-ismatch - public const string FULLMATCH = "FullMatch"; - public const string STARTMATCH = "StartMatch"; - public const string SUBMATCHES = "SubMatches"; - - private const string DefaultIsMatchOptions = "^c$"; - private const string DefaultMatchOptions = "c"; - private const string DefaultMatchAllOptions = "c"; - /// /// Creates instances of the [Is]Match[All] functions and returns them so they can be added to the runtime. /// @@ -59,16 +51,17 @@ internal class IsMatchImplementation : RegexCommonImplementation { private readonly TimeSpan _regexTimeout; - protected override string RegexOptions => DefaultIsMatchOptions; + protected override string DefaultRegexOptions => DefaultIsMatchOptions; public IsMatchImplementation(TimeSpan regexTimeout) { _regexTimeout = regexTimeout; } - protected override FormulaValue InvokeRegexFunction(string input, string regex, RegexOptions options) + internal override FormulaValue InvokeRegexFunction(string input, string regex, RegexOptions options) { - Regex rex = new Regex(regex, options, _regexTimeout); + var regexAltered = AlterRegex_DotNet(regex, options); + Regex rex = new Regex(regexAltered, options, _regexTimeout); bool b = rex.IsMatch(input); return new BooleanValue(IRContext.NotInSource(FormulaType.Boolean), b); @@ -79,16 +72,17 @@ internal class MatchImplementation : RegexCommonImplementation { private readonly TimeSpan _regexTimeout; - protected override string RegexOptions => DefaultMatchOptions; + protected override string DefaultRegexOptions => DefaultMatchOptions; public MatchImplementation(TimeSpan regexTimeout) { _regexTimeout = regexTimeout; } - protected override FormulaValue InvokeRegexFunction(string input, string regex, RegexOptions options) + internal override FormulaValue InvokeRegexFunction(string input, string regex, RegexOptions options) { - Regex rex = new Regex(regex, options, _regexTimeout); + var regexAltered = AlterRegex_DotNet(regex, options); + Regex rex = new Regex(regexAltered, options, _regexTimeout); Match m = rex.Match(input); if (!m.Success) @@ -104,16 +98,17 @@ internal class MatchAllImplementation : RegexCommonImplementation { private readonly TimeSpan _regexTimeout; - protected override string RegexOptions => DefaultMatchAllOptions; + protected override string DefaultRegexOptions => DefaultMatchAllOptions; public MatchAllImplementation(TimeSpan regexTimeout) { _regexTimeout = regexTimeout; } - protected override FormulaValue InvokeRegexFunction(string input, string regex, RegexOptions options) + internal override FormulaValue InvokeRegexFunction(string input, string regex, RegexOptions options) { - Regex rex = new Regex(regex, options, _regexTimeout); + var regexAltered = AlterRegex_DotNet(regex, options); + Regex rex = new Regex(regexAltered, options, _regexTimeout); MatchCollection mc = rex.Matches(input); List records = new (); @@ -126,84 +121,129 @@ protected override FormulaValue InvokeRegexFunction(string input, string regex, } } - private static RecordValue GetRecordFromMatch(Regex rex, Match m, RegexOptions options) + internal abstract class RegexCommonImplementation : IAsyncTexlFunction { - Dictionary fields = new () - { - { FULLMATCH, new NamedValue(FULLMATCH, StringValue.New(m.Value)) }, - { STARTMATCH, new NamedValue(STARTMATCH, NumberValue.New((double)m.Index + 1)) } - }; + internal abstract FormulaValue InvokeRegexFunction(string input, string regex, RegexOptions options); + + protected abstract string DefaultRegexOptions { get; } + + protected const string FULLMATCH = "FullMatch"; + protected const string STARTMATCH = "StartMatch"; + protected const string SUBMATCHES = "SubMatches"; - List subMatches = new List(); - string[] groupNames = rex.GetGroupNames(); + protected const string DefaultIsMatchOptions = "^c$"; + protected const string DefaultMatchOptions = "c"; + protected const string DefaultMatchAllOptions = "c"; - for (int i = 0; i < groupNames.Length; i++) + public Task InvokeAsync(FormulaValue[] args, CancellationToken cancellationToken) { - string groupName = groupNames[i]; - string validName = DName.MakeValid(groupName, out _).Value; - Group g = m.Groups[i]; + cancellationToken.ThrowIfCancellationRequested(); - if (!int.TryParse(groupName, out _)) + if (args[0] is not StringValue && args[0] is not BlankValue) { - if (!fields.ContainsKey(validName)) - { - fields.Add(validName, new NamedValue(validName, StringValue.New(g.Value))); - } - else + return Task.FromResult(args[0] is ErrorValue ? args[0] : CommonErrors.GenericInvalidArgument(args[0].IRContext)); + } + + string regularExpression; + switch (args[1]) + { + case StringValue sv1: + regularExpression = sv1.Value; + break; + case OptionSetValue osv1: + regularExpression = (string)osv1.ExecutionValue; + break; + default: + return Task.FromResult(args[1] is ErrorValue ? args[1] : CommonErrors.GenericInvalidArgument(args[1].IRContext)); + } + + string inputString = args[0] is StringValue sv0 ? sv0.Value : string.Empty; + + string matchOptions; + if (args.Length == 3) + { + switch (args[2]) { - fields[validName] = new NamedValue(validName, StringValue.New(g.Value)); + case StringValue sv3: + matchOptions = sv3.Value; + break; + case OptionSetValue osv3: + matchOptions = (string)osv3.ExecutionValue; + break; + default: + return Task.FromResult(args[2] is ErrorValue ? args[2] : CommonErrors.GenericInvalidArgument(args[2].IRContext)); } } + else + { + matchOptions = DefaultRegexOptions; + } + + RegexOptions regOptions = System.Text.RegularExpressions.RegexOptions.CultureInvariant; - if (i > 0) + if (matchOptions.Contains("i")) { - subMatches.Add(g.Value); + regOptions |= System.Text.RegularExpressions.RegexOptions.IgnoreCase; } - } - if (!fields.ContainsKey(SUBMATCHES) && (options & RegexOptions.ExplicitCapture) == 0) - { - fields.Add(SUBMATCHES, new NamedValue(SUBMATCHES, TableValue.NewSingleColumnTable(subMatches.Select(s => StringValue.New(s)).ToArray()))); - } + if (matchOptions.Contains("m")) + { + regOptions |= System.Text.RegularExpressions.RegexOptions.Multiline; + } - return RecordValue.NewRecordFromFields(fields.Values); - } + if (matchOptions.Contains("^") && !regularExpression.StartsWith("^", StringComparison.Ordinal)) + { + regularExpression = "^" + regularExpression; + } - private static DType GetRecordTypeFromRegularExpression(string regularExpression, RegexOptions regularExpressionOptions) - { - Dictionary propertyNames = new (); - Regex rex = new Regex(regularExpression); + if (matchOptions.Contains("$") && !regularExpression.EndsWith("$", StringComparison.Ordinal)) + { + regularExpression += "$"; + } - propertyNames.Add(FULLMATCH, new TypedName(DType.String, new DName(FULLMATCH))); - propertyNames.Add(STARTMATCH, new TypedName(DType.Number, new DName(STARTMATCH))); - if ((regularExpressionOptions & RegexOptions.ExplicitCapture) == 0) - { - propertyNames.Add(SUBMATCHES, new TypedName(DType.CreateTable(new TypedName(DType.String, new DName(TexlFunction.ColumnName_ValueStr))), new DName(SUBMATCHES))); - } + if (matchOptions.Contains("s")) + { + regOptions |= System.Text.RegularExpressions.RegexOptions.Singleline; + } - foreach (string groupName in rex.GetGroupNames()) - { - if (!int.TryParse(groupName, out _)) + // lack of NumberedSubMatches turns on ExplicitCapture for higher performance + if (!matchOptions.Contains("N")) { - DName validName = DName.MakeValid(groupName, out _); + regOptions |= System.Text.RegularExpressions.RegexOptions.ExplicitCapture; + } - if (!propertyNames.ContainsKey(validName.Value)) + try + { + return Task.FromResult(InvokeRegexFunction(inputString, regularExpression, regOptions)); + } + catch (RegexMatchTimeoutException rexTimeoutEx) + { + return Task.FromResult(new ErrorValue(args[0].IRContext, new ExpressionError() { - propertyNames.Add(validName.Value, new TypedName(DType.String, validName)); - } + Message = $"Regular expression timeout (above {rexTimeoutEx.MatchTimeout.TotalMilliseconds} ms) - {rexTimeoutEx.Message}", + Span = args[0].IRContext.SourceContext, + Kind = ErrorKind.Timeout + })); } - } - return DType.CreateRecord(propertyNames.Values); - } - - internal abstract class RegexCommonImplementation : IAsyncTexlFunction - { - protected abstract FormulaValue InvokeRegexFunction(string input, string regex, RegexOptions options); +#pragma warning disable SA1119 // Statement should not use unnecessary parenthesis + + // Internal exception till .Net 7 where it becomes public + // .Net 4.6.2 will throw ArgumentException + catch (Exception rexParseEx) when ((rexParseEx.GetType().Name.Equals("RegexParseException", StringComparison.OrdinalIgnoreCase)) || rexParseEx is ArgumentException) + { + return Task.FromResult(new ErrorValue(args[1].IRContext, new ExpressionError() + { + Message = $"Invalid regular expression - {rexParseEx.Message}", + Span = args[1].IRContext.SourceContext, + Kind = ErrorKind.BadRegex + })); + } - protected abstract string RegexOptions { get; } +#pragma warning restore SA1119 // Statement should not use unnecessary parenthesis + } - private string AlterNewlineMatching(string regex, RegexOptions options) + protected string AlterRegex_DotNet(string regex, RegexOptions options) { var openCharacterClass = false; // are we defining a character class? var freeSpacing = (options & System.Text.RegularExpressions.RegexOptions.IgnorePatternWhitespace) != 0 || Regex.IsMatch(regex, @"^\(\?[A-Za-z-[x]]*x"); @@ -270,113 +310,75 @@ private string AlterNewlineMatching(string regex, RegexOptions options) return alteredRegex.ToString(); } - public Task InvokeAsync(FormulaValue[] args, CancellationToken cancellationToken) + protected static RecordValue GetRecordFromMatch(Regex rex, Match m, RegexOptions options) { - cancellationToken.ThrowIfCancellationRequested(); - - if (args[0] is not StringValue && args[0] is not BlankValue) + Dictionary fields = new () { - return Task.FromResult(args[0] is ErrorValue ? args[0] : CommonErrors.GenericInvalidArgument(args[0].IRContext)); - } + { FULLMATCH, new NamedValue(FULLMATCH, StringValue.New(m.Value)) }, + { STARTMATCH, new NamedValue(STARTMATCH, NumberValue.New((double)m.Index + 1)) } + }; - string regularExpression; - switch (args[1]) - { - case StringValue sv1: - regularExpression = sv1.Value; - break; - case OptionSetValue osv1: - regularExpression = (string)osv1.ExecutionValue; - break; - default: - return Task.FromResult(args[1] is ErrorValue ? args[1] : CommonErrors.GenericInvalidArgument(args[1].IRContext)); - } + List subMatches = new List(); + string[] groupNames = rex.GetGroupNames(); - string inputString = args[0] is StringValue sv0 ? sv0.Value : string.Empty; - - string matchOptions; - if (args.Length == 3) + for (int i = 0; i < groupNames.Length; i++) { - switch (args[2]) + string groupName = groupNames[i]; + string validName = DName.MakeValid(groupName, out _).Value; + Group g = m.Groups[i]; + + if (!int.TryParse(groupName, out _)) { - case StringValue sv3: - matchOptions = sv3.Value; - break; - case OptionSetValue osv3: - matchOptions = (string)osv3.ExecutionValue; - break; - default: - return Task.FromResult(args[2] is ErrorValue ? args[2] : CommonErrors.GenericInvalidArgument(args[2].IRContext)); + if (!fields.ContainsKey(validName)) + { + fields.Add(validName, new NamedValue(validName, StringValue.New(g.Value))); + } + else + { + fields[validName] = new NamedValue(validName, StringValue.New(g.Value)); + } } - } - else - { - matchOptions = RegexOptions; - } - RegexOptions regOptions = System.Text.RegularExpressions.RegexOptions.CultureInvariant; - - if (matchOptions.Contains("i")) - { - regOptions |= System.Text.RegularExpressions.RegexOptions.IgnoreCase; - } - - if (matchOptions.Contains("m")) - { - regOptions |= System.Text.RegularExpressions.RegexOptions.Multiline; + if (i > 0) + { + subMatches.Add(g.Value); + } } - if (matchOptions.Contains("^") && !regularExpression.StartsWith("^", StringComparison.Ordinal)) + if (!fields.ContainsKey(SUBMATCHES) && (options & RegexOptions.ExplicitCapture) == 0) { - regularExpression = "^" + regularExpression; + fields.Add(SUBMATCHES, new NamedValue(SUBMATCHES, TableValue.NewSingleColumnTable(subMatches.Select(s => StringValue.New(s)).ToArray()))); } - if (matchOptions.Contains("$") && !regularExpression.EndsWith("$", StringComparison.Ordinal)) - { - regularExpression += "$"; - } + return RecordValue.NewRecordFromFields(fields.Values); + } - if (matchOptions.Contains("s")) - { - regOptions |= System.Text.RegularExpressions.RegexOptions.Singleline; - } + protected static DType GetRecordTypeFromRegularExpression(string regularExpression, RegexOptions regularExpressionOptions) + { + Dictionary propertyNames = new (); + Regex rex = new Regex(regularExpression, regularExpressionOptions); - if (!matchOptions.Contains("N")) // lack of NumberedSubMatches turns on ExplicitCapture for higher performance + propertyNames.Add(FULLMATCH, new TypedName(DType.String, new DName(FULLMATCH))); + propertyNames.Add(STARTMATCH, new TypedName(DType.Number, new DName(STARTMATCH))); + if ((regularExpressionOptions & RegexOptions.ExplicitCapture) == 0) { - regOptions |= System.Text.RegularExpressions.RegexOptions.ExplicitCapture; + propertyNames.Add(SUBMATCHES, new TypedName(DType.CreateTable(new TypedName(DType.String, new DName(TexlFunction.ColumnName_ValueStr))), new DName(SUBMATCHES))); } - regularExpression = AlterNewlineMatching(regularExpression, regOptions); - - try + foreach (string groupName in rex.GetGroupNames()) { - return Task.FromResult(InvokeRegexFunction(inputString, regularExpression, regOptions)); - } - catch (RegexMatchTimeoutException rexTimeoutEx) - { - return Task.FromResult(new ErrorValue(args[0].IRContext, new ExpressionError() + if (!int.TryParse(groupName, out _)) { - Message = $"Regular expression timeout (above {rexTimeoutEx.MatchTimeout.TotalMilliseconds} ms) - {rexTimeoutEx.Message}", - Span = args[0].IRContext.SourceContext, - Kind = ErrorKind.Timeout - })); - } + DName validName = DName.MakeValid(groupName, out _); -#pragma warning disable SA1119 // Statement should not use unnecessary parenthesis - - // Internal exception till .Net 7 where it becomes public - // .Net 4.6.2 will throw ArgumentException - catch (Exception rexParseEx) when ((rexParseEx.GetType().Name.Equals("RegexParseException", StringComparison.OrdinalIgnoreCase)) || rexParseEx is ArgumentException) - { - return Task.FromResult(new ErrorValue(args[1].IRContext, new ExpressionError() - { - Message = $"Invalid regular expression - {rexParseEx.Message}", - Span = args[1].IRContext.SourceContext, - Kind = ErrorKind.BadRegex - })); + if (!propertyNames.ContainsKey(validName.Value)) + { + propertyNames.Add(validName.Value, new TypedName(DType.String, validName)); + } + } } -#pragma warning restore SA1119 // Statement should not use unnecessary parenthesis + return DType.CreateRecord(propertyNames.Values); } } } diff --git a/src/strings/PowerFxResources.en-US.resx b/src/strings/PowerFxResources.en-US.resx index 0992f7bfcd..ed58356d9d 100644 --- a/src/strings/PowerFxResources.en-US.resx +++ b/src/strings/PowerFxResources.en-US.resx @@ -4387,10 +4387,18 @@ Invalid regular expression: Literal curly braces must be escaped with a backslash, for example \{ or \}, found "{0}". Error message indicating that the regular expression has literal curly braces. + + Invalid regular expression: Literal square braces must be escaped with a backslash even in character classes, for example \[ or \], found "{0}". + Error message indicating that the regular expression has literal square braces. + Invalid regular expression: Unsupported special group, found "{0}". Error message indicating that the regular expression that starts with a paren. + + Invalid regular expression: Escape character not permitted within character class, found "{0}". + Error message indicating that the regular expression has an escape character within a character class. + Invalid regular expression: Repeated inline option, found "{0}". Error message indicating that the regular expression includes more than one of the same option. diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1Compat.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1Compat.txt index 3ef6a9af28..e76d26d33a 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1Compat.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1Compat.txt @@ -1,15 +1,4 @@ #SETUP: RegEx,PowerFxV1CompatibilityRules -// Dangerous Regex, will timeout (should take >2h on a fast CPU) - but only with Pre-V1 or MatchOptions.NumberedSubMatches ->> IsMatch("ababababababababababababababababababababababababababababababababababa", "^((ab)*)+$", MatchOptions.NumberedSubMatches) -Error({Kind:ErrorKind.Timeout}) - -// but will finish quickly without captures ->> IsMatch("ababababababababababababababababababababababababababababababababababa", "^((ab)*)+$") -false - ->> IsMatch("ababababababababababababababababababababababababababababababababababa", "^((ab)*)+$") -false - >> IsMatch("Foo", "J(") Errors: Error 15-19: Invalid regular expression: Unclosed groups, too few closing parenthesis.|Error 0-7: The function 'IsMatch' has some invalid arguments. diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1CompatDisabled.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1CompatDisabled.txt index d791baebc6..f4c31860e3 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1CompatDisabled.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch_V1CompatDisabled.txt @@ -1,8 +1,4 @@ #SETUP: RegEx,disable:PowerFxV1CompatibilityRules -// Dangerous Regex, will timeout (should take >2h on a fast CPU) - but only with Pre-V1 or MatchOptions.NumberedSubMatches ->> IsMatch("ababababababababababababababababababababababababababababababababababa", "^((ab)*)+$") -Error({Kind:ErrorKind.Timeout}) - >> IsMatch("Foo", "J(") Error({Kind:ErrorKind.BadRegex}) diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt index 447f3960cc..be3c5bb058 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt @@ -23,7 +23,7 @@ // We chose to use canonical .NET instead of RegexOptions.ECMAScript because we wanted the unicode definitions for words. // See https://learn.microsoft.com/dotnet/standard/base-types/regular-expression-options#ecmascript-matching-behavior for more details -// Unicode letters as word characters are allowed +// Unicode letters as word characters are matched >> Match( "the whole world", "\b(\w+\s*)+" ) {FullMatch:"the whole world",StartMatch:1} @@ -37,6 +37,26 @@ >> Match( "Müller", "^\w+$" ) {FullMatch:"Müller",StartMatch:1} +// Unicode numbers as digits are matched + +>> Match( "12345", "^\d+$" ) +{FullMatch:"12345",StartMatch:1} + +>> Match( "12٤45", "^\d+$" ) +{FullMatch:"12٤45",StartMatch:1} + +>> Match( "123४5", "^\d+$" ) +{FullMatch:"123४5",StartMatch:1} + +>> Match( "abc3d", "^\D+" ) +{FullMatch:"abc",StartMatch:1} + +>> Match( "abc٤45", "^\D+" ) +{FullMatch:"abc",StartMatch:1} + +>> Match( "abc४5", "^\D+" ) +{FullMatch:"abc",StartMatch:1} + // Self referencing groups are disallowed >> Match( "aa aaaa aaaaaa ", "((a+)(\1) ?)+" ) @@ -150,6 +170,15 @@ Blank() >> Match( "hello"&Char(13)&Char(10)&"howdy", "(?s)hello.howdy" ) Blank() +>> With( Match( "hello"&Char(10)&"howdy", "hello.howdy", MatchOptions.DotAll ), {StartMatch: StartMatch, LengthMatch: Len(FullMatch)} ) +{LengthMatch:11,StartMatch:1} + +>> With( Match( "hello"&Char(13)&"howdy", "hello.howdy", MatchOptions.DotAll ), {StartMatch: StartMatch, LengthMatch: Len(FullMatch)} ) +{LengthMatch:11,StartMatch:1} + +>> Match( "hello"&Char(13)&Char(10)&"howdy", "hello.howdy", MatchOptions.DotAll ) +Blank() + >> Match( "hello, howdy", "(?x) llo , \s how # comment" ) {FullMatch:"llo, how",StartMatch:3} @@ -233,11 +262,11 @@ Errors: Error 12-17: Invalid regular expression: Square bracket character classe >> Match( "]", "[]]" ) Errors: Error 12-17: Invalid regular expression: Square bracket character classes cannot be empty and cannot include unescaped literal open or close square brackets, escape with "\[" or "\]".|Error 0-5: The function 'Match' has some invalid arguments. ->> Match( "abcdef]ghijk", "[\w]\w]" ) // second closing square bracket is allowed unescaped as it is outside a character class -{FullMatch:"ef]",StartMatch:5} +>> Match( "abcdef]ghijk", "[\w]\w]" ) +Errors: Error 23-32: Invalid regular expression: Literal square braces must be escaped with a backslash even in character classes, for example \[ or \], found "w]".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "a]", "[a]]" ) -{FullMatch:"a]",StartMatch:1} +Errors: Error 13-19: Invalid regular expression: Literal square braces must be escaped with a backslash even in character classes, for example \[ or \], found "]]".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "abcdef]ghijk", "[\w\]\w]" ) // escaped closing square bracket {FullMatch:"a",StartMatch:1} @@ -248,10 +277,10 @@ Errors: Error 12-17: Invalid regular expression: Square bracket character classe >> Match( "]", "[\]]" ) {FullMatch:"]",StartMatch:1} ->> Match( ">test[", "[\w\[\>]+" ) +>> Match( ">test[", "[\w\[>]+" ) {FullMatch:">test[",StartMatch:1} ->> Match( ">test[", "[\w\]\>]+" ) +>> Match( ">test[", "[\w\]>]+" ) {FullMatch:">test",StartMatch:1} // character class subtraction @@ -278,12 +307,27 @@ Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\A" >> Match( "$test atest test", "\btest" ) {FullMatch:"test",StartMatch:2} ->> Match( "$test" & Char(8) & "test", "[\b]test" ) // \b acts differentely in a character class -{FullMatch:"test",StartMatch:6} - >> Match( "$test atest test", "\Btest" ) {FullMatch:"test",StartMatch:8} +>> Match( "$test" & Char(8) & "test", "[\b]test" ) +Errors: Error 35-45: Invalid regular expression: Escape character not permitted within character class, found "[\b]te...".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "$test" & Char(8) & "test", "[\B]test" ) +Errors: Error 35-45: Invalid regular expression: Escape character not permitted within character class, found "[\B]te...".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "$test" & Char(8) & "test", "[\W]test" ) +Errors: Error 35-45: Invalid regular expression: Escape character not permitted within character class, found "[\W]te...".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "$test" & Char(8) & "test", "[\S]test" ) +Errors: Error 35-45: Invalid regular expression: Escape character not permitted within character class, found "[\S]te...".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "$test" & Char(8) & "test", "[\w]test" ) // \w is OK +Blank() + +>> Match( "$test" & Char(8) & "atest", "[\w]test" ) // \w is OK +{FullMatch:"atest",StartMatch:7} + >> DropColumns( Match( "test" & Char(10) & "bed", "\cj" ), FullMatch ) {StartMatch:5} @@ -460,18 +504,74 @@ Errors: Error 15-22: Invalid regular expression: Invalid escape code, found "\p" >> Match( "test", "\P{@}" ) Errors: Error 15-22: Invalid regular expression: Invalid escape code, found "\P".|Error 0-5: The function 'Match' has some invalid arguments. -// Escape is OK for non alpha-numeric characters +// Escape characters acceptable to ECMAScript + +>> Match("^$\.*+?()[]{}|/", "\^\$\\\.\*\+\?\(\)\[\]\{\}\|\/" ) +{FullMatch:"^$\.*+?()[]{}|/",StartMatch:1} + +>> Match("^$\.*+?()[]{}|/", "[\^\$\\\.\*\+\?\(\)\[\]\{\}\|\/]+" ) +{FullMatch:"^$\.*+?()[]{}|/",StartMatch:1} + +// Escape characters that are blocked + +>> Match( "!@#%&=-`~><';:,""", "\!" ) +Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\!".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "!@#%&=-`~><';:,""", "\@" ) +Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\@".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "!@#%&=-`~><';:,""", "\#" ) +Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\#".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "!@#%&=-`~><';:,""", "\%" ) +Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\%".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "!@#%&=-`~><';:,""", "\&" ) +Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\&".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "!@#%&=-`~><';:,""", "\=" ) +Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\=".|Error 0-5: The function 'Match' has some invalid arguments. ->> Match( "!@#$%^&*()[]{}+=-`~/><';:,.""", "\!\@\#\$\%\^\&\*\(\)\[\]\{\}\+\=\-\`\~\/\>\<\'\;\:\,\.\""" ) -{FullMatch:"!@#$%^&*()[]{}+=-`~/><';:,.""",StartMatch:1} +>> Match( "!@#%&=-`~><';:,""", "\-" ) +Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\-".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "!@#%&=-`~><';:,""", "\`" ) +Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\`".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "!@#%&=-`~><';:,""", "\~" ) +Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\~".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "!@#%&=-`~><';:,""", "\>" ) +Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\>".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "!@#%&=-`~><';:,""", "\<" ) +Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\<".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "!@#%&=-`~><';:,""", "\'" ) +Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\'".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "!@#%&=-`~><';:,""", "\;" ) +Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\;".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "!@#%&=-`~><';:,""", "\:" ) +Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\:".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "!@#%&=-`~><';:,""", "\," ) +Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\,".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "!@#%&=-`~><';:,""", "\""" ) +Errors: Error 28-33: Invalid regular expression: Invalid escape code, found "\"".|Error 0-5: The function 'Match' has some invalid arguments. // Inline comments >> Match( "test", "(?# this is a test)st" ) {FullMatch:"st",StartMatch:3} ->> Match( "test", "(?# this is a test ( with an open paren)st" ) -Errors: Error 15-59: Invalid regular expression: Inline comments cannot include open parenthesis, found in "(?# this is a test ( with an open paren)".|Error 0-5: The function 'Match' has some invalid arguments. +>> Match( "test", "(?# this is a test ( with an open paren )st" ) +Errors: Error 15-60: Invalid regular expression: Inline comments cannot include open parenthesis, found in "(?# this is a test ( with an open paren )".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "(?# this is a test \) with an escaped close paren )st" ) // can't escape a paren in an inline comment +Errors: Error 15-70: Invalid regular expression: Unopened groups, too few opening parenthesis.|Error 0-5: The function 'Match' has some invalid arguments. // Can't define named capture group more than once diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index 8a1ce9e9c3..eeb254454a 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -91,6 +91,20 @@ public void None_Float(ExpressionTestCase testCase) } #endif + // used by the following test run, but needs to be outside the #if for standard usage + public static bool RegExCompareEnabled = false; + +#if false + // This test run will compare the results between .NET, NodeJS with JavaScript (used in Canvas), and PCRE2 (used in Excel) + [TxtFileData("ExpressionTestCases", "InterpreterExpressionTestCases", nameof(InterpreterRunner), "PowerFxV1,disable:NumberIsFloat,DecimalSupport,RegEx")] + [InterpreterTheory] + public void RegExCompare(ExpressionTestCase t) + { + RegExCompareEnabled = true; + RunExpressionTestCase(t, Features.PowerFxV1, numberIsFloat: false, Console); + } +#endif + private static string _currentNetVersion = null; private static readonly object _cnvLock = new object(); diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_Compare.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_Compare.cs new file mode 100644 index 0000000000..c956895187 --- /dev/null +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_Compare.cs @@ -0,0 +1,124 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +// This file compares the results from .NET, PCRE2, and NODEJS. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using Microsoft.PowerFx.Core.Functions; +using Microsoft.PowerFx.Core.Texl.Builtins; +using Microsoft.PowerFx.Types; +using static Microsoft.PowerFx.Functions.RegEx_NodeJS; +using static Microsoft.PowerFx.Functions.RegEx_PCRE2; + +namespace Microsoft.PowerFx.Functions +{ + public class RegEx_Compare + { + public static void EnableRegExFunctions(PowerFxConfig config, TimeSpan regExTimeout = default, int regexCacheSize = -1) + { + RegexTypeCache regexTypeCache = new (regexCacheSize); + + foreach (KeyValuePair func in RegexFunctions(regExTimeout, regexTypeCache)) + { + if (config.SymbolTable.Functions.AnyWithName(func.Key.Name)) + { + throw new InvalidOperationException("Cannot add RegEx functions more than once."); + } + + config.SymbolTable.AddFunction(func.Key); + config.AdditionalFunctions.Add(func.Key, func.Value); + } + } + + internal static Dictionary RegexFunctions(TimeSpan regexTimeout, RegexTypeCache regexCache) + { + if (regexTimeout == TimeSpan.Zero) + { + regexTimeout = new TimeSpan(0, 0, 1); + } + + if (regexTimeout.TotalMilliseconds < 0) + { + throw new ArgumentOutOfRangeException(nameof(regexTimeout), "Timeout duration for regular expression execution must be positive."); + } + + return new Dictionary() + { + { new IsMatchFunction(), new Compare_IsMatchImplementation(regexTimeout) }, + { new MatchFunction(regexCache), new Compare_MatchImplementation(regexTimeout) }, + { new MatchAllFunction(regexCache), new Compare_MatchAllImplementation(regexTimeout) } + }; + } + + internal abstract class Compare_CommonImplementation : Library.RegexCommonImplementation + { + protected Library.RegexCommonImplementation node; + protected Library.RegexCommonImplementation pcre2; + protected Library.RegexCommonImplementation dotnet; + + internal override FormulaValue InvokeRegexFunction(string input, string regex, RegexOptions options) + { + var nodeMatch = node.InvokeRegexFunction(input, regex, options); + var nodeExpr = nodeMatch.ToExpression(); + + var pcre2Match = pcre2.InvokeRegexFunction(input, regex, options); + var pcre2Expr = pcre2Match.ToExpression(); + + var dotnetMatch = dotnet.InvokeRegexFunction(input, regex, options); + var dotnetExpr = dotnetMatch.ToExpression(); + + if (nodeExpr != dotnetExpr) + { + throw new Exception($"node != net on input='{input}', re='{regex}', options='{options}', node='{nodeExpr}', net='{dotnetExpr}'"); + } + + if (pcre2Expr != dotnetExpr) + { + throw new Exception($"pcre2 != net on input='{input}', re='{regex}', options='{options}', pcre2='{pcre2Expr}', net='{dotnetExpr}'"); + } + + return dotnetMatch; + } + } + + internal class Compare_IsMatchImplementation : Compare_CommonImplementation + { + protected override string DefaultRegexOptions => DefaultIsMatchOptions; + + internal Compare_IsMatchImplementation(TimeSpan regexTimeout) + { + node = new NodeJS_IsMatchImplementation(regexTimeout); + pcre2 = new PCRE2_IsMatchImplementation(regexTimeout); + dotnet = new Library.IsMatchImplementation(regexTimeout); + } + } + + internal class Compare_MatchImplementation : Compare_CommonImplementation + { + protected override string DefaultRegexOptions => DefaultMatchOptions; + + internal Compare_MatchImplementation(TimeSpan regexTimeout) + { + node = new NodeJS_MatchImplementation(regexTimeout); + pcre2 = new PCRE2_MatchImplementation(regexTimeout); + dotnet = new Library.MatchImplementation(regexTimeout); + } + } + + internal class Compare_MatchAllImplementation : Compare_CommonImplementation + { + protected override string DefaultRegexOptions => DefaultMatchAllOptions; + + internal Compare_MatchAllImplementation(TimeSpan regexTimeout) + { + node = new NodeJS_MatchAllImplementation(regexTimeout); + pcre2 = new PCRE2_MatchAllImplementation(regexTimeout); + dotnet = new Library.MatchAllImplementation(regexTimeout); + } + } + } +} diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs new file mode 100644 index 0000000000..51a8ab1d6c --- /dev/null +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs @@ -0,0 +1,446 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +// This file implements our Regular Expression functions using ECMAScript hosted by Node.js. +// We run tests with this to find semantic differences between our regular expression language and what the JavaScript runtime (Canvas) supports. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Text.RegularExpressions; +using Microsoft.CodeAnalysis.Differencing; +using Microsoft.PowerFx.Core.Functions; +using Microsoft.PowerFx.Core.IR; +using Microsoft.PowerFx.Core.Texl.Builtins; +using Microsoft.PowerFx.Types; + +namespace Microsoft.PowerFx.Functions +{ + public class RegEx_NodeJS + { + internal abstract class NodeJS_RegexCommonImplementation : Library.RegexCommonImplementation + { + internal static FormulaValue Match(string subject, string pattern, RegexOptions options, bool matchAll = false) + { + StringBuilder flags = new StringBuilder(); + + // RegexOptions.ExplicitCapture -> "n" is not done as ECMAScript does not support this flag + + if ((options & RegexOptions.IgnoreCase) != 0) + { + flags.Append("i"); + } + + if ((options & RegexOptions.Multiline) != 0) + { + flags.Append("m"); + } + + if ((options & RegexOptions.Singleline) != 0) + { + flags.Append("s"); + } + + if ((options & RegexOptions.IgnorePatternWhitespace) != 0) + { + flags.Append("x"); + } + + var js = new StringBuilder(); + + js.AppendLine($"const subject='{subject.Replace("\\", "\\\\").Replace("\r", "\\r").Replace("\n", "\\n").Replace("'", "\\'")}';"); + js.AppendLine($"const pattern='{pattern.Replace("\\", "\\\\").Replace("\r", "\\r").Replace("\n", "\\n").Replace("'", "\\'")}';"); + js.AppendLine($"const flags='{flags}';"); + js.AppendLine($"const matchAll={(matchAll ? "true" : "false")};"); + +#if false + // for debugging unicode passing of strings to Node, output ignored by deserializer but visible in the debugger + js.AppendLine(@" + for (var i = 0; i < subject.length; i++) + { + console.log(subject[i] + '> ' + subject.charCodeAt(i).toString(16)); + } + "); +#endif + + js.AppendLine(@" + const [alteredPattern, alteredFlags] = AlterRegex_NodeJS( pattern, flags ); + const regex = RegExp(alteredPattern, alteredFlags.concat(matchAll ? 'g' : '')); + const matches = matchAll ? [...subject.matchAll(regex)] : [subject.match(regex)]; + for(const match of matches) + { + if (match != null) + { + console.log('%start%:' + match.index); + for(var group in match.groups) + { + var val = match.groups[group]; + if (val === undefined) + { + val = ''; + } + console.log(group + ':""' + val.replace( / "" /, '""""') + '""'); + } + for (var num = 0; num < match.length; num++) + { + var val = match[num]; + if (val === undefined) + { + val = ''; + } + console.log(num + ':""' + val.replace( / "" /, '""""') + '""'); + } + console.log('%end%:'); + } + } + console.log('%done%:'); + "); + + var node = new Process(); + node.StartInfo.FileName = "node.exe"; + node.StartInfo.RedirectStandardInput = true; + node.StartInfo.RedirectStandardOutput = true; + node.StartInfo.RedirectStandardError = true; + node.StartInfo.CreateNoWindow = true; + node.StartInfo.UseShellExecute = false; + node.StartInfo.StandardOutputEncoding = System.Text.Encoding.UTF8; + + // Not supported by .NET framework 4.6.2, we need to use the manual GetBytes method below + // node.StartInfo.StandardInputEncoding = System.Text.Encoding.UTF8; + + node.Start(); + + var jsString = js.ToString(); + var bytes = Encoding.UTF8.GetBytes(AlterRegex_NodeJS_Src + jsString); + node.StandardInput.BaseStream.Write(bytes, 0, bytes.Length); + node.StandardInput.WriteLine(); + node.StandardInput.Close(); + + string output = node.StandardOutput.ReadToEnd(); + string error = node.StandardError.ReadToEnd(); + + node.WaitForExit(); + node.Dispose(); + + if (error.Length > 0) + { + throw new InvalidOperationException(error); + } + + var outputRE = new Regex( + @" + ^%start%:(?[-\d]+)$ | + ^(?%end%): | + ^(?%done%): | + ^(?\d+):""(?(""""|[^""])*)""$ | + ^(?[^:]+):""(?(""""|[^""])*)""$ + ", RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace); + + List subMatches = new (); + Dictionary fields = new (); + List allMatches = new (); + + foreach (Match token in outputRE.Matches(output)) + { + if (token.Groups["end"].Success) + { + if ((options & RegexOptions.ExplicitCapture) == 0) + { + fields.Add(SUBMATCHES, new NamedValue(SUBMATCHES, TableValue.NewSingleColumnTable(subMatches.Select(s => StringValue.New(s)).ToArray()))); + } + + allMatches.Add(RecordValue.NewRecordFromFields(fields.Values)); + } + if (token.Groups["done"].Success) + { + if (allMatches.Count == 0) + { + return matchAll ? FormulaValue.NewTable(new KnownRecordType(GetRecordTypeFromRegularExpression(pattern, options))) + : new BlankValue(IRContext.NotInSource(new KnownRecordType(GetRecordTypeFromRegularExpression(pattern, options)))); + } + else + { + return matchAll ? FormulaValue.NewTable(allMatches.First().Type, allMatches) + : allMatches.First(); + } + } + else if (token.Groups["start"].Success) + { + fields = new (); + subMatches = new (); + fields.Add(STARTMATCH, new NamedValue(STARTMATCH, NumberValue.New(Convert.ToDouble(token.Groups["start"].Value) + 1))); + } + else if (token.Groups["name"].Success) + { + fields.Add(token.Groups["name"].Value, new NamedValue(token.Groups["name"].Value, StringValue.New(token.Groups["nameMatch"].Value.Replace(@"""""", @"""")))); + } + else if (token.Groups["num"].Success) + { + var num = Convert.ToInt32(token.Groups["num"].Value); + if (num == 0) + { + fields.Add(FULLMATCH, new NamedValue(FULLMATCH, StringValue.New(token.Groups["numMatch"].Value.Replace(@"""""", @"""")))); + } + else + { + subMatches.Add(token.Groups["numMatch"].Value.Replace(@"""""", @"""")); + } + } + } + + throw new Exception("%done% marker not found"); + } + + // This JavaScript function assumes that the regular expression has already been compiled and comforms to the Power Fx regular expression language. + // For example, no affodance is made for nested character classes or inline options on a subexpression, as those would have already been blocked. + private const string AlterRegex_NodeJS_Src = @" + function AlterRegex_NodeJS(regex, flags) + { + var regexIndex = 0; + + const inlineFlagsRE = /^\(\?(?[imsx]+)\)/; + const inlineFlags = inlineFlagsRE.exec( regex ); + if (inlineFlags != null) + { + flags = flags.concat(inlineFlags.groups['flags']); + regexIndex = inlineFlags[0].length; + } + + const freeSpacing = flags.includes('x'); + const multiline = flags.includes('m'); + const dotAll = flags.includes('s'); + const ignoreCase = flags.includes('i'); + + // rebuilding from booleans avoids possible duplicate letters + // x has been handled in this function and does not need to be passed on (and would cause an error) + const alteredFlags = 'u'.concat((ignoreCase ? 'i' : ''), (multiline ? 'm' : ''), (dotAll ? 's' : '')); + + var openCharacterClass = false; // are we defining a character class? + var altered = ''; + + for ( ; regexIndex < regex.length; regexIndex++) + { + switch (regex.charAt(regexIndex) ) + { + case '[': + openCharacterClass = true; + altered = altered.concat('['); + break; + + case ']': + openCharacterClass = false; + altered = altered.concat(']'); + break; + + case '\\': + if (++regexIndex < regex.length) + { + const letterChar = '\\p{Ll}\\p{Lu}\\p{Lt}\\p{Lo}\\p{Lm}\\p{Nd}\\p{Pc}'; + const wordChar = '(?:(?:\\p{L}\\p{M}*)|\\p{N}|_)'; + const spaceChar = '\\f\\n\\r\\t\\v\\x85\\p{Z}'; + const digitChar = '\\p{Nd}'; + + switch (regex.charAt(regexIndex)) + { + case 'w': + altered = altered.concat((openCharacterClass ? '' : '['), letterChar, (openCharacterClass ? '' : ']')); + break; + case 'W': + altered = altered.concat('[^', letterChar, ']'); + break; + + case 'b': + altered = altered.concat(`(?:(?<=${wordChar})(?!${wordChar})|(? 2 && regex.charAt(regexIndex+1) == '?' && regex.charAt(regexIndex+2) == '#') + { + // inline comment + for ( regexIndex++; regexIndex < regex.length && regex.charAt(regexIndex) != ')'; regexIndex++) + { + // eat characters until a close paren, it doesn't matter if it is escaped (consistent with .NET) + } + } + else + { + altered = altered.concat('('); + } + + break; + + case ' ': + case '\f': + case '\n': + case '\r': + case '\t': + case '\v': + if (!freeSpacing) + { + altered = altered.concat(regex.charAt(regexIndex)); + } + + break; + + case '#': + if (freeSpacing) + { + for ( regexIndex++; regexIndex < regex.length && regex.charAt(regexIndex) != '\r' && regex.charAt(regexIndex) != '\n'; regexIndex++) + { + // eat characters until the end of the line + // leaving dangling whitespace characters will be eaten on next iteration + } + } + else + { + altered = altered.concat('#'); + } + + break; + + default: + altered = altered.concat(regex.charAt(regexIndex)); + break; + } + } + + return [altered, alteredFlags]; + } + "; + } + + public static void EnableRegExFunctions(PowerFxConfig config, TimeSpan regExTimeout = default, int regexCacheSize = -1) + { + RegexTypeCache regexTypeCache = new (regexCacheSize); + + foreach (KeyValuePair func in RegexFunctions(regExTimeout, regexTypeCache)) + { + if (config.SymbolTable.Functions.AnyWithName(func.Key.Name)) + { + throw new InvalidOperationException("Cannot add RegEx functions more than once."); + } + + config.SymbolTable.AddFunction(func.Key); + config.AdditionalFunctions.Add(func.Key, func.Value); + } + } + + internal static Dictionary RegexFunctions(TimeSpan regexTimeout, RegexTypeCache regexCache) + { + if (regexTimeout == TimeSpan.Zero) + { + regexTimeout = new TimeSpan(0, 0, 1); + } + + if (regexTimeout.TotalMilliseconds < 0) + { + throw new ArgumentOutOfRangeException(nameof(regexTimeout), "Timeout duration for regular expression execution must be positive."); + } + + return new Dictionary() + { + { new IsMatchFunction(), new NodeJS_IsMatchImplementation(regexTimeout) }, + { new MatchFunction(regexCache), new NodeJS_MatchImplementation(regexTimeout) }, + { new MatchAllFunction(regexCache), new NodeJS_MatchAllImplementation(regexTimeout) } + }; + } + + internal class NodeJS_IsMatchImplementation : NodeJS_RegexCommonImplementation + { + private readonly TimeSpan _regexTimeout; + + protected override string DefaultRegexOptions => DefaultIsMatchOptions; + + public NodeJS_IsMatchImplementation(TimeSpan regexTimeout) + { + _regexTimeout = regexTimeout; + } + + internal override FormulaValue InvokeRegexFunction(string input, string regex, RegexOptions options) + { + var match = Match(input, regex, options); + + return new BooleanValue(IRContext.NotInSource(FormulaType.Boolean), !match.IsBlank()); + } + } + + internal class NodeJS_MatchImplementation : NodeJS_RegexCommonImplementation + { + private readonly TimeSpan _regexTimeout; + + protected override string DefaultRegexOptions => DefaultMatchOptions; + + public NodeJS_MatchImplementation(TimeSpan regexTimeout) + { + _regexTimeout = regexTimeout; + } + + internal override FormulaValue InvokeRegexFunction(string input, string regex, RegexOptions options) + { + return Match(input, regex, options); + } + } + + internal class NodeJS_MatchAllImplementation : NodeJS_RegexCommonImplementation + { + private readonly TimeSpan _regexTimeout; + + protected override string DefaultRegexOptions => DefaultMatchAllOptions; + + public NodeJS_MatchAllImplementation(TimeSpan regexTimeout) + { + _regexTimeout = regexTimeout; + } + + internal override FormulaValue InvokeRegexFunction(string input, string regex, RegexOptions options) + { + return Match(input, regex, options, matchAll: true); + } + } + } +} diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs new file mode 100644 index 0000000000..21cef3b78e --- /dev/null +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs @@ -0,0 +1,276 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +// This file implements our Regular Expression functions using PCRE2 instead of .NET. +// We run tests with this to find semantic differences between our regular expression language and what Excel supports. +// To run this code, make sure that pcre2-16d.dll in your path, built from https://github.com/PCRE2Project/pcre2 +// with cmake , shared library, + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Text.RegularExpressions; +using Microsoft.PowerFx.Core.Functions; +using Microsoft.PowerFx.Core.IR; +using Microsoft.PowerFx.Core.Texl.Builtins; +using Microsoft.PowerFx.Types; + +namespace Microsoft.PowerFx.Functions +{ + public class RegEx_PCRE2 + { + internal abstract class PCRE2_RegexCommonImplementation : Library.RegexCommonImplementation + { + internal static class NativeMethods + { + [DllImport("pcre2-16d.dll", CharSet = CharSet.Unicode)] + [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] + internal static extern IntPtr pcre2_compile_16(string pattern, int patternLength, uint patternOptions, ref int errorNumber, ref int errorOffset, IntPtr context); + + [DllImport("pcre2-16d.dll", CharSet = CharSet.Unicode)] + [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] + internal static extern int pcre2_match_16(IntPtr code, string subject, int subjectLength, int subjectOffset, uint subjectOptions, IntPtr matchData, IntPtr matchContext); + + [DllImport("pcre2-16d.dll")] + [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] + internal static extern IntPtr pcre2_match_data_create_16(int ovecSize, IntPtr generalContext); + + [DllImport("pcre2-16d.dll")] + [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] + internal static extern IntPtr pcre2_match_data_create_from_pattern_16(IntPtr code, IntPtr generalContext); + + [DllImport("pcre2-16d.dll")] + [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] + internal static extern int pcre2_get_startchar_16(IntPtr matchData); + + [DllImport("pcre2-16d.dll")] + [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] + internal static extern int pcre2_get_ovector_count_16(IntPtr matchData); + + [DllImport("pcre2-16d.dll")] + [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] + internal static extern IntPtr pcre2_get_ovector_pointer_16(IntPtr matchData); + + [DllImport("pcre2-16d.dll", CharSet = CharSet.Unicode)] + [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] + internal static extern int pcre2_substring_number_from_name_16(IntPtr code, string name); + + [DllImport("pcre2-16d.dll", CharSet = CharSet.Unicode)] + [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] + internal static extern void pcre2_match_data_free_16(IntPtr data); + + [DllImport("pcre2-16d.dll", CharSet = CharSet.Unicode)] + [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] + internal static extern void pcre2_code_free_16(IntPtr code); + } + + internal enum PCRE2_OPTIONS : uint + { + CASELESS = 0x00000008, + MULTILINE = 0x00000400, + DOTALL = 0x00000020, + EXTENDED = 0x00000080, + UCP = 0x00020000, + UTF = 0x00080000, + NO_AUTO_CAPTURE = 0x00002000, + } + + internal static FormulaValue Match(string subject, string pattern, RegexOptions options, bool matchAll = false) + { + int errorNumber = 0; + int errorOffset = 0; + IntPtr context = (IntPtr)0; + IntPtr matchContext = (IntPtr)0; + IntPtr generalContext = (IntPtr)0; + + PCRE2_OPTIONS pcreOptions = PCRE2_OPTIONS.UCP; + + if ((options & RegexOptions.ExplicitCapture) != 0) + { + pcreOptions |= PCRE2_OPTIONS.NO_AUTO_CAPTURE; + } + + if ((options & RegexOptions.IgnoreCase) != 0) + { + pcreOptions |= PCRE2_OPTIONS.CASELESS; + } + + if ((options & RegexOptions.Multiline) != 0) + { + pcreOptions |= PCRE2_OPTIONS.MULTILINE; + } + + if ((options & RegexOptions.Singleline) != 0) + { + pcreOptions |= PCRE2_OPTIONS.DOTALL; + } + + if ((options & RegexOptions.IgnorePatternWhitespace) != 0) + { + pcreOptions |= PCRE2_OPTIONS.EXTENDED; + } + + var patternPCRE2 = Regex.Replace(pattern, @"\\u(?\w\w\w\w)", @"\x{${hex}}"); + var code = NativeMethods.pcre2_compile_16(patternPCRE2, -1, (uint)pcreOptions, ref errorNumber, ref errorOffset, context); + var md = NativeMethods.pcre2_match_data_create_from_pattern_16(code, generalContext); + + var startMatch = 0; + List allMatches = new (); + + while (startMatch >= 0 && NativeMethods.pcre2_match_16(code, subject, -1, startMatch, 0, md, matchContext) > 0) + { + Dictionary fields = new (); + + var sc = NativeMethods.pcre2_get_startchar_16(md); + fields.Add(STARTMATCH, new NamedValue(STARTMATCH, NumberValue.New((double)sc + 1))); + + IntPtr op = NativeMethods.pcre2_get_ovector_pointer_16(md); + var start0 = Marshal.ReadInt32(op, 0); + var end0 = Marshal.ReadInt32(op, Marshal.SizeOf(typeof(long))); + fields.Add(FULLMATCH, new NamedValue(FULLMATCH, StringValue.New(subject.Substring(start0, end0 - start0)))); + startMatch = matchAll ? end0 : -1; // for next iteration + + List subMatches = new List(); + var oc = NativeMethods.pcre2_get_ovector_count_16(md); + for (var i = 1; i < oc; i++) + { + var start = Marshal.ReadInt32(op, i * 2 * Marshal.SizeOf(typeof(long))); + var end = Marshal.ReadInt32(op, ((i * 2) + 1) * Marshal.SizeOf(typeof(long))); + if (start >= 0 && end >= 0) + { + subMatches.Add(subject.Substring(start, end - start)); + } + else + { + subMatches.Add(string.Empty); + } + } + + if (!fields.ContainsKey(SUBMATCHES) && (options & RegexOptions.ExplicitCapture) == 0) + { + fields.Add(SUBMATCHES, new NamedValue(SUBMATCHES, TableValue.NewSingleColumnTable(subMatches.Select(s => StringValue.New(s)).ToArray()))); + } + else + { + var regex = new Regex(pattern, options); + foreach (var name in regex.GetGroupNames()) + { + if (!int.TryParse(name, out _)) + { + var ni = NativeMethods.pcre2_substring_number_from_name_16(code, name); + fields.Add(name, new NamedValue(name, StringValue.New(subMatches[ni - 1]))); + } + } + } + + allMatches.Add(RecordValue.NewRecordFromFields(fields.Values)); + } + + NativeMethods.pcre2_match_data_free_16(md); + NativeMethods.pcre2_code_free_16(code); + + if (allMatches.Count == 0) + { + return matchAll ? FormulaValue.NewTable(new KnownRecordType(GetRecordTypeFromRegularExpression(pattern, options))) + : new BlankValue(IRContext.NotInSource(new KnownRecordType(GetRecordTypeFromRegularExpression(pattern, options)))); + } + else + { + return matchAll ? FormulaValue.NewTable(allMatches.First().Type, allMatches) + : allMatches.First(); + } + } + } + + public static void EnableRegExFunctions(PowerFxConfig config, TimeSpan regExTimeout = default, int regexCacheSize = -1) + { + RegexTypeCache regexTypeCache = new (regexCacheSize); + + foreach (KeyValuePair func in RegexFunctions(regExTimeout, regexTypeCache)) + { + if (config.SymbolTable.Functions.AnyWithName(func.Key.Name)) + { + throw new InvalidOperationException("Cannot add RegEx functions more than once."); + } + + config.SymbolTable.AddFunction(func.Key); + config.AdditionalFunctions.Add(func.Key, func.Value); + } + } + + internal static Dictionary RegexFunctions(TimeSpan regexTimeout, RegexTypeCache regexCache) + { + if (regexTimeout == TimeSpan.Zero) + { + regexTimeout = new TimeSpan(0, 0, 1); + } + + if (regexTimeout.TotalMilliseconds < 0) + { + throw new ArgumentOutOfRangeException(nameof(regexTimeout), "Timeout duration for regular expression execution must be positive."); + } + + return new Dictionary() + { + { new IsMatchFunction(), new PCRE2_IsMatchImplementation(regexTimeout) }, + { new MatchFunction(regexCache), new PCRE2_MatchImplementation(regexTimeout) }, + { new MatchAllFunction(regexCache), new PCRE2_MatchAllImplementation(regexTimeout) } + }; + } + + internal class PCRE2_IsMatchImplementation : PCRE2_RegexCommonImplementation + { + private readonly TimeSpan _regexTimeout; + + protected override string DefaultRegexOptions => DefaultIsMatchOptions; + + public PCRE2_IsMatchImplementation(TimeSpan regexTimeout) + { + _regexTimeout = regexTimeout; + } + + internal override FormulaValue InvokeRegexFunction(string input, string regex, RegexOptions options) + { + var match = Match(input, regex, options); + + return new BooleanValue(IRContext.NotInSource(FormulaType.Boolean), !match.IsBlank()); + } + } + + internal class PCRE2_MatchImplementation : PCRE2_RegexCommonImplementation + { + private readonly TimeSpan _regexTimeout; + + protected override string DefaultRegexOptions => DefaultMatchOptions; + + public PCRE2_MatchImplementation(TimeSpan regexTimeout) + { + _regexTimeout = regexTimeout; + } + + internal override FormulaValue InvokeRegexFunction(string input, string regex, RegexOptions options) + { + return Match(input, regex, options); + } + } + + internal class PCRE2_MatchAllImplementation : PCRE2_RegexCommonImplementation + { + private readonly TimeSpan _regexTimeout; + + protected override string DefaultRegexOptions => DefaultMatchAllOptions; + + public PCRE2_MatchAllImplementation(TimeSpan regexTimeout) + { + _regexTimeout = regexTimeout; + } + + internal override FormulaValue InvokeRegexFunction(string input, string regex, RegexOptions options) + { + return Match(input, regex, options, matchAll: true); + } + } + } +} diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/PowerFxEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/PowerFxEvaluationTests.cs index 4ff4f5b7db..95e760b7b6 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/PowerFxEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/PowerFxEvaluationTests.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; using System.Drawing; using System.Globalization; using System.Linq; @@ -66,9 +67,16 @@ private static object EnableJsonFunctions(PowerFxConfig config, SymbolTable symb private static object RegExSetup(PowerFxConfig config, SymbolTable symbolTable) { + if (FileExpressionEvaluationTests.RegExCompareEnabled) + { + Functions.RegEx_Compare.EnableRegExFunctions(config, new TimeSpan(0, 0, 5)); + } + else + { #pragma warning disable CS0618 // Type or member is obsolete - config.EnableRegExFunctions(new TimeSpan(0, 0, 5)); + config.EnableRegExFunctions(new TimeSpan(0, 0, 5)); #pragma warning restore CS0618 // Type or member is obsolete + } return null; } diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/RegExTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/RegExTests.cs index c5d3207807..42bf550f14 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/RegExTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/RegExTests.cs @@ -2,6 +2,10 @@ // Licensed under the MIT license. using System; +using System.Linq; +using System.Security.Cryptography.X509Certificates; +using Microsoft.PowerFx.Types; +using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Serialization; using Xunit; namespace Microsoft.PowerFx.Interpreter.Tests @@ -46,5 +50,34 @@ public void TestRegExEnableTwice2() PowerFxConfig config2 = new PowerFxConfig(); config2.EnableRegExFunctions(TimeSpan.FromMilliseconds(50), 20); } + + // First of these iss a dangerous Regex, will timeout (should take >2h on a fast CPU) - but only MatchOptions.NumberedSubMatches + [Theory] + [InlineData("ababababababababababababababababababababababababababababababababababa", "^((ab)*)+$", true, true, true)] + [InlineData("ababababababababababababababababababababababababababababababababababa", "^((ab)*)+$", false, false, false)] + [InlineData("ababababababababababababababababababababababababababababababababababa", "^((ab)*)+$", false, false, false)] + public void TestRegExTimeoutWorks(string subject, string pattern, bool subMatches, bool expError, bool expBoolean) + { + PowerFxConfig config = new PowerFxConfig(); + config.EnableRegExFunctions(new TimeSpan(0, 0, 5)); + RecalcEngine engine = new RecalcEngine(config); + + var formula = $"IsMatch(\"{subject}\", \"{pattern}\" {(subMatches ? ", MatchOptions.NumberedSubMatches" : string.Empty)})"; + + FormulaValue fv = engine.Eval(formula, null, new ParserOptions { AllowsSideEffects = true }); + + if (expError) + { + Assert.True(fv is ErrorValue); + ErrorValue ev = (ErrorValue)fv; + Assert.Equal(ErrorKind.Timeout, ev.Errors.First().Kind); + } + else + { + Assert.True(fv is BooleanValue); + BooleanValue bv = (BooleanValue)fv; + Assert.Equal(expBoolean, bv.Value); + } + } } } diff --git a/src/tools/Repl/Program.cs b/src/tools/Repl/Program.cs index 63ee94d22a..6c24d0e2f1 100644 --- a/src/tools/Repl/Program.cs +++ b/src/tools/Repl/Program.cs @@ -40,6 +40,9 @@ public static class ConsoleRepl private const string OptionTextFirst = "TextFirst"; private static bool _textFirst = false; + private const string OptionRegExCompare = "RegExCompare"; + private static bool _regExCompare = false; + private static readonly Features _features = Features.PowerFxV1; private static StandardFormatter _standardFormatter; @@ -66,7 +69,8 @@ private static RecalcEngine ReplRecalcEngine() { OptionPowerFxV1, OptionPowerFxV1 }, { OptionHashCodes, OptionHashCodes }, { OptionStackTrace, OptionStackTrace }, - { OptionTextFirst, OptionTextFirst } + { OptionTextFirst, OptionTextFirst }, + { OptionRegExCompare, OptionRegExCompare }, }; foreach (var featureProperty in typeof(Features).GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) @@ -96,9 +100,18 @@ private static RecalcEngine ReplRecalcEngine() var optionsSet = new OptionSet("Options", DisplayNameUtility.MakeUnique(options)); + if (_regExCompare) + { + // requires PCRE2 DLL (pcre2-16d.dll) on the path and Node.JS installed + // can also use RegEx_PCRE2 and RegEx_NodeJS directly too + Functions.RegEx_Compare.EnableRegExFunctions(config, new TimeSpan(0, 0, 5)); + } + else + { #pragma warning disable CS0618 // Type or member is obsolete - config.EnableRegExFunctions(new TimeSpan(0, 0, 5)); + config.EnableRegExFunctions(new TimeSpan(0, 0, 5)); #pragma warning restore CS0618 // Type or member is obsolete + } config.AddOptionSet(optionsSet); @@ -369,6 +382,13 @@ public FormulaValue Execute(StringValue option, BooleanValue value) return value; } + if (string.Equals(option.Value, OptionRegExCompare, StringComparison.OrdinalIgnoreCase)) + { + _regExCompare = value.Value; + _reset = true; + return value; + } + if (string.Equals(option.Value, OptionPowerFxV1, StringComparison.OrdinalIgnoreCase)) { foreach (var prop in typeof(Features).GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) diff --git a/src/tools/Repl/Repl.csproj b/src/tools/Repl/Repl.csproj index c8f1f2f87e..6cd59dab8e 100644 --- a/src/tools/Repl/Repl.csproj +++ b/src/tools/Repl/Repl.csproj @@ -13,6 +13,7 @@ + From 98ad8e41b36e688a9e6ccb0d05d7db550462fec2 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Thu, 22 Aug 2024 09:41:28 -0700 Subject: [PATCH 30/61] Updates --- .../Helpers/LibraryRegEx_NodeJS.cs | 16 ++++++++-------- .../RegExTests.cs | 1 - 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs index 51a8ab1d6c..418cbee6c7 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs @@ -145,7 +145,13 @@ internal static FormulaValue Match(string subject, string pattern, RegexOptions foreach (Match token in outputRE.Matches(output)) { - if (token.Groups["end"].Success) + if (token.Groups["start"].Success) + { + fields = new (); + subMatches = new (); + fields.Add(STARTMATCH, new NamedValue(STARTMATCH, NumberValue.New(Convert.ToDouble(token.Groups["start"].Value) + 1))); + } + else if (token.Groups["end"].Success) { if ((options & RegexOptions.ExplicitCapture) == 0) { @@ -154,7 +160,7 @@ internal static FormulaValue Match(string subject, string pattern, RegexOptions allMatches.Add(RecordValue.NewRecordFromFields(fields.Values)); } - if (token.Groups["done"].Success) + else if (token.Groups["done"].Success) { if (allMatches.Count == 0) { @@ -167,12 +173,6 @@ internal static FormulaValue Match(string subject, string pattern, RegexOptions : allMatches.First(); } } - else if (token.Groups["start"].Success) - { - fields = new (); - subMatches = new (); - fields.Add(STARTMATCH, new NamedValue(STARTMATCH, NumberValue.New(Convert.ToDouble(token.Groups["start"].Value) + 1))); - } else if (token.Groups["name"].Success) { fields.Add(token.Groups["name"].Value, new NamedValue(token.Groups["name"].Value, StringValue.New(token.Groups["nameMatch"].Value.Replace(@"""""", @"""")))); diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/RegExTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/RegExTests.cs index 42bf550f14..7947f26a4d 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/RegExTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/RegExTests.cs @@ -5,7 +5,6 @@ using System.Linq; using System.Security.Cryptography.X509Certificates; using Microsoft.PowerFx.Types; -using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Serialization; using Xunit; namespace Microsoft.PowerFx.Interpreter.Tests From c55a8428ab4cdc704861d93a83a9de76d4a5bf1f Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Fri, 30 Aug 2024 00:03:12 -0700 Subject: [PATCH 31/61] Updates --- .../Texl/Builtins/Match.cs | 4 +- .../Functions/LibraryRegEx.cs | 12 +++-- .../ExpressionTestCases/Culture_en-US.txt | 15 ------ .../ExpressionTestCases/Culture_tr-TR.txt | 14 ----- .../ExpressionTestCases/Match_Limited.txt | 39 +++++++++++++- .../FileExpressionEvaluationTests.cs | 4 +- .../Helpers/LibraryRegEx_NodeJS.cs | 51 +++++++++++++------ .../Helpers/LibraryRegEx_PCRE2.cs | 11 ++-- 8 files changed, 90 insertions(+), 60 deletions(-) diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index aa879af6f0..b8cea73cdd 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -177,12 +177,12 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter \\(?\d+) | # numeric backreference, must be enabled with MatchOptions.NumberedSubMatches (?\\ ([dfnrstw] | # standard regex character classes, missing from .NET are aAeGzZv (no XRegExp support), other common are u{} and o - [pP]\{\w+\} | # unicode character classes + p\{\w+\} | # unicode character classes [\^\$\\\.\*\+\?\(\)\[\]\{\}\|\/] | # acceptable escaped characters with Unicode aware ECMAScript c[a-zA-Z] | # Ctrl character classes x[0-9a-fA-F]{2} | # hex character, must be exactly 2 hex digits u[0-9a-fA-F]{4})) | # Unicode characters, must be exactly 4 hex digits - (?\\[bBWDS]) | # acceptable outside a character class, but not within + (?\\([bBWDS]|P\{\w+\})) | # acceptable outside a character class, but not within (?\\.) | # all other escaped characters are invalid and reserved for future use # leading (?<, named captures diff --git a/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs b/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs index 909fc636a4..5d6dcf38b5 100644 --- a/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs +++ b/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs @@ -318,7 +318,7 @@ protected static RecordValue GetRecordFromMatch(Regex rex, Match m, RegexOptions { STARTMATCH, new NamedValue(STARTMATCH, NumberValue.New((double)m.Index + 1)) } }; - List subMatches = new List(); + List subMatches = new List(); string[] groupNames = rex.GetGroupNames(); for (int i = 0; i < groupNames.Length; i++) @@ -326,28 +326,30 @@ protected static RecordValue GetRecordFromMatch(Regex rex, Match m, RegexOptions string groupName = groupNames[i]; string validName = DName.MakeValid(groupName, out _).Value; Group g = m.Groups[i]; + FormulaValue val = g.Success ? StringValue.New(g.Value) : BlankValue.NewBlank(FormulaType.String); if (!int.TryParse(groupName, out _)) { if (!fields.ContainsKey(validName)) { - fields.Add(validName, new NamedValue(validName, StringValue.New(g.Value))); + fields.Add(validName, new NamedValue(validName, val)); } else { - fields[validName] = new NamedValue(validName, StringValue.New(g.Value)); + fields[validName] = new NamedValue(validName, val); } } if (i > 0) { - subMatches.Add(g.Value); + subMatches.Add(FormulaValue.NewRecordFromFields(new NamedValue(TableValue.ValueName, val))); } } if (!fields.ContainsKey(SUBMATCHES) && (options & RegexOptions.ExplicitCapture) == 0) { - fields.Add(SUBMATCHES, new NamedValue(SUBMATCHES, TableValue.NewSingleColumnTable(subMatches.Select(s => StringValue.New(s)).ToArray()))); + var recordType = RecordType.Empty().Add(TableValue.ValueName, FormulaType.String); + fields.Add(SUBMATCHES, new NamedValue(SUBMATCHES, TableValue.NewTable(recordType, subMatches))); } return RecordValue.NewRecordFromFields(fields.Values); diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_en-US.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_en-US.txt index 16d45f724d..5934827f7e 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_en-US.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_en-US.txt @@ -115,21 +115,6 @@ true >> "SIgh" in ["bcde","sigh"] true -// SORT -// Relative order of i, I, ı, İ are different between en-US and tr-TR - ->> Sort( [ "Z", "İ", "z", "I", "J", "j", "ı", "a", "h", "i", "A", "H"], Value ) -Table({Value:"a"},{Value:"A"},{Value:"h"},{Value:"H"},{Value:"i"},{Value:"I"},{Value:"İ"},{Value:"ı"},{Value:"j"},{Value:"J"},{Value:"z"},{Value:"Z"}) - ->> SortByColumns( [ "Z", "İ", "z", "I", "J", "j", "ı", "a", "h", "i", "A", "H"], "Value" ) -Table({Value:"a"},{Value:"A"},{Value:"h"},{Value:"H"},{Value:"i"},{Value:"I"},{Value:"İ"},{Value:"ı"},{Value:"j"},{Value:"J"},{Value:"z"},{Value:"Z"}) - ->> Concat( Sort( Split( "j J k K l L m M n N o O p P r R s S t T u U v V y Y z Z Ç ç Ş ş Ü ü Ö ö İ ı Ğ ğ a A b B c C d D e E f F g G h H i I", " " ), Value ), Value, " " ) -"a A b B c C ç Ç d D e E f F g G ğ Ğ h H i I İ ı j J k K l L m M n N o O ö Ö p P r R s S ş Ş t T u U ü Ü v V y Y z Z" - ->> Concat( SortByColumns( Split( "d D e E f F g G h H i I j J k K l L m M n N o O p P r R s S t T u U v V y Y z Z Ç ç Ş ş Ü ü Ö ö İ ı Ğ ğ a A b B c C", " " ), "Value" ), Value, " " ) -"a A b B c C ç Ç d D e E f F g G ğ Ğ h H i I İ ı j J k K l L m M n N o O ö Ö p P r R s S ş Ş t T u U ü Ü v V y Y z Z" - // REGULAR EXPRESSIONS // Always uses invariant even though tr-TR is set, subject of https://github.com/microsoft/Power-Fx/issues/2538 diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_tr-TR.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_tr-TR.txt index 233cf95a9f..d3aed5eec7 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_tr-TR.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Culture_tr-TR.txt @@ -145,20 +145,6 @@ true >> "SIgh" in ["bcde","sıgh"] true -// SORT - ->> Sort( [ "Z", "İ", "z", "I", "J", "j", "ı", "a", "h", "i", "A", "H"], Value ) -Table({Value:"a"},{Value:"A"},{Value:"h"},{Value:"H"},{Value:"ı"},{Value:"I"},{Value:"i"},{Value:"İ"},{Value:"j"},{Value:"J"},{Value:"z"},{Value:"Z"}) - ->> SortByColumns( [ "Z", "İ", "z", "I", "J", "j", "ı", "a", "h", "i", "A", "H"], "Value" ) -Table({Value:"a"},{Value:"A"},{Value:"h"},{Value:"H"},{Value:"ı"},{Value:"I"},{Value:"i"},{Value:"İ"},{Value:"j"},{Value:"J"},{Value:"z"},{Value:"Z"}) - ->> Concat( Sort( Split( "j J k K l L m M n N o O p P r R s S t T u U v V y Y z Z Ç ç Ş ş Ü ü Ö ö İ ı Ğ ğ a A b B c C d D e E f F g G h H i I", " " ), Value ), Value, " " ) -"a A b B c C ç Ç d D e E f F g G ğ Ğ h H ı I i İ j J k K l L m M n N o O ö Ö p P r R s S ş Ş t T u U ü Ü v V y Y z Z" - ->> Concat( SortByColumns( Split( "d D e E f F g G h H i I j J k K l L m M n N o O p P r R s S t T u U v V y Y z Z Ç ç Ş ş Ü ü Ö ö İ ı Ğ ğ a A b B c C", " " ), "Value" ), Value, " " ) -"a A b B c C ç Ç d D e E f F g G ğ Ğ h H ı I i İ j J k K l L m M n N o O ö Ö p P r R s S ş Ş t T u U ü Ü v V y Y z Z" - // REGULAR EXPRESSIONS // Always uses invariant even though tr-TR is set, subject of https://github.com/microsoft/Power-Fx/issues/2538 diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt index be3c5bb058..89f803d547 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt @@ -579,7 +579,7 @@ Errors: Error 15-70: Invalid regular expression: Unopened groups, too few openin {FullMatch:"test",StartMatch:1,one:"t",two:"t"} >> Match( "test", "((?t)|(?t))" ) -{FullMatch:"t",StartMatch:1,one:"t",two:""} +{FullMatch:"t",StartMatch:1,one:"t",two:Blank()} >> Match( "test", "(?t).*(?t)" ) Errors: Error 15-37: Invalid regular expression: Named capture group "(?" defined more than once.|Error 0-5: The function 'Match' has some invalid arguments. @@ -955,3 +955,40 @@ false >> Match( "abcdef", "\w{2,4}?" ).FullMatch "ab" + +>> Match( UniChar(Hex2Dec("03a9")), "\u03c9", MatchOptions.IgnoreCase ).FullMatch +"Ω" + +>> Match( UniChar(Hex2Dec("03a9")), "\u2126", MatchOptions.IgnoreCase ).FullMatch +"Ω" + +>> Match( UniChar(Hex2Dec("03c9")), "\u03a9", MatchOptions.IgnoreCase ).FullMatch +"ω" + +>> Match( UniChar(Hex2Dec("03c9")), "\u2126", MatchOptions.IgnoreCase ).FullMatch +"ω" + +>> Match( UniChar(Hex2Dec("2126")), "\u03c9", MatchOptions.IgnoreCase ).FullMatch +"Ω" + +>> Match( UniChar(Hex2Dec("2126")), "\u03a9", MatchOptions.IgnoreCase ).FullMatch +"Ω" + +>> Match( "asdf", "(*MARK)") // PCRE2 extension +Errors: Error 15-24: Invalid regular expression: Unsupported special group, found "(*MAR...".|Error 0-5: The function 'Match' has some invalid arguments. + +// Node != Net for this test ("b" is empty for Node), a known difference between PCRE2 and Perl too +// >> Match( "aba", "^(a(b)?)+$", MatchOptions.NumberedSubMatches ) +// {FullMatch:"aba",StartMatch:1,SubMatches:Table({Value:"a"},{Value:"b"})} + +>> Match( "ab", "a(d)?b", MatchOptions.NumberedSubMatches ) +{FullMatch:"ab",StartMatch:1,SubMatches:Table({Value:Blank()})} + +>> Match( "ab", "a(d?)b", MatchOptions.NumberedSubMatches ) +{FullMatch:"ab",StartMatch:1,SubMatches:Table({Value:""})} + +>> Match( "ab", "a(?d)?b" ) +{FullMatch:"ab",StartMatch:1,one:Blank()} + +>> Match( "ab", "a(?d?)b" ) +{FullMatch:"ab",StartMatch:1,one:""} diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index eeb254454a..49b1dc685b 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -95,7 +95,7 @@ public void None_Float(ExpressionTestCase testCase) public static bool RegExCompareEnabled = false; #if false - // This test run will compare the results between .NET, NodeJS with JavaScript (used in Canvas), and PCRE2 (used in Excel) + // a This test run will compare the results between .NET, NodeJS with JavaScript (used in Canvas), and PCRE2 (used in Excel) [TxtFileData("ExpressionTestCases", "InterpreterExpressionTestCases", nameof(InterpreterRunner), "PowerFxV1,disable:NumberIsFloat,DecimalSupport,RegEx")] [InterpreterTheory] public void RegExCompare(ExpressionTestCase t) @@ -172,7 +172,7 @@ private static bool ShouldSkipDotNetVersion(ExpressionTestCase testCase, string [Fact] public void RunOne() { - var path = @"d:\repos\regex-min\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\match_limited.txt"; + var path = @"d:\repos\regex-min-nolocale\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\match_limited.txt"; var line = 0; var runner = new InterpreterRunner(); diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs index 418cbee6c7..9b98cda9eb 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs @@ -70,6 +70,7 @@ internal static FormulaValue Match(string subject, string pattern, RegexOptions const [alteredPattern, alteredFlags] = AlterRegex_NodeJS( pattern, flags ); const regex = RegExp(alteredPattern, alteredFlags.concat(matchAll ? 'g' : '')); const matches = matchAll ? [...subject.matchAll(regex)] : [subject.match(regex)]; + for(const match of matches) { if (match != null) @@ -78,20 +79,20 @@ internal static FormulaValue Match(string subject, string pattern, RegexOptions for(var group in match.groups) { var val = match.groups[group]; - if (val === undefined) + if (val !== undefined) { - val = ''; + val = '""' + val.replace( / "" /, '""""') + '""' } - console.log(group + ':""' + val.replace( / "" /, '""""') + '""'); + console.log(group + ':' + val); } for (var num = 0; num < match.length; num++) { var val = match[num]; - if (val === undefined) + if (val !== undefined) { - val = ''; + val = '""' + val.replace( / "" /, '""""') + '""' } - console.log(num + ':""' + val.replace( / "" /, '""""') + '""'); + console.log(num + ':' + val); } console.log('%end%:'); } @@ -136,10 +137,12 @@ internal static FormulaValue Match(string subject, string pattern, RegexOptions ^(?%end%): | ^(?%done%): | ^(?\d+):""(?(""""|[^""])*)""$ | - ^(?[^:]+):""(?(""""|[^""])*)""$ + ^(?[^:]+):""(?(""""|[^""])*)""$ | + ^(?\d+):undefined$ | + ^(?[^:]+):undefined$ ", RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace); - List subMatches = new (); + List subMatches = new List(); Dictionary fields = new (); List allMatches = new (); @@ -155,7 +158,8 @@ internal static FormulaValue Match(string subject, string pattern, RegexOptions { if ((options & RegexOptions.ExplicitCapture) == 0) { - fields.Add(SUBMATCHES, new NamedValue(SUBMATCHES, TableValue.NewSingleColumnTable(subMatches.Select(s => StringValue.New(s)).ToArray()))); + var recordType = RecordType.Empty().Add(TableValue.ValueName, FormulaType.String); + fields.Add(SUBMATCHES, new NamedValue(SUBMATCHES, TableValue.NewTable(recordType, subMatches))); } allMatches.Add(RecordValue.NewRecordFromFields(fields.Values)); @@ -177,6 +181,10 @@ internal static FormulaValue Match(string subject, string pattern, RegexOptions { fields.Add(token.Groups["name"].Value, new NamedValue(token.Groups["name"].Value, StringValue.New(token.Groups["nameMatch"].Value.Replace(@"""""", @"""")))); } + else if (token.Groups["nameBlank"].Success) + { + fields.Add(token.Groups["nameBlank"].Value, new NamedValue(token.Groups["nameBlank"].Value, BlankValue.NewBlank(FormulaType.String))); + } else if (token.Groups["num"].Success) { var num = Convert.ToInt32(token.Groups["num"].Value); @@ -186,7 +194,19 @@ internal static FormulaValue Match(string subject, string pattern, RegexOptions } else { - subMatches.Add(token.Groups["numMatch"].Value.Replace(@"""""", @"""")); + subMatches.Add(FormulaValue.NewRecordFromFields(new NamedValue(TableValue.ValueName, StringValue.New(token.Groups["numMatch"].Value.Replace(@"""""", @""""))))); + } + } + else if (token.Groups["numBlank"].Success) + { + var num = Convert.ToInt32(token.Groups["numBlank"].Value); + if (num == 0) + { + fields.Add(FULLMATCH, new NamedValue(FULLMATCH, BlankValue.NewBlank(FormulaType.String))); + } + else + { + subMatches.Add(FormulaValue.NewRecordFromFields(new NamedValue(TableValue.ValueName, BlankValue.NewBlank(FormulaType.String)))); } } } @@ -238,25 +258,24 @@ function AlterRegex_NodeJS(regex, flags) case '\\': if (++regexIndex < regex.length) { - const letterChar = '\\p{Ll}\\p{Lu}\\p{Lt}\\p{Lo}\\p{Lm}\\p{Nd}\\p{Pc}'; - const wordChar = '(?:(?:\\p{L}\\p{M}*)|\\p{N}|_)'; + const wordChar = '\\p{Ll}\\p{Lu}\\p{Lt}\\p{Lo}\\p{Lm}\\p{Nd}\\p{Pc}'; const spaceChar = '\\f\\n\\r\\t\\v\\x85\\p{Z}'; const digitChar = '\\p{Nd}'; switch (regex.charAt(regexIndex)) { case 'w': - altered = altered.concat((openCharacterClass ? '' : '['), letterChar, (openCharacterClass ? '' : ']')); + altered = altered.concat((openCharacterClass ? '' : '['), wordChar, (openCharacterClass ? '' : ']')); break; case 'W': - altered = altered.concat('[^', letterChar, ']'); + altered = altered.concat('[^', wordChar, ']'); break; case 'b': - altered = altered.concat(`(?:(?<=${wordChar})(?!${wordChar})|(? subMatches = new List(); + List subMatches = new List(); var oc = NativeMethods.pcre2_get_ovector_count_16(md); for (var i = 1; i < oc; i++) { @@ -140,17 +140,18 @@ internal static FormulaValue Match(string subject, string pattern, RegexOptions var end = Marshal.ReadInt32(op, ((i * 2) + 1) * Marshal.SizeOf(typeof(long))); if (start >= 0 && end >= 0) { - subMatches.Add(subject.Substring(start, end - start)); + subMatches.Add(StringValue.New(subject.Substring(start, end - start))); } else { - subMatches.Add(string.Empty); + subMatches.Add(BlankValue.NewBlank(FormulaType.String)); } } if (!fields.ContainsKey(SUBMATCHES) && (options & RegexOptions.ExplicitCapture) == 0) { - fields.Add(SUBMATCHES, new NamedValue(SUBMATCHES, TableValue.NewSingleColumnTable(subMatches.Select(s => StringValue.New(s)).ToArray()))); + var recordType = RecordType.Empty().Add(TableValue.ValueName, FormulaType.String); + fields.Add(SUBMATCHES, new NamedValue(SUBMATCHES, TableValue.NewTable(recordType, subMatches.Select(s => FormulaValue.NewRecordFromFields(new NamedValue(TableValue.ValueName, s)))))); } else { @@ -160,7 +161,7 @@ internal static FormulaValue Match(string subject, string pattern, RegexOptions if (!int.TryParse(name, out _)) { var ni = NativeMethods.pcre2_substring_number_from_name_16(code, name); - fields.Add(name, new NamedValue(name, StringValue.New(subMatches[ni - 1]))); + fields.Add(name, new NamedValue(name, subMatches[ni - 1])); } } } From 856bdfed3754e19c769c42b07590126294d4c8b4 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Fri, 30 Aug 2024 19:38:13 -0700 Subject: [PATCH 32/61] Updates --- .../Match_Limited_Net7.txt | 22 +++ .../Match_Limited_Net7Disabled.txt | 22 +++ .../ExpressionTestHelpers/TestRunner.cs | 36 +++- .../TxtFileDataAttribute.cs | 19 +- .../Helpers/RegEx_JavaScript.cs | 171 ++++++++++++++++++ .../TestRunnerTests/TestRunnerTests.cs | 2 +- .../FileExpressionEvaluationTests.cs | 17 +- .../Helpers/LibraryRegEx_NodeJS.cs | 168 +---------------- .../PowerFxEvaluationTests.cs | 6 +- 9 files changed, 277 insertions(+), 186 deletions(-) create mode 100644 src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net7.txt create mode 100644 src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net7Disabled.txt create mode 100644 src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net7.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net7.txt new file mode 100644 index 0000000000..ba73431747 --- /dev/null +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net7.txt @@ -0,0 +1,22 @@ +#SETUP: RegEx,PowerFxV1CompatibilityRules,SupportColumnNamesAsIdentifiers,Net7 + +// Changes in case insensitive matching in .NET 7 causes different answers that are consistent with PCRE2 and Node +// See https://devblogs.microsoft.com/dotnet/regular-expression-improvements-in-dotnet-7/#case-insensitive-matching-and-regexoptions-ignorecase + +>> Match( UniChar(Hex2Dec("03a9")), "\u03c9", MatchOptions.IgnoreCase ).FullMatch +"Ω" + +>> Match( UniChar(Hex2Dec("03a9")), "\u2126", MatchOptions.IgnoreCase ).FullMatch +"Ω" + +>> Match( UniChar(Hex2Dec("03c9")), "\u03a9", MatchOptions.IgnoreCase ).FullMatch +"ω" + +>> Match( UniChar(Hex2Dec("03c9")), "\u2126", MatchOptions.IgnoreCase ).FullMatch +"ω" + +>> Match( UniChar(Hex2Dec("2126")), "\u03c9", MatchOptions.IgnoreCase ).FullMatch +"Ω" + +>> Match( UniChar(Hex2Dec("2126")), "\u03a9", MatchOptions.IgnoreCase ).FullMatch +"Ω" diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net7Disabled.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net7Disabled.txt new file mode 100644 index 0000000000..3d72e62f48 --- /dev/null +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net7Disabled.txt @@ -0,0 +1,22 @@ +#SETUP: RegEx,PowerFxV1CompatibilityRules,SupportColumnNamesAsIdentifiers,disable:Net7 + +// Changes in case insensitive matching in .NET 7 causes different answers that are consistent with PCRE2 and Node +// See https://devblogs.microsoft.com/dotnet/regular-expression-improvements-in-dotnet-7/#case-insensitive-matching-and-regexoptions-ignorecase + +>> Match( UniChar(Hex2Dec("03a9")), "\u03c9", MatchOptions.IgnoreCase ).FullMatch +Blank() + +>> Match( UniChar(Hex2Dec("03a9")), "\u2126", MatchOptions.IgnoreCase ).FullMatch +Blank() + +>> Match( UniChar(Hex2Dec("03c9")), "\u03a9", MatchOptions.IgnoreCase ).FullMatch +Blank() + +>> Match( UniChar(Hex2Dec("03c9")), "\u2126", MatchOptions.IgnoreCase ).FullMatch +Blank() + +>> Match( UniChar(Hex2Dec("2126")), "\u03c9", MatchOptions.IgnoreCase ).FullMatch +Blank() + +>> Match( UniChar(Hex2Dec("2126")), "\u03a9", MatchOptions.IgnoreCase ).FullMatch +Blank() diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestHelpers/TestRunner.cs b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestHelpers/TestRunner.cs index 4a3a3f9e50..130f79930a 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestHelpers/TestRunner.cs +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestHelpers/TestRunner.cs @@ -61,12 +61,17 @@ public static string GetDefaultTestDir() // * Default, special case // * PowerFxV1, special case, will expand to its constituent Features // * Other handlers listed in this routine - public static Dictionary ParseSetupString(string setup) + public static Dictionary ParseSetupString(string setup, bool includeContext = false) { var settings = new Dictionary(); var possible = new HashSet(); var powerFxV1 = new Dictionary(); + if (includeContext) + { + setup += (setup.Length > 0 ? "," : string.Empty) + (Environment.Version.Major >= 7 ? "Net7" : "disable:Net7"); + } + // Features foreach (var featureProperty in typeof(Features).GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) { @@ -103,6 +108,7 @@ public static Dictionary ParseSetupString(string setup) possible.Add("TimeZoneInfo"); possible.Add("TraceSetup"); possible.Add("CultureInfo"); + possible.Add("Net7"); foreach (Match match in Regex.Matches(setup, @"(disable:)?(([\w]+|//)(\([^\)]*\))?)")) { @@ -135,25 +141,25 @@ public static Dictionary ParseSetupString(string setup) return settings; } - public void AddDir(Dictionary setup, string directory = "") + public void AddDir(Dictionary setup, Dictionary requiredSetup, string directory = "") { directory = GetFullPath(directory, TestRoot); var allFiles = Directory.EnumerateFiles(directory); - AddFile(setup, allFiles); + AddFile(setup, requiredSetup, allFiles); } - public void AddFile(Dictionary setup, params string[] files) + public void AddFile(Dictionary setup, Dictionary requiredSetup, params string[] files) { var x = (IEnumerable)files; - AddFile(setup, x); + AddFile(setup, requiredSetup, x); } - public void AddFile(Dictionary setup, IEnumerable files) + public void AddFile(Dictionary setup, Dictionary requiredSetup, IEnumerable files) { foreach (var file in files) { - AddFile(setup, file); + AddFile(setup, requiredSetup, file); } } @@ -180,7 +186,7 @@ private static bool TryParseDirective(string line, string directive, out string } } - public void AddFile(Dictionary setup, string thisFile) + public void AddFile(Dictionary setup, Dictionary requiredSetup, string thisFile) { thisFile = GetFullPath(thisFile, TestRoot); @@ -265,7 +271,19 @@ public void AddFile(Dictionary setup, string thisFile) { return; } - } + } + + // If requiredSetup is supplied, then those setup elements must be present and agree + if (requiredSetup != null) + { + foreach (var flag in requiredSetup) + { + if (!fileSetupDict.ContainsKey(flag.Key) || flag.Value != fileSetupDict[flag.Key]) + { + return; + } + } + } fileSetup = string.Join(",", fileSetupDict.Select(i => (i.Value ? string.Empty : "disable:") + i.Key)); diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestHelpers/TxtFileDataAttribute.cs b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestHelpers/TxtFileDataAttribute.cs index 7dd826dcbb..50ac052b3f 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestHelpers/TxtFileDataAttribute.cs +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestHelpers/TxtFileDataAttribute.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Reflection; using Xunit.Sdk; @@ -21,19 +22,31 @@ public class TxtFileDataAttribute : DataAttribute private readonly string _filePathSpecific; private readonly string _engineName; private readonly Dictionary _setup; + private readonly Dictionary _requiredSetup; public TxtFileDataAttribute(string filePathCommon, string filePathSpecific, string engineName, string setup) { _filePathCommon = filePathCommon; _filePathSpecific = filePathSpecific; _engineName = engineName; - _setup = TestRunner.ParseSetupString(setup); + _setup = TestRunner.ParseSetupString(setup, true); + } + + public TxtFileDataAttribute(string filePathCommon, string filePathSpecific, string engineName, string setup, string requiredSetup) + { + System.Diagnostics.Debugger.Launch(); + + _filePathCommon = filePathCommon; + _filePathSpecific = filePathSpecific; + _engineName = engineName; + _setup = TestRunner.ParseSetupString(setup, true); + _requiredSetup = TestRunner.ParseSetupString(requiredSetup); } public override IEnumerable GetData(MethodInfo testMethod) { // This is run in a separate process. To debug, need to call Launch() and attach a debugger. - // System.Diagnostics.Debugger.Launch(); + // System.Diagnostics.Debugger.Launch(); if (testMethod == null) { @@ -58,7 +71,7 @@ public override IEnumerable GetData(MethodInfo testMethod) if (file.EndsWith(".txt", StringComparison.InvariantCultureIgnoreCase)) { - parser.AddFile(_setup, file); + parser.AddFile(_setup, _requiredSetup, file); } } } diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs new file mode 100644 index 0000000000..6ec277edb3 --- /dev/null +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs @@ -0,0 +1,171 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +// This file contains the source for AlterRegex in JavaScript. +// It is included here so that the test suite can compare results from .NET, JavaScript, and PCRE2. +// It is here in the Core library so that it can be extracted in the Canvas build and compared against the version stored there. + +namespace Microsoft.PowerFx.Functions +{ + public class RegEx_JavaScript + { + // This JavaScript function assumes that the regular expression has already been compiled and comforms to the Power Fx regular expression language. + // For example, no affodance is made for nested character classes or inline options on a subexpression, as those would have already been blocked. + // Stick to single ticks for strings to keep this easier to read and maintain here in C#. + public const string AlterRegex_JavaScript = @" + function AlterRegex_JavaScript(regex, flags) + { + var regexIndex = 0; + + const inlineFlagsRE = /^\(\?(?[imsx]+)\)/; + const inlineFlags = inlineFlagsRE.exec( regex ); + if (inlineFlags != null) + { + flags = flags.concat(inlineFlags.groups['flags']); + regexIndex = inlineFlags[0].length; + } + + const freeSpacing = flags.includes('x'); + const multiline = flags.includes('m'); + const dotAll = flags.includes('s'); + const ignoreCase = flags.includes('i'); + + // rebuilding from booleans avoids possible duplicate letters + // x has been handled in this function and does not need to be passed on (and would cause an error) + const alteredFlags = 'u'.concat((ignoreCase ? 'i' : ''), (multiline ? 'm' : ''), (dotAll ? 's' : '')); + + var openCharacterClass = false; // are we defining a character class? + var altered = ''; + + for ( ; regexIndex < regex.length; regexIndex++) + { + switch (regex.charAt(regexIndex) ) + { + case '[': + openCharacterClass = true; + altered = altered.concat('['); + break; + + case ']': + openCharacterClass = false; + altered = altered.concat(']'); + break; + + case '\\': + if (++regexIndex < regex.length) + { + const wordChar = '\\p{Ll}\\p{Lu}\\p{Lt}\\p{Lo}\\p{Lm}\\p{Nd}\\p{Pc}'; + const spaceChar = '\\f\\n\\r\\t\\v\\x85\\p{Z}'; + const digitChar = '\\p{Nd}'; + + switch (regex.charAt(regexIndex)) + { + case 'w': + altered = altered.concat((openCharacterClass ? '' : '['), wordChar, (openCharacterClass ? '' : ']')); + break; + case 'W': + altered = altered.concat('[^', wordChar, ']'); + break; + + case 'b': + altered = altered.concat(`(?:(?<=[${wordChar}])(?![${wordChar}])|(? 2 && regex.charAt(regexIndex+1) == '?' && regex.charAt(regexIndex+2) == '#') + { + // inline comment + for ( regexIndex++; regexIndex < regex.length && regex.charAt(regexIndex) != ')'; regexIndex++) + { + // eat characters until a close paren, it doesn't matter if it is escaped (consistent with .NET) + } + } + else + { + altered = altered.concat('('); + } + + break; + + case ' ': + case '\f': + case '\n': + case '\r': + case '\t': + case '\v': + if (!freeSpacing) + { + altered = altered.concat(regex.charAt(regexIndex)); + } + + break; + + case '#': + if (freeSpacing) + { + for ( regexIndex++; regexIndex < regex.length && regex.charAt(regexIndex) != '\r' && regex.charAt(regexIndex) != '\n'; regexIndex++) + { + // eat characters until the end of the line + // leaving dangling whitespace characters will be eaten on next iteration + } + } + else + { + altered = altered.concat('#'); + } + + break; + + default: + altered = altered.concat(regex.charAt(regexIndex)); + break; + } + } + + return [altered, alteredFlags]; + } + "; + } +} diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/TestRunnerTests/TestRunnerTests.cs b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/TestRunnerTests/TestRunnerTests.cs index a929452ea6..f7d6a15805 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/TestRunnerTests/TestRunnerTests.cs +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/TestRunnerTests/TestRunnerTests.cs @@ -533,7 +533,7 @@ public void TestErrorOverride3() private static void AddFile(TestRunner runner, string filename) { var test1 = GetFullPath(filename, TxtFileDataAttribute.GetDefaultTestDir("TestRunnerTests")); - runner.AddFile(TestRunner.ParseSetupString(string.Empty), test1); + runner.AddFile(TestRunner.ParseSetupString(string.Empty), null, test1); } } } diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index 49b1dc685b..b04a59bcb8 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -91,16 +91,15 @@ public void None_Float(ExpressionTestCase testCase) } #endif - // used by the following test run, but needs to be outside the #if for standard usage - public static bool RegExCompareEnabled = false; - -#if false - // a This test run will compare the results between .NET, NodeJS with JavaScript (used in Canvas), and PCRE2 (used in Excel) - [TxtFileData("ExpressionTestCases", "InterpreterExpressionTestCases", nameof(InterpreterRunner), "PowerFxV1,disable:NumberIsFloat,DecimalSupport,RegEx")] +#if true + // Runs only tests that have asked for RegEx setup. This test run will compare the regular expression results between + // .NET (used in the C# interpreter), NodeJS with JavaScript (used in Canvas), and PCRE2 (used in Excel). + // This is not run all the time. It requires Node to be installed and PCRE2 built as a shared library DLL and on the path. a + [TxtFileData("ExpressionTestCases", "InterpreterExpressionTestCases", nameof(InterpreterRunner), "PowerFxV1,disable:NumberIsFloat,DecimalSupport", "RegEx")] [InterpreterTheory] public void RegExCompare(ExpressionTestCase t) { - RegExCompareEnabled = true; + ExpressionEvaluationTests.RegExCompareEnabled = true; RunExpressionTestCase(t, Features.PowerFxV1, numberIsFloat: false, Console); } #endif @@ -245,7 +244,7 @@ private void RunMutationTestFile(string file, Features features, string setup) var testRunner = new TestRunner(runner); - testRunner.AddFile(TestRunner.ParseSetupString(setup), path); + testRunner.AddFile(TestRunner.ParseSetupString(setup), null, path); if (testRunner.Tests.Count > 0 && testRunner.Tests[0].SetupHandlerName.Contains("MutationFunctionsTestSetup")) { @@ -306,7 +305,7 @@ public void ScanNotYetReadyForTxtParseErrors() var runner = new TestRunner(); // Verify this runs without throwing an exception. - runner.AddDir(new Dictionary(), path); + runner.AddDir(new Dictionary(), null, path); // Ensure that we actually found tests and not pointed to an empty directory Assert.True(runner.Tests.Count > 10); diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs index 9b98cda9eb..5855e7ff9b 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs @@ -115,7 +115,7 @@ internal static FormulaValue Match(string subject, string pattern, RegexOptions node.Start(); var jsString = js.ToString(); - var bytes = Encoding.UTF8.GetBytes(AlterRegex_NodeJS_Src + jsString); + var bytes = Encoding.UTF8.GetBytes(RegEx_JavaScript.AlterRegex_JavaScript + jsString); node.StandardInput.BaseStream.Write(bytes, 0, bytes.Length); node.StandardInput.WriteLine(); node.StandardInput.Close(); @@ -143,15 +143,15 @@ internal static FormulaValue Match(string subject, string pattern, RegexOptions ", RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace); List subMatches = new List(); - Dictionary fields = new (); - List allMatches = new (); + Dictionary fields = new(); + List allMatches = new(); foreach (Match token in outputRE.Matches(output)) { if (token.Groups["start"].Success) { - fields = new (); - subMatches = new (); + fields = new(); + subMatches = new(); fields.Add(STARTMATCH, new NamedValue(STARTMATCH, NumberValue.New(Convert.ToDouble(token.Groups["start"].Value) + 1))); } else if (token.Groups["end"].Success) @@ -213,164 +213,6 @@ internal static FormulaValue Match(string subject, string pattern, RegexOptions throw new Exception("%done% marker not found"); } - - // This JavaScript function assumes that the regular expression has already been compiled and comforms to the Power Fx regular expression language. - // For example, no affodance is made for nested character classes or inline options on a subexpression, as those would have already been blocked. - private const string AlterRegex_NodeJS_Src = @" - function AlterRegex_NodeJS(regex, flags) - { - var regexIndex = 0; - - const inlineFlagsRE = /^\(\?(?[imsx]+)\)/; - const inlineFlags = inlineFlagsRE.exec( regex ); - if (inlineFlags != null) - { - flags = flags.concat(inlineFlags.groups['flags']); - regexIndex = inlineFlags[0].length; - } - - const freeSpacing = flags.includes('x'); - const multiline = flags.includes('m'); - const dotAll = flags.includes('s'); - const ignoreCase = flags.includes('i'); - - // rebuilding from booleans avoids possible duplicate letters - // x has been handled in this function and does not need to be passed on (and would cause an error) - const alteredFlags = 'u'.concat((ignoreCase ? 'i' : ''), (multiline ? 'm' : ''), (dotAll ? 's' : '')); - - var openCharacterClass = false; // are we defining a character class? - var altered = ''; - - for ( ; regexIndex < regex.length; regexIndex++) - { - switch (regex.charAt(regexIndex) ) - { - case '[': - openCharacterClass = true; - altered = altered.concat('['); - break; - - case ']': - openCharacterClass = false; - altered = altered.concat(']'); - break; - - case '\\': - if (++regexIndex < regex.length) - { - const wordChar = '\\p{Ll}\\p{Lu}\\p{Lt}\\p{Lo}\\p{Lm}\\p{Nd}\\p{Pc}'; - const spaceChar = '\\f\\n\\r\\t\\v\\x85\\p{Z}'; - const digitChar = '\\p{Nd}'; - - switch (regex.charAt(regexIndex)) - { - case 'w': - altered = altered.concat((openCharacterClass ? '' : '['), wordChar, (openCharacterClass ? '' : ']')); - break; - case 'W': - altered = altered.concat('[^', wordChar, ']'); - break; - - case 'b': - altered = altered.concat(`(?:(?<=[${wordChar}])(?![${wordChar}])|(? 2 && regex.charAt(regexIndex+1) == '?' && regex.charAt(regexIndex+2) == '#') - { - // inline comment - for ( regexIndex++; regexIndex < regex.length && regex.charAt(regexIndex) != ')'; regexIndex++) - { - // eat characters until a close paren, it doesn't matter if it is escaped (consistent with .NET) - } - } - else - { - altered = altered.concat('('); - } - - break; - - case ' ': - case '\f': - case '\n': - case '\r': - case '\t': - case '\v': - if (!freeSpacing) - { - altered = altered.concat(regex.charAt(regexIndex)); - } - - break; - - case '#': - if (freeSpacing) - { - for ( regexIndex++; regexIndex < regex.length && regex.charAt(regexIndex) != '\r' && regex.charAt(regexIndex) != '\n'; regexIndex++) - { - // eat characters until the end of the line - // leaving dangling whitespace characters will be eaten on next iteration - } - } - else - { - altered = altered.concat('#'); - } - - break; - - default: - altered = altered.concat(regex.charAt(regexIndex)); - break; - } - } - - return [altered, alteredFlags]; - } - "; } public static void EnableRegExFunctions(PowerFxConfig config, TimeSpan regExTimeout = default, int regexCacheSize = -1) diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/PowerFxEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/PowerFxEvaluationTests.cs index 95e760b7b6..a9279c4446 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/PowerFxEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/PowerFxEvaluationTests.cs @@ -57,6 +57,7 @@ public class ExpressionEvaluationTests : PowerFxTest { "OptionSetTestSetup", (null, OptionSetTestSetup1, OptionSetTestSetup2, null) }, { "RegEx", (null, RegExSetup, null, null) }, { "TraceSetup", (null, null, null, TraceSetup) }, + { "Net7", (null, null, null, null) }, // Using .NET 7 or later }; private static object EnableJsonFunctions(PowerFxConfig config, SymbolTable symbolTable) @@ -65,9 +66,12 @@ private static object EnableJsonFunctions(PowerFxConfig config, SymbolTable symb return null; } + // This "global" turns on regex comparison. Yes, it is a hack, but it is only used for manual testing (no automated testing). + public static bool RegExCompareEnabled = false; + private static object RegExSetup(PowerFxConfig config, SymbolTable symbolTable) { - if (FileExpressionEvaluationTests.RegExCompareEnabled) + if (RegExCompareEnabled) { Functions.RegEx_Compare.EnableRegExFunctions(config, new TimeSpan(0, 0, 5)); } From 14d7fe5ff45284e40f9b84caf2bebaa2e70556a5 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Fri, 30 Aug 2024 19:42:28 -0700 Subject: [PATCH 33/61] Updates --- .../TxtFileDataAttribute.cs | 19 ++++++------------- .../FileExpressionEvaluationTests.cs | 4 ++-- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestHelpers/TxtFileDataAttribute.cs b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestHelpers/TxtFileDataAttribute.cs index 50ac052b3f..7730bcd493 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestHelpers/TxtFileDataAttribute.cs +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestHelpers/TxtFileDataAttribute.cs @@ -24,29 +24,22 @@ public class TxtFileDataAttribute : DataAttribute private readonly Dictionary _setup; private readonly Dictionary _requiredSetup; - public TxtFileDataAttribute(string filePathCommon, string filePathSpecific, string engineName, string setup) + public TxtFileDataAttribute(string filePathCommon, string filePathSpecific, string engineName, string setup, string requiredSetup = null) { _filePathCommon = filePathCommon; _filePathSpecific = filePathSpecific; _engineName = engineName; _setup = TestRunner.ParseSetupString(setup, true); - } - - public TxtFileDataAttribute(string filePathCommon, string filePathSpecific, string engineName, string setup, string requiredSetup) - { - System.Diagnostics.Debugger.Launch(); - - _filePathCommon = filePathCommon; - _filePathSpecific = filePathSpecific; - _engineName = engineName; - _setup = TestRunner.ParseSetupString(setup, true); - _requiredSetup = TestRunner.ParseSetupString(requiredSetup); + if (requiredSetup != null) + { + _requiredSetup = TestRunner.ParseSetupString(requiredSetup); + } } public override IEnumerable GetData(MethodInfo testMethod) { // This is run in a separate process. To debug, need to call Launch() and attach a debugger. - // System.Diagnostics.Debugger.Launch(); + // System.Diagnostics.Debugger.Launch(); if (testMethod == null) { diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index b04a59bcb8..ad9681b91d 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -91,10 +91,10 @@ public void None_Float(ExpressionTestCase testCase) } #endif -#if true +#if false // Runs only tests that have asked for RegEx setup. This test run will compare the regular expression results between // .NET (used in the C# interpreter), NodeJS with JavaScript (used in Canvas), and PCRE2 (used in Excel). - // This is not run all the time. It requires Node to be installed and PCRE2 built as a shared library DLL and on the path. a + // This is not run all the time. It requires Node to be installed and PCRE2 built as a shared library DLL and on the path. [TxtFileData("ExpressionTestCases", "InterpreterExpressionTestCases", nameof(InterpreterRunner), "PowerFxV1,disable:NumberIsFloat,DecimalSupport", "RegEx")] [InterpreterTheory] public void RegExCompare(ExpressionTestCase t) From 78d1197d41f7f21180d593d035a28b3390184bfd Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Fri, 30 Aug 2024 20:29:21 -0700 Subject: [PATCH 34/61] updates --- .../Helpers/LibraryRegEx_NodeJS.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs index 5855e7ff9b..dd5127b921 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs @@ -143,15 +143,15 @@ internal static FormulaValue Match(string subject, string pattern, RegexOptions ", RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace); List subMatches = new List(); - Dictionary fields = new(); - List allMatches = new(); + Dictionary fields = new (); + List allMatches = new (); foreach (Match token in outputRE.Matches(output)) { if (token.Groups["start"].Success) { - fields = new(); - subMatches = new(); + fields = new (); + subMatches = new (); fields.Add(STARTMATCH, new NamedValue(STARTMATCH, NumberValue.New(Convert.ToDouble(token.Groups["start"].Value) + 1))); } else if (token.Groups["end"].Success) From 3c6f50b723752b90345cd2926f5d4468c99dd739 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Sat, 31 Aug 2024 00:50:06 -0700 Subject: [PATCH 35/61] Updates --- .../ExpressionTestCases/Match_Limited.txt | 18 ------------------ ...t7Disabled.txt => Match_Limited_Net462.txt} | 3 ++- ...imited_Net7.txt => Match_Limited_Net70.txt} | 3 ++- .../ExpressionTestHelpers/TestRunner.cs | 7 +------ .../TxtFileDataAttribute.cs | 2 +- .../TestRunnerTests/InternalSetup.cs | 17 ++++++++++++++++- .../FileExpressionEvaluationTests.cs | 6 +++--- .../Helpers/LibraryRegEx_NodeJS.cs | 2 +- .../PowerFxEvaluationTests.cs | 1 - 9 files changed, 26 insertions(+), 33 deletions(-) rename src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/{Match_Limited_Net7Disabled.txt => Match_Limited_Net462.txt} (96%) rename src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/{Match_Limited_Net7.txt => Match_Limited_Net70.txt} (96%) diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt index 89f803d547..4f458dd4df 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt @@ -956,24 +956,6 @@ false >> Match( "abcdef", "\w{2,4}?" ).FullMatch "ab" ->> Match( UniChar(Hex2Dec("03a9")), "\u03c9", MatchOptions.IgnoreCase ).FullMatch -"Ω" - ->> Match( UniChar(Hex2Dec("03a9")), "\u2126", MatchOptions.IgnoreCase ).FullMatch -"Ω" - ->> Match( UniChar(Hex2Dec("03c9")), "\u03a9", MatchOptions.IgnoreCase ).FullMatch -"ω" - ->> Match( UniChar(Hex2Dec("03c9")), "\u2126", MatchOptions.IgnoreCase ).FullMatch -"ω" - ->> Match( UniChar(Hex2Dec("2126")), "\u03c9", MatchOptions.IgnoreCase ).FullMatch -"Ω" - ->> Match( UniChar(Hex2Dec("2126")), "\u03a9", MatchOptions.IgnoreCase ).FullMatch -"Ω" - >> Match( "asdf", "(*MARK)") // PCRE2 extension Errors: Error 15-24: Invalid regular expression: Unsupported special group, found "(*MAR...".|Error 0-5: The function 'Match' has some invalid arguments. diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net7Disabled.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net462.txt similarity index 96% rename from src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net7Disabled.txt rename to src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net462.txt index 3d72e62f48..1526827130 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net7Disabled.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net462.txt @@ -1,4 +1,5 @@ -#SETUP: RegEx,PowerFxV1CompatibilityRules,SupportColumnNamesAsIdentifiers,disable:Net7 +#SETUP: RegEx,PowerFxV1CompatibilityRules,SupportColumnNamesAsIdentifiers +#DISABLE.NET:70 // Changes in case insensitive matching in .NET 7 causes different answers that are consistent with PCRE2 and Node // See https://devblogs.microsoft.com/dotnet/regular-expression-improvements-in-dotnet-7/#case-insensitive-matching-and-regexoptions-ignorecase diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net7.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net70.txt similarity index 96% rename from src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net7.txt rename to src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net70.txt index ba73431747..0089ecf644 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net7.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net70.txt @@ -1,4 +1,5 @@ -#SETUP: RegEx,PowerFxV1CompatibilityRules,SupportColumnNamesAsIdentifiers,Net7 +#SETUP: RegEx,PowerFxV1CompatibilityRules,SupportColumnNamesAsIdentifiers +#DISABLE.NET:462 // Changes in case insensitive matching in .NET 7 causes different answers that are consistent with PCRE2 and Node // See https://devblogs.microsoft.com/dotnet/regular-expression-improvements-in-dotnet-7/#case-insensitive-matching-and-regexoptions-ignorecase diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestHelpers/TestRunner.cs b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestHelpers/TestRunner.cs index 130f79930a..8685d709ed 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestHelpers/TestRunner.cs +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestHelpers/TestRunner.cs @@ -61,17 +61,12 @@ public static string GetDefaultTestDir() // * Default, special case // * PowerFxV1, special case, will expand to its constituent Features // * Other handlers listed in this routine - public static Dictionary ParseSetupString(string setup, bool includeContext = false) + public static Dictionary ParseSetupString(string setup) { var settings = new Dictionary(); var possible = new HashSet(); var powerFxV1 = new Dictionary(); - if (includeContext) - { - setup += (setup.Length > 0 ? "," : string.Empty) + (Environment.Version.Major >= 7 ? "Net7" : "disable:Net7"); - } - // Features foreach (var featureProperty in typeof(Features).GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) { diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestHelpers/TxtFileDataAttribute.cs b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestHelpers/TxtFileDataAttribute.cs index 7730bcd493..6d0a91e12a 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestHelpers/TxtFileDataAttribute.cs +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestHelpers/TxtFileDataAttribute.cs @@ -29,7 +29,7 @@ public TxtFileDataAttribute(string filePathCommon, string filePathSpecific, stri _filePathCommon = filePathCommon; _filePathSpecific = filePathSpecific; _engineName = engineName; - _setup = TestRunner.ParseSetupString(setup, true); + _setup = TestRunner.ParseSetupString(setup); if (requiredSetup != null) { _requiredSetup = TestRunner.ParseSetupString(requiredSetup); diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/TestRunnerTests/InternalSetup.cs b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/TestRunnerTests/InternalSetup.cs index b39f3d8a1e..545f5a4319 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/TestRunnerTests/InternalSetup.cs +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/TestRunnerTests/InternalSetup.cs @@ -68,6 +68,11 @@ internal static InternalSetup Parse(string setupHandlerName, Features features, if (string.Equals(part, "DisableMemChecks", StringComparison.OrdinalIgnoreCase)) { + if (isDisable) + { + throw new ArgumentException("Invalid DisableMemChecks setup!"); + } + iSetup.DisableMemoryChecks = true; parts.Remove(part); } @@ -99,6 +104,11 @@ internal static InternalSetup Parse(string setupHandlerName, Features features, } else if (part.StartsWith("TimeZoneInfo", StringComparison.OrdinalIgnoreCase)) { + if (isDisable) + { + throw new ArgumentException("Invalid TimeZoneInfo setup!"); + } + var m = new Regex(@"TimeZoneInfo\(""(?[^)]+)""\)", RegexOptions.IgnoreCase).Match(part); if (m.Success) @@ -116,6 +126,11 @@ internal static InternalSetup Parse(string setupHandlerName, Features features, } else if (part.StartsWith("CultureInfo", StringComparison.OrdinalIgnoreCase)) { + if (isDisable) + { + throw new ArgumentException("Invalid CultureInfo setup!"); + } + var m = new Regex(@"CultureInfo\(""(?[^)]+)""\)", RegexOptions.IgnoreCase).Match(part); if (m.Success) @@ -128,7 +143,7 @@ internal static InternalSetup Parse(string setupHandlerName, Features features, } else { - throw new ArgumentException("Invalid TimeZoneInfo setup!"); + throw new ArgumentException("Invalid CultureInfo setup!"); } } } diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index ad9681b91d..02b0d9468d 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -23,7 +23,7 @@ public FileExpressionEvaluationTests(ITestOutputHelper output) Console = output; } - // File expression tests are run multiple times for the different ways a host can use Power Fx. + // ab File expression tests are run multiple times for the different ways a host can use Power Fx. // // 1. Features.PowerFxV1 without NumberIsFloat - the main way that most hosts will use Power Fx. // 2. Feautres.PowerFxV1 with NumberIsFloat - for hosts that wish to use floating point instead of Decimal. @@ -171,13 +171,13 @@ private static bool ShouldSkipDotNetVersion(ExpressionTestCase testCase, string [Fact] public void RunOne() { - var path = @"d:\repos\regex-min-nolocale\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\match_limited.txt"; + var path = @"d:\repos\regex-min-nolocale\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\match_limited_Net462.txt"; var line = 0; var runner = new InterpreterRunner(); var testRunner = new TestRunner(runner); - testRunner.AddFile(new Dictionary(), path); + testRunner.AddFile(new Dictionary(), null, path); // We can filter to just cases we want, set line above if (line > 0) diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs index dd5127b921..e36063d816 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs @@ -67,7 +67,7 @@ internal static FormulaValue Match(string subject, string pattern, RegexOptions #endif js.AppendLine(@" - const [alteredPattern, alteredFlags] = AlterRegex_NodeJS( pattern, flags ); + const [alteredPattern, alteredFlags] = AlterRegex_JavaScript( pattern, flags ); const regex = RegExp(alteredPattern, alteredFlags.concat(matchAll ? 'g' : '')); const matches = matchAll ? [...subject.matchAll(regex)] : [subject.match(regex)]; diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/PowerFxEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/PowerFxEvaluationTests.cs index a9279c4446..645c71005b 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/PowerFxEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/PowerFxEvaluationTests.cs @@ -57,7 +57,6 @@ public class ExpressionEvaluationTests : PowerFxTest { "OptionSetTestSetup", (null, OptionSetTestSetup1, OptionSetTestSetup2, null) }, { "RegEx", (null, RegExSetup, null, null) }, { "TraceSetup", (null, null, null, TraceSetup) }, - { "Net7", (null, null, null, null) }, // Using .NET 7 or later }; private static object EnableJsonFunctions(PowerFxConfig config, SymbolTable symbolTable) From 9a7e568a7b653752ff59ef49b2684e12aeaa2521 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Sat, 31 Aug 2024 08:58:27 -0700 Subject: [PATCH 36/61] Updates --- .../ExpressionTestCases/Match_Limited.txt | 27 +++++++++++++++++++ .../Match_Limited_Net462.txt | 7 ++++- .../Match_Limited_Net70.txt | 23 ---------------- 3 files changed, 33 insertions(+), 24 deletions(-) delete mode 100644 src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net70.txt diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt index 4f458dd4df..21afa883c9 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt @@ -974,3 +974,30 @@ Errors: Error 15-24: Invalid regular expression: Unsupported special group, foun >> Match( "ab", "a(?d?)b" ) {FullMatch:"ab",StartMatch:1,one:""} + +// Changes in case insensitive matching in .NET 7 causes different answers that are consistent with PCRE2 and Node +// See https://devblogs.microsoft.com/dotnet/regular-expression-improvements-in-dotnet-7/#case-insensitive-matching-and-regexoptions-ignorecase + +#DISABLE.NET:462 +>> Match( UniChar(Hex2Dec("03a9")), "\u03c9", MatchOptions.IgnoreCase ).FullMatch +"Ω" + +#DISABLE.NET:462 +>> Match( UniChar(Hex2Dec("03a9")), "\u2126", MatchOptions.IgnoreCase ).FullMatch +"Ω" + +#DISABLE.NET:462 +>> Match( UniChar(Hex2Dec("03c9")), "\u03a9", MatchOptions.IgnoreCase ).FullMatch +"ω" + +#DISABLE.NET:462 +>> Match( UniChar(Hex2Dec("03c9")), "\u2126", MatchOptions.IgnoreCase ).FullMatch +"ω" + +#DISABLE.NET:462 +>> Match( UniChar(Hex2Dec("2126")), "\u03c9", MatchOptions.IgnoreCase ).FullMatch +"Ω" + +#DISABLE.NET:462 +>> Match( UniChar(Hex2Dec("2126")), "\u03a9", MatchOptions.IgnoreCase ).FullMatch +"Ω" diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net462.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net462.txt index 1526827130..ec2d9d9eba 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net462.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net462.txt @@ -1,23 +1,28 @@ #SETUP: RegEx,PowerFxV1CompatibilityRules,SupportColumnNamesAsIdentifiers -#DISABLE.NET:70 // Changes in case insensitive matching in .NET 7 causes different answers that are consistent with PCRE2 and Node // See https://devblogs.microsoft.com/dotnet/regular-expression-improvements-in-dotnet-7/#case-insensitive-matching-and-regexoptions-ignorecase +#DISABLE.NET:70 >> Match( UniChar(Hex2Dec("03a9")), "\u03c9", MatchOptions.IgnoreCase ).FullMatch Blank() +#DISABLE.NET:70 >> Match( UniChar(Hex2Dec("03a9")), "\u2126", MatchOptions.IgnoreCase ).FullMatch Blank() +#DISABLE.NET:70 >> Match( UniChar(Hex2Dec("03c9")), "\u03a9", MatchOptions.IgnoreCase ).FullMatch Blank() +#DISABLE.NET:70 >> Match( UniChar(Hex2Dec("03c9")), "\u2126", MatchOptions.IgnoreCase ).FullMatch Blank() +#DISABLE.NET:70 >> Match( UniChar(Hex2Dec("2126")), "\u03c9", MatchOptions.IgnoreCase ).FullMatch Blank() +#DISABLE.NET:70 >> Match( UniChar(Hex2Dec("2126")), "\u03a9", MatchOptions.IgnoreCase ).FullMatch Blank() diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net70.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net70.txt deleted file mode 100644 index 0089ecf644..0000000000 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net70.txt +++ /dev/null @@ -1,23 +0,0 @@ -#SETUP: RegEx,PowerFxV1CompatibilityRules,SupportColumnNamesAsIdentifiers -#DISABLE.NET:462 - -// Changes in case insensitive matching in .NET 7 causes different answers that are consistent with PCRE2 and Node -// See https://devblogs.microsoft.com/dotnet/regular-expression-improvements-in-dotnet-7/#case-insensitive-matching-and-regexoptions-ignorecase - ->> Match( UniChar(Hex2Dec("03a9")), "\u03c9", MatchOptions.IgnoreCase ).FullMatch -"Ω" - ->> Match( UniChar(Hex2Dec("03a9")), "\u2126", MatchOptions.IgnoreCase ).FullMatch -"Ω" - ->> Match( UniChar(Hex2Dec("03c9")), "\u03a9", MatchOptions.IgnoreCase ).FullMatch -"ω" - ->> Match( UniChar(Hex2Dec("03c9")), "\u2126", MatchOptions.IgnoreCase ).FullMatch -"ω" - ->> Match( UniChar(Hex2Dec("2126")), "\u03c9", MatchOptions.IgnoreCase ).FullMatch -"Ω" - ->> Match( UniChar(Hex2Dec("2126")), "\u03a9", MatchOptions.IgnoreCase ).FullMatch -"Ω" From 7bf14389986ea1139052b6382991f3b8a745f1e5 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Sat, 31 Aug 2024 09:39:03 -0700 Subject: [PATCH 37/61] Updates --- .../ExpressionTestCases/Match_Limited.txt | 8 +++----- .../ExpressionTestCases/Match_Limited_Net462.txt | 8 -------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt index 21afa883c9..87ddd35ce7 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt @@ -978,18 +978,16 @@ Errors: Error 15-24: Invalid regular expression: Unsupported special group, foun // Changes in case insensitive matching in .NET 7 causes different answers that are consistent with PCRE2 and Node // See https://devblogs.microsoft.com/dotnet/regular-expression-improvements-in-dotnet-7/#case-insensitive-matching-and-regexoptions-ignorecase -#DISABLE.NET:462 >> Match( UniChar(Hex2Dec("03a9")), "\u03c9", MatchOptions.IgnoreCase ).FullMatch "Ω" +>> Match( UniChar(Hex2Dec("03c9")), "\u03a9", MatchOptions.IgnoreCase ).FullMatch +"ω" + #DISABLE.NET:462 >> Match( UniChar(Hex2Dec("03a9")), "\u2126", MatchOptions.IgnoreCase ).FullMatch "Ω" -#DISABLE.NET:462 ->> Match( UniChar(Hex2Dec("03c9")), "\u03a9", MatchOptions.IgnoreCase ).FullMatch -"ω" - #DISABLE.NET:462 >> Match( UniChar(Hex2Dec("03c9")), "\u2126", MatchOptions.IgnoreCase ).FullMatch "ω" diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net462.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net462.txt index ec2d9d9eba..32fc5ff248 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net462.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net462.txt @@ -3,18 +3,10 @@ // Changes in case insensitive matching in .NET 7 causes different answers that are consistent with PCRE2 and Node // See https://devblogs.microsoft.com/dotnet/regular-expression-improvements-in-dotnet-7/#case-insensitive-matching-and-regexoptions-ignorecase -#DISABLE.NET:70 ->> Match( UniChar(Hex2Dec("03a9")), "\u03c9", MatchOptions.IgnoreCase ).FullMatch -Blank() - #DISABLE.NET:70 >> Match( UniChar(Hex2Dec("03a9")), "\u2126", MatchOptions.IgnoreCase ).FullMatch Blank() -#DISABLE.NET:70 ->> Match( UniChar(Hex2Dec("03c9")), "\u03a9", MatchOptions.IgnoreCase ).FullMatch -Blank() - #DISABLE.NET:70 >> Match( UniChar(Hex2Dec("03c9")), "\u2126", MatchOptions.IgnoreCase ).FullMatch Blank() From 54aea5fb1113bc95f1a49776e03779e62d250054 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Sat, 31 Aug 2024 23:21:50 -0700 Subject: [PATCH 38/61] Updates --- .../Binding/BinderUtils.cs | 45 ++ .../Localization/Strings.cs | 2 + .../Texl/Builtins/Match.cs | 8 +- .../Functions/LibraryRegEx.cs | 137 ++-- src/strings/PowerFxResources.en-US.resx | 4 + .../ExpressionTestCases/IsMatch.txt | 22 +- .../ExpressionTestCases/Match_Comments.txt | 69 ++ .../ExpressionTestCases/Match_Limited.txt | 742 ++++++------------ .../ExpressionTestCases/Match_Newlines.txt | 255 ++++++ .../ExpressionTestCases/Match_Unicode.txt | 72 ++ ...ed_Net462.txt => Match_Unicode_Net462.txt} | 0 .../Helpers/RegEx_JavaScript.cs | 14 +- .../FileExpressionEvaluationTests.cs | 4 +- .../Helpers/LibraryRegEx_Compare.cs | 2 +- .../Helpers/LibraryRegEx_NodeJS.cs | 38 +- .../Helpers/LibraryRegEx_PCRE2.cs | 93 ++- 16 files changed, 909 insertions(+), 598 deletions(-) create mode 100644 src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Comments.txt create mode 100644 src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Newlines.txt create mode 100644 src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Unicode.txt rename src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/{Match_Limited_Net462.txt => Match_Unicode_Net462.txt} (100%) diff --git a/src/libraries/Microsoft.PowerFx.Core/Binding/BinderUtils.cs b/src/libraries/Microsoft.PowerFx.Core/Binding/BinderUtils.cs index 29a5f44006..3c05880c62 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Binding/BinderUtils.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Binding/BinderUtils.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.PowerFx.Core.App.Controls; @@ -14,6 +15,7 @@ using Microsoft.PowerFx.Core.Localization; using Microsoft.PowerFx.Core.Logging.Trackers; using Microsoft.PowerFx.Core.Texl; +using Microsoft.PowerFx.Core.Texl.Builtins; using Microsoft.PowerFx.Core.Types; using Microsoft.PowerFx.Core.Types.Enums; using Microsoft.PowerFx.Core.Utils; @@ -1540,6 +1542,49 @@ public static bool TryGetConstantValue(CheckTypesContext context, TexlNode node, nodeValue = string.Join(string.Empty, parameters); return true; } + } + else if (callNode.Head.Name.Value == BuiltinFunctionsCore.Char.Name && callNode.Args.Children.Count == 1) + { + int val = -1; + + if (callNode.Args.Children[0].Kind == NodeKind.DecLit) + { + val = (int)((DecLitNode)callNode.Args.Children[0]).ActualDecValue; + } + else if (callNode.Args.Children[0].Kind == NodeKind.NumLit) + { + val = (int)((NumLitNode)callNode.Args.Children[0]).ActualNumValue; + } + + if (val < 1 || val > 255) + { + return false; + } + + nodeValue = ((char)val).ToString(); + return true; + } + else if (callNode.Head.Name.Value == BuiltinFunctionsCore.UniChar.Name && callNode.Args.Children.Count == 1) + { + int val = -1; + + if (callNode.Args.Children[0].Kind == NodeKind.DecLit) + { + val = (int)((DecLitNode)callNode.Args.Children[0]).ActualDecValue; + } + else if (callNode.Args.Children[0].Kind == NodeKind.NumLit) + { + val = (int)((NumLitNode)callNode.Args.Children[0]).ActualNumValue; + } + + // partial surrogate pair not supported, consistent with interpreter UniChar implementation + if (val < 1 || val > 0x10FFFF || (val >= 0xD800 && val <= 0xDFFF)) + { + return false; + } + + nodeValue = char.ConvertFromUtf32(val); + return true; } break; diff --git a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs index dd9de4de28..8d237d3567 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs @@ -740,6 +740,8 @@ internal static class TexlStrings public static ErrorResourceKey ErrInvalidRegExBadEscapeWithinCharacterClass = new ErrorResourceKey("ErrInvalidRegExBadEscapeWithinCharacterClass"); public static ErrorResourceKey ErrInvalidRegExRepeatInCharClass = new ErrorResourceKey("ErrInvalidRegExRepeatInCharClass"); public static ErrorResourceKey ErrInvalidRegExRepeatedInlineOption = new ErrorResourceKey("ErrInvalidRegExRepeatedInlineOption"); + public static ErrorResourceKey ErrInvalidRegExInlineOptionConflictsWithNumberedSubMatches = new ErrorResourceKey("ErrInvalidRegExInlineOptionConflictsWithNumberedSubMatches"); + public static ErrorResourceKey ErrInvalidRegExConflictingInlineOptions = new ErrorResourceKey("ErrInvalidRegExConflictingInlineOptions"); public static ErrorResourceKey ErrInvalidRegExBadQuantifier = new ErrorResourceKey("ErrInvalidRegExBadQuantifier"); public static ErrorResourceKey ErrInvalidRegExBadBackRefSelfReferencing = new ErrorResourceKey("ErrInvalidRegExBadBackRefSelfReferencing"); public static ErrorResourceKey ErrInvalidRegExBadBackRefNotDefined = new ErrorResourceKey("ErrInvalidRegExBadBackRefNotDefined"); diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index b8cea73cdd..be1feb8792 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -193,7 +193,7 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter # leading (?, misc (?\(\?:) | # non-capture group, still need to track to match with closing paren - \A\(\?(?[imsx]+)\) | # inline options + \A\(\?(?[imnsx]+)\) | # inline options (?\(\?\#[^\)]*\)) | # inline comment (?\(\?(=|!|<=|\(\?(\w+|\w*-\w+)[\:\)]) | # inline options, including disable of options @@ -405,6 +405,12 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter return false; } + if (token.Groups["goodInlineOptions"].Value.Contains("n") && numberedCpature) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExInlineOptionConflictsWithNumberedSubMatches, token.Value); + return false; + } + if (token.Groups["goodInlineOptions"].Value.Contains("x")) { freeSpacing = true; diff --git a/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs b/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs index 45ec488464..230fc1d004 100644 --- a/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs +++ b/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.NetworkInformation; using System.Text; using System.Text.RegularExpressions; using System.Threading; @@ -59,10 +60,10 @@ public IsMatchImplementation(TimeSpan regexTimeout) _regexTimeout = regexTimeout; } - internal override FormulaValue InvokeRegexFunction(string input, string regex, RegexOptions options) + internal override FormulaValue InvokeRegexFunction(string input, string regex, string options) { - var regexAltered = AlterRegex_DotNet(regex, options); - Regex rex = new Regex(regexAltered, options, _regexTimeout); + var (regexAltered, regexOptions) = AlterRegex_DotNet(regex, options); + Regex rex = new Regex(regexAltered, regexOptions, _regexTimeout); bool b = rex.IsMatch(input); return new BooleanValue(IRContext.NotInSource(FormulaType.Boolean), b); @@ -80,18 +81,18 @@ public MatchImplementation(TimeSpan regexTimeout) _regexTimeout = regexTimeout; } - internal override FormulaValue InvokeRegexFunction(string input, string regex, RegexOptions options) + internal override FormulaValue InvokeRegexFunction(string input, string regex, string options) { - var regexAltered = AlterRegex_DotNet(regex, options); - Regex rex = new Regex(regexAltered, options, _regexTimeout); + var (regexAltered, regexOptions) = AlterRegex_DotNet(regex, options); + Regex rex = new Regex(regexAltered, regexOptions, _regexTimeout); Match m = rex.Match(input); if (!m.Success) { - return new BlankValue(IRContext.NotInSource(new KnownRecordType(GetRecordTypeFromRegularExpression(regex, options)))); + return new BlankValue(IRContext.NotInSource(new KnownRecordType(GetRecordTypeFromRegularExpression(regex, regexOptions)))); } - return GetRecordFromMatch(rex, m, options); + return GetRecordFromMatch(rex, m, regexOptions); } } @@ -106,25 +107,25 @@ public MatchAllImplementation(TimeSpan regexTimeout) _regexTimeout = regexTimeout; } - internal override FormulaValue InvokeRegexFunction(string input, string regex, RegexOptions options) + internal override FormulaValue InvokeRegexFunction(string input, string regex, string options) { - var regexAltered = AlterRegex_DotNet(regex, options); - Regex rex = new Regex(regexAltered, options, _regexTimeout); + var (regexAltered, regexOptions) = AlterRegex_DotNet(regex, options); + Regex rex = new Regex(regexAltered, regexOptions, _regexTimeout); MatchCollection mc = rex.Matches(input); List records = new (); foreach (Match m in mc) { - records.Add(GetRecordFromMatch(rex, m, options)); + records.Add(GetRecordFromMatch(rex, m, regexOptions)); } - return TableValue.NewTable(new KnownRecordType(GetRecordTypeFromRegularExpression(regex, options)), records.ToArray()); + return TableValue.NewTable(new KnownRecordType(GetRecordTypeFromRegularExpression(regex, regexOptions)), records.ToArray()); } } internal abstract class RegexCommonImplementation : IAsyncTexlFunction { - internal abstract FormulaValue InvokeRegexFunction(string input, string regex, RegexOptions options); + internal abstract FormulaValue InvokeRegexFunction(string input, string regex, string options); protected abstract string DefaultRegexOptions { get; } @@ -180,42 +181,9 @@ public Task InvokeAsync(FormulaValue[] args, CancellationToken can matchOptions = DefaultRegexOptions; } - RegexOptions regOptions = System.Text.RegularExpressions.RegexOptions.CultureInvariant; - - if (matchOptions.Contains("i")) - { - regOptions |= System.Text.RegularExpressions.RegexOptions.IgnoreCase; - } - - if (matchOptions.Contains("m")) - { - regOptions |= System.Text.RegularExpressions.RegexOptions.Multiline; - } - - if (matchOptions.Contains("^") && !regularExpression.StartsWith("^", StringComparison.Ordinal)) - { - regularExpression = "^" + regularExpression; - } - - if (matchOptions.Contains("$") && !regularExpression.EndsWith("$", StringComparison.Ordinal)) - { - regularExpression += "$"; - } - - if (matchOptions.Contains("s")) - { - regOptions |= System.Text.RegularExpressions.RegexOptions.Singleline; - } - - // lack of NumberedSubMatches turns on ExplicitCapture for higher performance - if (!matchOptions.Contains("N")) - { - regOptions |= System.Text.RegularExpressions.RegexOptions.ExplicitCapture; - } - try { - return Task.FromResult(InvokeRegexFunction(inputString, regularExpression, regOptions)); + return Task.FromResult(InvokeRegexFunction(inputString, regularExpression, matchOptions)); } catch (RegexMatchTimeoutException rexTimeoutEx) { @@ -246,17 +214,31 @@ public Task InvokeAsync(FormulaValue[] args, CancellationToken can #pragma warning restore SA1119 // Statement should not use unnecessary parenthesis } - protected string AlterRegex_DotNet(string regex, RegexOptions options) + protected (string, RegexOptions) AlterRegex_DotNet(string regex, string options) { - var openCharacterClass = false; // are we defining a character class? - var freeSpacing = (options & System.Text.RegularExpressions.RegexOptions.IgnorePatternWhitespace) != 0 || Regex.IsMatch(regex, @"^\(\?[A-Za-z-[x]]*x"); - var multiline = (options & System.Text.RegularExpressions.RegexOptions.Multiline) != 0 || Regex.IsMatch(regex, @"^\(\?[A-Za-z-[m]]*m"); - var dotAll = (options & System.Text.RegularExpressions.RegexOptions.Singleline) != 0 || Regex.IsMatch(regex, @"^\(\?[A-Za-z-[s]]*s"); var alteredRegex = new StringBuilder(); + bool openCharacterClass = false; // are we defining a character class? + int index = 0; - for (int i = 0; i < regex.Length; i++) + Match inlineOptions = Regex.Match(regex, @"^\(\?([imnsx]+)\)"); + + if (inlineOptions.Success) + { + options = options + inlineOptions.Groups[1]; + index = inlineOptions.Length; + } + + bool freeSpacing = options.Contains("x"); + bool multiline = options.Contains("m"); + bool ignoreCase = options.Contains("i"); + bool dotAll = options.Contains("s"); + bool matchStart = options.Contains("^"); + bool matchEnd = options.Contains("$"); + bool numberedSubMatches = options.Contains("N"); + + for (; index < regex.Length; index++) { - switch (regex[i]) + switch (regex[index]) { case '[': openCharacterClass = true; @@ -271,10 +253,12 @@ protected string AlterRegex_DotNet(string regex, RegexOptions options) case '#': if (freeSpacing) { - for (i++; i < regex.Length && regex[i] != '\r' && regex[i] != '\n'; i++) + for (index++; index < regex.Length && regex[index] != '\r' && regex[index] != '\n'; index++) { // skip the comment characters until the next newline, in case it includes [ ] } + + index--; } else { @@ -285,9 +269,9 @@ protected string AlterRegex_DotNet(string regex, RegexOptions options) case '\\': alteredRegex.Append("\\"); - if (++i < regex.Length) + if (++index < regex.Length) { - alteredRegex.Append(regex[i]); + alteredRegex.Append(regex[index]); } break; @@ -304,13 +288,46 @@ protected string AlterRegex_DotNet(string regex, RegexOptions options) alteredRegex.Append(openCharacterClass ? "$" : (multiline ? @"(?=\z|\r\n|\r|\n)" : @"(?=\z|\r\n\z|\r\z|\n\z)")); break; + case ' ': + case '\f': + case '\n': + case '\r': + case '\t': + case '\v': + if (!freeSpacing) + { + alteredRegex.Append(regex[index]); + } + + break; + default: - alteredRegex.Append(regex[i]); + alteredRegex.Append(regex[index]); break; } } - return alteredRegex.ToString(); + string prefix = string.Empty; + string postfix = string.Empty; + + if (matchStart && (alteredRegex.Length == 0 || alteredRegex[0] != '^')) + { + prefix = "^"; + } + + if (matchEnd && (alteredRegex.Length == 0 || alteredRegex[alteredRegex.Length - 1] != '$')) + { + postfix = "$"; + } + + // freeSpacing has already been taken care of in this routine + RegexOptions alteredOptions = RegexOptions.CultureInvariant | + (multiline ? RegexOptions.Multiline : 0) | + (ignoreCase ? RegexOptions.IgnoreCase : 0) | + (dotAll ? RegexOptions.Singleline : 0) | + (numberedSubMatches ? 0 : RegexOptions.ExplicitCapture); + + return (prefix + alteredRegex.ToString() + postfix, alteredOptions); } protected static RecordValue GetRecordFromMatch(Regex rex, Match m, RegexOptions options) diff --git a/src/strings/PowerFxResources.en-US.resx b/src/strings/PowerFxResources.en-US.resx index 13dc0ff0d4..f31a249ef3 100644 --- a/src/strings/PowerFxResources.en-US.resx +++ b/src/strings/PowerFxResources.en-US.resx @@ -4457,6 +4457,10 @@ Invalid regular expression: Repeated inline option, found "{0}". Error message indicating that the regular expression includes more than one of the same option. + + Invalid regular expression: Inline option is incompatible with MatchOptions.NumberedSubMatches, found "{0}". + Error message indicating that the regular expression includes an inline option that is incompatible with numbered sub matches. + Invalid regular expression: Possessive quantifiers are not supported, found "{0}". Error message indicating that the regular expression does not support possessive quantifiers. diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch.txt index 24d1d1bf01..a641680980 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch.txt @@ -91,8 +91,26 @@ true >> IsMatch("(44) 123-4567", "^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$") false ->> IsMatch("""Hello world""", Char(34) & "Hello", MatchOptions.Contains) -Errors: Error 36-37: Regular expressions must be constant values.|Error 0-7: The function 'IsMatch' has some invalid arguments. +>> IsMatch("""Hello world""", Char(34) & "Hello", MatchOptions.Contains) +true + +>> IsMatch("""Hello world""", UniChar(34) & "Hello", MatchOptions.Contains) +true + +>> IsMatch("👽Hello world", UniChar(Hex2Dec("1F47D")) & "Hello", MatchOptions.Contains) +Errors: Error 51-52: Regular expressions must be constant values.|Error 0-7: The function 'IsMatch' has some invalid arguments. + +>> IsMatch("👽Hello world", UniChar(128125) & "Hello", MatchOptions.Contains) +true + +>> IsMatch("👽Hello world", "\ud83d\udc7dHello", MatchOptions.Contains) // surrrogate pairs +true + +>> IsMatch(UniChar(Hex2Dec("1f47d")) & "Hello world", UniChar(128125) & "Hello", MatchOptions.Contains) +true + +>> IsMatch("""Hello world""", Mid( "Hello", 1 ), MatchOptions.Contains) +Errors: Error 27-44: Regular expressions must be constant values.|Error 0-7: The function 'IsMatch' has some invalid arguments. >> IsMatch("Hello 123 world", $"Hello {Sqrt(1)}{Sqrt(4)}{Sqrt(9)} world") Errors: Error 27-69: Regular expressions must be constant values.|Error 0-7: The function 'IsMatch' has some invalid arguments. diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Comments.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Comments.txt new file mode 100644 index 0000000000..1c8b47d61c --- /dev/null +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Comments.txt @@ -0,0 +1,69 @@ +#SETUP: RegEx,PowerFxV1CompatibilityRules,SupportColumnNamesAsIdentifiers + +// Comments and free spacing behavior in Power Fx regular expressions. +// +// Effective Usage .NET ECMAScript PCRE2 +// ===================================================================================================================================== +// (?# ...) Inline comment Yes No Yes +// "x" option space insiginificant and # comments Yes No Yes + +// Inline comments + +>> Match( "test", "(?# this is a test)st" ) +{FullMatch:"st",StartMatch:3} + +>> Match( "test", "(?# this is a test ( with an open paren )st" ) +Errors: Error 15-60: Invalid regular expression: Inline comments cannot include open parenthesis, found in "(?# this is a test ( with an open paren )".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test", "(?# this is a test \) with an escaped close paren )st" ) // can't escape a paren in an inline comment +Errors: Error 15-70: Invalid regular expression: Unopened groups, too few opening parenthesis.|Error 0-5: The function 'Match' has some invalid arguments. + +// Free spacing with different newline characters between + +>> Match( "atestz", "(?x) + # this is free spacing! + + t + + e # e is for elephant + + s + + t # t is for terminte + + ").FullMatch +"test" + +>> Match( "atestz", "(?x)" &Char(13)& "# this is free spacing!" &Char(13)&Char(13)& "t" &Char(13)&Char(13) & "e # e is for elephant" &Char(13)&Char(13)& "s" &Char(13)&Char(13)& "t # t is for terminte" &Char(13)&Char(13)).FullMatch +"test" + +>> Match( "atestz", "(?x)" &Char(13)& "# this is free spacing!" &Char(10)&Char(10)& "t" &Char(10)&Char(10) & "e # e is for elephant" &Char(10)&Char(10)& "s" &Char(13)&Char(13)& "t # t is for terminte" &Char(10)&Char(10)).FullMatch +"test" + +>> Match( "atestz", "(?x)" &Char(13)&Char(10)& "# this is free spacing!" &Char(13)&Char(10)&Char(13)&Char(10)& "t" &Char(13)&Char(10)&Char(13)&Char(10)& "e # e is for elephant" &Char(13)&Char(10)&Char(13)&Char(10)& "s" &Char(13)&Char(10)&Char(13)&Char(10)& "t # t is for terminte" &Char(13)&Char(10)&Char(13)&Char(10)).FullMatch +"test" + +>> Match( "atestz", "(?x)" &Char(13)& "# this is free spacing!" &Char(13)& "t" &Char(13)& "e # e is for elephant" &Char(13)& "s" &Char(13)& "t # t is for terminte").FullMatch +"test" + +>> Match( "atestz", "(?x)" &Char(13)& "# this is free spacing!" &Char(10)& "t" &Char(10)& "e # e is for elephant" &Char(10)& "s" &Char(10)& "t # t is for terminte" &Char(10)).FullMatch +"test" + +>> Match( "atestz", "(?x)" &Char(13)&Char(10)& "# this is free spacing!" &Char(13)&Char(10)& "t" &Char(13)&Char(10)& "e # e is for elephant" &Char(13)&Char(10)& "s" &Char(13)&Char(10)& "t # t is for terminte" &Char(13)&Char(10)).FullMatch +"test" + +>> IsMatch( "ab", "(?x)a # b" ) +false + +>> IsMatch( "ab", "(?x)a # " &Char(13)& " b" ) +true + +>> IsMatch( "ab", "(?x)a # " &Char(10)& " b" ) +true + +>> IsMatch( "ab", "(?x)a # " &Char(13)&Char(10)& " b" ) // one is the newline, the other is just whitespace that is ignored +true + +>> IsMatch( "ab", "(?x)a # " &Char(133)& " b" ) // \x85 +false + diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt index 87ddd35ce7..bf1693b4c6 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt @@ -1,61 +1,69 @@ #SETUP: RegEx,PowerFxV1CompatibilityRules,SupportColumnNamesAsIdentifiers -// Limit regular expressions to common features that are supported, with consistent semantics, by both canonical .NET and XRegExp. -// It is better to disallow now and bring back with customer demand or as platforms add more support. +// Power Fx regular expressions are limited to features that can be transpiled to native .NET (Interpreter), ECMAScript (Canvas), or PCRE2 (Excel). +// We want the same results everywhere for Power Fx, even if the underlying implementation is different. +// These tests can be run through all three engines and the results compared with by setting ExpressionEvaluationTests.RegExCompareEnabled, a PCRE2 DLL and NodeJS must be installed on the system. // -// Features that are disallowed: -// Capture groups -// Numbered capture groups, use named capture groups instead (.NET different from XRegExp). -// Self-referncing groups, such as "(a\1)" (.NET different from XRegExp). -// Single quoted "(?'name'..." and "\k'name'" (.NET only). -// Balancing capture groups (.NET only). -// Octal character codes, use \x or \u instead (.NET different from XRegExp) -// "\o" could be added in the future, but we should avoid "\0" which causes backreference confusion. -// Inline options -// Anywhere in the expression except the beginning (.NET only). -// For subexpressions (.NET only). +// In addition, Power Fx regular expressions are opinionated and try to eliminate some of the ambiguity in regular expressions: +// Numbered capture groups are disabled by default, and cannot be mixed with named capture groups. +// Octal character codes are not supported. +// -, [, ], {, and } must be escaped when used in a character class. +// Escaping is only supported for special characters and unknown alphanumeric escape sequences are not supported. +// Unicode characters are used throughout. +// Newlines support Windows friendly \r\n as well as \r and \n. +// +// Features that are supported: +// Literal characters. Any character except the special characters [ ] \ ^ $ . | ? * + ( ) can be inserted directly. +// Escaped special characters. \ (backslash) followed by a special character to insert it directly, includes \- when in a character class. +// Operators +// Dot (.), matches everything except [\r\n] unless MatchOptions.DotAll is used. +// Anchors, ^ and $, matches the beginning and end of the string, or of a line if MatchOptions.Multiline is used. +// Quanitfiers +// Greedy quantifiers. ? matches 0 or 1 times, + matches 1 or more times, * matches 0 or more times, {3} matches exactly 3 times, {1,} matches at least 1 time, {1,3} matches between 1 and 3 times. By default, matching is "greedy" and the match will be as large as possible. +// Lazy quantifiers. Same as the greedy quantifiers followed by ?, for example *? or {1,3}?. With the lazy modifier, the match will be as small as possible. +// Alternation. a|b matches "a" or "b". // Character classes -// Character class subtraction "[a-z-[m-n]]" (.NET only). -// Conditional alternation (.NET only). +// Custom character class. [abc] list of characters, [a-fA-f0-9] range of characters, [^a-z] everything but these characters. Character classes cannot be nested, subtracted, or intersected, and the same character cannot appear twice in the character class (except for a hyphen). +// Word characters and breaks. \w, \W, \b, \B, using the Unicode definition of letters [\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}\p{Pc}\p{Lm}]. +// Digit characters. \d includes the digits 0-9 and \p{Nd}, \D matches everything except characters matched by \d. +// Space characters. \s includes spacing characters [ \r\n\t\f\x0B\x85\p{Z}], \S which matches everything except characters matched by \s, \r carriage return, \n newline, \t tab, \f form feed. +// Control characters. \cA, where the control characters is [A-Za-z]. +// Hexadecimal and Unicode character codes. \x20 with two hexadecimal digits, \u2028 with four hexadecimal digits. +// Unicode character class and property. \p{Ll} matches all Unicode lowercase letters, while \P{Ll} matches everything that is not a Unicode lowercase letter. +// Capture groups +// Non capture group. (?:a), group without capturing the result as a named or numbered sub-match. +// Named group and back reference. (?chars) captures a sub-match with the name name, referenced with \k. Cannot be used if MatchOptions.NumberedSubMatches is enabled. +// Numbered group and back referencs. (a|b) captures a sub-match, referenced with \1. MatchOptions.NumberedSubMatches must be enabled. +// Lookahead and lookbehind. (?=a), (?!a), (?<=b), (?> Match( "the whole world", "\b(\w+\s*)+" ) -{FullMatch:"the whole world",StartMatch:1} - ->> Match( "целый мир", "\b(\w+\s*)+" ) -{FullMatch:"целый мир",StartMatch:1} - ->> Match( "el niño", "\b(\w+\s*)+" ) -{FullMatch:"el niño",StartMatch:1} - ->> Match( "Müller", "^\w+$" ) -{FullMatch:"Müller",StartMatch:1} - -// Unicode numbers as digits are matched - ->> Match( "12345", "^\d+$" ) -{FullMatch:"12345",StartMatch:1} +// In addition, the Power Fx compiler uses the .NET regular expression engine to validate the expression and determine capture group names. +// So, any regular expression that does not compile with .NET is also automatically disallowed. ->> Match( "12٤45", "^\d+$" ) -{FullMatch:"12٤45",StartMatch:1} - ->> Match( "123४5", "^\d+$" ) -{FullMatch:"123४5",StartMatch:1} - ->> Match( "abc3d", "^\D+" ) -{FullMatch:"abc",StartMatch:1} - ->> Match( "abc٤45", "^\D+" ) -{FullMatch:"abc",StartMatch:1} - ->> Match( "abc४5", "^\D+" ) -{FullMatch:"abc",StartMatch:1} +// +// GROUPS +// // Self referencing groups are disallowed @@ -142,104 +150,71 @@ Errors: Error 22-82: Invalid regular expression: Named captures cannot be used w >> Match( "hello world", "(((())(())(())(((((((())))))))))()(l)()\18", MatchOptions.NumberedSubMatches) {FullMatch:"ll",StartMatch:3,SubMatches:Table({Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:""},{Value:"l"},{Value:""})} -// Octal characters are not allowed - ->> Match( "as$df", "\044" ) -Errors: Error 16-22: Invalid regular expression: Octal \0 character codes are not supported, use hexadecimal \x or Unicode \u instead, found "\044".|Error 0-5: The function 'Match' has some invalid arguments. - -// inline options - ->> Match( "hello"&Char(10)&"howdy", "o$" ) -Blank() - ->> Match( "hello"&Char(10)&"howdy", "o$", MatchOptions.Multiline ) -{FullMatch:"o",StartMatch:5} - ->> Match( "hello"&Char(10)&"howdy", "(?im)o$" ) -{FullMatch:"o",StartMatch:5} - ->> Match( "hello"&Char(10)&"howdy", "(?m)o$" ) -{FullMatch:"o",StartMatch:5} - ->> With( Match( "hello"&Char(10)&"howdy", "(?s)hello.howdy" ), {StartMatch: StartMatch, LengthMatch: Len(FullMatch)} ) -{LengthMatch:11,StartMatch:1} - ->> With( Match( "hello"&Char(13)&"howdy", "(?s)hello.howdy" ), {StartMatch: StartMatch, LengthMatch: Len(FullMatch)} ) -{LengthMatch:11,StartMatch:1} - ->> Match( "hello"&Char(13)&Char(10)&"howdy", "(?s)hello.howdy" ) -Blank() - ->> With( Match( "hello"&Char(10)&"howdy", "hello.howdy", MatchOptions.DotAll ), {StartMatch: StartMatch, LengthMatch: Len(FullMatch)} ) -{LengthMatch:11,StartMatch:1} - ->> With( Match( "hello"&Char(13)&"howdy", "hello.howdy", MatchOptions.DotAll ), {StartMatch: StartMatch, LengthMatch: Len(FullMatch)} ) -{LengthMatch:11,StartMatch:1} +// balancing groups ->> Match( "hello"&Char(13)&Char(10)&"howdy", "hello.howdy", MatchOptions.DotAll ) -Blank() +>> Match( "(hello world)", "(?)a") +Errors: Error 24-35: Invalid regular expression: Balancing capture groups is not supported, found "(?".|Error 0-5: The function 'Match' has some invalid arguments. ->> Match( "hello, howdy", "(?x) llo , \s how # comment" ) -{FullMatch:"llo, how",StartMatch:3} +>> Match( "(hello world)", "(?)a(?<-s>)b") +Errors: Error 24-41: Invalid regular expression: Balancing capture groups is not supported, found "(?<-s>".|Error 0-5: The function 'Match' has some invalid arguments. -// unsupported inline options +// groups with single ticks ->> Match( "hello"&Char(10)&"howdy", "(?-m)o$" ) -Errors: Error 33-42: Invalid regular expression: Inline options are limited to a combination of the letters [imsx], cannot disable options, and cannot be used on a subexpression, found "(?-m)".|Error 0-5: The function 'Match' has some invalid arguments. +>> Match( "(hello world)", "(?'name'l)") +Errors: Error 24-36: Invalid regular expression: Using single quoted named captures is not supported, use (?<...>) syntax instead, found "(?'name'".|Error 0-5: The function 'Match' has some invalid arguments. ->> Match( "hello"&Char(10)&"howdy", "(?i-m)o$" ) -Errors: Error 33-43: Invalid regular expression: Inline options are limited to a combination of the letters [imsx], cannot disable options, and cannot be used on a subexpression, found "(?i-m)".|Error 0-5: The function 'Match' has some invalid arguments. +>> Match( "(hello world)", "(?'s-e'l)") +Errors: Error 24-35: Invalid regular expression: Using single quoted named captures is not supported, use (?<...>) syntax instead, found "(?'s-e'".|Error 0-5: The function 'Match' has some invalid arguments. ->> Match( "hello"&Char(10)&"howdy", "^(?m)o$" ) -Errors: Error 33-42: Invalid regular expression: Inline options must appear at the beginning of the regular expression, found "(?m)" later.|Error 0-5: The function 'Match' has some invalid arguments. +// Octal characters are not allowed ->> Match( "hello"&Char(10)&"howdy", "^(?i-m)o$" ) -Errors: Error 33-44: Invalid regular expression: Inline options must appear at the beginning of the regular expression, found "(?i-m)" later.|Error 0-5: The function 'Match' has some invalid arguments. +>> Match( "as$df", "\044" ) +Errors: Error 16-22: Invalid regular expression: Octal \0 character codes are not supported, use hexadecimal \x or Unicode \u instead, found "\044".|Error 0-5: The function 'Match' has some invalid arguments. ->> Match( "hello"&Char(10)&"howdy", "^(?m:o$)" ) -Errors: Error 33-43: Invalid regular expression: Inline options must appear at the beginning of the regular expression, found "(?m:" later.|Error 0-5: The function 'Match' has some invalid arguments. +// Can't define named capture group more than once ->> Match( "hello world", "(?n)o") -Errors: Error 22-29: Invalid regular expression: Inline options are limited to a combination of the letters [imsx], cannot disable options, and cannot be used on a subexpression, found "(?n)".|Error 0-5: The function 'Match' has some invalid arguments. +>> Match( "test", "(?t).*(?t)" ) +{FullMatch:"test",StartMatch:1,one:"t",two:"t"} ->> Match( "hello world", "(?s)o") -{FullMatch:"o",StartMatch:5} +>> Match( "test", "((?t)|(?t))" ) +{FullMatch:"t",StartMatch:1,one:"t",two:Blank()} ->> Match( "hello world", "(?x)o") -{FullMatch:"o",StartMatch:5} +>> Match( "test", "(?t).*(?t)" ) +Errors: Error 15-37: Invalid regular expression: Named capture group "(?" defined more than once.|Error 0-5: The function 'Match' has some invalid arguments. ->> Match( "hello world", "(?A)o") -Errors: Error 22-29: Invalid regular expression: Inline options are limited to a combination of the letters [imsx], cannot disable options, and cannot be used on a subexpression, found "(?A)".|Error 0-5: The function 'Match' has some invalid arguments. +>> Match( "test", "((?t)|(?t))" ) +Errors: Error 15-38: Invalid regular expression: Named capture group "(?" defined more than once.|Error 0-5: The function 'Match' has some invalid arguments. ->> Match ("hello world", "(?^)o") // PCRE2 -Errors: Error 22-29: Invalid regular expression: Unsupported special group, found "(?^)o".|Error 0-5: The function 'Match' has some invalid arguments. +// Bad named capture group names ->> Match ("hello world", "(?xx)o") // PCRE2 -Errors: Error 22-30: Invalid regular expression: Repeated inline option, found "(?xx)".|Error 0-5: The function 'Match' has some invalid arguments. +>> Match( "test", "(?s).*" ) +{FullMatch:"st",StartMatch:3,a:"s"} ->> Match ("hello world", "(?J)o") // PCRE2 -Errors: Error 22-29: Invalid regular expression: Inline options are limited to a combination of the letters [imsx], cannot disable options, and cannot be used on a subexpression, found "(?J)".|Error 0-5: The function 'Match' has some invalid arguments. +>> Match( "test", "(?s).*" ) +{FullMatch:"st",StartMatch:3,a1:"s"} ->> Match ("hello world", "(?U)o") // PCRE2 -Errors: Error 22-29: Invalid regular expression: Inline options are limited to a combination of the letters [imsx], cannot disable options, and cannot be used on a subexpression, found "(?U)".|Error 0-5: The function 'Match' has some invalid arguments. +>> Match( "test", "(?<1>s).*" ) +Errors: Error 15-26: Invalid regular expression: Named capture group name must be a combination of letters and digits and begin with a letter, found "(?<1>".|Error 0-5: The function 'Match' has some invalid arguments. -// inline options overriding explicit options, conflicts? +>> Match( "test", "(?<1a>s).*" ) +Errors: Error 15-27: Invalid regular expression: Named capture group name must be a combination of letters and digits and begin with a letter, found "(?<1a>".|Error 0-5: The function 'Match' has some invalid arguments. -// balancing groups +>> Match( "test", "(?s).*" ) +Errors: Error 15-27: Invalid regular expression: Named capture group name must be a combination of letters and digits and begin with a letter, found "(?".|Error 0-5: The function 'Match' has some invalid arguments. ->> Match( "(hello world)", "(?)a") -Errors: Error 24-35: Invalid regular expression: Balancing capture groups is not supported, found "(?".|Error 0-5: The function 'Match' has some invalid arguments. +>> Match( "test", "(?s).*" ) +Errors: Error 15-27: Invalid regular expression: Named capture group name must be a combination of letters and digits and begin with a letter, found "(?".|Error 0-5: The function 'Match' has some invalid arguments. ->> Match( "(hello world)", "(?)a(?<-s>)b") -Errors: Error 24-41: Invalid regular expression: Balancing capture groups is not supported, found "(?<-s>".|Error 0-5: The function 'Match' has some invalid arguments. +// Group name case sensitivity -// groups with single ticks +>> Match( "test", "(?t).*\k") +{FullMatch:"test",StartMatch:1,a:"t"} ->> Match( "(hello world)", "(?'name'l)") -Errors: Error 24-36: Invalid regular expression: Using single quoted named captures is not supported, use (?<...>) syntax instead, found "(?'name'".|Error 0-5: The function 'Match' has some invalid arguments. +>> Match( "test", "(?t).*\k") +Errors: Error 15-31: Invalid regular expression: Capture group "\k" not defined.|Error 0-5: The function 'Match' has some invalid arguments. ->> Match( "(hello world)", "(?'s-e'l)") -Errors: Error 24-35: Invalid regular expression: Using single quoted named captures is not supported, use (?<...>) syntax instead, found "(?'s-e'".|Error 0-5: The function 'Match' has some invalid arguments. +>> Match( "test", "(?t).*\k") +Errors: Error 15-31: Invalid regular expression: Capture group "\k" not defined.|Error 0-5: The function 'Match' has some invalid arguments. // conditional alternation @@ -251,6 +226,28 @@ Errors: Error 24-60: Invalid regular expression: Conditional alternation is not >> Match( "hello world", "(e)(?(1)l|d)" ) Errors: Error 22-36: Invalid regular expression: Conditional alternation is not supported, found "(?(".|Error 0-5: The function 'Match' has some invalid arguments. +// Other + +// Node != Net for this test ("b" is empty for Node), a known difference between PCRE2 and Perl too +// >> Match( "aba", "^(a(b)?)+$", MatchOptions.NumberedSubMatches ) +// {FullMatch:"aba",StartMatch:1,SubMatches:Table({Value:"a"},{Value:"b"})} + +>> Match( "ab", "a(d)?b", MatchOptions.NumberedSubMatches ) +{FullMatch:"ab",StartMatch:1,SubMatches:Table({Value:Blank()})} + +>> Match( "ab", "a(d?)b", MatchOptions.NumberedSubMatches ) +{FullMatch:"ab",StartMatch:1,SubMatches:Table({Value:""})} + +>> Match( "ab", "a(?d)?b" ) +{FullMatch:"ab",StartMatch:1,one:Blank()} + +>> Match( "ab", "a(?d?)b" ) +{FullMatch:"ab",StartMatch:1,one:""} + +// +// CHARACTER CLASSES +// + // character class and literal square brackets >> Match( "a", "[]" ) @@ -288,15 +285,29 @@ Errors: Error 13-19: Invalid regular expression: Literal square braces must be e >> Match( "k", "[a-z-[b-c]]" ) Errors: Error 12-25: Invalid regular expression: Character class subtraction is not supported, found "-[b-c]...".|Error 0-5: The function 'Match' has some invalid arguments. -// regular expression parsing +// repeated characters in character class, used by intersection and future character class features, also would catch POSIX cases if wasn't already blocked by nested square brackets ->> Match( "test\123bed", "\\(\a)" ) -Errors: Error 22-30: Invalid regular expression: Invalid escape code, found "\a".|Error 0-5: The function 'Match' has some invalid arguments. +>> Match( "hello", "[a-z&&[k-m]]" ) +Errors: Error 16-30: Invalid regular expression: Character appears more than once in character class, found repeated "&".|Error 0-5: The function 'Match' has some invalid arguments. ->> Match( "test\123bed", "\\(\d)" ) -{FullMatch:"\1",StartMatch:5} +>> Match( "hello", "[a-z&&k-m]" ) +Errors: Error 16-28: Invalid regular expression: Character appears more than once in character class, found repeated "&".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "hello", "[a-hh-z]" ) +Errors: Error 16-26: Invalid regular expression: Character appears more than once in character class, found repeated "h".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "HellO", "[[:lower:]]" ) +Errors: Error 16-29: Invalid regular expression: Square bracket character classes cannot be empty and cannot include unescaped literal open or close square brackets, escape with "\[" or "\]".|Error 0-5: The function 'Match' has some invalid arguments. -// character classes +>> Match( "hello", "[[:s:]]" ) +Errors: Error 16-25: Invalid regular expression: Square bracket character classes cannot be empty and cannot include unescaped literal open or close square brackets, escape with "\[" or "\]".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "hello", "[[=x=]]" ) +Errors: Error 16-25: Invalid regular expression: Square bracket character classes cannot be empty and cannot include unescaped literal open or close square brackets, escape with "\[" or "\]".|Error 0-5: The function 'Match' has some invalid arguments. + +// +// ESCAPES +// >> Match( "test", "\a" ) Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\a".|Error 0-5: The function 'Match' has some invalid arguments. @@ -310,24 +321,6 @@ Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\A" >> Match( "$test atest test", "\Btest" ) {FullMatch:"test",StartMatch:8} ->> Match( "$test" & Char(8) & "test", "[\b]test" ) -Errors: Error 35-45: Invalid regular expression: Escape character not permitted within character class, found "[\b]te...".|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "$test" & Char(8) & "test", "[\B]test" ) -Errors: Error 35-45: Invalid regular expression: Escape character not permitted within character class, found "[\B]te...".|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "$test" & Char(8) & "test", "[\W]test" ) -Errors: Error 35-45: Invalid regular expression: Escape character not permitted within character class, found "[\W]te...".|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "$test" & Char(8) & "test", "[\S]test" ) -Errors: Error 35-45: Invalid regular expression: Escape character not permitted within character class, found "[\S]te...".|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "$test" & Char(8) & "test", "[\w]test" ) // \w is OK -Blank() - ->> Match( "$test" & Char(8) & "atest", "[\w]test" ) // \w is OK -{FullMatch:"atest",StartMatch:7} - >> DropColumns( Match( "test" & Char(10) & "bed", "\cj" ), FullMatch ) {StartMatch:5} @@ -475,6 +468,32 @@ Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\Z" >> Match( "test", "\_" ) Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\_".|Error 0-5: The function 'Match' has some invalid arguments. +// negated escape class and \b can't appear in a character classes, can't easily transpile without character class subtraction or intersection in ECMAScript + +>> Match( "$test" & Char(8) & "test", "[\b]test" ) +Errors: Error 35-45: Invalid regular expression: Escape character not permitted within character class, found "[\b]te...".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "$test" & Char(8) & "test", "[\B]test" ) +Errors: Error 35-45: Invalid regular expression: Escape character not permitted within character class, found "[\B]te...".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "test123bed", "[\D]+" ) +Errors: Error 21-28: Invalid regular expression: Escape character not permitted within character class, found "[\D]+".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "$test" & Char(8) & "test", "[\W]test" ) +Errors: Error 35-45: Invalid regular expression: Escape character not permitted within character class, found "[\W]te...".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "$test" & Char(8) & "test", "[\S]test" ) +Errors: Error 35-45: Invalid regular expression: Escape character not permitted within character class, found "[\S]te...".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "foo123test456", "[\P{L}]+" ) // would be problematic if we wanted to implement MatchOptions.LocaleAware in the future +Errors: Error 24-34: Invalid regular expression: Escape character not permitted within character class, found "[\P{L}...".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "$test" & Char(8) & "test", "[\w]test" ) // \w is OK +Blank() + +>> Match( "$test" & Char(8) & "atest", "[\w]test" ) // \w is OK +{FullMatch:"atest",StartMatch:7} + // Limits on character classes >> Match( "test", "\c@" ) @@ -562,111 +581,90 @@ Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\," >> Match( "!@#%&=-`~><';:,""", "\""" ) Errors: Error 28-33: Invalid regular expression: Invalid escape code, found "\"".|Error 0-5: The function 'Match' has some invalid arguments. -// Inline comments - ->> Match( "test", "(?# this is a test)st" ) -{FullMatch:"st",StartMatch:3} - ->> Match( "test", "(?# this is a test ( with an open paren )st" ) -Errors: Error 15-60: Invalid regular expression: Inline comments cannot include open parenthesis, found in "(?# this is a test ( with an open paren )".|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "test", "(?# this is a test \) with an escaped close paren )st" ) // can't escape a paren in an inline comment -Errors: Error 15-70: Invalid regular expression: Unopened groups, too few opening parenthesis.|Error 0-5: The function 'Match' has some invalid arguments. - -// Can't define named capture group more than once - ->> Match( "test", "(?t).*(?t)" ) -{FullMatch:"test",StartMatch:1,one:"t",two:"t"} - ->> Match( "test", "((?t)|(?t))" ) -{FullMatch:"t",StartMatch:1,one:"t",two:Blank()} - ->> Match( "test", "(?t).*(?t)" ) -Errors: Error 15-37: Invalid regular expression: Named capture group "(?" defined more than once.|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "test", "((?t)|(?t))" ) -Errors: Error 15-38: Invalid regular expression: Named capture group "(?" defined more than once.|Error 0-5: The function 'Match' has some invalid arguments. - -// Bad named capture group names +// +// OPTIONS +// ->> Match( "test", "(?s).*" ) -{FullMatch:"st",StartMatch:3,a:"s"} +// inline options ->> Match( "test", "(?s).*" ) -{FullMatch:"st",StartMatch:3,a1:"s"} +>> Match( "hello"&Char(10)&"howdy", "o$" ) +Blank() ->> Match( "test", "(?<1>s).*" ) -Errors: Error 15-26: Invalid regular expression: Named capture group name must be a combination of letters and digits and begin with a letter, found "(?<1>".|Error 0-5: The function 'Match' has some invalid arguments. +>> Match( "hello"&Char(10)&"howdy", "o$", MatchOptions.Multiline ) +{FullMatch:"o",StartMatch:5} ->> Match( "test", "(?<1a>s).*" ) -Errors: Error 15-27: Invalid regular expression: Named capture group name must be a combination of letters and digits and begin with a letter, found "(?<1a>".|Error 0-5: The function 'Match' has some invalid arguments. +>> Match( "hello"&Char(10)&"howdy", "(?im)o$" ) +{FullMatch:"o",StartMatch:5} ->> Match( "test", "(?s).*" ) -Errors: Error 15-27: Invalid regular expression: Named capture group name must be a combination of letters and digits and begin with a letter, found "(?".|Error 0-5: The function 'Match' has some invalid arguments. +>> Match( "hello"&Char(10)&"howdy", "(?m)o$" ) +{FullMatch:"o",StartMatch:5} ->> Match( "test", "(?s).*" ) -Errors: Error 15-27: Invalid regular expression: Named capture group name must be a combination of letters and digits and begin with a letter, found "(?".|Error 0-5: The function 'Match' has some invalid arguments. +>> With( Match( "hello"&Char(10)&"howdy", "(?s)hello.howdy" ), {StartMatch: StartMatch, LengthMatch: Len(FullMatch)} ) +{LengthMatch:11,StartMatch:1} -// Group name case sensitivity +>> With( Match( "hello"&Char(13)&"howdy", "(?s)hello.howdy" ), {StartMatch: StartMatch, LengthMatch: Len(FullMatch)} ) +{LengthMatch:11,StartMatch:1} ->> Match( "test", "(?t).*\k") -{FullMatch:"test",StartMatch:1,a:"t"} +>> Match( "hello"&Char(13)&Char(10)&"howdy", "(?s)hello.howdy" ) +Blank() ->> Match( "test", "(?t).*\k") -Errors: Error 15-31: Invalid regular expression: Capture group "\k" not defined.|Error 0-5: The function 'Match' has some invalid arguments. +>> With( Match( "hello"&Char(10)&"howdy", "hello.howdy", MatchOptions.DotAll ), {StartMatch: StartMatch, LengthMatch: Len(FullMatch)} ) +{LengthMatch:11,StartMatch:1} ->> Match( "test", "(?t).*\k") -Errors: Error 15-31: Invalid regular expression: Capture group "\k" not defined.|Error 0-5: The function 'Match' has some invalid arguments. +>> With( Match( "hello"&Char(13)&"howdy", "hello.howdy", MatchOptions.DotAll ), {StartMatch: StartMatch, LengthMatch: Len(FullMatch)} ) +{LengthMatch:11,StartMatch:1} -// Remaining differences between .NET and XRegExp +>> Match( "hello"&Char(13)&Char(10)&"howdy", "hello.howdy", MatchOptions.DotAll ) +Blank() -// .NET will match up to the final newline, XRegExp and JavaScript do not +>> Match( "hello, howdy", "(?x) llo , \s how # comment" ) +{FullMatch:"llo, how",StartMatch:3} ->> AddColumns( Match( "test" & Char(10), "^test$" ), len, Len(FullMatch) ) -{FullMatch:"test",StartMatch:1,len:4} +// unsupported inline options ->> AddColumns( Match( "test" & Char(10) & Char(10), "^test$" ), len, Len(FullMatch) ) -Blank() +>> Match( "hello"&Char(10)&"howdy", "(?-m)o$" ) +Errors: Error 33-42: Invalid regular expression: Inline options are limited to a combination of the letters [imsx], cannot disable options, and cannot be used on a subexpression, found "(?-m)".|Error 0-5: The function 'Match' has some invalid arguments. ->> AddColumns( Match( "test" & Char(13), "^test$" ), len, Len(FullMatch) ) -{FullMatch:"test",StartMatch:1,len:4} +>> Match( "hello"&Char(10)&"howdy", "(?i-m)o$" ) +Errors: Error 33-43: Invalid regular expression: Inline options are limited to a combination of the letters [imsx], cannot disable options, and cannot be used on a subexpression, found "(?i-m)".|Error 0-5: The function 'Match' has some invalid arguments. ->> AddColumns( Match( "test" & Char(13) & Char(10), "^test$" ), len, Len(FullMatch) ) -{FullMatch:"test",StartMatch:1,len:4} +>> Match( "hello"&Char(10)&"howdy", "^(?m)o$" ) +Errors: Error 33-42: Invalid regular expression: Inline options must appear at the beginning of the regular expression, found "(?m)" later.|Error 0-5: The function 'Match' has some invalid arguments. -// .NET treats dot as [^\n], XRegExp and JavaScript use [^\n\r\u2028\u2029] +>> Match( "hello"&Char(10)&"howdy", "^(?i-m)o$" ) +Errors: Error 33-44: Invalid regular expression: Inline options must appear at the beginning of the regular expression, found "(?i-m)" later.|Error 0-5: The function 'Match' has some invalid arguments. ->> DropColumns( Match( "te" & " " & "t", "te.t" ), FullMatch ) -{StartMatch:1} +>> Match( "hello"&Char(10)&"howdy", "^(?m:o$)" ) +Errors: Error 33-43: Invalid regular expression: Inline options must appear at the beginning of the regular expression, found "(?m:" later.|Error 0-5: The function 'Match' has some invalid arguments. ->> DropColumns( Match( "te" & Char(10) & "t", "te.t" ), FullMatch ) -Blank() +>> Match( "hello world", "(?n)o") // n accepted for compatibility, but is already turned on +{FullMatch:"o",StartMatch:5} ->> DropColumns( Match( "te" & Char(13) & "t", "te.t" ), FullMatch ) -Blank() +>> Match( "hello world", "(?n)o", MatchOptions.NumberedSubMatches) // but n not accepted if it contradicts MatchOptions.NumberedSubMatches +Errors: Error 22-29: Invalid regular expression: Inline option is incompatible with MatchOptions.NumberedSubMatches, found "(?n)".|Error 0-5: The function 'Match' has some invalid arguments. ->> DropColumns( Match( "te" & UniChar(Hex2Dec("2028")) & "t", "te.t" ), FullMatch ) -{StartMatch:1} +>> Match( "hello world", "(?s)o") +{FullMatch:"o",StartMatch:5} ->> DropColumns( Match( "te" & UniChar(Hex2Dec("2029")) & "t", "te.t" ), FullMatch ) -{StartMatch:1} +>> Match( "hello world", "(?x)o") +{FullMatch:"o",StartMatch:5} -// Inline DotAll +>> Match( "hello world", "(?A)o") +Errors: Error 22-29: Invalid regular expression: Inline options are limited to a combination of the letters [imsx], cannot disable options, and cannot be used on a subexpression, found "(?A)".|Error 0-5: The function 'Match' has some invalid arguments. ->> DropColumns( Match( "te" & " " & "t", "(?s)te.t" ), FullMatch ) -{StartMatch:1} +>> Match ("hello world", "(?^)o") // PCRE2 +Errors: Error 22-29: Invalid regular expression: Unsupported special group, found "(?^)o".|Error 0-5: The function 'Match' has some invalid arguments. ->> DropColumns( Match( "te" & Char(10) & "t", "(?s)te.t" ), FullMatch ) -{StartMatch:1} +>> Match ("hello world", "(?xx)o") // PCRE2 +Errors: Error 22-30: Invalid regular expression: Repeated inline option, found "(?xx)".|Error 0-5: The function 'Match' has some invalid arguments. ->> DropColumns( Match( "te" & Char(13) & "t", "(?s)te.t" ), FullMatch ) -{StartMatch:1} +>> Match ("hello world", "(?J)o") // PCRE2 +Errors: Error 22-29: Invalid regular expression: Inline options are limited to a combination of the letters [imsx], cannot disable options, and cannot be used on a subexpression, found "(?J)".|Error 0-5: The function 'Match' has some invalid arguments. ->> DropColumns( Match( "te" & UniChar(Hex2Dec("2028")) & "t", "(?s)te.t" ), FullMatch ) -{StartMatch:1} +>> Match ("hello world", "(?U)o") // PCRE2 +Errors: Error 22-29: Invalid regular expression: Inline options are limited to a combination of the letters [imsx], cannot disable options, and cannot be used on a subexpression, found "(?U)".|Error 0-5: The function 'Match' has some invalid arguments. ->> DropColumns( Match( "te" & UniChar(Hex2Dec("2029")) & "t", "(?s)te.t" ), FullMatch ) -{StartMatch:1} +// inline options overriding explicit options, conflicts? // Option DotAll @@ -685,238 +683,9 @@ Blank() >> DropColumns( Match( "te" & UniChar(Hex2Dec("2029")) & "t", "te.t", MatchOptions.DotAll ), FullMatch ) {StartMatch:1} -// $ end anchor, multiline, and newline characters - ->> MatchAll( "a1" & Char(10) & "b2" & Char(10) & "c3", "\d$" ) -Table({FullMatch:"3",StartMatch:8}) - ->> MatchAll( "a1" & Char(10) & "b2" & Char(10) & "c3", "\d$", MatchOptions.Multiline ) -Table({FullMatch:"1",StartMatch:2},{FullMatch:"2",StartMatch:5},{FullMatch:"3",StartMatch:8}) - ->> MatchAll( "a1" & Char(13) & "b2" & Char(10) & "c3", "\d$" ) -Table({FullMatch:"3",StartMatch:8}) - ->> MatchAll( "a1" & Char(13) & "b2" & Char(13) & "c3", "\d$", MatchOptions.Multiline ) -Table({FullMatch:"1",StartMatch:2},{FullMatch:"2",StartMatch:5},{FullMatch:"3",StartMatch:8}) - ->> MatchAll( "a1" & Char(13)&Char(10) & "b2" & Char(13)&Char(10) & "c3", "\d$" ) -Table({FullMatch:"3",StartMatch:10}) - ->> MatchAll( "a1" & Char(13)&Char(10) & "b2" & Char(13)&Char(10) & "c3", "\d$", MatchOptions.Multiline ) -Table({FullMatch:"1",StartMatch:2},{FullMatch:"2",StartMatch:6},{FullMatch:"3",StartMatch:10}) - -// ^ beginning anchor, multiline, and newline characters - ->> MatchAll( "1a" & Char(10) & "2b" & Char(10) & "3c", "^\d" ) -Table({FullMatch:"1",StartMatch:1}) - ->> MatchAll( "1a" & Char(10) & "2b" & Char(10) & "3c", "^\d", MatchOptions.Multiline ) -Table({FullMatch:"1",StartMatch:1},{FullMatch:"2",StartMatch:4},{FullMatch:"3",StartMatch:7}) - ->> MatchAll( "1a" & Char(13) & "2b" & Char(10) & "3c", "^\d" ) -Table({FullMatch:"1",StartMatch:1}) - ->> MatchAll( "1a" & Char(13) & "2b" & Char(13) & "3c", "^\d", MatchOptions.Multiline ) -Table({FullMatch:"1",StartMatch:1},{FullMatch:"2",StartMatch:4},{FullMatch:"3",StartMatch:7}) - ->> MatchAll( "1a" & Char(13)&Char(10) & "2b" & Char(13)&Char(10) & "3c", "^\d" ) -Table({FullMatch:"1",StartMatch:1}) - ->> MatchAll( "1a" & Char(13)&Char(10) & "2b" & Char(13)&Char(10) & "3c", "^\d", MatchOptions.Multiline ) -Table({FullMatch:"1",StartMatch:1},{FullMatch:"2",StartMatch:5},{FullMatch:"3",StartMatch:9}) - ->> ForAll( MatchAll( " - a - b - c - ", "^.+$", MatchOptions.Multiline), { Match: FullMatch, Len: Len(FullMatch) } ) -Table({Len:2,Match:" a"},{Len:2,Match:" b"},{Len:2,Match:" c"},{Len:1,Match:" "}) - -// repeated characters in character class, used by intersection and future character class features, also would catch POSIX cases if wasn't already blocked by nested square brackets - ->> Match( "hello", "[a-z&&[k-m]]" ) -Errors: Error 16-30: Invalid regular expression: Character appears more than once in character class, found repeated "&".|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "hello", "[a-z&&k-m]" ) -Errors: Error 16-28: Invalid regular expression: Character appears more than once in character class, found repeated "&".|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "hello", "[a-hh-z]" ) -Errors: Error 16-26: Invalid regular expression: Character appears more than once in character class, found repeated "h".|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "HellO", "[[:lower:]]" ) -Errors: Error 16-29: Invalid regular expression: Square bracket character classes cannot be empty and cannot include unescaped literal open or close square brackets, escape with "\[" or "\]".|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "hello", "[[:s:]]" ) -Errors: Error 16-25: Invalid regular expression: Square bracket character classes cannot be empty and cannot include unescaped literal open or close square brackets, escape with "\[" or "\]".|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "hello", "[[=x=]]" ) -Errors: Error 16-25: Invalid regular expression: Square bracket character classes cannot be empty and cannot include unescaped literal open or close square brackets, escape with "\[" or "\]".|Error 0-5: The function 'Match' has some invalid arguments. - -// spaces - ->> IsMatch( "h" & "a" & "d", "h\sd") // control -false - ->> IsMatch( "h" & UniChar(Hex2Dec("0020")) & "d", "h\sd") // " " -true - ->> IsMatch( "h" & UniChar(Hex2Dec("000d")) & "d", "h\sd") // \r -true - ->> IsMatch( "h" & UniChar(Hex2Dec("000c")) & "d", "h\sd") // \f -true - ->> IsMatch( "h" & UniChar(Hex2Dec("000a")) & "d", "h\sd") // \n -true - ->> IsMatch( "h" & UniChar(Hex2Dec("0009")) & "d", "h\sd") // \t -true - ->> IsMatch( "h" & UniChar(Hex2Dec("000b")) & "d", "h\sd") // \v -true - ->> IsMatch( "h" & UniChar(Hex2Dec("0085")) & "d", "h\sd") // \x85, not in ECMAScript -true - ->> IsMatch( "h" & UniChar(Hex2Dec("1680")) & "d", "h\sd") -true - ->> IsMatch( "h" & UniChar(Hex2Dec("2000")) & "d", "h\sd") -true - ->> IsMatch( "h" & UniChar(Hex2Dec("2001")) & "d", "h\sd") -true - ->> IsMatch( "h" & UniChar(Hex2Dec("2002")) & "d", "h\sd") -true - ->> IsMatch( "h" & UniChar(Hex2Dec("2003")) & "d", "h\sd") -true - ->> IsMatch( "h" & UniChar(Hex2Dec("2004")) & "d", "h\sd") -true - ->> IsMatch( "h" & UniChar(Hex2Dec("2005")) & "d", "h\sd") -true - ->> IsMatch( "h" & UniChar(Hex2Dec("2006")) & "d", "h\sd") -true - ->> IsMatch( "h" & UniChar(Hex2Dec("2007")) & "d", "h\sd") -true - ->> IsMatch( "h" & UniChar(Hex2Dec("2008")) & "d", "h\sd") -true - ->> IsMatch( "h" & UniChar(Hex2Dec("2009")) & "d", "h\sd") -true - ->> IsMatch( "h" & UniChar(Hex2Dec("200a")) & "d", "h\sd") -true - ->> IsMatch( "h" & UniChar(Hex2Dec("202f")) & "d", "h\sd") -true - ->> IsMatch( "h" & UniChar(Hex2Dec("205f")) & "d", "h\sd") -true - ->> IsMatch( "h" & UniChar(Hex2Dec("3000")) & "d", "h\sd") -true - ->> IsMatch( "h" & UniChar(Hex2Dec("2028")) & "d", "h\sd") -true - ->> IsMatch( "h" & UniChar(Hex2Dec("2029")) & "d", "h\sd") -true - ->> IsMatch( "h" & UniChar(Hex2Dec("feff")) & "d", "h\sd") // ECMAScript -false - ->> IsMatch( "h" & UniChar(Hex2Dec("00a0")) & "d", "h\sd") -true - -// non-space - ->> IsMatch( "h" & "a" & "d", "h\Sd") // control -true - ->> IsMatch( "h" & UniChar(Hex2Dec("0020")) & "d", "h\Sd") // " " -false - ->> IsMatch( "h" & UniChar(Hex2Dec("000d")) & "d", "h\Sd") // \r -false - ->> IsMatch( "h" & UniChar(Hex2Dec("000c")) & "d", "h\Sd") // \f -false - ->> IsMatch( "h" & UniChar(Hex2Dec("000a")) & "d", "h\Sd") // \n -false - ->> IsMatch( "h" & UniChar(Hex2Dec("0009")) & "d", "h\Sd") // \t -false - ->> IsMatch( "h" & UniChar(Hex2Dec("000b")) & "d", "h\Sd") // \v -false - ->> IsMatch( "h" & UniChar(Hex2Dec("0085")) & "d", "h\Sd") // \x85, not in ECMAScript -false - ->> IsMatch( "h" & UniChar(Hex2Dec("1680")) & "d", "h\Sd") -false - ->> IsMatch( "h" & UniChar(Hex2Dec("2000")) & "d", "h\Sd") -false - ->> IsMatch( "h" & UniChar(Hex2Dec("2001")) & "d", "h\Sd") -false - ->> IsMatch( "h" & UniChar(Hex2Dec("2002")) & "d", "h\Sd") -false - ->> IsMatch( "h" & UniChar(Hex2Dec("2003")) & "d", "h\Sd") -false - ->> IsMatch( "h" & UniChar(Hex2Dec("2004")) & "d", "h\Sd") -false - ->> IsMatch( "h" & UniChar(Hex2Dec("2005")) & "d", "h\Sd") -false - ->> IsMatch( "h" & UniChar(Hex2Dec("2006")) & "d", "h\Sd") -false - ->> IsMatch( "h" & UniChar(Hex2Dec("2007")) & "d", "h\Sd") -false - ->> IsMatch( "h" & UniChar(Hex2Dec("2008")) & "d", "h\Sd") -false - ->> IsMatch( "h" & UniChar(Hex2Dec("2009")) & "d", "h\Sd") -false - ->> IsMatch( "h" & UniChar(Hex2Dec("200a")) & "d", "h\Sd") -false - ->> IsMatch( "h" & UniChar(Hex2Dec("202f")) & "d", "h\Sd") -false - ->> IsMatch( "h" & UniChar(Hex2Dec("205f")) & "d", "h\Sd") -false - ->> IsMatch( "h" & UniChar(Hex2Dec("3000")) & "d", "h\Sd") -false - ->> IsMatch( "h" & UniChar(Hex2Dec("2028")) & "d", "h\Sd") -false - ->> IsMatch( "h" & UniChar(Hex2Dec("2029")) & "d", "h\Sd") -false - ->> IsMatch( "h" & UniChar(Hex2Dec("feff")) & "d", "h\Sd") // ECMAScript -true - ->> IsMatch( "h" & UniChar(Hex2Dec("00a0")) & "d", "h\Sd") -false +// +// QUANTIFIERS +// // greedy and lazy quantifiers @@ -956,46 +725,39 @@ false >> Match( "abcdef", "\w{2,4}?" ).FullMatch "ab" ->> Match( "asdf", "(*MARK)") // PCRE2 extension -Errors: Error 15-24: Invalid regular expression: Unsupported special group, found "(*MAR...".|Error 0-5: The function 'Match' has some invalid arguments. +// possessive quantifiers -// Node != Net for this test ("b" is empty for Node), a known difference between PCRE2 and Perl too -// >> Match( "aba", "^(a(b)?)+$", MatchOptions.NumberedSubMatches ) -// {FullMatch:"aba",StartMatch:1,SubMatches:Table({Value:"a"},{Value:"b"})} +>> Match( "abcdef", "\w++" ).FullMatch +Errors: Error 17-23: Invalid regular expression.|Error 0-5: The function 'Match' has some invalid arguments.|Error 25-35: Name isn't valid. 'FullMatch' isn't recognized. ->> Match( "ab", "a(d)?b", MatchOptions.NumberedSubMatches ) -{FullMatch:"ab",StartMatch:1,SubMatches:Table({Value:Blank()})} +>> Match( "abcdef", "\w*+" ).FullMatch +Errors: Error 17-23: Invalid regular expression.|Error 0-5: The function 'Match' has some invalid arguments.|Error 25-35: Name isn't valid. 'FullMatch' isn't recognized. ->> Match( "ab", "a(d?)b", MatchOptions.NumberedSubMatches ) -{FullMatch:"ab",StartMatch:1,SubMatches:Table({Value:""})} +>> Match( "abcdef", "\w?+" ).FullMatch +Errors: Error 17-23: Invalid regular expression.|Error 0-5: The function 'Match' has some invalid arguments.|Error 25-35: Name isn't valid. 'FullMatch' isn't recognized. ->> Match( "ab", "a(?d)?b" ) -{FullMatch:"ab",StartMatch:1,one:Blank()} +>> Match( "abcdef", "\w{2}+" ).FullMatch +Errors: Error 17-25: Invalid regular expression.|Error 0-5: The function 'Match' has some invalid arguments.|Error 27-37: Name isn't valid. 'FullMatch' isn't recognized. ->> Match( "ab", "a(?d?)b" ) -{FullMatch:"ab",StartMatch:1,one:""} +>> Match( "abcdef", "\w{2,}+" ).FullMatch +Errors: Error 17-26: Invalid regular expression.|Error 0-5: The function 'Match' has some invalid arguments.|Error 28-38: Name isn't valid. 'FullMatch' isn't recognized. -// Changes in case insensitive matching in .NET 7 causes different answers that are consistent with PCRE2 and Node -// See https://devblogs.microsoft.com/dotnet/regular-expression-improvements-in-dotnet-7/#case-insensitive-matching-and-regexoptions-ignorecase +>> Match( "abcdef", "\w{2,4}+" ).FullMatch +Errors: Error 17-27: Invalid regular expression.|Error 0-5: The function 'Match' has some invalid arguments.|Error 29-39: Name isn't valid. 'FullMatch' isn't recognized. ->> Match( UniChar(Hex2Dec("03a9")), "\u03c9", MatchOptions.IgnoreCase ).FullMatch -"Ω" +// +// OTHER +// ->> Match( UniChar(Hex2Dec("03c9")), "\u03a9", MatchOptions.IgnoreCase ).FullMatch -"ω" +// Features supported by PCRE2 -#DISABLE.NET:462 ->> Match( UniChar(Hex2Dec("03a9")), "\u2126", MatchOptions.IgnoreCase ).FullMatch -"Ω" +>> Match( "asdf", "(*MARK)") +Errors: Error 15-24: Invalid regular expression: Unsupported special group, found "(*MAR...".|Error 0-5: The function 'Match' has some invalid arguments. -#DISABLE.NET:462 ->> Match( UniChar(Hex2Dec("03c9")), "\u2126", MatchOptions.IgnoreCase ).FullMatch -"ω" +// regular expression parsing -#DISABLE.NET:462 ->> Match( UniChar(Hex2Dec("2126")), "\u03c9", MatchOptions.IgnoreCase ).FullMatch -"Ω" +>> Match( "test\123bed", "\\(\a)" ) +Errors: Error 22-30: Invalid regular expression: Invalid escape code, found "\a".|Error 0-5: The function 'Match' has some invalid arguments. -#DISABLE.NET:462 ->> Match( UniChar(Hex2Dec("2126")), "\u03a9", MatchOptions.IgnoreCase ).FullMatch -"Ω" +>> Match( "test\123bed", "\\(\d)" ) +{FullMatch:"\1",StartMatch:5} diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Newlines.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Newlines.txt new file mode 100644 index 0000000000..a074f3f77a --- /dev/null +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Newlines.txt @@ -0,0 +1,255 @@ +#SETUP: RegEx,PowerFxV1CompatibilityRules,SupportColumnNamesAsIdentifiers + +// Newline and space character behavior in Power Fx regular expressions. +// +// Effective Usage .NET ECMAScript PCRE2 +// ===================================================================================================================================== +// (\r|\n|\r\n) ^ and $ in multline mode No No Yes (as configured by Excel) +// (\z|\r\z|\n\z|\r\n\z) ^ and $ when not in multline mode Yes No Yes (as configured by Excel) +// [^\n\r] . No No (close) Yes +// [ \r\n\f\v\t\x85\p{Z}] \s and \S Yes No (close) Yes + +// .NET will match up to the final newline, XRegExp and JavaScript do not + +>> AddColumns( Match( "test" & Char(10), "^test$" ), len, Len(FullMatch) ) +{FullMatch:"test",StartMatch:1,len:4} + +>> AddColumns( Match( "test" & Char(10) & Char(10), "^test$" ), len, Len(FullMatch) ) +Blank() + +>> AddColumns( Match( "test" & Char(13), "^test$" ), len, Len(FullMatch) ) +{FullMatch:"test",StartMatch:1,len:4} + +>> AddColumns( Match( "test" & Char(13) & Char(10), "^test$" ), len, Len(FullMatch) ) +{FullMatch:"test",StartMatch:1,len:4} + +// .NET treats dot as [^\n], XRegExp and JavaScript use [^\n\r\u2028\u2029] + +>> DropColumns( Match( "te" & " " & "t", "te.t" ), FullMatch ) +{StartMatch:1} + +>> DropColumns( Match( "te" & Char(10) & "t", "te.t" ), FullMatch ) +Blank() + +>> DropColumns( Match( "te" & Char(13) & "t", "te.t" ), FullMatch ) +Blank() + +>> DropColumns( Match( "te" & UniChar(Hex2Dec("2028")) & "t", "te.t" ), FullMatch ) +{StartMatch:1} + +>> DropColumns( Match( "te" & UniChar(Hex2Dec("2029")) & "t", "te.t" ), FullMatch ) +{StartMatch:1} + +// $ end anchor, multiline, and newline characters + +>> MatchAll( "a1" & Char(10) & "b2" & Char(10) & "c3", "\d$" ) +Table({FullMatch:"3",StartMatch:8}) + +>> MatchAll( "a1" & Char(10) & "b2" & Char(10) & "c3", "\d$", MatchOptions.Multiline ) +Table({FullMatch:"1",StartMatch:2},{FullMatch:"2",StartMatch:5},{FullMatch:"3",StartMatch:8}) + +>> MatchAll( "a1" & Char(13) & "b2" & Char(10) & "c3", "\d$" ) +Table({FullMatch:"3",StartMatch:8}) + +>> MatchAll( "a1" & Char(13) & "b2" & Char(13) & "c3", "\d$", MatchOptions.Multiline ) +Table({FullMatch:"1",StartMatch:2},{FullMatch:"2",StartMatch:5},{FullMatch:"3",StartMatch:8}) + +>> MatchAll( "a1" & Char(13)&Char(10) & "b2" & Char(13)&Char(10) & "c3", "\d$" ) +Table({FullMatch:"3",StartMatch:10}) + +>> MatchAll( "a1" & Char(13)&Char(10) & "b2" & Char(13)&Char(10) & "c3", "\d$", MatchOptions.Multiline ) +Table({FullMatch:"1",StartMatch:2},{FullMatch:"2",StartMatch:6},{FullMatch:"3",StartMatch:10}) + +// ^ beginning anchor, multiline, and newline characters + +>> MatchAll( "1a" & Char(10) & "2b" & Char(10) & "3c", "^\d" ) +Table({FullMatch:"1",StartMatch:1}) + +>> MatchAll( "1a" & Char(10) & "2b" & Char(10) & "3c", "^\d", MatchOptions.Multiline ) +Table({FullMatch:"1",StartMatch:1},{FullMatch:"2",StartMatch:4},{FullMatch:"3",StartMatch:7}) + +>> MatchAll( "1a" & Char(13) & "2b" & Char(10) & "3c", "^\d" ) +Table({FullMatch:"1",StartMatch:1}) + +>> MatchAll( "1a" & Char(13) & "2b" & Char(13) & "3c", "^\d", MatchOptions.Multiline ) +Table({FullMatch:"1",StartMatch:1},{FullMatch:"2",StartMatch:4},{FullMatch:"3",StartMatch:7}) + +>> MatchAll( "1a" & Char(13)&Char(10) & "2b" & Char(13)&Char(10) & "3c", "^\d" ) +Table({FullMatch:"1",StartMatch:1}) + +>> MatchAll( "1a" & Char(13)&Char(10) & "2b" & Char(13)&Char(10) & "3c", "^\d", MatchOptions.Multiline ) +Table({FullMatch:"1",StartMatch:1},{FullMatch:"2",StartMatch:5},{FullMatch:"3",StartMatch:9}) + +>> ForAll( MatchAll( " + a + b + c + ", "^.+$", MatchOptions.Multiline), { Match: FullMatch, Len: Len(FullMatch) } ) +Table({Len:2,Match:" a"},{Len:2,Match:" b"},{Len:2,Match:" c"},{Len:1,Match:" "}) + +// spaces + +>> IsMatch( "h" & "a" & "d", "h\sd") // control +false + +>> IsMatch( "h" & UniChar(Hex2Dec("0020")) & "d", "h\sd") // " " +true + +>> IsMatch( "h" & UniChar(Hex2Dec("000d")) & "d", "h\sd") // \r +true + +>> IsMatch( "h" & UniChar(Hex2Dec("000c")) & "d", "h\sd") // \f +true + +>> IsMatch( "h" & UniChar(Hex2Dec("000a")) & "d", "h\sd") // \n +true + +>> IsMatch( "h" & UniChar(Hex2Dec("0009")) & "d", "h\sd") // \t +true + +>> IsMatch( "h" & UniChar(Hex2Dec("000b")) & "d", "h\sd") // \v +true + +>> IsMatch( "h" & UniChar(Hex2Dec("0085")) & "d", "h\sd") // \x85, not in ECMAScript +true + +>> IsMatch( "h" & UniChar(Hex2Dec("1680")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("2000")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("2001")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("2002")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("2003")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("2004")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("2005")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("2006")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("2007")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("2008")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("2009")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("200a")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("202f")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("205f")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("3000")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("2028")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("2029")) & "d", "h\sd") +true + +>> IsMatch( "h" & UniChar(Hex2Dec("feff")) & "d", "h\sd") // ECMAScript +false + +>> IsMatch( "h" & UniChar(Hex2Dec("00a0")) & "d", "h\sd") +true + +// non-space + +>> IsMatch( "h" & "a" & "d", "h\Sd") // control +true + +>> IsMatch( "h" & UniChar(Hex2Dec("0020")) & "d", "h\Sd") // " " +false + +>> IsMatch( "h" & UniChar(Hex2Dec("000d")) & "d", "h\Sd") // \r +false + +>> IsMatch( "h" & UniChar(Hex2Dec("000c")) & "d", "h\Sd") // \f +false + +>> IsMatch( "h" & UniChar(Hex2Dec("000a")) & "d", "h\Sd") // \n +false + +>> IsMatch( "h" & UniChar(Hex2Dec("0009")) & "d", "h\Sd") // \t +false + +>> IsMatch( "h" & UniChar(Hex2Dec("000b")) & "d", "h\Sd") // \v +false + +>> IsMatch( "h" & UniChar(Hex2Dec("0085")) & "d", "h\Sd") // \x85, not in ECMAScript +false + +>> IsMatch( "h" & UniChar(Hex2Dec("1680")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("2000")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("2001")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("2002")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("2003")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("2004")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("2005")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("2006")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("2007")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("2008")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("2009")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("200a")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("202f")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("205f")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("3000")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("2028")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("2029")) & "d", "h\Sd") +false + +>> IsMatch( "h" & UniChar(Hex2Dec("feff")) & "d", "h\Sd") // ECMAScript +true + +>> IsMatch( "h" & UniChar(Hex2Dec("00a0")) & "d", "h\Sd") +false + diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Unicode.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Unicode.txt new file mode 100644 index 0000000000..fd555031a3 --- /dev/null +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Unicode.txt @@ -0,0 +1,72 @@ +#SETUP: RegEx,PowerFxV1CompatibilityRules,SupportColumnNamesAsIdentifiers + +// Unicode character behavior in Power Fx regular expressions. +// +// Effective Usage .NET ECMAScript PCRE2 +// ===================================================================================================================================== +// \p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Lm}\p{Nd}\p{Pc} \w, \W, \b, \B Yes No Yes +// \p{Nd} \d, \D Yes No Yes +// \p{Category} \p, \P Yes Yes Yes +// \p{Script} \p, \P Yes Yes Yes +// +// We chose to use canonical .NET instead of RegexOptions.ECMAScript because we wanted the unicode definitions for words. +// See https://learn.microsoft.com/dotnet/standard/base-types/regular-expression-options#ecmascript-matching-behavior for more details + +// Unicode letters as word characters are matched + +>> Match( "the whole world", "\b(\w+\s*)+" ) +{FullMatch:"the whole world",StartMatch:1} + +>> Match( "целый мир", "\b(\w+\s*)+" ) +{FullMatch:"целый мир",StartMatch:1} + +>> Match( "el niño", "\b(\w+\s*)+" ) +{FullMatch:"el niño",StartMatch:1} + +>> Match( "Müller", "^\w+$" ) +{FullMatch:"Müller",StartMatch:1} + +// Unicode numbers as digits are matched + +>> Match( "12345", "^\d+$" ) +{FullMatch:"12345",StartMatch:1} + +>> Match( "12٤45", "^\d+$" ) +{FullMatch:"12٤45",StartMatch:1} + +>> Match( "123४5", "^\d+$" ) +{FullMatch:"123४5",StartMatch:1} + +>> Match( "abc3d", "^\D+" ) +{FullMatch:"abc",StartMatch:1} + +>> Match( "abc٤45", "^\D+" ) +{FullMatch:"abc",StartMatch:1} + +>> Match( "abc४5", "^\D+" ) +{FullMatch:"abc",StartMatch:1} + +// Changes in case insensitive matching in .NET 7 causes different answers that are consistent with PCRE2 and Node +// See https://devblogs.microsoft.com/dotnet/regular-expression-improvements-in-dotnet-7/#case-insensitive-matching-and-regexoptions-ignorecase + +>> Match( UniChar(Hex2Dec("03a9")), "\u03c9", MatchOptions.IgnoreCase ).FullMatch +"Ω" + +>> Match( UniChar(Hex2Dec("03c9")), "\u03a9", MatchOptions.IgnoreCase ).FullMatch +"ω" + +#DISABLE.NET:462 +>> Match( UniChar(Hex2Dec("03a9")), "\u2126", MatchOptions.IgnoreCase ).FullMatch +"Ω" + +#DISABLE.NET:462 +>> Match( UniChar(Hex2Dec("03c9")), "\u2126", MatchOptions.IgnoreCase ).FullMatch +"ω" + +#DISABLE.NET:462 +>> Match( UniChar(Hex2Dec("2126")), "\u03c9", MatchOptions.IgnoreCase ).FullMatch +"Ω" + +#DISABLE.NET:462 +>> Match( UniChar(Hex2Dec("2126")), "\u03a9", MatchOptions.IgnoreCase ).FullMatch +"Ω" diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net462.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Unicode_Net462.txt similarity index 100% rename from src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited_Net462.txt rename to src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Unicode_Net462.txt diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs index 6ec277edb3..6db38815e5 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs @@ -17,7 +17,7 @@ function AlterRegex_JavaScript(regex, flags) { var regexIndex = 0; - const inlineFlagsRE = /^\(\?(?[imsx]+)\)/; + const inlineFlagsRE = /^\(\?(?[imnsx]+)\)/; const inlineFlags = inlineFlagsRE.exec( regex ); if (inlineFlags != null) { @@ -150,6 +150,8 @@ function AlterRegex_JavaScript(regex, flags) // eat characters until the end of the line // leaving dangling whitespace characters will be eaten on next iteration } + + regexIndex--; } else { @@ -164,6 +166,16 @@ function AlterRegex_JavaScript(regex, flags) } } + if (flags.includes('^') && (altered.length == 0 || altered[0] != '^')) + { + altered = '^' + altered; + } + + if (flags.includes('$') && (altered.length == 0 || altered[altered.length-1] != '$')) + { + altered = altered + '$'; + } + return [altered, alteredFlags]; } "; diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index 02b0d9468d..4ed5d48020 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -167,11 +167,11 @@ private static bool ShouldSkipDotNetVersion(ExpressionTestCase testCase, string } #if false - // Helper to run a single .txt + // Helper to run a single .txt d [Fact] public void RunOne() { - var path = @"d:\repos\regex-min-nolocale\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\match_limited_Net462.txt"; + var path = @"d:\repos\regex-min-3\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\match_comments.txt"; var line = 0; var runner = new InterpreterRunner(); diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_Compare.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_Compare.cs index c956895187..a255a56e2e 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_Compare.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_Compare.cs @@ -60,7 +60,7 @@ internal abstract class Compare_CommonImplementation : Library.RegexCommonImplem protected Library.RegexCommonImplementation pcre2; protected Library.RegexCommonImplementation dotnet; - internal override FormulaValue InvokeRegexFunction(string input, string regex, RegexOptions options) + internal override FormulaValue InvokeRegexFunction(string input, string regex, string options) { var nodeMatch = node.InvokeRegexFunction(input, regex, options); var nodeExpr = nodeMatch.ToExpression(); diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs index e36063d816..8b79a2b89f 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs @@ -23,32 +23,8 @@ public class RegEx_NodeJS { internal abstract class NodeJS_RegexCommonImplementation : Library.RegexCommonImplementation { - internal static FormulaValue Match(string subject, string pattern, RegexOptions options, bool matchAll = false) + internal static FormulaValue Match(string subject, string pattern, string flags, bool matchAll = false) { - StringBuilder flags = new StringBuilder(); - - // RegexOptions.ExplicitCapture -> "n" is not done as ECMAScript does not support this flag - - if ((options & RegexOptions.IgnoreCase) != 0) - { - flags.Append("i"); - } - - if ((options & RegexOptions.Multiline) != 0) - { - flags.Append("m"); - } - - if ((options & RegexOptions.Singleline) != 0) - { - flags.Append("s"); - } - - if ((options & RegexOptions.IgnorePatternWhitespace) != 0) - { - flags.Append("x"); - } - var js = new StringBuilder(); js.AppendLine($"const subject='{subject.Replace("\\", "\\\\").Replace("\r", "\\r").Replace("\n", "\\n").Replace("'", "\\'")}';"); @@ -156,7 +132,7 @@ internal static FormulaValue Match(string subject, string pattern, RegexOptions } else if (token.Groups["end"].Success) { - if ((options & RegexOptions.ExplicitCapture) == 0) + if (flags.Contains('N')) { var recordType = RecordType.Empty().Add(TableValue.ValueName, FormulaType.String); fields.Add(SUBMATCHES, new NamedValue(SUBMATCHES, TableValue.NewTable(recordType, subMatches))); @@ -168,8 +144,8 @@ internal static FormulaValue Match(string subject, string pattern, RegexOptions { if (allMatches.Count == 0) { - return matchAll ? FormulaValue.NewTable(new KnownRecordType(GetRecordTypeFromRegularExpression(pattern, options))) - : new BlankValue(IRContext.NotInSource(new KnownRecordType(GetRecordTypeFromRegularExpression(pattern, options)))); + return matchAll ? FormulaValue.NewTable(new KnownRecordType(GetRecordTypeFromRegularExpression(pattern, flags.Contains('N') ? RegexOptions.None : RegexOptions.ExplicitCapture))) + : new BlankValue(IRContext.NotInSource(new KnownRecordType(GetRecordTypeFromRegularExpression(pattern, flags.Contains('N') ? RegexOptions.None : RegexOptions.ExplicitCapture)))); } else { @@ -262,7 +238,7 @@ public NodeJS_IsMatchImplementation(TimeSpan regexTimeout) _regexTimeout = regexTimeout; } - internal override FormulaValue InvokeRegexFunction(string input, string regex, RegexOptions options) + internal override FormulaValue InvokeRegexFunction(string input, string regex, string options) { var match = Match(input, regex, options); @@ -281,7 +257,7 @@ public NodeJS_MatchImplementation(TimeSpan regexTimeout) _regexTimeout = regexTimeout; } - internal override FormulaValue InvokeRegexFunction(string input, string regex, RegexOptions options) + internal override FormulaValue InvokeRegexFunction(string input, string regex, string options) { return Match(input, regex, options); } @@ -298,7 +274,7 @@ public NodeJS_MatchAllImplementation(TimeSpan regexTimeout) _regexTimeout = regexTimeout; } - internal override FormulaValue InvokeRegexFunction(string input, string regex, RegexOptions options) + internal override FormulaValue InvokeRegexFunction(string input, string regex, string options) { return Match(input, regex, options, matchAll: true); } diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs index 5c42c14697..1b747197ea 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs @@ -9,6 +9,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; @@ -77,7 +78,7 @@ internal enum PCRE2_OPTIONS : uint NO_AUTO_CAPTURE = 0x00002000, } - internal static FormulaValue Match(string subject, string pattern, RegexOptions options, bool matchAll = false) + internal static FormulaValue Match(string subject, string pattern, string flags, bool matchAll = false) { int errorNumber = 0; int errorOffset = 0; @@ -86,30 +87,58 @@ internal static FormulaValue Match(string subject, string pattern, RegexOptions IntPtr generalContext = (IntPtr)0; PCRE2_OPTIONS pcreOptions = PCRE2_OPTIONS.UCP; + RegexOptions options = RegexOptions.None; - if ((options & RegexOptions.ExplicitCapture) != 0) + Match inlineOptions = Regex.Match(pattern, @"^\(\?([imnsx]+)\)"); + + if (inlineOptions.Success) + { + flags = flags + inlineOptions.Groups[1]; + pattern = pattern.Substring(inlineOptions.Length); + } + + if (!flags.Contains('N')) { pcreOptions |= PCRE2_OPTIONS.NO_AUTO_CAPTURE; + options |= RegexOptions.ExplicitCapture; } - if ((options & RegexOptions.IgnoreCase) != 0) + if (flags.Contains('i')) { pcreOptions |= PCRE2_OPTIONS.CASELESS; } - if ((options & RegexOptions.Multiline) != 0) + if (flags.Contains('m')) { pcreOptions |= PCRE2_OPTIONS.MULTILINE; } - if ((options & RegexOptions.Singleline) != 0) + if (flags.Contains('s')) { pcreOptions |= PCRE2_OPTIONS.DOTALL; } - if ((options & RegexOptions.IgnorePatternWhitespace) != 0) + if (flags.Contains('x')) { - pcreOptions |= PCRE2_OPTIONS.EXTENDED; + if (flags.Contains('^') || flags.Contains('$')) + { + // we can't use PCRE2_OPTIONS.EXTENDED here because we need to add ^ or $ appropriately next + pattern = StripExtended(pattern); + } + else + { + pcreOptions |= PCRE2_OPTIONS.EXTENDED; + } + } + + if (flags.Contains('^') && (pattern.Length == 0 || pattern[0] != '^')) + { + pattern = "^" + pattern; + } + + if (flags.Contains('$') && (pattern.Length == 0 || pattern[pattern.Length - 1] != '$')) + { + pattern = pattern + "$"; } var patternPCRE2 = Regex.Replace(pattern, @"\\u(?\w\w\w\w)", @"\x{${hex}}"); @@ -185,6 +214,50 @@ internal static FormulaValue Match(string subject, string pattern, RegexOptions } } + public static string StripExtended(string regex) + { + StringBuilder alteredRegex = new StringBuilder(); + + for (int index = 0; index < regex.Length; index++) + { + switch (regex[index]) + { + case '#': + for (index++; index < regex.Length && regex[index] != '\r' && regex[index] != '\n'; index++) + { + // skip the comment characters until the next newline, in case it includes [ ] + } + + index--; + + break; + + case '\\': + alteredRegex.Append("\\"); + if (++index < regex.Length) + { + alteredRegex.Append(regex[index]); + } + + break; + + case ' ': + case '\f': + case '\n': + case '\r': + case '\t': + case '\v': + break; + + default: + alteredRegex.Append(regex[index]); + break; + } + } + + return alteredRegex.ToString(); + } + public static void EnableRegExFunctions(PowerFxConfig config, TimeSpan regExTimeout = default, int regexCacheSize = -1) { RegexTypeCache regexTypeCache = new (regexCacheSize); @@ -232,7 +305,7 @@ public PCRE2_IsMatchImplementation(TimeSpan regexTimeout) _regexTimeout = regexTimeout; } - internal override FormulaValue InvokeRegexFunction(string input, string regex, RegexOptions options) + internal override FormulaValue InvokeRegexFunction(string input, string regex, string options) { var match = Match(input, regex, options); @@ -251,7 +324,7 @@ public PCRE2_MatchImplementation(TimeSpan regexTimeout) _regexTimeout = regexTimeout; } - internal override FormulaValue InvokeRegexFunction(string input, string regex, RegexOptions options) + internal override FormulaValue InvokeRegexFunction(string input, string regex, string options) { return Match(input, regex, options); } @@ -268,7 +341,7 @@ public PCRE2_MatchAllImplementation(TimeSpan regexTimeout) _regexTimeout = regexTimeout; } - internal override FormulaValue InvokeRegexFunction(string input, string regex, RegexOptions options) + internal override FormulaValue InvokeRegexFunction(string input, string regex, string options) { return Match(input, regex, options, matchAll: true); } From df249485d2ad3daa81f0964a97b25935bd578efa Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Sat, 31 Aug 2024 23:41:26 -0700 Subject: [PATCH 39/61] Updates --- .../ExpressionTestCases/Match_Comments.txt | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Comments.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Comments.txt index 1c8b47d61c..887cbb72c2 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Comments.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Comments.txt @@ -67,3 +67,35 @@ true >> IsMatch( "ab", "(?x)a # " &Char(133)& " b" ) // \x85 false +// MatchOptions.Contains doesn't strip free spacing on PCRE2, good to compare results + +>> IsMatch( "ab", "(?x)a # c", MatchOptions.Contains ) +true + +>> IsMatch( "ab", "(?x)a # " &Char(13)& " c", MatchOptions.Contains ) +false + +>> IsMatch( "ab", "(?x)a # " &Char(10)& " c", MatchOptions.Contains ) +false + +>> IsMatch( "ab", "(?x)a # " &Char(13)&Char(10)& " c", MatchOptions.Contains ) // one is the newline, the other is just whitespace that is ignored +false + +>> IsMatch( "ab", "(?x)a # " &Char(133)& " c", MatchOptions.Contains ) // \x85 +true + +>> IsMatch( "ab", "(?x)a # " &Char(12)& " c", MatchOptions.Contains ) // \f +true + +>> IsMatch( "ab", "(?x)a # " &Char(11)& " c", MatchOptions.Contains ) // \v +true + +>> IsMatch( "ab", "(?x)a # " &Char(9)& " c", MatchOptions.Contains ) // \h +true + +>> IsMatch( "ab", "(?x)a # " &UniChar(2028)& " c", MatchOptions.Contains ) // \u2028 +true + +>> IsMatch( "ab", "(?x)a # " &UniChar(2029)& " c", MatchOptions.Contains ) // \u2029 +true + From d506d23c4b4481de26151d71c381066415ddc1dd Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Tue, 3 Sep 2024 16:54:19 -0700 Subject: [PATCH 40/61] Updates --- .../Localization/Strings.cs | 1 + .../Texl/Builtins/Match.cs | 101 +++++---- .../Functions/LibraryRegEx.cs | 49 ++++- src/strings/PowerFxResources.en-US.resx | 4 + .../ExpressionTestCases/Match_Comments.txt | 193 +++++++++++++++++- .../Helpers/RegEx_JavaScript.cs | 58 ++++-- .../FileExpressionEvaluationTests.cs | 5 +- .../Helpers/LibraryRegEx_PCRE2.cs | 67 +++++- 8 files changed, 386 insertions(+), 92 deletions(-) diff --git a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs index 8d237d3567..6d9a6371cc 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs @@ -754,6 +754,7 @@ internal static class TexlStrings public static ErrorResourceKey ErrInvalidRegExBadNamedCaptureName = new ErrorResourceKey("ErrInvalidRegExBadNamedCaptureName"); public static ErrorResourceKey ErrInvalidRegExBadCharacterClassLiteralSquareBracket = new ErrorResourceKey("ErrInvalidRegExBadCharacterClassLiteralSquareBracket"); public static ErrorResourceKey ErrInvalidRegExUnclosedCaptureGroups = new ErrorResourceKey("ErrInvalidRegExUnclosedCaptureGroups"); + public static ErrorResourceKey ErrInvalidRegExUnclosedInlineComment = new ErrorResourceKey("ErrInvalidRegExUnclosedInlineComment"); public static ErrorResourceKey ErrInvalidRegExUnopenedCaptureGroups = new ErrorResourceKey("ErrInvalidRegExUnopenedCaptureGroups"); public static ErrorResourceKey ErrInvalidRegExUnclosedCharacterClass = new ErrorResourceKey("ErrInvalidRegExUnclosedCharacterClass"); public static ErrorResourceKey ErrInvalidRegExMixingNamedAndNumberedSubMatches = new ErrorResourceKey("ErrInvalidRegExMixingNamedAndNumberedSubMatches"); diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index be1feb8792..694113c8ae 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -172,58 +172,59 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter var tokenRE = new Regex( @" # leading backslash, escape sequences - \\k<(?\w+)> | # named backreference - (?\\0\d*) | # \0 and octal are not accepted, amiguous and not needed (use \x instead) - \\(?\d+) | # numeric backreference, must be enabled with MatchOptions.NumberedSubMatches + \\k<(?\w+)> | # named backreference + (?\\0\d*) | # \0 and octal are not accepted, amiguous and not needed (use \x instead) + \\(?\d+) | # numeric backreference, must be enabled with MatchOptions.NumberedSubMatches (?\\ - ([dfnrstw] | # standard regex character classes, missing from .NET are aAeGzZv (no XRegExp support), other common are u{} and o - p\{\w+\} | # unicode character classes - [\^\$\\\.\*\+\?\(\)\[\]\{\}\|\/] | # acceptable escaped characters with Unicode aware ECMAScript - c[a-zA-Z] | # Ctrl character classes - x[0-9a-fA-F]{2} | # hex character, must be exactly 2 hex digits - u[0-9a-fA-F]{4})) | # Unicode characters, must be exactly 4 hex digits - (?\\([bBWDS]|P\{\w+\})) | # acceptable outside a character class, but not within - (?\\.) | # all other escaped characters are invalid and reserved for future use + ([dfnrstw] | # standard regex character classes, missing from .NET are aAeGzZv (no XRegExp support), other common are u{} and o + p\{\w+\} | # unicode character classes + [\^\$\\\.\*\+\?\(\)\[\]\{\}\|\/|\#|\ ] | # acceptable escaped characters with Unicode aware ECMAScript with # and space for Free Spacing + c[a-zA-Z] | # Ctrl character classes + x[0-9a-fA-F]{2} | # hex character, must be exactly 2 hex digits + u[0-9a-fA-F]{4})) | # Unicode characters, must be exactly 4 hex digits + (?\\([bBWDS]|P\{\w+\})) | # acceptable outside a character class, but not within + (?\\.) | # all other escaped characters are invalid and reserved for future use # leading (?<, named captures - \(\?<(?[a-zA-Z][a-zA-Z\d]*)> | # named capture group, can only be letters and numbers and must start with a letter - (?\(\?<\w*-\w*>) | # .NET balancing captures are not supported - (?\(\?<[^>]*>) | # bad named capture name, didn't match goodNamedCapture - (?\(\?'[^']*') | # single quoted capture names are not supported + \(\?<(?[a-zA-Z][a-zA-Z\d]*)> | # named capture group, can only be letters and numbers and must start with a letter + (?\(\?<\w*-\w*>) | # .NET balancing captures are not supported + (?\(\?<[^>]*>) | # bad named capture name, didn't match goodNamedCapture + (?\(\?'[^']*') | # single quoted capture names are not supported # leading (?, misc - (?\(\?:) | # non-capture group, still need to track to match with closing paren - \A\(\?(?[imnsx]+)\) | # inline options - (?\(\?\#[^\)]*\)) | # inline comment - (?\(\?(=|!|<=|\(\?(\w+|\w*-\w+)[\:\)]) | # inline options, including disable of options - (?\(\?\() | # .NET conditional alternations are not supported - (?\([\?\+\*\|]) | # everything else unsupported that could start with a (, includes atomic groups, recursion, subroutines, branch reset, and future features + (?\(\?:) | # non-capture group, still need to track to match with closing paren + \A\(\?(?[imnsx]+)\) | # inline options + (?\(\?\#) | # inline comment + (?\(\?(=|!|<=|\(\?(\w+|\w*-\w+)[\:\)]) | # inline options, including disable of options + (?\(\?\() | # .NET conditional alternations are not supported + (?\([\?\+\*\|]) | # everything else unsupported that could start with a (, includes atomic groups, recursion, subroutines, branch reset, and future features # leading ?\*\+, quantifiers - (?[\?\*\+]\??) | # greedy and lazy quantifiers - (?[\?\*\+][\+\*]) | # possessive and useless quantifiers + (?[\?\*\+]\??) | # greedy and lazy quantifiers + (?[\?\*\+][\+\*]) | # possessive and useless quantifiers # leading {, limited quantifiers - (?{\d+(,\d*)?}\??) | # standard limited quantifiers - (?{\d+(,\d*)?}[\+|\*]) | # possessive and useless quantifiers - (?[{}]) | # more constrained, blocks {,3} and Java/Rust semantics that does not treat this as a literal + (?{\d+(,\d*)?}\??) | # standard limited quantifiers + (?{\d+(,\d*)?}[\+|\*]) | # possessive and useless quantifiers + (?[{}]) | # more constrained, blocks {,3} and Java/Rust semantics that does not treat this as a literal # open and close regions - (?\[\]) | # disallow empty chararcter class (supported by XRegExp) and literal ] at front of character class (supported by .NET) - (?\() | - (?\)) | - (?\[) | - (?\]) | - (?\#) | # used in free spacing mode (to detect start of comment), ignored otherwise - (?[\r\n]) | # used in free spacing mode (to detect end of comment), ignored otherwise - (?.) # used in free spacing mode (to detect repeats), ignored otherwise - ", RegexOptions.IgnorePatternWhitespace | RegexOptions.ExplicitCapture); + (?\[\]) | # disallow empty chararcter class (supported by XRegExp) and literal ] at front of character class (supported by .NET) + (?\() | + (?\)) | + (?\[) | + (?\]) | + (?\#) | # used in free spacing mode (to detect start of comment), ignored otherwise + (?[\r\n]) | # used in free spacing mode (to detect end of comment), ignored otherwise + (?.) # used in free spacing mode (to detect repeats), ignored otherwise + ", RegexOptions.IgnorePatternWhitespace | RegexOptions.ExplicitCapture | RegexOptions.Singleline); int captureNumber = 0; // last numbered capture encountered var captureStack = new Stack(); // stack of all open capture groups, including null for non capturing groups, for detecting if a named group is closed var captureNames = new List(); // list of seen named groups, does not included numbered groups or non capture groups - var openComment = false; // there is an open end-of-line pound comment, only in freeFormMode + var openPoundComment = false; // there is an open end-of-line pound comment, only in freeFormMode + var openInlineComment = false; // there is an open inline comment var freeSpacing = regexOptions.Contains("x"); // can also be set with inline mode modifier var numberedCpature = regexOptions.Contains("N"); // can only be set here, no inline mode modifier var openCharacterClass = false; // are we defining a character class? @@ -233,13 +234,13 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter { if (token.Groups["newline"].Success) { - openComment = false; + openPoundComment = false; } - else if (token.Groups["poundComment"].Success) + else if (openInlineComment && token.Groups["closeParen"].Success) { - openComment = freeSpacing; + openInlineComment = false; } - else if (!openComment) + else if (!openPoundComment && !openInlineComment) { // ordered from most common/good to least common/bad, for fewer tests if (token.Groups["goodEscape"].Success || @@ -436,10 +437,16 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter } else if (token.Groups["goodInlineComment"].Success) { - if (token.Groups["goodInlineComment"].Value.Substring(1).Contains("(")) + if (!openCharacterClass) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExOpenParenInComment, token.Groups["goodInlineComment"].Value); - return false; + openInlineComment = true; + } + } + else if (token.Groups["poundComment"].Success) + { + if (!openCharacterClass) + { + openPoundComment = freeSpacing; } } else if (token.Groups["badBackRefNum"].Success) @@ -510,6 +517,12 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter } } + if (openInlineComment) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExUnclosedInlineComment); + return false; + } + if (captureStack.Count > 0) { errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExUnclosedCaptureGroups); diff --git a/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs b/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs index 230fc1d004..39678af741 100644 --- a/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs +++ b/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs @@ -89,7 +89,7 @@ internal override FormulaValue InvokeRegexFunction(string input, string regex, s if (!m.Success) { - return new BlankValue(IRContext.NotInSource(new KnownRecordType(GetRecordTypeFromRegularExpression(regex, regexOptions)))); + return new BlankValue(IRContext.NotInSource(new KnownRecordType(GetRecordTypeFromRegularExpression(regexAltered, regexOptions)))); } return GetRecordFromMatch(rex, m, regexOptions); @@ -119,7 +119,7 @@ internal override FormulaValue InvokeRegexFunction(string input, string regex, s records.Add(GetRecordFromMatch(rex, m, regexOptions)); } - return TableValue.NewTable(new KnownRecordType(GetRecordTypeFromRegularExpression(regex, regexOptions)), records.ToArray()); + return TableValue.NewTable(new KnownRecordType(GetRecordTypeFromRegularExpression(regexAltered, regexOptions)), records.ToArray()); } } @@ -251,14 +251,18 @@ public Task InvokeAsync(FormulaValue[] args, CancellationToken can break; case '#': - if (freeSpacing) + if (freeSpacing && !openCharacterClass) { for (index++; index < regex.Length && regex[index] != '\r' && regex[index] != '\n'; index++) { // skip the comment characters until the next newline, in case it includes [ ] } - index--; + if (numberedSubMatches && Regex.IsMatch(alteredRegex.ToString(), @"\\[\d]+\z")) + { + // add no op to separate tokens, for the case of "\1#" & Char(10) & "1" which should not be interpreted as "\11" + alteredRegex.Append("(?:)"); + } } else { @@ -267,6 +271,28 @@ public Task InvokeAsync(FormulaValue[] args, CancellationToken can break; + case '(': + // inline comment + if (regex.Length - index > 2 && regex[index + 1] == '?' && regex[index + 2] == '#') + { + for (index++; index < regex.Length && regex[index] != ')'; index++) + { + // skip the comment characters until the next closing paren, in case it includes [ ] + } + + if (numberedSubMatches && Regex.IsMatch(alteredRegex.ToString(), @"\\[\d]+\z")) + { + // add no op to separate tokens, for the case of "\1(?#comment)1" which should not be interpreted as "\11" + alteredRegex.Append("(?:)"); + } + } + else + { + alteredRegex.Append(regex[index]); + } + + break; + case '\\': alteredRegex.Append("\\"); if (++index < regex.Length) @@ -288,16 +314,17 @@ public Task InvokeAsync(FormulaValue[] args, CancellationToken can alteredRegex.Append(openCharacterClass ? "$" : (multiline ? @"(?=\z|\r\n|\r|\n)" : @"(?=\z|\r\n\z|\r\z|\n\z)")); break; - case ' ': - case '\f': - case '\n': - case '\r': - case '\t': - case '\v': - if (!freeSpacing) + // space characters in freespacing + case ' ': case '\f': case '\n': case '\r': case '\t': + if (!freeSpacing || openCharacterClass) { alteredRegex.Append(regex[index]); } + else if (numberedSubMatches && Regex.IsMatch(alteredRegex.ToString(), @"\\[\d]+\z")) + { + // add no op to separate tokens, for the case of '\1 1' which should not be interpreted as '\11' + alteredRegex.Append("(?:)"); + } break; diff --git a/src/strings/PowerFxResources.en-US.resx b/src/strings/PowerFxResources.en-US.resx index f31a249ef3..b6ac4d860b 100644 --- a/src/strings/PowerFxResources.en-US.resx +++ b/src/strings/PowerFxResources.en-US.resx @@ -4457,6 +4457,10 @@ Invalid regular expression: Repeated inline option, found "{0}". Error message indicating that the regular expression includes more than one of the same option. + + Invalid regular expression: Unclosed inline comment, starts with "(?#...". + Error message indicating that the regular expression includes an unclosed inline comment. + Invalid regular expression: Inline option is incompatible with MatchOptions.NumberedSubMatches, found "{0}". Error message indicating that the regular expression includes an inline option that is incompatible with numbered sub matches. diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Comments.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Comments.txt index 887cbb72c2..e7d0d2eb41 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Comments.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Comments.txt @@ -7,18 +7,41 @@ // (?# ...) Inline comment Yes No Yes // "x" option space insiginificant and # comments Yes No Yes -// Inline comments +// INLINE COMMENTS >> Match( "test", "(?# this is a test)st" ) {FullMatch:"st",StartMatch:3} +>> Match( "test", "(?# this is a test with a " & Char(10) & " newline)st" ) +{FullMatch:"st",StartMatch:3} + >> Match( "test", "(?# this is a test ( with an open paren )st" ) Errors: Error 15-60: Invalid regular expression: Inline comments cannot include open parenthesis, found in "(?# this is a test ( with an open paren )".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test", "(?# this is a test \) with an escaped close paren )st" ) // can't escape a paren in an inline comment Errors: Error 15-70: Invalid regular expression: Unopened groups, too few opening parenthesis.|Error 0-5: The function 'Match' has some invalid arguments. -// Free spacing with different newline characters between +>> Match( "test", "te (?# this is a test with an unclosed comment" ) +Errors: Error 15-63: Invalid regular expression: Unclosed inline comment, starts with "(?#...".|Error 0-5: The function 'Match' has some invalid arguments. + +// with free spacing + +>> Match( "test", "(?# this is # a test)st", MatchOptions.FreeSpacing ) // # isn't seen because it is before the closing ) of the inline comment +{FullMatch:"st",StartMatch:3} + +>> Match( "test", " # (?# this is a test)st", MatchOptions.FreeSpacing ) // # inline comment entirely within # comment +{FullMatch:"",StartMatch:1} + +>> Match( "test", " # (?# this is " & Char(10) & " t es t", MatchOptions.FreeSpacing ) // # unclosed inline comment within # comment +{FullMatch:"test",StartMatch:1} + +>> Match( "test", "(?x) # (?# this is a test ( with an open paren )" & Char(10) & "st" ) +{FullMatch:"st", StartMatch:3} + +>> Match( "test", "(?x) # (?# this is a test \) with an escaped close paren ) " & Char(13) & "st" ) // can't escape a paren in an inline comment +{FullMatch:"st", StartMatch:3} + +// FREE SPACING NEWLINES SUPPORTED >> Match( "atestz", "(?x) # this is free spacing! @@ -90,7 +113,7 @@ true >> IsMatch( "ab", "(?x)a # " &Char(11)& " c", MatchOptions.Contains ) // \v true ->> IsMatch( "ab", "(?x)a # " &Char(9)& " c", MatchOptions.Contains ) // \h +>> IsMatch( "ab", "(?x)a # " &Char(9)& " c", MatchOptions.Contains ) // \t true >> IsMatch( "ab", "(?x)a # " &UniChar(2028)& " c", MatchOptions.Contains ) // \u2028 @@ -99,3 +122,167 @@ true >> IsMatch( "ab", "(?x)a # " &UniChar(2029)& " c", MatchOptions.Contains ) // \u2029 true +>> IsMatch( "ac", "(?x)a # \n b" & Char(10) & "c", MatchOptions.Contains ) // \n doesn't terminate comment +true + +>> IsMatch( "ac", "(?x)a # \r b" & Char(10) & "c", MatchOptions.Contains ) // \r doesn't terminate comment +true + +// ESCAPED # + +>> Match( "ab#cd", "ab#cd" ) +{FullMatch:"abd",StartMatch:1} + +>> Match( "abd#cd", "ab\#cd" ) +{FullMatch:"abd",StartMatch:1} + +>> Match( "abd#cd", "ab[#]cd" ) +{FullMatch:"abd",StartMatch:1} + +>> Match( "ab#cd", "a" & Char(10) & " b # c " & Char(10) & "d", MatchOptions.FreeSpacing ) +Blank() + +>> Match( "abd", "a" & Char(10) & " b # c " & Char(10) & "d", MatchOptions.FreeSpacing ) +{FullMatch:"abd",StartMatch:1} + +>> Match( "ab#cd", "a" & Char(10) & " b \# c" & Char(10) & "d", MatchOptions.FreeSpacing ) +{FullMatch:"ab#cd",StartMatch:1} + +>> Match( "ab#cd", "a" & Char(10) & " b [#] c" & Char(10) & "d", MatchOptions.FreeSpacing ) +{FullMatch:"ab#cd",StartMatch:1} + +>> Match( "ab#cd", "a" & Char(10) & " b [\#] c" & Char(10) & "d", MatchOptions.FreeSpacing ) +{FullMatch:"ab#cd",StartMatch:1} + +// ESCAPED SPACE + +>> Match( "ab cd", "ab cd" ) +{FullMatch:"ab cd",StartMatch:1} + +>> Match( "ab cd", "ab\ cd" ) +{FullMatch:"ab cd",StartMatch:1} + +>> Match( "ab cd", "ab[ ]cd" ) +{FullMatch:"ab cd",StartMatch:1} + +>> Match( "ab cd", "ab[\ ]cd" ) +{FullMatch:"ab cd",StartMatch:1} + +>> Match( "ab cd", "a" & Char(10) & " b c " & Char(10) & "d", MatchOptions.FreeSpacing ) +{FullMatch:"ab cd",StartMatch:1} + +>> Match( "ab cd", "a" & Char(10) & " b \ c " & Char(10) & "d", MatchOptions.FreeSpacing ) +{FullMatch:"ab cd",StartMatch:1} + +>> Match( "ab cd", "a" & Char(10) & " b [ ] c" & Char(10) & "d", MatchOptions.FreeSpacing ) +{FullMatch:"ab cd",StartMatch:1} + +>> Match( "ab cd", "a" & Char(10) & " b [\ ] c" & Char(10) & "d", MatchOptions.FreeSpacing ) +{FullMatch:"ab cd",StartMatch:1} + +// FREE SPACING IGNORED SPACE CHARACTERS + +>> IsMatch( "ab", "a b", MatchOptions.FreeSpacing) // space +true + +>> IsMatch( "ab", "a" &UniChar(9)& "b", MatchOptions.FreeSpacing) // \t +true + +>> IsMatch( "ab", "a" &UniChar(10)& "b", MatchOptions.FreeSpacing) // \n +true + +>> IsMatch( "ab", "a" &UniChar(13)& "b", MatchOptions.FreeSpacing) // \r +true + +>> IsMatch( "ab", "a" &UniChar(12)& "b", MatchOptions.FreeSpacing) // \f +true + +>> IsMatch( "ab", "a" &UniChar(11)& "b", MatchOptions.FreeSpacing) // \v +false + +>> IsMatch( "ab", "a" &UniChar(160)& "b", MatchOptions.FreeSpacing) // \u00a0 +false + +>> IsMatch( "ab", "a" &UniChar(5760)& "b", MatchOptions.FreeSpacing) // \u1680 +false + +>> IsMatch( "ab", "a" &UniChar(8192)& "b", MatchOptions.FreeSpacing) // \u2000 +false + +>> IsMatch( "ab", "a" &UniChar(8193)& "b", MatchOptions.FreeSpacing) // \u2001 +false + +>> IsMatch( "ab", "a" &UniChar(8194)& "b", MatchOptions.FreeSpacing) // \u2002 +false + +>> IsMatch( "ab", "a" &UniChar(8195)& "b", MatchOptions.FreeSpacing) // \u2003 +false + +>> IsMatch( "ab", "a" &UniChar(8196)& "b", MatchOptions.FreeSpacing) // \u2004 +false + +>> IsMatch( "ab", "a" &UniChar(8197)& "b", MatchOptions.FreeSpacing) // \u2005 +false + +>> IsMatch( "ab", "a" &UniChar(8198)& "b", MatchOptions.FreeSpacing) // \u2006 +false + +>> IsMatch( "ab", "a" &UniChar(8199)& "b", MatchOptions.FreeSpacing) // \u2007 +false + +>> IsMatch( "ab", "a" &UniChar(8200)& "b", MatchOptions.FreeSpacing) // \u2008 +false + +>> IsMatch( "ab", "a" &UniChar(8201)& "b", MatchOptions.FreeSpacing) // \u2009 +false + +>> IsMatch( "ab", "a" &UniChar(8202)& "b", MatchOptions.FreeSpacing) // \u200a +false + +>> IsMatch( "ab", "a" &UniChar(8232)& "b", MatchOptions.FreeSpacing) // \u2028 +false + +>> IsMatch( "ab", "a" &UniChar(8233)& "b", MatchOptions.FreeSpacing) // \u2029 +false + +>> IsMatch( "ab", "a" &UniChar(8239)& "b", MatchOptions.FreeSpacing) // \u202f +false + +>> IsMatch( "ab", "a" &UniChar(8287)& "b", MatchOptions.FreeSpacing) // \u205f +false + +>> IsMatch( "ab", "a" &UniChar(12288)& "b", MatchOptions.FreeSpacing) // \u3000 +false + +>> IsMatch( "ab", "a" &UniChar(65279)& "b", MatchOptions.FreeSpacing) // \ufeff +false + +// spaces are not merely removed, they are no-ops and regular expression tokens still end at them + +>> IsMatch( UniChar(123) & "4", "(?x)\u123 4" ) // too few characters for \u +Errors: Error 29-42: Invalid regular expression: Invalid escape code, found "\u".|Error 0-7: The function 'IsMatch' has some invalid arguments. + +>> Match( "aBa1", "(?x)(a)(((((((((((((((B)))))))))))))))\1 1", MatchOptions.NumberedSubMatches ).FullMatch +"aBa1" + +>> Match( "aBa1", "(?x)(a)(((((((((((((((B)))))))))))))))\11", MatchOptions.NumberedSubMatches ).FullMatch +Blank() + +>> Match( "aBa1", "(?x)(a)(((((((((((((((B)))))))))))))))\1(?#comment)1", MatchOptions.NumberedSubMatches ).FullMatch +"aBa1" + +>> Match( "aBa1", "(a)(((((((((((((((B)))))))))))))))\1(?#comment)1", MatchOptions.NumberedSubMatches ).FullMatch +"aBa1" + +>> Match( "aaaaaa", "(?x)a {3}" ) +{FullMatch:"aaa",StartMatch:1} + +>> Match( "aaaaaaaaaaaaaaaaaaaaaaaaaa", "(?x)a { 3 }" ) +Errors: Error 37-56: Invalid regular expression: Literal curly braces must be escaped with a backslash, for example \Invalid regular expression: Literal curly braces must be escaped with a backslash, for example \{ or \}, found "{0}".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "aaaaaaaaaaaaaaaaaaaaaaaaaa", "(?x)a { 1 2 }" ) +Errors: Error 37-58: Invalid regular expression: Literal curly braces must be escaped with a backslash, for example \Invalid regular expression: Literal curly braces must be escaped with a backslash, for example \{ or \}, found "{0}".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "aaaaaa", "(?x)a +" ) +{FullMatch:"aaaaaa",StartMatch:1} + diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs index 6db38815e5..9139f651f7 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs @@ -15,20 +15,21 @@ public class RegEx_JavaScript public const string AlterRegex_JavaScript = @" function AlterRegex_JavaScript(regex, flags) { - var regexIndex = 0; + var index = 0; const inlineFlagsRE = /^\(\?(?[imnsx]+)\)/; const inlineFlags = inlineFlagsRE.exec( regex ); if (inlineFlags != null) { flags = flags.concat(inlineFlags.groups['flags']); - regexIndex = inlineFlags[0].length; + index = inlineFlags[0].length; } const freeSpacing = flags.includes('x'); const multiline = flags.includes('m'); const dotAll = flags.includes('s'); const ignoreCase = flags.includes('i'); + const numberedSubMatches = flags.includes('N'); // rebuilding from booleans avoids possible duplicate letters // x has been handled in this function and does not need to be passed on (and would cause an error) @@ -37,9 +38,9 @@ function AlterRegex_JavaScript(regex, flags) var openCharacterClass = false; // are we defining a character class? var altered = ''; - for ( ; regexIndex < regex.length; regexIndex++) + for ( ; index < regex.length; index++) { - switch (regex.charAt(regexIndex) ) + switch (regex.charAt(index) ) { case '[': openCharacterClass = true; @@ -52,13 +53,13 @@ function AlterRegex_JavaScript(regex, flags) break; case '\\': - if (++regexIndex < regex.length) + if (++index < regex.length) { const wordChar = '\\p{Ll}\\p{Lu}\\p{Lt}\\p{Lo}\\p{Lm}\\p{Nd}\\p{Pc}'; const spaceChar = '\\f\\n\\r\\t\\v\\x85\\p{Z}'; const digitChar = '\\p{Nd}'; - switch (regex.charAt(regexIndex)) + switch (regex.charAt(index)) { case 'w': altered = altered.concat((openCharacterClass ? '' : '['), wordChar, (openCharacterClass ? '' : ']')); @@ -88,8 +89,13 @@ function AlterRegex_JavaScript(regex, flags) altered = altered.concat('[^', digitChar, ']'); break; + // needed for free spacing + case '#': case ' ': + altered = altered.concat(regex.charAt(index)); + break; + default: - altered = altered.concat('\\', regex.charAt(regexIndex)); + altered = altered.concat('\\', regex.charAt(index)); break; } } @@ -114,13 +120,19 @@ function AlterRegex_JavaScript(regex, flags) break; case '(': - if (regex.length - regexIndex > 2 && regex.charAt(regexIndex+1) == '?' && regex.charAt(regexIndex+2) == '#') + if (regex.length - index > 2 && regex.charAt(index+1) == '?' && regex.charAt(index+2) == '#') { // inline comment - for ( regexIndex++; regexIndex < regex.length && regex.charAt(regexIndex) != ')'; regexIndex++) + for ( index++; index < regex.length && regex.charAt(index) != ')'; index++) { // eat characters until a close paren, it doesn't matter if it is escaped (consistent with .NET) } + + if (numberedSubMatches && /\\[\d]+$/.test(altered)) + { + // add no op to separate tokens, for the case of \1(?#comment)1 which should not be interpreted as \11 + altered = altered.concat('(?:)'); + } } else { @@ -129,29 +141,33 @@ function AlterRegex_JavaScript(regex, flags) break; - case ' ': - case '\f': - case '\n': - case '\r': - case '\t': - case '\v': - if (!freeSpacing) + case ' ': case '\f': case '\n': case '\r': case '\t': + if (!freeSpacing || openCharacterClass) { - altered = altered.concat(regex.charAt(regexIndex)); + altered = altered.concat(regex.charAt(index)); + } + if (numberedSubMatches && /\\[\d]+$/.test(altered)) + { + // add no op to separate tokens, for the case of '\1 1' which should not be interpreted as '\11' + altered = altered.concat('(?:)'); } break; case '#': - if (freeSpacing) + if (freeSpacing && !openCharacterClass) { - for ( regexIndex++; regexIndex < regex.length && regex.charAt(regexIndex) != '\r' && regex.charAt(regexIndex) != '\n'; regexIndex++) + for ( index++; index < regex.length && regex.charAt(index) != '\r' && regex.charAt(index) != '\n'; index++) { // eat characters until the end of the line // leaving dangling whitespace characters will be eaten on next iteration } - regexIndex--; + if (numberedSubMatches && /\\[\d]+$/.test(alteredRegex)) + { + // add no op to separate tokens, for the case of '\1# commment\n1' which should not be interpreted as '\11' + altered = altered.concat('(?:)'); + } } else { @@ -161,7 +177,7 @@ function AlterRegex_JavaScript(regex, flags) break; default: - altered = altered.concat(regex.charAt(regexIndex)); + altered = altered.concat(regex.charAt(index)); break; } } diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index 4ed5d48020..dbe0ca45bd 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -166,8 +166,8 @@ private static bool ShouldSkipDotNetVersion(ExpressionTestCase testCase, string return false; } -#if false - // Helper to run a single .txt d +#if true + // Helper to run a single .txt dee [Fact] public void RunOne() { @@ -185,6 +185,7 @@ public void RunOne() testRunner.Tests.RemoveAll(x => x.SourceLine != line); } + ExpressionEvaluationTests.RegExCompareEnabled = true; var result = testRunner.RunTests(); if (result.Fail > 0) { diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs index 1b747197ea..646be7f605 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs @@ -123,7 +123,7 @@ internal static FormulaValue Match(string subject, string pattern, string flags, if (flags.Contains('^') || flags.Contains('$')) { // we can't use PCRE2_OPTIONS.EXTENDED here because we need to add ^ or $ appropriately next - pattern = StripExtended(pattern); + pattern = StripExtended(pattern, (options & RegexOptions.ExplicitCapture) == 0); } else { @@ -214,21 +214,39 @@ internal static FormulaValue Match(string subject, string pattern, string flags, } } - public static string StripExtended(string regex) + public static string StripExtended(string regex, bool numberedSubMatches) { StringBuilder alteredRegex = new StringBuilder(); + bool openCharacterClass = false; for (int index = 0; index < regex.Length; index++) { switch (regex[index]) { + case '[': + openCharacterClass = true; + alteredRegex.Append('['); + break; + + case ']': + openCharacterClass = false; + alteredRegex.Append(']'); + break; + case '#': - for (index++; index < regex.Length && regex[index] != '\r' && regex[index] != '\n'; index++) + if (!openCharacterClass) { - // skip the comment characters until the next newline, in case it includes [ ] + for (index++; index < regex.Length && regex[index] != '\r' && regex[index] != '\n'; index++) + { + // skip the comment characters until the next newline, in case it includes [ ] + } } - index--; + if (numberedSubMatches && Regex.IsMatch(alteredRegex.ToString(), @"\\[\d]+\z")) + { + // add no op to separate tokens, for the case of "\1#" & Char(10) & "1" which should not be interpreted as "\11" + alteredRegex.Append("(?:)"); + } break; @@ -241,12 +259,39 @@ public static string StripExtended(string regex) break; - case ' ': - case '\f': - case '\n': - case '\r': - case '\t': - case '\v': + case '(': + // inline comment + if (regex.Length - index > 2 && regex[index + 1] == '?' && regex[index + 2] == '#') + { + for (index++; index < regex.Length && regex[index] != ')'; index++) + { + // skip the comment characters until the next closing paren, in case it includes [ ] + } + + if (numberedSubMatches && Regex.IsMatch(alteredRegex.ToString(), @"\\[\d]+\z")) + { + // add no op to separate tokens, for the case of "\1(?#comment)1" which should not be interpreted as "\11" + alteredRegex.Append("(?:)"); + } + } + else + { + alteredRegex.Append(regex[index]); + } + + break; + + case ' ': case '\f': case '\n': case '\r': case '\t': + if (openCharacterClass) + { + alteredRegex.Append(regex[index]); + } + else if (numberedSubMatches && Regex.IsMatch(alteredRegex.ToString(), @"\\[\d]+\z")) + { + // add no op to separate tokens, for the case of "\1 1" which should not be interpreted as "\11" + alteredRegex.Append("(?:)"); + } + break; default: From 47086b6167f8550abc266082b44841f77e210e88 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Tue, 3 Sep 2024 23:33:12 -0700 Subject: [PATCH 41/61] Updates --- .../Texl/Builtins/Match.cs | 86 +++++++++---------- .../Functions/LibraryRegEx.cs | 72 +++++----------- .../ExpressionTestCases/Match_Comments.txt | 24 +++--- .../ExpressionTestCases/Match_Limited.txt | 19 ++-- .../Helpers/RegEx_JavaScript.cs | 25 ++---- .../FileExpressionEvaluationTests.cs | 10 +-- .../Helpers/LibraryRegEx_PCRE2.cs | 14 +-- 7 files changed, 97 insertions(+), 153 deletions(-) diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index 694113c8ae..cea5843150 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -160,6 +160,9 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp // See https://learn.microsoft.com/dotnet/standard/base-types/regular-expression-options#ecmascript-matching-behavior for more details private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPattern, string regexOptions, IErrorContainer errors) { + bool freeSpacing = regexOptions.Contains("x"); // can also be set with inline mode modifier + bool numberedCpature = regexOptions.Contains("N"); // can only be set here, no inline mode modifier + // Scans the regular expression for interesting constructs, ignoring other elements and constructs that are legal, such as letters and numbers. // Order of alternation is important. .NET regular expressions are greedy and will match the first of these that it can. // Many subexpressions here take advantage of this, matching something that is valid, before falling through to check for something that is invalid. @@ -198,11 +201,13 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter (?\(\?(=|!|<=|\(\?(\w+|\w*-\w+)[\:\)]) | # inline options, including disable of options (?\(\?\() | # .NET conditional alternations are not supported - (?\([\?\+\*\|]) | # everything else unsupported that could start with a (, includes atomic groups, recursion, subroutines, branch reset, and future features + + # leading (, used for other special purposes + (?\([\?\+\*]) | # everything else unsupported that could start with a (, includes atomic groups, recursion, subroutines, branch reset, and future features # leading ?\*\+, quantifiers (?[\?\*\+]\??) | # greedy and lazy quantifiers - (?[\?\*\+][\+\*]) | # possessive and useless quantifiers + (?[\?\*\+][\+\*]) | # possessive (ends with +) and useless quantifiers (ends with *) # leading {, limited quantifiers (?{\d+(,\d*)?}\??) | # standard limited quantifiers @@ -210,25 +215,22 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter (?[{}]) | # more constrained, blocks {,3} and Java/Rust semantics that does not treat this as a literal # open and close regions - (?\[\]) | # disallow empty chararcter class (supported by XRegExp) and literal ] at front of character class (supported by .NET) - (?\() | - (?\)) | - (?\[) | - (?\]) | + (?\() | + (?\)) | + (?\[) | + (?\]) | (?\#) | # used in free spacing mode (to detect start of comment), ignored otherwise - (?[\r\n]) | # used in free spacing mode (to detect end of comment), ignored otherwise - (?.) # used in free spacing mode (to detect repeats), ignored otherwise - ", RegexOptions.IgnorePatternWhitespace | RegexOptions.ExplicitCapture | RegexOptions.Singleline); + (?[\r\n]) # used in free spacing mode (to detect end of comment), ignored otherwise + ", RegexOptions.IgnorePatternWhitespace | RegexOptions.ExplicitCapture); int captureNumber = 0; // last numbered capture encountered var captureStack = new Stack(); // stack of all open capture groups, including null for non capturing groups, for detecting if a named group is closed var captureNames = new List(); // list of seen named groups, does not included numbered groups or non capture groups - var openPoundComment = false; // there is an open end-of-line pound comment, only in freeFormMode - var openInlineComment = false; // there is an open inline comment - var freeSpacing = regexOptions.Contains("x"); // can also be set with inline mode modifier - var numberedCpature = regexOptions.Contains("N"); // can only be set here, no inline mode modifier - var openCharacterClass = false; // are we defining a character class? - List characterClassRepeat = new List(); // encountered character class characters, to detect repeats + + bool openPoundComment = false; // there is an open end-of-line pound comment, only in freeFormMode + bool openInlineComment = false; // there is an open inline comment + bool openCharacterClass = false; // are we defining a character class? + int openCharacterClassStart = -1; foreach (Match token in tokenRE.Matches(regexPattern)) { @@ -236,14 +238,14 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter { openPoundComment = false; } - else if (openInlineComment && token.Groups["closeParen"].Success) + else if (openInlineComment && (token.Groups["closeParen"].Success || token.Groups["goodEscape"].Value == "\\)")) { openInlineComment = false; } else if (!openPoundComment && !openInlineComment) { // ordered from most common/good to least common/bad, for fewer tests - if (token.Groups["goodEscape"].Success || + if (token.Groups["goodEscape"].Success || token.Groups["goodQuantifiers"].Success || token.Groups["goodLookaround"].Success || token.Groups["goodLimited"].Success) { // all is well, nothing to do @@ -256,7 +258,7 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter return false; } } - else if (token.Groups["openCharacterClass"].Success) + else if (token.Groups["openCharClass"].Success) { if (openCharacterClass) { @@ -273,14 +275,29 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter } else { + openCharacterClassStart = token.Index; openCharacterClass = true; - characterClassRepeat = new List(); } } - else if (token.Groups["closeCharacterClass"].Success) + else if (token.Groups["closeCharClass"].Success) { if (openCharacterClass) { + if (token.Index == openCharacterClassStart + 1) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadCharacterClassLiteralSquareBracket, token.Groups["badCharacterClassEmpty"].Value); + return false; + } + + // looking for any doubled punctuaion marks in the character class, as this can be used in the future for set subtraction, intserection, union, etc. + // for example, see https://www.unicode.org/reports/tr18/#Subtraction_and_Intersection + Match matchRepeat = Regex.Match(regexPattern.Substring(openCharacterClassStart, token.Index - openCharacterClassStart), "([-|&~+?!@#$%^=:;])\\1"); + if (matchRepeat.Success) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExRepeatInCharClass, matchRepeat.Value); + return false; + } + openCharacterClass = false; } else @@ -318,7 +335,7 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter captureStack.Push(null); } } - else if (token.Groups["openCapture"].Success) + else if (token.Groups["openParen"].Success) { // parens do not need to be escaped within square brackets if (!openCharacterClass) @@ -334,7 +351,7 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter } } } - else if (token.Groups["closeCapture"].Success) + else if (token.Groups["closeParen"].Success) { // parens do not need to be escaped within square brackets if (!openCharacterClass) @@ -417,24 +434,6 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter freeSpacing = true; } } - else if (token.Groups["goodQuantifiers"].Success || token.Groups["remainingChars"].Success) - { - if (openCharacterClass) - { - foreach (char singleChar in token.Value) - { - if (characterClassRepeat.Contains(singleChar)) - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExRepeatInCharClass, singleChar); - return false; - } - else if (singleChar != '-') - { - characterClassRepeat.Add(singleChar); - } - } - } - } else if (token.Groups["goodInlineComment"].Success) { if (!openCharacterClass) @@ -484,11 +483,6 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadConditional, token.Groups["badConditional"].Value); return false; } - else if (token.Groups["badCharacterClassEmpty"].Success) - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadCharacterClassLiteralSquareBracket, token.Groups["badCharacterClassEmpty"].Value); - return false; - } else if (token.Groups["badEscape"].Success) { errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadEscape, token.Groups["badEscape"].Value); diff --git a/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs b/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs index 39678af741..65b599e1c5 100644 --- a/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs +++ b/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs @@ -216,12 +216,11 @@ public Task InvokeAsync(FormulaValue[] args, CancellationToken can protected (string, RegexOptions) AlterRegex_DotNet(string regex, string options) { - var alteredRegex = new StringBuilder(); + var altered = new StringBuilder(); bool openCharacterClass = false; // are we defining a character class? int index = 0; - Match inlineOptions = Regex.Match(regex, @"^\(\?([imnsx]+)\)"); - + Match inlineOptions = Regex.Match(regex, @"\A\(\?([imnsx]+)\)"); if (inlineOptions.Success) { options = options + inlineOptions.Groups[1]; @@ -242,12 +241,12 @@ public Task InvokeAsync(FormulaValue[] args, CancellationToken can { case '[': openCharacterClass = true; - alteredRegex.Append('['); + altered.Append('['); break; case ']': openCharacterClass = false; - alteredRegex.Append(']'); + altered.Append(']'); break; case '#': @@ -258,15 +257,14 @@ public Task InvokeAsync(FormulaValue[] args, CancellationToken can // skip the comment characters until the next newline, in case it includes [ ] } - if (numberedSubMatches && Regex.IsMatch(alteredRegex.ToString(), @"\\[\d]+\z")) - { - // add no op to separate tokens, for the case of "\1#" & Char(10) & "1" which should not be interpreted as "\11" - alteredRegex.Append("(?:)"); - } + // need to replace a \r ending comment (supported by Power Fx) with a \n ending comment (supported by .NET) + // also need to make sure the comment terminates with a newline in case we add a "$" below + // need something to be emitted to avoid "\1#" & Char(10) & "1" being interpreted as "\11" + altered.Append("\n"); } else { - alteredRegex.Append('#'); + altered.Append('#'); } break; @@ -280,81 +278,51 @@ public Task InvokeAsync(FormulaValue[] args, CancellationToken can // skip the comment characters until the next closing paren, in case it includes [ ] } - if (numberedSubMatches && Regex.IsMatch(alteredRegex.ToString(), @"\\[\d]+\z")) - { - // add no op to separate tokens, for the case of "\1(?#comment)1" which should not be interpreted as "\11" - alteredRegex.Append("(?:)"); - } + // need something to be emitted to avoid "\1(?:)1" being interpreted as "\11" + altered.Append("(?:)"); } else { - alteredRegex.Append(regex[index]); + altered.Append(regex[index]); } break; case '\\': - alteredRegex.Append("\\"); + altered.Append("\\"); if (++index < regex.Length) { - alteredRegex.Append(regex[index]); + altered.Append(regex[index]); } break; case '.': - alteredRegex.Append(!openCharacterClass && !dotAll ? @"[^\r\n]" : "."); + altered.Append(!openCharacterClass && !dotAll ? @"[^\r\n]" : "."); break; case '^': - alteredRegex.Append(!openCharacterClass && multiline ? @"(?<=\A|\r\n|\r|\n)" : "^"); + altered.Append(!openCharacterClass && multiline ? @"(?<=\A|\r\n|\r|\n)" : "^"); break; case '$': - alteredRegex.Append(openCharacterClass ? "$" : (multiline ? @"(?=\z|\r\n|\r|\n)" : @"(?=\z|\r\n\z|\r\z|\n\z)")); - break; - - // space characters in freespacing - case ' ': case '\f': case '\n': case '\r': case '\t': - if (!freeSpacing || openCharacterClass) - { - alteredRegex.Append(regex[index]); - } - else if (numberedSubMatches && Regex.IsMatch(alteredRegex.ToString(), @"\\[\d]+\z")) - { - // add no op to separate tokens, for the case of '\1 1' which should not be interpreted as '\11' - alteredRegex.Append("(?:)"); - } - + altered.Append(openCharacterClass ? "$" : (multiline ? @"(?=\z|\r\n|\r|\n)" : @"(?=\z|\r\n\z|\r\z|\n\z)")); break; default: - alteredRegex.Append(regex[index]); + altered.Append(regex[index]); break; } } - string prefix = string.Empty; - string postfix = string.Empty; - - if (matchStart && (alteredRegex.Length == 0 || alteredRegex[0] != '^')) - { - prefix = "^"; - } - - if (matchEnd && (alteredRegex.Length == 0 || alteredRegex[alteredRegex.Length - 1] != '$')) - { - postfix = "$"; - } - - // freeSpacing has already been taken care of in this routine RegexOptions alteredOptions = RegexOptions.CultureInvariant | (multiline ? RegexOptions.Multiline : 0) | (ignoreCase ? RegexOptions.IgnoreCase : 0) | (dotAll ? RegexOptions.Singleline : 0) | + (freeSpacing ? RegexOptions.IgnorePatternWhitespace : 0) | (numberedSubMatches ? 0 : RegexOptions.ExplicitCapture); - return (prefix + alteredRegex.ToString() + postfix, alteredOptions); + return ((matchStart ? "^" : string.Empty) + altered.ToString() + (matchEnd ? "$" : string.Empty), alteredOptions); } protected static RecordValue GetRecordFromMatch(Regex rex, Match m, RegexOptions options) diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Comments.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Comments.txt index e7d0d2eb41..ad3b136023 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Comments.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Comments.txt @@ -16,7 +16,7 @@ {FullMatch:"st",StartMatch:3} >> Match( "test", "(?# this is a test ( with an open paren )st" ) -Errors: Error 15-60: Invalid regular expression: Inline comments cannot include open parenthesis, found in "(?# this is a test ( with an open paren )".|Error 0-5: The function 'Match' has some invalid arguments. +{FullMatch:"st",StartMatch:3} >> Match( "test", "(?# this is a test \) with an escaped close paren )st" ) // can't escape a paren in an inline comment Errors: Error 15-70: Invalid regular expression: Unopened groups, too few opening parenthesis.|Error 0-5: The function 'Match' has some invalid arguments. @@ -36,10 +36,10 @@ Errors: Error 15-63: Invalid regular expression: Unclosed inline comment, starts {FullMatch:"test",StartMatch:1} >> Match( "test", "(?x) # (?# this is a test ( with an open paren )" & Char(10) & "st" ) -{FullMatch:"st", StartMatch:3} +{FullMatch:"st",StartMatch:3} >> Match( "test", "(?x) # (?# this is a test \) with an escaped close paren ) " & Char(13) & "st" ) // can't escape a paren in an inline comment -{FullMatch:"st", StartMatch:3} +{FullMatch:"st",StartMatch:3} // FREE SPACING NEWLINES SUPPORTED @@ -131,18 +131,18 @@ true // ESCAPED # >> Match( "ab#cd", "ab#cd" ) -{FullMatch:"abd",StartMatch:1} +{FullMatch:"ab#cd",StartMatch:1} ->> Match( "abd#cd", "ab\#cd" ) -{FullMatch:"abd",StartMatch:1} +>> Match( "ab#cd", "ab\#cd" ) +{FullMatch:"ab#cd",StartMatch:1} ->> Match( "abd#cd", "ab[#]cd" ) -{FullMatch:"abd",StartMatch:1} +>> Match( "ab#cd", "ab[#]cd" ) +{FullMatch:"ab#cd",StartMatch:1} ->> Match( "ab#cd", "a" & Char(10) & " b # c " & Char(10) & "d", MatchOptions.FreeSpacing ) +>> Match( "ab#cd", "a" & Char(10) & " b # c " & Char(10) & "d", MatchOptions.FreeSpacing ) // c is in a # comment Blank() ->> Match( "abd", "a" & Char(10) & " b # c " & Char(10) & "d", MatchOptions.FreeSpacing ) +>> Match( "abd", "a" & Char(10) & " b # c " & Char(10) & "d", MatchOptions.FreeSpacing ) {FullMatch:"abd",StartMatch:1} >> Match( "ab#cd", "a" & Char(10) & " b \# c" & Char(10) & "d", MatchOptions.FreeSpacing ) @@ -168,8 +168,8 @@ Blank() >> Match( "ab cd", "ab[\ ]cd" ) {FullMatch:"ab cd",StartMatch:1} ->> Match( "ab cd", "a" & Char(10) & " b c " & Char(10) & "d", MatchOptions.FreeSpacing ) -{FullMatch:"ab cd",StartMatch:1} +>> Match( "ab cd", "a" & Char(10) & " b c " & Char(10) & "d", MatchOptions.FreeSpacing ) // no actual space between b and c +Blank() >> Match( "ab cd", "a" & Char(10) & " b \ c " & Char(10) & "d", MatchOptions.FreeSpacing ) {FullMatch:"ab cd",StartMatch:1} diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt index bf1693b4c6..82c1897d49 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt @@ -288,13 +288,13 @@ Errors: Error 12-25: Invalid regular expression: Character class subtraction is // repeated characters in character class, used by intersection and future character class features, also would catch POSIX cases if wasn't already blocked by nested square brackets >> Match( "hello", "[a-z&&[k-m]]" ) -Errors: Error 16-30: Invalid regular expression: Character appears more than once in character class, found repeated "&".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 16-30: Invalid regular expression: Square bracket character classes cannot be empty and cannot include unescaped literal open or close square brackets, escape with "\[" or "\]".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "hello", "[a-z&&k-m]" ) -Errors: Error 16-28: Invalid regular expression: Character appears more than once in character class, found repeated "&".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 16-28: Invalid regular expression: Character appears more than once in character class, found repeated "&&".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "hello", "[a-hh-z]" ) -Errors: Error 16-26: Invalid regular expression: Character appears more than once in character class, found repeated "h".|Error 0-5: The function 'Match' has some invalid arguments. +{FullMatch:"h",StartMatch:1} >> Match( "HellO", "[[:lower:]]" ) Errors: Error 16-29: Invalid regular expression: Square bracket character classes cannot be empty and cannot include unescaped literal open or close square brackets, escape with "\[" or "\]".|Error 0-5: The function 'Match' has some invalid arguments. @@ -523,13 +523,13 @@ Errors: Error 15-22: Invalid regular expression: Invalid escape code, found "\p" >> Match( "test", "\P{@}" ) Errors: Error 15-22: Invalid regular expression: Invalid escape code, found "\P".|Error 0-5: The function 'Match' has some invalid arguments. -// Escape characters acceptable to ECMAScript +// Escape characters acceptable to ECMAScript, plus \# and \ for x mode ->> Match("^$\.*+?()[]{}|/", "\^\$\\\.\*\+\?\(\)\[\]\{\}\|\/" ) -{FullMatch:"^$\.*+?()[]{}|/",StartMatch:1} +>> Match("^$\.*+?()[]{}|/# ", "\^\$\\\.\*\+\?\(\)\[\]\{\}\|\/\#\ " ) +{FullMatch:"^$\.*+?()[]{}|/# ",StartMatch:1} ->> Match("^$\.*+?()[]{}|/", "[\^\$\\\.\*\+\?\(\)\[\]\{\}\|\/]+" ) -{FullMatch:"^$\.*+?()[]{}|/",StartMatch:1} +>> Match("^$\.*+?()[]{}|/# ", "[\^\$\\\.\*\+\?\(\)\[\]\{\}\|\/\#\ ]+" ) +{FullMatch:"^$\.*+?()[]{}|/# ",StartMatch:1} // Escape characters that are blocked @@ -539,9 +539,6 @@ Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\!" >> Match( "!@#%&=-`~><';:,""", "\@" ) Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\@".|Error 0-5: The function 'Match' has some invalid arguments. ->> Match( "!@#%&=-`~><';:,""", "\#" ) -Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\#".|Error 0-5: The function 'Match' has some invalid arguments. - >> Match( "!@#%&=-`~><';:,""", "\%" ) Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\%".|Error 0-5: The function 'Match' has some invalid arguments. diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs index 9139f651f7..9fc6004bde 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs @@ -128,11 +128,7 @@ function AlterRegex_JavaScript(regex, flags) // eat characters until a close paren, it doesn't matter if it is escaped (consistent with .NET) } - if (numberedSubMatches && /\\[\d]+$/.test(altered)) - { - // add no op to separate tokens, for the case of \1(?#comment)1 which should not be interpreted as \11 - altered = altered.concat('(?:)'); - } + altered = altered.concat('(?:)'); } else { @@ -142,14 +138,13 @@ function AlterRegex_JavaScript(regex, flags) break; case ' ': case '\f': case '\n': case '\r': case '\t': - if (!freeSpacing || openCharacterClass) + if (freeSpacing && !openCharacterClass) { - altered = altered.concat(regex.charAt(index)); + altered = altered.concat('(?:)'); } - if (numberedSubMatches && /\\[\d]+$/.test(altered)) + else { - // add no op to separate tokens, for the case of '\1 1' which should not be interpreted as '\11' - altered = altered.concat('(?:)'); + altered = altered.concat(regex.charAt(index)); } break; @@ -163,11 +158,7 @@ function AlterRegex_JavaScript(regex, flags) // leaving dangling whitespace characters will be eaten on next iteration } - if (numberedSubMatches && /\\[\d]+$/.test(alteredRegex)) - { - // add no op to separate tokens, for the case of '\1# commment\n1' which should not be interpreted as '\11' - altered = altered.concat('(?:)'); - } + altered = altered.concat('(?:)'); } else { @@ -182,12 +173,12 @@ function AlterRegex_JavaScript(regex, flags) } } - if (flags.includes('^') && (altered.length == 0 || altered[0] != '^')) + if (flags.includes('^')) { altered = '^' + altered; } - if (flags.includes('$') && (altered.length == 0 || altered[altered.length-1] != '$')) + if (flags.includes('$')) { altered = altered + '$'; } diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index dbe0ca45bd..53c85e5c24 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -91,7 +91,7 @@ public void None_Float(ExpressionTestCase testCase) } #endif -#if false +#if true // Runs only tests that have asked for RegEx setup. This test run will compare the regular expression results between // .NET (used in the C# interpreter), NodeJS with JavaScript (used in Canvas), and PCRE2 (used in Excel). // This is not run all the time. It requires Node to be installed and PCRE2 built as a shared library DLL and on the path. @@ -166,12 +166,12 @@ private static bool ShouldSkipDotNetVersion(ExpressionTestCase testCase, string return false; } -#if true - // Helper to run a single .txt dee +#if false + // Helper to run a single .txt deefee [Fact] public void RunOne() { - var path = @"d:\repos\regex-min-3\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\match_comments.txt"; + var path = @"d:\repos\regex-min-6\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\match_comments.txt"; var line = 0; var runner = new InterpreterRunner(); @@ -179,7 +179,7 @@ public void RunOne() testRunner.AddFile(new Dictionary(), null, path); - // We can filter to just cases we want, set line above + // We can filter to just cases we want, set line above a if (line > 0) { testRunner.Tests.RemoveAll(x => x.SourceLine != line); diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs index 646be7f605..b48bed42e8 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs @@ -90,7 +90,6 @@ internal static FormulaValue Match(string subject, string pattern, string flags, RegexOptions options = RegexOptions.None; Match inlineOptions = Regex.Match(pattern, @"^\(\?([imnsx]+)\)"); - if (inlineOptions.Success) { flags = flags + inlineOptions.Groups[1]; @@ -120,15 +119,10 @@ internal static FormulaValue Match(string subject, string pattern, string flags, if (flags.Contains('x')) { - if (flags.Contains('^') || flags.Contains('$')) - { - // we can't use PCRE2_OPTIONS.EXTENDED here because we need to add ^ or $ appropriately next - pattern = StripExtended(pattern, (options & RegexOptions.ExplicitCapture) == 0); - } - else - { - pcreOptions |= PCRE2_OPTIONS.EXTENDED; - } + // replace the three characters that PCRE2 recognizes as white space that Power Fx does not + // add a \n so that we can add a $ at the end, in case there is an unterminated pound comment + pattern = Regex.Replace(pattern, "[\u0011\u2028\u2029]", " ") + '\n'; + pcreOptions |= PCRE2_OPTIONS.EXTENDED; } if (flags.Contains('^') && (pattern.Length == 0 || pattern[0] != '^')) From 390448498f7f6b674df26c91c994a2d80eff2398 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Tue, 3 Sep 2024 23:59:40 -0700 Subject: [PATCH 42/61] Updates --- .../Helpers/LibraryRegEx_PCRE2.cs | 95 +------------------ 1 file changed, 5 insertions(+), 90 deletions(-) diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs index b48bed42e8..f55a745da6 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs @@ -105,24 +105,28 @@ internal static FormulaValue Match(string subject, string pattern, string flags, if (flags.Contains('i')) { pcreOptions |= PCRE2_OPTIONS.CASELESS; + options |= RegexOptions.IgnoreCase; } if (flags.Contains('m')) { pcreOptions |= PCRE2_OPTIONS.MULTILINE; + options |= RegexOptions.Multiline; } if (flags.Contains('s')) { pcreOptions |= PCRE2_OPTIONS.DOTALL; + options |= RegexOptions.Singleline; } if (flags.Contains('x')) { // replace the three characters that PCRE2 recognizes as white space that Power Fx does not // add a \n so that we can add a $ at the end, in case there is an unterminated pound comment - pattern = Regex.Replace(pattern, "[\u0011\u2028\u2029]", " ") + '\n'; + pattern = pattern.Replace("\u000b", "\\u000b").Replace("\u2028", "\\u2028").Replace("\u2029", "\\u2029") + '\n'; pcreOptions |= PCRE2_OPTIONS.EXTENDED; + options |= RegexOptions.IgnorePatternWhitespace; } if (flags.Contains('^') && (pattern.Length == 0 || pattern[0] != '^')) @@ -208,95 +212,6 @@ internal static FormulaValue Match(string subject, string pattern, string flags, } } - public static string StripExtended(string regex, bool numberedSubMatches) - { - StringBuilder alteredRegex = new StringBuilder(); - bool openCharacterClass = false; - - for (int index = 0; index < regex.Length; index++) - { - switch (regex[index]) - { - case '[': - openCharacterClass = true; - alteredRegex.Append('['); - break; - - case ']': - openCharacterClass = false; - alteredRegex.Append(']'); - break; - - case '#': - if (!openCharacterClass) - { - for (index++; index < regex.Length && regex[index] != '\r' && regex[index] != '\n'; index++) - { - // skip the comment characters until the next newline, in case it includes [ ] - } - } - - if (numberedSubMatches && Regex.IsMatch(alteredRegex.ToString(), @"\\[\d]+\z")) - { - // add no op to separate tokens, for the case of "\1#" & Char(10) & "1" which should not be interpreted as "\11" - alteredRegex.Append("(?:)"); - } - - break; - - case '\\': - alteredRegex.Append("\\"); - if (++index < regex.Length) - { - alteredRegex.Append(regex[index]); - } - - break; - - case '(': - // inline comment - if (regex.Length - index > 2 && regex[index + 1] == '?' && regex[index + 2] == '#') - { - for (index++; index < regex.Length && regex[index] != ')'; index++) - { - // skip the comment characters until the next closing paren, in case it includes [ ] - } - - if (numberedSubMatches && Regex.IsMatch(alteredRegex.ToString(), @"\\[\d]+\z")) - { - // add no op to separate tokens, for the case of "\1(?#comment)1" which should not be interpreted as "\11" - alteredRegex.Append("(?:)"); - } - } - else - { - alteredRegex.Append(regex[index]); - } - - break; - - case ' ': case '\f': case '\n': case '\r': case '\t': - if (openCharacterClass) - { - alteredRegex.Append(regex[index]); - } - else if (numberedSubMatches && Regex.IsMatch(alteredRegex.ToString(), @"\\[\d]+\z")) - { - // add no op to separate tokens, for the case of "\1 1" which should not be interpreted as "\11" - alteredRegex.Append("(?:)"); - } - - break; - - default: - alteredRegex.Append(regex[index]); - break; - } - } - - return alteredRegex.ToString(); - } - public static void EnableRegExFunctions(PowerFxConfig config, TimeSpan regExTimeout = default, int regexCacheSize = -1) { RegexTypeCache regexTypeCache = new (regexCacheSize); From d7542de8e1b9236f23b03eaa4565a047a632528a Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Wed, 4 Sep 2024 00:31:00 -0700 Subject: [PATCH 43/61] Updates --- .../Helpers/RegEx_JavaScript.cs | 34 ++++++++++++++++--- .../FileExpressionEvaluationTests.cs | 4 +-- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs index 9fc6004bde..94c3b78bb3 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs @@ -37,6 +37,7 @@ function AlterRegex_JavaScript(regex, flags) var openCharacterClass = false; // are we defining a character class? var altered = ''; + var spaceWaiting = false; for ( ; index < regex.length; index++) { @@ -45,11 +46,13 @@ function AlterRegex_JavaScript(regex, flags) case '[': openCharacterClass = true; altered = altered.concat('['); + spaceWaiting = false; break; case ']': openCharacterClass = false; altered = altered.concat(']'); + spaceWaiting = false; break; case '\\': @@ -104,19 +107,22 @@ function AlterRegex_JavaScript(regex, flags) // backslash at end of regex altered = altered.concat( '\\' ); } - + spaceWaiting = false; break; case '.': altered = altered.concat(!openCharacterClass && !dotAll ? '[^\\r\\n]' : '.'); + spaceWaiting = false; break; case '^': altered = altered.concat(!openCharacterClass && multiline ? '(?<=^|\\r\\n|\\r|\\n)' : '^'); + spaceWaiting = false; break; case '$': altered = altered.concat(openCharacterClass ? '$' : (multiline ? '(?=$|\\r\\n|\\r|\\n)' : '(?=$|\\r\\n$|\\r$|\\n$)')); + spaceWaiting = false; break; case '(': @@ -128,11 +134,12 @@ function AlterRegex_JavaScript(regex, flags) // eat characters until a close paren, it doesn't matter if it is escaped (consistent with .NET) } - altered = altered.concat('(?:)'); + spaceWaiting = true; } else { - altered = altered.concat('('); + altered = altered.concat('('); + spaceWaiting = false; } break; @@ -140,11 +147,12 @@ function AlterRegex_JavaScript(regex, flags) case ' ': case '\f': case '\n': case '\r': case '\t': if (freeSpacing && !openCharacterClass) { - altered = altered.concat('(?:)'); + spaceWaiting = true; } else { altered = altered.concat(regex.charAt(index)); + spaceWaiting = false; } break; @@ -158,16 +166,32 @@ function AlterRegex_JavaScript(regex, flags) // leaving dangling whitespace characters will be eaten on next iteration } - altered = altered.concat('(?:)'); + spaceWaiting = true; } else { altered = altered.concat('#'); + spaceWaiting = false; } break; + case '*': case '+': case '?': case '{': + if (spaceWaiting && altered.length > 0 && altered.charAt(altered.length-1) == '(') + { + altered = altered.concat( '(?:)' ); + spaceWaiting = false; + } + altered = altered.concat(regex.charAt(index)); + spaceWaiting = false; + break; + default: + if (spaceWaiting) + { + altered = altered.concat( '(?:)' ); + spaceWaiting = false; + } altered = altered.concat(regex.charAt(index)); break; } diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index 53c85e5c24..3196c65ff7 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -91,7 +91,7 @@ public void None_Float(ExpressionTestCase testCase) } #endif -#if true +#if false // Runs only tests that have asked for RegEx setup. This test run will compare the regular expression results between // .NET (used in the C# interpreter), NodeJS with JavaScript (used in Canvas), and PCRE2 (used in Excel). // This is not run all the time. It requires Node to be installed and PCRE2 built as a shared library DLL and on the path. @@ -171,7 +171,7 @@ private static bool ShouldSkipDotNetVersion(ExpressionTestCase testCase, string [Fact] public void RunOne() { - var path = @"d:\repos\regex-min-6\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\match_comments.txt"; + var path = @"d:\repos\regex-min-7\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\match_comments.txt"; var line = 0; var runner = new InterpreterRunner(); From 273e37ec957d8fdb6e5c5c240fb75f7d13cbe424 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Wed, 4 Sep 2024 12:19:02 -0700 Subject: [PATCH 44/61] Updates --- .../Texl/Builtins/Match.cs | 34 +++++++++----- src/strings/PowerFxResources.en-US.resx | 2 +- .../ExpressionTestCases/Match_Comments.txt | 4 +- .../ExpressionTestCases/Match_Limited.txt | 44 ++++++++++++++++++- .../FileExpressionEvaluationTests.cs | 4 +- .../Helpers/LibraryRegEx_Compare.cs | 4 +- .../Helpers/LibraryRegEx_PCRE2.cs | 2 + 7 files changed, 75 insertions(+), 19 deletions(-) diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index cea5843150..6467c10505 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -131,9 +131,11 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp regularExpressionOptions += "N"; } + string alteredOptions = regularExpressionOptions; + return fValid && - (!context.Features.PowerFxV1CompatibilityRules || IsSupportedRegularExpression(regExNode, regularExpression, regularExpressionOptions, errors)) && - (returnType == DType.Boolean || TryCreateReturnType(regExNode, regularExpression, regularExpressionOptions, errors, ref returnType)); + (!context.Features.PowerFxV1CompatibilityRules || IsSupportedRegularExpression(regExNode, regularExpression, regularExpressionOptions, out alteredOptions, errors)) && + (returnType == DType.Boolean || TryCreateReturnType(regExNode, regularExpression, alteredOptions, errors, ref returnType)); } // Limit regular expressions to common features that are supported, with consistent semantics, by both canonical .NET and XRegExp. @@ -158,11 +160,13 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp // // We chose to use canonical .NET instead of RegexOptions.ECMAScript because we wanted the unicode definitions for words. // See https://learn.microsoft.com/dotnet/standard/base-types/regular-expression-options#ecmascript-matching-behavior for more details - private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPattern, string regexOptions, IErrorContainer errors) + private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPattern, string regexOptions, out string alteredOptions, IErrorContainer errors) { bool freeSpacing = regexOptions.Contains("x"); // can also be set with inline mode modifier bool numberedCpature = regexOptions.Contains("N"); // can only be set here, no inline mode modifier + alteredOptions = regexOptions; + // Scans the regular expression for interesting constructs, ignoring other elements and constructs that are legal, such as letters and numbers. // Order of alternation is important. .NET regular expressions are greedy and will match the first of these that it can. // Many subexpressions here take advantage of this, matching something that is valid, before falling through to check for something that is invalid. @@ -291,11 +295,13 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter // looking for any doubled punctuaion marks in the character class, as this can be used in the future for set subtraction, intserection, union, etc. // for example, see https://www.unicode.org/reports/tr18/#Subtraction_and_Intersection - Match matchRepeat = Regex.Match(regexPattern.Substring(openCharacterClassStart, token.Index - openCharacterClassStart), "([-|&~+?!@#$%^=:;])\\1"); - if (matchRepeat.Success) + for (int i = openCharacterClassStart; i < token.Index - 1; i++) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExRepeatInCharClass, matchRepeat.Value); - return false; + if (regexPattern[i] == regexPattern[i + 1] && "-|&~+?!@#$%^=:;".Contains(regexPattern[i])) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExRepeatInCharClass, regexPattern.Substring(i, 2)); + return false; + } } openCharacterClass = false; @@ -490,7 +496,7 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter } else if (token.Groups["badQuantifier"].Success || token.Groups["badLimited"].Success) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadQuantifier, token.Groups["badQuantifier"].Value); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadQuantifier, token.Value); return false; } else if (token.Groups["badCurly"].Success) @@ -529,11 +535,14 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter return false; } + // may be modifed by inline options; we only care about x and N in the next stage + alteredOptions = (freeSpacing ? "x" : string.Empty) + (numberedCpature ? "N" : string.Empty); + return true; } // Creates a typed result: [Match:s, Captures:*[Value:s], NamedCaptures:r[:s]] - private bool TryCreateReturnType(TexlNode regExNode, string regexPattern, string regexOptions, IErrorContainer errors, ref DType returnType) + private bool TryCreateReturnType(TexlNode regExNode, string regexPattern, string alteredOptions, IErrorContainer errors, ref DType returnType) { Contracts.AssertValue(regexPattern); string prefixedRegexPattern = this._cachePrefix + regexPattern; @@ -565,9 +574,12 @@ private bool TryCreateReturnType(TexlNode regExNode, string regexPattern, string try { var regexDotNetOptions = RegexOptions.None; - if (regexOptions.Contains("x")) + if (alteredOptions.Contains("x")) { regexDotNetOptions |= RegexOptions.IgnorePatternWhitespace; + + // In x mode, comment line endings are [\r\n], but .NET only supports \n. For our purposes here, we can just replace the \r. + regexPattern = regexPattern.Replace('\r', '\n'); } var regex = new Regex(regexPattern, regexDotNetOptions); @@ -604,7 +616,7 @@ private bool TryCreateReturnType(TexlNode regExNode, string regexPattern, string propertyNames.Add(new TypedName(DType.String, ColumnName_FullMatch)); } - if (!subMatchesHidden && regexOptions.Contains("N")) + if (!subMatchesHidden && alteredOptions.Contains("N")) { propertyNames.Add(new TypedName(DType.CreateTable(new TypedName(DType.String, ColumnName_Value)), ColumnName_SubMatches)); } diff --git a/src/strings/PowerFxResources.en-US.resx b/src/strings/PowerFxResources.en-US.resx index b6ac4d860b..737949653b 100644 --- a/src/strings/PowerFxResources.en-US.resx +++ b/src/strings/PowerFxResources.en-US.resx @@ -4438,7 +4438,7 @@ Error message indicating that the regular expression has octal characters. - Invalid regular expression: Literal curly braces must be escaped with a backslash, for example \{ or \}, found "{0}". + Invalid regular expression: Literal curly braces must be escaped with a backslash, found "{0}". Error message indicating that the regular expression has literal curly braces. diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Comments.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Comments.txt index ad3b136023..cf319e0dc7 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Comments.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Comments.txt @@ -278,10 +278,10 @@ Blank() {FullMatch:"aaa",StartMatch:1} >> Match( "aaaaaaaaaaaaaaaaaaaaaaaaaa", "(?x)a { 3 }" ) -Errors: Error 37-56: Invalid regular expression: Literal curly braces must be escaped with a backslash, for example \Invalid regular expression: Literal curly braces must be escaped with a backslash, for example \{ or \}, found "{0}".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 37-56: Invalid regular expression: Literal curly braces must be escaped with a backslash, found "{".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "aaaaaaaaaaaaaaaaaaaaaaaaaa", "(?x)a { 1 2 }" ) -Errors: Error 37-58: Invalid regular expression: Literal curly braces must be escaped with a backslash, for example \Invalid regular expression: Literal curly braces must be escaped with a backslash, for example \{ or \}, found "{0}".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 37-58: Invalid regular expression: Literal curly braces must be escaped with a backslash, found "{".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "aaaaaa", "(?x)a +" ) {FullMatch:"aaaaaa",StartMatch:1} diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt index 82c1897d49..4ac3f46891 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt @@ -226,12 +226,39 @@ Errors: Error 24-60: Invalid regular expression: Conditional alternation is not >> Match( "hello world", "(e)(?(1)l|d)" ) Errors: Error 22-36: Invalid regular expression: Conditional alternation is not supported, found "(?(".|Error 0-5: The function 'Match' has some invalid arguments. -// Other +// support for \r in compile time checks + +>> ShowColumns( Match( "ab", "(?x)a # " & Char(13) & " (?b)" ), capture ) +{capture:"b"} + +>> ShowColumns( Match( "ab", "(?x)a # " & Char(10) & " (?b)" ), capture ) +{capture:"b"} + +>> ShowColumns( Match( "ab", "a # " & Char(13) & " (?b)", MatchOptions.FreeSpacing ), capture ) +{capture:"b"} + +>> ShowColumns( Match( "ab", "a # " & Char(10) & " (?b)", MatchOptions.FreeSpacing ), capture ) +{capture:"b"} + +// quantified capture groups // Node != Net for this test ("b" is empty for Node), a known difference between PCRE2 and Perl too // >> Match( "aba", "^(a(b)?)+$", MatchOptions.NumberedSubMatches ) // {FullMatch:"aba",StartMatch:1,SubMatches:Table({Value:"a"},{Value:"b"})} +>> Match( "aba", "^(a(b)?)+$" ) +{FullMatch:"aba",StartMatch:1} + +// Node != Net for this test +// >> Match( "b", "(a)?b\1", MatchOptions.NumberedSubMatches ) +// Blank() + +// Node != Net for this test +// >> Match( "b", "(?a)?b\k", MatchOptions.NumberedSubMatches ) +// Blank() + +// difference between null and empty string + >> Match( "ab", "a(d)?b", MatchOptions.NumberedSubMatches ) {FullMatch:"ab",StartMatch:1,SubMatches:Table({Value:Blank()})} @@ -324,6 +351,15 @@ Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\A" >> DropColumns( Match( "test" & Char(10) & "bed", "\cj" ), FullMatch ) {StartMatch:5} +>> DropColumns( Match( "test" & Char(10) & "bed", "\cJ" ), FullMatch ) +{StartMatch:5} + +>> DropColumns( Match( "test" & Char(13) & "bed", "\cm" ), FullMatch ) +{StartMatch:5} + +>> DropColumns( Match( "test" & Char(13) & "bed", "\cM" ), FullMatch ) +{StartMatch:5} + >> Match( "test", "\C" ) Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\C".|Error 0-5: The function 'Match' has some invalid arguments. @@ -722,6 +758,12 @@ Errors: Error 22-29: Invalid regular expression: Inline options are limited to a >> Match( "abcdef", "\w{2,4}?" ).FullMatch "ab" +>> Match( "abcdef", "\w{,2}" ).FullMatch +Errors: Error 17-25: Invalid regular expression: Literal curly braces must be escaped with a backslash, found "{".|Error 0-5: The function 'Match' has some invalid arguments.|Error 27-37: Name isn't valid. 'FullMatch' isn't recognized. + +>> Match( "abcdef", "\w{,2}?" ).FullMatch +Errors: Error 17-26: Invalid regular expression: Literal curly braces must be escaped with a backslash, found "{".|Error 0-5: The function 'Match' has some invalid arguments.|Error 28-38: Name isn't valid. 'FullMatch' isn't recognized. + // possessive quantifiers >> Match( "abcdef", "\w++" ).FullMatch diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index 3196c65ff7..13ead0353f 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -91,10 +91,10 @@ public void None_Float(ExpressionTestCase testCase) } #endif -#if false +#if true // Runs only tests that have asked for RegEx setup. This test run will compare the regular expression results between // .NET (used in the C# interpreter), NodeJS with JavaScript (used in Canvas), and PCRE2 (used in Excel). - // This is not run all the time. It requires Node to be installed and PCRE2 built as a shared library DLL and on the path. + // This is not run all the time. It requires Node to be installed and PCRE2 built as a shared library DLL and on the path.a [TxtFileData("ExpressionTestCases", "InterpreterExpressionTestCases", nameof(InterpreterRunner), "PowerFxV1,disable:NumberIsFloat,DecimalSupport", "RegEx")] [InterpreterTheory] public void RegExCompare(ExpressionTestCase t) diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_Compare.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_Compare.cs index a255a56e2e..005fe576bc 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_Compare.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_Compare.cs @@ -73,12 +73,12 @@ internal override FormulaValue InvokeRegexFunction(string input, string regex, s if (nodeExpr != dotnetExpr) { - throw new Exception($"node != net on input='{input}', re='{regex}', options='{options}', node='{nodeExpr}', net='{dotnetExpr}'"); + throw new Exception($"node != net on input='{input}', re='{regex}', options='{options}', \n node='{nodeExpr}', \n net='{dotnetExpr}'"); } if (pcre2Expr != dotnetExpr) { - throw new Exception($"pcre2 != net on input='{input}', re='{regex}', options='{options}', pcre2='{pcre2Expr}', net='{dotnetExpr}'"); + throw new Exception($"pcre2 != net on input='{input}', re='{regex}', options='{options}', \n pcre2='{pcre2Expr}', \n net='{dotnetExpr}'"); } return dotnetMatch; diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs index f55a745da6..1a0af4184c 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs @@ -182,6 +182,8 @@ internal static FormulaValue Match(string subject, string pattern, string flags, } else { + // In x mode, comment line endings are [\r\n], but .NET only supports \n. For our purposes here, we can just replace the \r. + pattern = pattern.Replace('\r', '\n'); var regex = new Regex(pattern, options); foreach (var name in regex.GetGroupNames()) { From e674cf6d0393dbdb79ff7cb0c598cffdcf5cc6b9 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Thu, 5 Sep 2024 23:50:50 -0700 Subject: [PATCH 45/61] Updates --- .../Localization/Strings.cs | 6 +- .../Texl/Builtins/Match.cs | 60 +++++++++++++++---- .../Functions/LibraryRegEx.cs | 4 +- src/strings/PowerFxResources.en-US.resx | 18 +++++- .../ExpressionTestCases/IsMatch.txt | 8 +-- .../ExpressionTestCases/Match_Limited.txt | 32 ++++++++-- .../ExpressionTestCases/Match_V1Compat.txt | 2 +- .../Helpers/RegEx_JavaScript.cs | 4 +- .../FileExpressionEvaluationTests.cs | 6 +- .../Helpers/LibraryRegEx_Compare.cs | 28 +++++++-- .../Helpers/LibraryRegEx_NodeJS.cs | 4 +- .../Helpers/LibraryRegEx_PCRE2.cs | 2 +- 12 files changed, 137 insertions(+), 37 deletions(-) diff --git a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs index 6d9a6371cc..6bff12ce2b 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs @@ -737,7 +737,8 @@ internal static class TexlStrings public static ErrorResourceKey ErrInvalidRegExBadCurly = new ErrorResourceKey("ErrInvalidRegExBadCurly"); public static ErrorResourceKey ErrInvalidRegExBadSquare = new ErrorResourceKey("ErrInvalidRegExBadSquare"); public static ErrorResourceKey ErrInvalidRegExBadParen = new ErrorResourceKey("ErrInvalidRegExBadParen"); - public static ErrorResourceKey ErrInvalidRegExBadEscapeWithinCharacterClass = new ErrorResourceKey("ErrInvalidRegExBadEscapeWithinCharacterClass"); + public static ErrorResourceKey ErrInvalidRegExBadEscapeInsideCharacterClass = new ErrorResourceKey("ErrInvalidRegExBadEscapeInsideCharacterClass"); + public static ErrorResourceKey ErrInvalidRegExBadEscapeOutsideCharacterClass = new ErrorResourceKey("ErrInvalidRegExBadEscapeOutsideCharacterClass"); public static ErrorResourceKey ErrInvalidRegExRepeatInCharClass = new ErrorResourceKey("ErrInvalidRegExRepeatInCharClass"); public static ErrorResourceKey ErrInvalidRegExRepeatedInlineOption = new ErrorResourceKey("ErrInvalidRegExRepeatedInlineOption"); public static ErrorResourceKey ErrInvalidRegExInlineOptionConflictsWithNumberedSubMatches = new ErrorResourceKey("ErrInvalidRegExInlineOptionConflictsWithNumberedSubMatches"); @@ -761,6 +762,9 @@ internal static class TexlStrings public static ErrorResourceKey ErrInvalidRegExNumberedSubMatchesDisabled = new ErrorResourceKey("ErrInvalidRegExNumberedSubMatchesDisabled"); public static ErrorResourceKey ErrInvalidRegExBadUnsupportedCharacterClassSubtraction = new ErrorResourceKey("ErrInvalidRegExBadUnsupportedCharacterClassSubtraction"); public static ErrorResourceKey ErrInvalidRegExOpenParenInComment = new ErrorResourceKey("ErrInvalidRegExOpenParenInComment"); + public static ErrorResourceKey ErrInvalidRegExLiteralHyphenInCharacterClass = new ErrorResourceKey("ErrInvalidRegExLiteralHyphenInCharacterClass"); + public static ErrorResourceKey ErrInvalidRegExBackRefInCharacterClass = new ErrorResourceKey("ErrInvalidRegExBackRefInCharacterClass"); + public static ErrorResourceKey ErrInvalidRegExUnescapedParensInCharacterClass = new ErrorResourceKey("ErrInvalidRegExUnescapedParensInCharacterClass"); public static ErrorResourceKey ErrVariableRegEx = new ErrorResourceKey("ErrVariableRegEx"); public static ErrorResourceKey ErrVariableRegExOptions = new ErrorResourceKey("ErrVariableRegExOptions"); diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index 6467c10505..8d547afc73 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -185,15 +185,17 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter (?\\ ([dfnrstw] | # standard regex character classes, missing from .NET are aAeGzZv (no XRegExp support), other common are u{} and o p\{\w+\} | # unicode character classes - [\^\$\\\.\*\+\?\(\)\[\]\{\}\|\/|\#|\ ] | # acceptable escaped characters with Unicode aware ECMAScript with # and space for Free Spacing + [\^\$\\\.\*\+\?\(\)\[\]\{\}\|\/\#\ ] | # acceptable escaped characters with Unicode aware ECMAScript with # and space for Free Spacing c[a-zA-Z] | # Ctrl character classes x[0-9a-fA-F]{2} | # hex character, must be exactly 2 hex digits u[0-9a-fA-F]{4})) | # Unicode characters, must be exactly 4 hex digits - (?\\([bBWDS]|P\{\w+\})) | # acceptable outside a character class, but not within + (?\\([bBWDS]|P\{\w+\})) | # acceptable outside a character class, includes negative classes until we have character class subtraction, include \P for future MatchOptions.LocaleAware + (?\\[\-]) | # needed for /v compatibility with ECMAScript (?\\.) | # all other escaped characters are invalid and reserved for future use # leading (?<, named captures \(\?<(?[a-zA-Z][a-zA-Z\d]*)> | # named capture group, can only be letters and numbers and must start with a letter + (?\(\?(=|!|<=|\(\?<\w*-\w*>) | # .NET balancing captures are not supported (?\(\?<[^>]*>) | # bad named capture name, didn't match goodNamedCapture (?\(\?'[^']*') | # single quoted capture names are not supported @@ -202,7 +204,6 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter (?\(\?:) | # non-capture group, still need to track to match with closing paren \A\(\?(?[imnsx]+)\) | # inline options (?\(\?\#) | # inline comment - (?\(\?(=|!|<=|\(\?(\w+|\w*-\w+)[\:\)]) | # inline options, including disable of options (?\(\?\() | # .NET conditional alternations are not supported @@ -218,6 +219,8 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter (?{\d+(,\d*)?}[\+|\*]) | # possessive and useless quantifiers (?[{}]) | # more constrained, blocks {,3} and Java/Rust semantics that does not treat this as a literal + (?\[\-|\-\]) | # literal not allowed within character class, needs to be escaped (ECMAScript v) + # open and close regions (?\() | (?\)) | @@ -250,7 +253,7 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter { // ordered from most common/good to least common/bad, for fewer tests if (token.Groups["goodEscape"].Success || token.Groups["goodQuantifiers"].Success || - token.Groups["goodLookaround"].Success || token.Groups["goodLimited"].Success) + token.Groups["goodLimited"].Success) { // all is well, nothing to do } @@ -258,7 +261,15 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter { if (openCharacterClass) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadEscapeWithinCharacterClass, token.Index >= regexPattern.Length - 5 ? regexPattern.Substring(token.Index - 1) : regexPattern.Substring(token.Index - 1, 6) + "..."); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadEscapeInsideCharacterClass, token.Index >= regexPattern.Length - 5 ? regexPattern.Substring(token.Index) : regexPattern.Substring(token.Index, 5) + "..."); + return false; + } + } + else if (token.Groups["goodEscapeInside"].Success) + { + if (!openCharacterClass) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadEscapeOutsideCharacterClass, token.Index >= regexPattern.Length - 5 ? regexPattern.Substring(token.Index) : regexPattern.Substring(token.Index, 5) + "..."); return false; } } @@ -268,7 +279,7 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter { if (token.Index > 0 && regexPattern[token.Index - 1] == '-') { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadUnsupportedCharacterClassSubtraction, token.Index >= regexPattern.Length - 5 ? regexPattern.Substring(token.Index - 1) : regexPattern.Substring(token.Index - 1, 6) + "..."); + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadUnsupportedCharacterClassSubtraction, token.Index - 1 >= regexPattern.Length - 5 ? regexPattern.Substring(token.Index - 1) : regexPattern.Substring(token.Index - 1, 5) + "..."); return false; } else @@ -297,7 +308,7 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter // for example, see https://www.unicode.org/reports/tr18/#Subtraction_and_Intersection for (int i = openCharacterClassStart; i < token.Index - 1; i++) { - if (regexPattern[i] == regexPattern[i + 1] && "-|&~+?!@#$%^=:;".Contains(regexPattern[i])) + if (regexPattern[i] == regexPattern[i + 1] && "-|&~+?!@#$%^=:;<>*,.`".Contains(regexPattern[i])) { errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExRepeatInCharClass, regexPattern.Substring(i, 2)); return false; @@ -333,7 +344,7 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter captureNames.Add(token.Groups["goodNamedCapture"].Value); } } - else if (token.Groups["goodNonCapture"].Success) + else if (token.Groups["goodNonCapture"].Success || token.Groups["goodLookaround"].Success) { // parens do not need to be escaped within square brackets if (!openCharacterClass) @@ -343,9 +354,13 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter } else if (token.Groups["openParen"].Success) { - // parens do not need to be escaped within square brackets - if (!openCharacterClass) + if (openCharacterClass) { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExUnescapedParensInCharacterClass); + return false; + } + else + { if (numberedCpature) { captureNumber++; @@ -359,8 +374,12 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter } else if (token.Groups["closeParen"].Success) { - // parens do not need to be escaped within square brackets - if (!openCharacterClass) + if (openCharacterClass) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExUnescapedParensInCharacterClass); + return false; + } + else { if (captureStack.Count == 0) { @@ -383,6 +402,12 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter return false; } + if (openCharacterClass) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBackRefInCharacterClass, token.Value); + return false; + } + // group isn't defined, or not defined yet if (!captureNames.Contains(backRefName)) { @@ -407,6 +432,12 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter return false; } + if (openCharacterClass) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBackRefInCharacterClass, token.Value); + return false; + } + // back ref number has not yet been defined if (backRefNumber < 1 || backRefNumber > captureNumber) { @@ -509,6 +540,11 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadParen, token.Index >= regexPattern.Length - 5 ? regexPattern.Substring(token.Index) : regexPattern.Substring(token.Index, 5) + "..."); return false; } + else if (token.Groups["badHyphen"].Success) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExLiteralHyphenInCharacterClass, token.Value); + return false; + } else { // This should never be hit. Here in case one of the names checked doesn't match the RE, in which case running tests would hit this. diff --git a/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs b/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs index 65b599e1c5..78720a9097 100644 --- a/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs +++ b/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryRegEx.cs @@ -278,8 +278,8 @@ public Task InvokeAsync(FormulaValue[] args, CancellationToken can // skip the comment characters until the next closing paren, in case it includes [ ] } - // need something to be emitted to avoid "\1(?:)1" being interpreted as "\11" - altered.Append("(?:)"); + // need something to be emitted to avoid "\1(?#)1" being interpreted as "\11" + altered.Append("(?#)"); } else { diff --git a/src/strings/PowerFxResources.en-US.resx b/src/strings/PowerFxResources.en-US.resx index 737949653b..cb9404bea2 100644 --- a/src/strings/PowerFxResources.en-US.resx +++ b/src/strings/PowerFxResources.en-US.resx @@ -4449,10 +4449,14 @@ Invalid regular expression: Unsupported special group, found "{0}". Error message indicating that the regular expression that starts with a paren. - + Invalid regular expression: Escape character not permitted within character class, found "{0}". Error message indicating that the regular expression has an escape character within a character class. + + Invalid regular expression: Escape character not permitted outside a character class, found "{0}". + Error message indicating that the regular expression has an escape character outside a character class. + Invalid regular expression: Repeated inline option, found "{0}". Error message indicating that the regular expression includes more than one of the same option. @@ -4545,6 +4549,18 @@ Invalid regular expression: Inline comments cannot include open parenthesis, found in "{0}". Error message indicating that the regular expression has an open paren in an inline comment. + + Invalid regular expression: Literal hyphen in character class must be escaped with backslash, found "{0}". + Error message indicating that the regular expression has a hyphen in a character class. + + + Invalid regular expression: Backref in character class, found "{0}". + Error message indicating that the regular expression has a backref in a character class. + + + Invalid regular expression: Literal parenthesis need to be escaped with a backslash when used in a character class. + Error message indicating that the regular expression has an unescaped paren within a character class. + Regular expressions must be constant values. Error Message. diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch.txt index a641680980..91a23aa28b 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsMatch.txt @@ -79,16 +79,16 @@ Errors: Error 15-37: Regular expressions must be constant values. >> IsMatch( "28", Concat( [2,8], If( false, Text(Now()), Value ) ) ) Errors: Error 15-63: Regular expressions must be constant values. ->> IsMatch("(555) 123-4567", "^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$") +>> IsMatch("(555) 123-4567", "^[\+]?[\(]?[0-9]{3}[\)]?[\-\s\.]?[0-9]{3}[\-\s\.]?[0-9]{4,6}$") true ->> IsMatch("(555)_123-4567", "^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$") +>> IsMatch("(555)_123-4567", "^[\+]?[\(]?[0-9]{3}[\)]?[\-\s\.]?[0-9]{3}[\-\s\.]?[0-9]{4,6}$") false ->> IsMatch("147 123-4567", "^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$") +>> IsMatch("147 123-4567", "^[\+]?[\(]?[0-9]{3}[\)]?[\-\s\.]?[0-9]{3}[\-\s\.]?[0-9]{4,6}$") true ->> IsMatch("(44) 123-4567", "^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$") +>> IsMatch("(44) 123-4567", "^[\+]?[\(]?[0-9]{3}[\)]?[\-\s\.]?[0-9]{3}[\-\s\.]?[0-9]{4,6}$") false >> IsMatch("""Hello world""", Char(34) & "Hello", MatchOptions.Contains) diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt index 4ac3f46891..18bcdb178d 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt @@ -246,6 +246,9 @@ Errors: Error 22-36: Invalid regular expression: Conditional alternation is not // >> Match( "aba", "^(a(b)?)+$", MatchOptions.NumberedSubMatches ) // {FullMatch:"aba",StartMatch:1,SubMatches:Table({Value:"a"},{Value:"b"})} +>> Match( "aba", "^(a(?:b)?)+$", MatchOptions.NumberedSubMatches ) +{FullMatch:"aba",StartMatch:1,SubMatches:Table({Value:"a"})} + >> Match( "aba", "^(a(b)?)+$" ) {FullMatch:"aba",StartMatch:1} @@ -310,7 +313,7 @@ Errors: Error 13-19: Invalid regular expression: Literal square braces must be e // character class subtraction >> Match( "k", "[a-z-[b-c]]" ) -Errors: Error 12-25: Invalid regular expression: Character class subtraction is not supported, found "-[b-c]...".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 12-25: Invalid regular expression: Character class subtraction is not supported, found "-[b-c...".|Error 0-5: The function 'Match' has some invalid arguments. // repeated characters in character class, used by intersection and future character class features, also would catch POSIX cases if wasn't already blocked by nested square brackets @@ -507,7 +510,7 @@ Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\_" // negated escape class and \b can't appear in a character classes, can't easily transpile without character class subtraction or intersection in ECMAScript >> Match( "$test" & Char(8) & "test", "[\b]test" ) -Errors: Error 35-45: Invalid regular expression: Escape character not permitted within character class, found "[\b]te...".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 35-45: Invalid regular expression: Escape character not permitted within character class, found "\b]te...".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "$test" & Char(8) & "test", "[\B]test" ) Errors: Error 35-45: Invalid regular expression: Escape character not permitted within character class, found "[\B]te...".|Error 0-5: The function 'Match' has some invalid arguments. @@ -519,10 +522,10 @@ Errors: Error 21-28: Invalid regular expression: Escape character not permitted Errors: Error 35-45: Invalid regular expression: Escape character not permitted within character class, found "[\W]te...".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "$test" & Char(8) & "test", "[\S]test" ) -Errors: Error 35-45: Invalid regular expression: Escape character not permitted within character class, found "[\S]te...".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 35-45: Invalid regular expression: Escape character not permitted within character class, found "\S]te...".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "foo123test456", "[\P{L}]+" ) // would be problematic if we wanted to implement MatchOptions.LocaleAware in the future -Errors: Error 24-34: Invalid regular expression: Escape character not permitted within character class, found "[\P{L}...".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 24-34: Invalid regular expression: Escape character not permitted within character class, found "\P{L}...".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "$test" & Char(8) & "test", "[\w]test" ) // \w is OK Blank() @@ -800,3 +803,24 @@ Errors: Error 22-30: Invalid regular expression: Invalid escape code, found "\a" >> Match( "test\123bed", "\\(\d)" ) {FullMatch:"\1",StartMatch:5} + +>> IsMatch( "abc", "[-a]" ) +Errors: Error 16-22: Invalid regular expression: Literal hyphen in character class must be escaped with backslash, found "[-".|Error 0-7: The function 'IsMatch' has some invalid arguments. + +>> IsMatch( "abc", "[a-]" ) +Errors: Error 16-22: Invalid regular expression: Literal hyphen in character class must be escaped with backslash, found "-]".|Error 0-7: The function 'IsMatch' has some invalid arguments. + +>> IsMatch( "abc", "[a-b]+c" ) +true + +>> IsMatch( "abc", "(a)[\1]") +Errors: Error 16-25: Invalid regular expression: Use named captures with "(?" and "\k" or enable MatchOptions.NumberedSubMatches, found "\1".|Error 0-7: The function 'IsMatch' has some invalid arguments. + +>> IsMatch( "abc", "(?a)[\k]") +Errors: Error 16-32: Invalid regular expression: Backref in character class, found "\k".|Error 0-7: The function 'IsMatch' has some invalid arguments. + +>> IsMatch( "abc", "[(]") +Errors: Error 16-21: Invalid regular expression: Literal parenthesis need to be escaped with a backslash when used in a character class.|Error 0-7: The function 'IsMatch' has some invalid arguments. + +>> IsMatch( "abc()", "[\(]", MatchOptions.Contains ) +true diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_V1Compat.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_V1Compat.txt index 552ff9cc2e..7f05de1c33 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_V1Compat.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_V1Compat.txt @@ -24,7 +24,7 @@ Blank() >> Match("JohnDoe@microsoft.com", Match.Email) {FullMatch:"JohnDoe@microsoft.com",StartMatch:1} ->> Match("(555) 123-4567", "^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$") +>> Match("(555) 123-4567", "^[\+]?[\(]?[0-9]{3}[\)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$") {FullMatch:"(555) 123-4567",StartMatch:1} >> Match("Hello", "Hello", MatchOptions.IgnoreCase) diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs index 94c3b78bb3..aceaaa0752 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs @@ -33,7 +33,7 @@ function AlterRegex_JavaScript(regex, flags) // rebuilding from booleans avoids possible duplicate letters // x has been handled in this function and does not need to be passed on (and would cause an error) - const alteredFlags = 'u'.concat((ignoreCase ? 'i' : ''), (multiline ? 'm' : ''), (dotAll ? 's' : '')); + const alteredFlags = 'v'.concat((ignoreCase ? 'i' : ''), (multiline ? 'm' : ''), (dotAll ? 's' : '')); var openCharacterClass = false; // are we defining a character class? var altered = ''; @@ -92,7 +92,7 @@ function AlterRegex_JavaScript(regex, flags) altered = altered.concat('[^', digitChar, ']'); break; - // needed for free spacing + // needed for free spacing, needs to be unescaped to avoid /v error case '#': case ' ': altered = altered.concat(regex.charAt(index)); break; diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index 13ead0353f..492bb5fa56 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -94,7 +94,7 @@ public void None_Float(ExpressionTestCase testCase) #if true // Runs only tests that have asked for RegEx setup. This test run will compare the regular expression results between // .NET (used in the C# interpreter), NodeJS with JavaScript (used in Canvas), and PCRE2 (used in Excel). - // This is not run all the time. It requires Node to be installed and PCRE2 built as a shared library DLL and on the path.a + // This is not run all the time. It requires Node to be installed and PCRE2 built as a shared library DLL and on the path.ababceeefeeerwee [TxtFileData("ExpressionTestCases", "InterpreterExpressionTestCases", nameof(InterpreterRunner), "PowerFxV1,disable:NumberIsFloat,DecimalSupport", "RegEx")] [InterpreterTheory] public void RegExCompare(ExpressionTestCase t) @@ -166,12 +166,12 @@ private static bool ShouldSkipDotNetVersion(ExpressionTestCase testCase, string return false; } -#if false +#if true // Helper to run a single .txt deefee [Fact] public void RunOne() { - var path = @"d:\repos\regex-min-7\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\match_comments.txt"; + var path = @"d:\repos\regex-min-7\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\match_pcre2.txt"; var line = 0; var runner = new InterpreterRunner(); diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_Compare.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_Compare.cs index 005fe576bc..c28229f595 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_Compare.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_Compare.cs @@ -56,11 +56,15 @@ internal static Dictionary RegexFunctions(Time internal abstract class Compare_CommonImplementation : Library.RegexCommonImplementation { + protected Library.RegexCommonImplementation dotnet; protected Library.RegexCommonImplementation node; protected Library.RegexCommonImplementation pcre2; - protected Library.RegexCommonImplementation dotnet; - internal override FormulaValue InvokeRegexFunction(string input, string regex, string options) + protected Library.RegexCommonImplementation dotnet_alt; + protected Library.RegexCommonImplementation node_alt; + protected Library.RegexCommonImplementation pcre2_alt; + + private FormulaValue InvokeRegexFunctionOne(string input, string regex, string options, Library.RegexCommonImplementation dotnet, Library.RegexCommonImplementation node, Library.RegexCommonImplementation pcre2, string kind) { var nodeMatch = node.InvokeRegexFunction(input, regex, options); var nodeExpr = nodeMatch.ToExpression(); @@ -73,16 +77,28 @@ internal override FormulaValue InvokeRegexFunction(string input, string regex, s if (nodeExpr != dotnetExpr) { - throw new Exception($"node != net on input='{input}', re='{regex}', options='{options}', \n node='{nodeExpr}', \n net='{dotnetExpr}'"); + throw new Exception($"{kind}: node != net on input='{input}', re='{regex}', options='{options}',\n net='{dotnetExpr}',\n node='{nodeExpr}',\n pcre2='{pcre2Expr}'"); } if (pcre2Expr != dotnetExpr) { - throw new Exception($"pcre2 != net on input='{input}', re='{regex}', options='{options}', \n pcre2='{pcre2Expr}', \n net='{dotnetExpr}'"); + throw new Exception($"{kind}: pcre2 != net on input='{input}', re='{regex}', options='{options}',\n net='{dotnetExpr}',\n node='{nodeExpr}',\n pcre2='{pcre2Expr}'"); } return dotnetMatch; } + + internal override FormulaValue InvokeRegexFunction(string input, string regex, string options) + { + var result = InvokeRegexFunctionOne(input, regex, options, dotnet, node, pcre2, "main"); + + if (dotnet_alt != null) + { + InvokeRegexFunctionOne(input, regex, options, dotnet_alt, node_alt, pcre2_alt, "alt"); + } + + return result; + } } internal class Compare_IsMatchImplementation : Compare_CommonImplementation @@ -94,6 +110,10 @@ internal Compare_IsMatchImplementation(TimeSpan regexTimeout) node = new NodeJS_IsMatchImplementation(regexTimeout); pcre2 = new PCRE2_IsMatchImplementation(regexTimeout); dotnet = new Library.IsMatchImplementation(regexTimeout); + + node_alt = new NodeJS_MatchImplementation(regexTimeout); + pcre2_alt = new PCRE2_MatchImplementation(regexTimeout); + dotnet_alt = new Library.MatchImplementation(regexTimeout); } } diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs index 8b79a2b89f..23145bb7ff 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs @@ -57,7 +57,7 @@ internal static FormulaValue Match(string subject, string pattern, string flags, var val = match.groups[group]; if (val !== undefined) { - val = '""' + val.replace( / "" /, '""""') + '""' + val = '""' + val.replace( /""/g, '""""') + '""' } console.log(group + ':' + val); } @@ -66,7 +66,7 @@ internal static FormulaValue Match(string subject, string pattern, string flags, var val = match[num]; if (val !== undefined) { - val = '""' + val.replace( / "" /, '""""') + '""' + val = '""' + val.replace( /""/g, '""""') + '""' } console.log(num + ':' + val); } diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs index 1a0af4184c..cf229cda6f 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs @@ -86,7 +86,7 @@ internal static FormulaValue Match(string subject, string pattern, string flags, IntPtr matchContext = (IntPtr)0; IntPtr generalContext = (IntPtr)0; - PCRE2_OPTIONS pcreOptions = PCRE2_OPTIONS.UCP; + PCRE2_OPTIONS pcreOptions = PCRE2_OPTIONS.UTF | PCRE2_OPTIONS.UCP; RegexOptions options = RegexOptions.None; Match inlineOptions = Regex.Match(pattern, @"^\(\?([imnsx]+)\)"); From 280beb2c5b5cf234dc640e1b957b8b7f5eb15a9c Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Thu, 5 Sep 2024 23:51:47 -0700 Subject: [PATCH 46/61] updates --- .../FileExpressionEvaluationTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index 492bb5fa56..6a5969eaf7 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -91,7 +91,7 @@ public void None_Float(ExpressionTestCase testCase) } #endif -#if true +#if false // Runs only tests that have asked for RegEx setup. This test run will compare the regular expression results between // .NET (used in the C# interpreter), NodeJS with JavaScript (used in Canvas), and PCRE2 (used in Excel). // This is not run all the time. It requires Node to be installed and PCRE2 built as a shared library DLL and on the path.ababceeefeeerwee @@ -166,7 +166,7 @@ private static bool ShouldSkipDotNetVersion(ExpressionTestCase testCase, string return false; } -#if true +#if false // Helper to run a single .txt deefee [Fact] public void RunOne() From 01d70981fe5e76ad9f0519aedf621f97397b983e Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Sun, 8 Sep 2024 09:56:31 -0700 Subject: [PATCH 47/61] Updates --- .../Localization/Strings.cs | 1 + .../Texl/Builtins/Match.cs | 23 +++++++++++++++++-- src/strings/PowerFxResources.en-US.resx | 4 ++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs index 6bff12ce2b..e7115f5242 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs @@ -765,6 +765,7 @@ internal static class TexlStrings public static ErrorResourceKey ErrInvalidRegExLiteralHyphenInCharacterClass = new ErrorResourceKey("ErrInvalidRegExLiteralHyphenInCharacterClass"); public static ErrorResourceKey ErrInvalidRegExBackRefInCharacterClass = new ErrorResourceKey("ErrInvalidRegExBackRefInCharacterClass"); public static ErrorResourceKey ErrInvalidRegExUnescapedParensInCharacterClass = new ErrorResourceKey("ErrInvalidRegExUnescapedParensInCharacterClass"); + public static ErrorResourceKey ErrInvalidRegExBadUnicodeCategory = new ErrorResourceKey("ErrInvalidRegExBadUnicodeCategory"); public static ErrorResourceKey ErrVariableRegEx = new ErrorResourceKey("ErrVariableRegEx"); public static ErrorResourceKey ErrVariableRegExOptions = new ErrorResourceKey("ErrVariableRegExOptions"); diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index 8d547afc73..adbcf2f716 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -138,6 +138,17 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp (returnType == DType.Boolean || TryCreateReturnType(regExNode, regularExpression, alteredOptions, errors, ref returnType)); } + private static readonly string[] UnicodeCategories = + { + "L", "Lu", "Ll", "Lt", "Lm", "Lo", + "M", "Mn", "Mc", "Me", + "N", "Nd", "Nl", "No", + "P", "Pc", "Pd", "Pd", "Ps", "Pe", "Pi", "Pf", "Po", + "S", "Sm", "Sc", "Sk", "So", + "Z", "Zs", "Zl", "Zp", + "C", "Cc", "Cf", "Cs", "Co", "Cn", + }; + // Limit regular expressions to common features that are supported, with consistent semantics, by both canonical .NET and XRegExp. // It is better to disallow now and bring back with customer demand or as platforms add more support. // @@ -184,12 +195,12 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter \\(?\d+) | # numeric backreference, must be enabled with MatchOptions.NumberedSubMatches (?\\ ([dfnrstw] | # standard regex character classes, missing from .NET are aAeGzZv (no XRegExp support), other common are u{} and o - p\{\w+\} | # unicode character classes [\^\$\\\.\*\+\?\(\)\[\]\{\}\|\/\#\ ] | # acceptable escaped characters with Unicode aware ECMAScript with # and space for Free Spacing c[a-zA-Z] | # Ctrl character classes x[0-9a-fA-F]{2} | # hex character, must be exactly 2 hex digits u[0-9a-fA-F]{4})) | # Unicode characters, must be exactly 4 hex digits - (?\\([bBWDS]|P\{\w+\})) | # acceptable outside a character class, includes negative classes until we have character class subtraction, include \P for future MatchOptions.LocaleAware + \\[pP]\{(?[\\w=:-]+)\} | # Unicode chaeracter classes, extra characters here for a better error message + (?\\[bBWDS]) | # acceptable outside a character class, includes negative classes until we have character class subtraction, include \P for future MatchOptions.LocaleAware (?\\[\-]) | # needed for /v compatibility with ECMAScript (?\\.) | # all other escaped characters are invalid and reserved for future use @@ -273,6 +284,14 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter return false; } } + else if (token.Groups["goodUnicodeCategory"].Success) + { + if (!UnicodeCategories.Contains(token.Groups["goodUnicodeCategory"].Value)) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadUnicodeCategory, token.Value); + return false; + } + } else if (token.Groups["openCharClass"].Success) { if (openCharacterClass) diff --git a/src/strings/PowerFxResources.en-US.resx b/src/strings/PowerFxResources.en-US.resx index cb9404bea2..4ed2598a71 100644 --- a/src/strings/PowerFxResources.en-US.resx +++ b/src/strings/PowerFxResources.en-US.resx @@ -4457,6 +4457,10 @@ Invalid regular expression: Escape character not permitted outside a character class, found "{0}". Error message indicating that the regular expression has an escape character outside a character class. + + Invalid regular expression: Invalid Unicode category name, found "{0}". + Error message indicating that the regular expression has an invalid Unicode caategory name. + Invalid regular expression: Repeated inline option, found "{0}". Error message indicating that the regular expression includes more than one of the same option. From a6bb1ad1c48ed94344749c73df96bfe21e26dcec Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Sun, 8 Sep 2024 23:22:41 -0700 Subject: [PATCH 48/61] Updates --- .../Texl/Builtins/Match.cs | 4 +- .../ExpressionTestCases/Match_Unicode.txt | 120 +++++++++ .../Helpers/LibraryRegEx_NodeJS.cs | 250 ++++++++++-------- 3 files changed, 256 insertions(+), 118 deletions(-) diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index adbcf2f716..04afc7b7c2 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -143,7 +143,7 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp "L", "Lu", "Ll", "Lt", "Lm", "Lo", "M", "Mn", "Mc", "Me", "N", "Nd", "Nl", "No", - "P", "Pc", "Pd", "Pd", "Ps", "Pe", "Pi", "Pf", "Po", + "P", "Pc", "Pd", "Ps", "Pe", "Pi", "Pf", "Po", "S", "Sm", "Sc", "Sk", "So", "Z", "Zs", "Zl", "Zp", "C", "Cc", "Cf", "Cs", "Co", "Cn", @@ -199,7 +199,7 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter c[a-zA-Z] | # Ctrl character classes x[0-9a-fA-F]{2} | # hex character, must be exactly 2 hex digits u[0-9a-fA-F]{4})) | # Unicode characters, must be exactly 4 hex digits - \\[pP]\{(?[\\w=:-]+)\} | # Unicode chaeracter classes, extra characters here for a better error message + \\[pP]\{(?[\w=:-]+)\} | # Unicode chaeracter classes, extra characters here for a better error message (?\\[bBWDS]) | # acceptable outside a character class, includes negative classes until we have character class subtraction, include \P for future MatchOptions.LocaleAware (?\\[\-]) | # needed for /v compatibility with ECMAScript (?\\.) | # all other escaped characters are invalid and reserved for future use diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Unicode.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Unicode.txt index fd555031a3..1119d1f7bb 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Unicode.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Unicode.txt @@ -70,3 +70,123 @@ #DISABLE.NET:462 >> Match( UniChar(Hex2Dec("2126")), "\u03a9", MatchOptions.IgnoreCase ).FullMatch "Ω" + +// L +>> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, + If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{L}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, + If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) +"0041,0042,0043,0044,0045,0046,0047,0048-004F,0050-0057,0058,0059,005A,0061,0062,0063,0064,0065,0066,0067,0068-006F,0070-0077,0078,0079,007A,00AA,00B5,00BA,00C0-00C7,00C8-00CF,00D0,00D1,00D2,00D3,00D4,00D5,00D6,00D8-00DF,00E0-00E7,00E8-00EF,00F0,00F1,00F2,00F3,00F4,00F5,00F6,00F8-00FF,0100-0107,0108-010F,0110-0117,0118-011F,0120-0127,0128-012F,0130-0137,0138-013F,0140-0147,0148-014F,0150-0157,0158-015F,0160-0167,0168-016F,0170-0177,0178-017F,0180-0187,0188-018F,0190-0197,0198-019F,01A0-01A7,01A8-01AF,01B0-01B7,01B8-01BF,01C0-01C7,01C8-01CF,01D0-01D7,01D8-01DF,01E0-01E7,01E8-01EF,01F0-01F7,01F8-01FF,0200-0207,0208-020F,0210-0217,0218-021F,0220-0227,0228-022F,0230-0237,0238-023F,0240-0247,0248-024F,0250-0257,0258-025F,0260-0267,0268-026F,0270-0277,0278-027F,0280-0287,0288-028F,0290-0297,0298-029F,02A0-02A7,02A8-02AF,02B0-02B7,02B8-02BF,02C0,02C1,02C6,02C7,02C8-02CF,02D0,02D1,02E0,02E1,02E2,02E3,02E4,02EC,02EE,0370,0371,0372,0373,0374,0376,0377,037A,037B,037C,037D,037F,0386,0388,0389,038A,038C,038E,038F,0390-0397,0398-039F,03A0,03A1,03A3,03A4,03A5,03A6,03A7,03A8-03AF,03B0-03B7,03B8-03BF,03C0-03C7,03C8-03CF,03D0-03D7,03D8-03DF,03E0-03E7,03E8-03EF,03F0,03F1,03F2,03F3,03F4,03F5,03F7,03F8-03FF,0400-0407,0408-040F,0410-0417,0418-041F,0420-0427,0428-042F,0430-0437,0438-043F,0440-0447,0448-044F,0450-0457,0458-045F,0460-0467,0468-046F,0470-0477,0478-047F,0480,0481,048A,048B,048C,048D,048E,048F,0490-0497,0498-049F,04A0-04A7,04A8-04AF,04B0-04B7,04B8-04BF,04C0-04C7,04C8-04CF,04D0-04D7,04D8-04DF,04E0-04E7,04E8-04EF,04F0-04F7,04F8-04FF,0500-0507,0508-050F,0510-0517,0518-051F,0520-0527,0528-052F,0531,0532,0533,0534,0535,0536,0537,0538-053F,0540-0547,0548-054F,0550,0551,0552,0553,0554,0555,0556,0559,0560-0567,0568-056F,0570-0577,0578-057F,0580-0587,0588,05D0-05D7,05D8-05DF,05E0-05E7,05E8,05E9,05EA,05EF,05F0,05F1,05F2,0620-0627,0628-062F,0630-0637,0638-063F,0640-0647,0648,0649,064A,066E,066F,0671,0672,0673,0674,0675,0676,0677,0678-067F,0680-0687,0688-068F,0690-0697,0698-069F,06A0-06A7,06A8-06AF,06B0-06B7,06B8-06BF,06C0-06C7,06C8-06CF,06D0,06D1,06D2,06D3,06D5,06E5,06E6,06EE,06EF,06FA,06FB,06FC,06FF,0710,0712,0713,0714,0715,0716,0717,0718-071F,0720-0727,0728-072F,074D,074E,074F,0750-0757,0758-075F,0760-0767,0768-076F,0770-0777,0778-077F,0780-0787,0788-078F,0790-0797,0798-079F,07A0,07A1,07A2,07A3,07A4,07A5,07B1,07CA,07CB,07CC,07CD,07CE,07CF,07D0-07D7,07D8-07DF,07E0-07E7,07E8,07E9,07EA,07F4,07F5,07FA,0800-0807,0808-080F,0810,0811,0812,0813,0814,0815,081A,0824,0828,0840-0847,0848-084F,0850-0857,0858,0860-0867,0868,0869,086A,0870-0877,0878-087F,0880-0887,0889,088A,088B,088C,088D,088E,08A0-08A7,08A8-08AF,08B0-08B7,08B8-08BF,08C0-08C7,08C8,08C9,0904,0905,0906,0907,0908-090F,0910-0917,0918-091F,0920-0927,0928-092F,0930-0937,0938,0939,093D,0950,0958-095F,0960,0961,0971,0972,0973,0974,0975,0976,0977,0978-097F,0980,0985,0986,0987,0988,0989,098A,098B,098C,098F,0990,0993,0994,0995,0996,0997,0998-099F,09A0-09A7,09A8,09AA,09AB,09AC,09AD,09AE,09AF,09B0,09B2,09B6,09B7,09B8,09B9,09BD,09CE,09DC,09DD,09DF,09E0,09E1,09F0,09F1,09FC,0A05,0A06,0A07,0A08,0A09,0A0A,0A0F,0A10,0A13,0A14,0A15,0A16,0A17,0A18-0A1F,0A20-0A27,0A28,0A2A,0A2B,0A2C,0A2D,0A2E,0A2F,0A30,0A32,0A33,0A35,0A36,0A38,0A39,0A59,0A5A,0A5B,0A5C,0A5E,0A72,0A73,0A74,0A85,0A86,0A87,0A88,0A89,0A8A,0A8B,0A8C,0A8D,0A8F,0A90,0A91,0A93,0A94,0A95,0A96,0A97,0A98-0A9F,0AA0-0AA7,0AA8,0AAA,0AAB,0AAC,0AAD,0AAE,0AAF,0AB0,0AB2,0AB3,0AB5,0AB6,0AB7,0AB8,0AB9,0ABD,0AD0,0AE0,0AE1,0AF9,0B05,0B06,0B07,0B08,0B09,0B0A,0B0B,0B0C,0B0F,0B10,0B13,0B14,0B15,0B16,0B17,0B18-0B1F,0B20-0B27,0B28,0B2A,0B2B,0B2C,0B2D,0B2E,0B2F,0B30,0B32,0B33,0B35,0B36,0B37,0B38,0B39,0B3D,0B5C,0B5D,0B5F,0B60,0B61,0B71,0B83,0B85,0B86,0B87,0B88,0B89,0B8A,0B8E,0B8F,0B90,0B92,0B93,0B94,0B95,0B99,0B9A,0B9C,0B9E,0B9F,0BA3,0BA4,0BA8,0BA9,0BAA,0BAE,0BAF,0BB0-0BB7,0BB8,0BB9,0BD0,0C05,0C06,0C07,0C08,0C09,0C0A,0C0B,0C0C,0C0E,0C0F,0C10,0C12,0C13,0C14,0C15,0C16,0C17,0C18-0C1F,0C20-0C27,0C28,0C2A,0C2B,0C2C,0C2D,0C2E,0C2F,0C30-0C37,0C38,0C39,0C3D,0C58,0C59,0C5A,0C5D,0C60,0C61,0C80,0C85,0C86,0C87,0C88,0C89,0C8A,0C8B,0C8C,0C8E,0C8F,0C90,0C92,0C93,0C94,0C95,0C96,0C97,0C98-0C9F,0CA0-0CA7,0CA8,0CAA,0CAB,0CAC,0CAD,0CAE,0CAF,0CB0,0CB1,0CB2,0CB3,0CB5,0CB6,0CB7,0CB8,0CB9,0CBD,0CDD,0CDE,0CE0,0CE1,0CF1,0CF2,0D04,0D05,0D06,0D07,0D08,0D09,0D0A,0D0B,0D0C,0D0E,0D0F,0D10,0D12,0D13,0D14,0D15,0D16,0D17,0D18-0D1F,0D20-0D27,0D28-0D2F,0D30-0D37,0D38,0D39,0D3A,0D3D,0D4E,0D54,0D55,0D56,0D5F,0D60,0D61,0D7A,0D7B,0D7C,0D7D,0D7E,0D7F,0D85,0D86,0D87,0D88-0D8F,0D90,0D91,0D92,0D93,0D94,0D95,0D96,0D9A,0D9B,0D9C,0D9D,0D9E,0D9F,0DA0-0DA7,0DA8-0DAF,0DB0,0DB1,0DB3,0DB4,0DB5,0DB6,0DB7,0DB8,0DB9,0DBA,0DBB,0DBD,0DC0,0DC1,0DC2,0DC3,0DC4,0DC5,0DC6,0E01,0E02,0E03,0E04,0E05,0E06,0E07,0E08-0E0F,0E10-0E17,0E18-0E1F,0E20-0E27,0E28-0E2F,0E30,0E32,0E33,0E40,0E41,0E42,0E43,0E44,0E45,0E46,0E81,0E82,0E84,0E86,0E87,0E88,0E89,0E8A,0E8C,0E8D,0E8E,0E8F,0E90-0E97,0E98-0E9F,0EA0,0EA1,0EA2,0EA3,0EA5,0EA7,0EA8-0EAF,0EB0,0EB2,0EB3,0EBD,0EC0,0EC1,0EC2,0EC3,0EC4,0EC6,0EDC,0EDD,0EDE,0EDF,0F00,0F40-0F47,0F49,0F4A,0F4B,0F4C,0F4D,0F4E,0F4F,0F50-0F57,0F58-0F5F,0F60-0F67,0F68,0F69,0F6A,0F6B,0F6C,0F88,0F89,0F8A,0F8B,0F8C,1000-1007,1008-100F,1010-1017,1018-101F,1020-1027,1028,1029,102A,103F,1050,1051,1052,1053,1054,1055,105A,105B,105C,105D,1061,1065,1066,106E,106F,1070,1075,1076,1077,1078-107F,1080,1081,108E,10A0-10A7,10A8-10AF,10B0-10B7,10B8-10BF,10C0,10C1,10C2,10C3,10C4,10C5,10C7,10CD,10D0-10D7,10D8-10DF,10E0-10E7,10E8-10EF,10F0-10F7,10F8,10F9,10FA,10FC,10FD,10FE,10FF,1100-1107,1108-110F,1110-1117,1118-111F,1120-1127,1128-112F,1130-1137,1138-113F,1140-1147,1148-114F,1150-1157,1158-115F,1160-1167,1168-116F,1170-1177,1178-117F,1180-1187,1188-118F,1190-1197,1198-119F,11A0-11A7,11A8-11AF,11B0-11B7,11B8-11BF,11C0-11C7,11C8-11CF,11D0-11D7,11D8-11DF,11E0-11E7,11E8-11EF,11F0-11F7,11F8-11FF,1200-1207,1208-120F,1210-1217,1218-121F,1220-1227,1228-122F,1230-1237,1238-123F,1240-1247,1248,124A,124B,124C,124D,1250,1251,1252,1253,1254,1255,1256,1258,125A,125B,125C,125D,1260-1267,1268-126F,1270-1277,1278-127F,1280-1287,1288,128A,128B,128C,128D,1290-1297,1298-129F,12A0-12A7,12A8-12AF,12B0,12B2,12B3,12B4,12B5,12B8,12B9,12BA,12BB,12BC,12BD,12BE,12C0,12C2,12C3,12C4,12C5,12C8-12CF,12D0,12D1,12D2,12D3,12D4,12D5,12D6,12D8-12DF,12E0-12E7,12E8-12EF,12F0-12F7,12F8-12FF,1300-1307,1308-130F,1310,1312,1313,1314,1315,1318-131F,1320-1327,1328-132F,1330-1337,1338-133F,1340-1347,1348-134F,1350-1357,1358,1359,135A,1380-1387,1388-138F,13A0-13A7,13A8-13AF,13B0-13B7,13B8-13BF,13C0-13C7,13C8-13CF,13D0-13D7,13D8-13DF,13E0-13E7,13E8-13EF,13F0,13F1,13F2,13F3,13F4,13F5,13F8,13F9,13FA,13FB,13FC,13FD,1401,1402,1403,1404,1405,1406,1407,1408-140F,1410-1417,1418-141F,1420-1427,1428-142F,1430-1437,1438-143F,1440-1447,1448-144F,1450-1457,1458-145F,1460-1467,1468-146F,1470-1477,1478-147F,1480-1487,1488-148F,1490-1497,1498-149F,14A0-14A7,14A8-14AF,14B0-14B7,14B8-14BF,14C0-14C7,14C8-14CF,14D0-14D7,14D8-14DF,14E0-14E7,14E8-14EF,14F0-14F7,14F8-14FF,1500-1507,1508-150F,1510-1517,1518-151F,1520-1527,1528-152F,1530-1537,1538-153F,1540-1547,1548-154F,1550-1557,1558-155F,1560-1567,1568-156F,1570-1577,1578-157F,1580-1587,1588-158F,1590-1597,1598-159F,15A0-15A7,15A8-15AF,15B0-15B7,15B8-15BF,15C0-15C7,15C8-15CF,15D0-15D7,15D8-15DF,15E0-15E7,15E8-15EF,15F0-15F7,15F8-15FF,1600-1607,1608-160F,1610-1617,1618-161F,1620-1627,1628-162F,1630-1637,1638-163F,1640-1647,1648-164F,1650-1657,1658-165F,1660-1667,1668,1669,166A,166B,166C,166F,1670-1677,1678-167F,1681,1682,1683,1684,1685,1686,1687,1688-168F,1690-1697,1698,1699,169A,16A0-16A7,16A8-16AF,16B0-16B7,16B8-16BF,16C0-16C7,16C8-16CF,16D0-16D7,16D8-16DF,16E0-16E7,16E8,16E9,16EA,16F1,16F2,16F3,16F4,16F5,16F6,16F7,16F8,1700-1707,1708-170F,1710,1711,171F,1720-1727,1728-172F,1730,1731,1740-1747,1748-174F,1750,1751,1760-1767,1768,1769,176A,176B,176C,176E,176F,1770,1780-1787,1788-178F,1790-1797,1798-179F,17A0-17A7,17A8-17AF,17B0,17B1,17B2,17B3,17D7,17DC,1820-1827,1828-182F,1830-1837,1838-183F,1840-1847,1848-184F,1850-1857,1858-185F,1860-1867,1868-186F,1870-1877,1878,1880,1881,1882,1883,1884,1887,1888-188F,1890-1897,1898-189F,18A0-18A7,18A8,18AA,18B0-18B7,18B8-18BF,18C0-18C7,18C8-18CF,18D0-18D7,18D8-18DF,18E0-18E7,18E8-18EF,18F0,18F1,18F2,18F3,18F4,18F5,1900-1907,1908-190F,1910-1917,1918,1919,191A,191B,191C,191D,191E,1950-1957,1958-195F,1960-1967,1968,1969,196A,196B,196C,196D,1970,1971,1972,1973,1974,1980-1987,1988-198F,1990-1997,1998-199F,19A0-19A7,19A8,19A9,19AA,19AB,19B0-19B7,19B8-19BF,19C0-19C7,19C8,19C9,1A00-1A07,1A08-1A0F,1A10,1A11,1A12,1A13,1A14,1A15,1A16,1A20-1A27,1A28-1A2F,1A30-1A37,1A38-1A3F,1A40-1A47,1A48-1A4F,1A50,1A51,1A52,1A53,1A54,1AA7,1B05,1B06,1B07,1B08-1B0F,1B10-1B17,1B18-1B1F,1B20-1B27,1B28-1B2F,1B30,1B31,1B32,1B33,1B45,1B46,1B47,1B48,1B49,1B4A,1B4B,1B4C,1B83,1B84,1B85,1B86,1B87,1B88-1B8F,1B90-1B97,1B98-1B9F,1BA0,1BAE,1BAF,1BBA,1BBB,1BBC,1BBD,1BBE,1BBF,1BC0-1BC7,1BC8-1BCF,1BD0-1BD7,1BD8-1BDF,1BE0,1BE1,1BE2,1BE3,1BE4,1BE5,1C00-1C07,1C08-1C0F,1C10-1C17,1C18-1C1F,1C20,1C21,1C22,1C23,1C4D,1C4E,1C4F,1C5A,1C5B,1C5C,1C5D,1C5E,1C5F,1C60-1C67,1C68-1C6F,1C70-1C77,1C78,1C79,1C7A,1C7B,1C7C,1C7D,1C80-1C87,1C88,1C90-1C97,1C98-1C9F,1CA0-1CA7,1CA8-1CAF,1CB0-1CB7,1CB8,1CB9,1CBA,1CBD,1CBE,1CBF,1CE9,1CEA,1CEB,1CEC,1CEE,1CEF,1CF0,1CF1,1CF2,1CF3,1CF5,1CF6,1CFA,1D00-1D07,1D08-1D0F,1D10-1D17,1D18-1D1F,1D20-1D27,1D28-1D2F,1D30-1D37,1D38-1D3F,1D40-1D47,1D48-1D4F,1D50-1D57,1D58-1D5F,1D60-1D67,1D68-1D6F,1D70-1D77,1D78-1D7F,1D80-1D87,1D88-1D8F,1D90-1D97,1D98-1D9F,1DA0-1DA7,1DA8-1DAF,1DB0-1DB7,1DB8-1DBF,1E00-1E07,1E08-1E0F,1E10-1E17,1E18-1E1F,1E20-1E27,1E28-1E2F,1E30-1E37,1E38-1E3F,1E40-1E47,1E48-1E4F,1E50-1E57,1E58-1E5F,1E60-1E67,1E68-1E6F,1E70-1E77,1E78-1E7F,1E80-1E87,1E88-1E8F,1E90-1E97,1E98-1E9F,1EA0-1EA7,1EA8-1EAF,1EB0-1EB7,1EB8-1EBF,1EC0-1EC7,1EC8-1ECF,1ED0-1ED7,1ED8-1EDF,1EE0-1EE7,1EE8-1EEF,1EF0-1EF7,1EF8-1EFF,1F00-1F07,1F08-1F0F,1F10,1F11,1F12,1F13,1F14,1F15,1F18,1F19,1F1A,1F1B,1F1C,1F1D,1F20-1F27,1F28-1F2F,1F30-1F37,1F38-1F3F,1F40,1F41,1F42,1F43,1F44,1F45,1F48,1F49,1F4A,1F4B,1F4C,1F4D,1F50-1F57,1F59,1F5B,1F5D,1F5F,1F60-1F67,1F68-1F6F,1F70-1F77,1F78,1F79,1F7A,1F7B,1F7C,1F7D,1F80-1F87,1F88-1F8F,1F90-1F97,1F98-1F9F,1FA0-1FA7,1FA8-1FAF,1FB0,1FB1,1FB2,1FB3,1FB4,1FB6,1FB7,1FB8,1FB9,1FBA,1FBB,1FBC,1FBE,1FC2,1FC3,1FC4,1FC6,1FC7,1FC8,1FC9,1FCA,1FCB,1FCC,1FD0,1FD1,1FD2,1FD3,1FD6,1FD7,1FD8,1FD9,1FDA,1FDB,1FE0-1FE7,1FE8,1FE9,1FEA,1FEB,1FEC,1FF2,1FF3,1FF4,1FF6,1FF7,1FF8,1FF9,1FFA,1FFB,1FFC," + +// Ll +>> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, + If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Ll}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, + If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) +"0061,0062,0063,0064,0065,0066,0067,0068-006F,0070-0077,0078,0079,007A,00B5,00DF,00E0-00E7,00E8-00EF,00F0,00F1,00F2,00F3,00F4,00F5,00F6,00F8-00FF,0101,0103,0105,0107,0109,010B,010D,010F,0111,0113,0115,0117,0119,011B,011D,011F,0121,0123,0125,0127,0129,012B,012D,012F,0131,0133,0135,0137,0138,013A,013C,013E,0140,0142,0144,0146,0148,0149,014B,014D,014F,0151,0153,0155,0157,0159,015B,015D,015F,0161,0163,0165,0167,0169,016B,016D,016F,0171,0173,0175,0177,017A,017C,017E,017F,0180,0183,0185,0188,018C,018D,0192,0195,0199,019A,019B,019E,01A1,01A3,01A5,01A8,01AA,01AB,01AD,01B0,01B4,01B6,01B9,01BA,01BD,01BE,01BF,01C6,01C9,01CC,01CE,01D0,01D2,01D4,01D6,01D8,01DA,01DC,01DD,01DF,01E1,01E3,01E5,01E7,01E9,01EB,01ED,01EF,01F0,01F3,01F5,01F9,01FB,01FD,01FF,0201,0203,0205,0207,0209,020B,020D,020F,0211,0213,0215,0217,0219,021B,021D,021F,0221,0223,0225,0227,0229,022B,022D,022F,0231,0233,0234,0235,0236,0237,0238,0239,023C,023F,0240,0242,0247,0249,024B,024D,024F,0250-0257,0258-025F,0260-0267,0268-026F,0270-0277,0278-027F,0280-0287,0288-028F,0290,0291,0292,0293,0295,0296,0297,0298-029F,02A0-02A7,02A8-02AF,0371,0373,0377,037B,037C,037D,0390,03AC,03AD,03AE,03AF,03B0-03B7,03B8-03BF,03C0-03C7,03C8,03C9,03CA,03CB,03CC,03CD,03CE,03D0,03D1,03D5,03D6,03D7,03D9,03DB,03DD,03DF,03E1,03E3,03E5,03E7,03E9,03EB,03ED,03EF,03F0,03F1,03F2,03F3,03F5,03F8,03FB,03FC,0430-0437,0438-043F,0440-0447,0448-044F,0450-0457,0458-045F,0461,0463,0465,0467,0469,046B,046D,046F,0471,0473,0475,0477,0479,047B,047D,047F,0481,048B,048D,048F,0491,0493,0495,0497,0499,049B,049D,049F,04A1,04A3,04A5,04A7,04A9,04AB,04AD,04AF,04B1,04B3,04B5,04B7,04B9,04BB,04BD,04BF,04C2,04C4,04C6,04C8,04CA,04CC,04CE,04CF,04D1,04D3,04D5,04D7,04D9,04DB,04DD,04DF,04E1,04E3,04E5,04E7,04E9,04EB,04ED,04EF,04F1,04F3,04F5,04F7,04F9,04FB,04FD,04FF,0501,0503,0505,0507,0509,050B,050D,050F,0511,0513,0515,0517,0519,051B,051D,051F,0521,0523,0525,0527,0529,052B,052D,052F,0560-0567,0568-056F,0570-0577,0578-057F,0580-0587,0588,10D0-10D7,10D8-10DF,10E0-10E7,10E8-10EF,10F0-10F7,10F8,10F9,10FA,10FD,10FE,10FF,13F8,13F9,13FA,13FB,13FC,13FD,1C80-1C87,1C88,1D00-1D07,1D08-1D0F,1D10-1D17,1D18-1D1F,1D20-1D27,1D28,1D29,1D2A,1D2B,1D6B,1D6C,1D6D,1D6E,1D6F,1D70-1D77,1D79,1D7A,1D7B,1D7C,1D7D,1D7E,1D7F,1D80-1D87,1D88-1D8F,1D90-1D97,1D98,1D99,1D9A,1E01,1E03,1E05,1E07,1E09,1E0B,1E0D,1E0F,1E11,1E13,1E15,1E17,1E19,1E1B,1E1D,1E1F,1E21,1E23,1E25,1E27,1E29,1E2B,1E2D,1E2F,1E31,1E33,1E35,1E37,1E39,1E3B,1E3D,1E3F,1E41,1E43,1E45,1E47,1E49,1E4B,1E4D,1E4F,1E51,1E53,1E55,1E57,1E59,1E5B,1E5D,1E5F,1E61,1E63,1E65,1E67,1E69,1E6B,1E6D,1E6F,1E71,1E73,1E75,1E77,1E79,1E7B,1E7D,1E7F,1E81,1E83,1E85,1E87,1E89,1E8B,1E8D,1E8F,1E91,1E93,1E95,1E96,1E97,1E98,1E99,1E9A,1E9B,1E9C,1E9D,1E9F,1EA1,1EA3,1EA5,1EA7,1EA9,1EAB,1EAD,1EAF,1EB1,1EB3,1EB5,1EB7,1EB9,1EBB,1EBD,1EBF,1EC1,1EC3,1EC5,1EC7,1EC9,1ECB,1ECD,1ECF,1ED1,1ED3,1ED5,1ED7,1ED9,1EDB,1EDD,1EDF,1EE1,1EE3,1EE5,1EE7,1EE9,1EEB,1EED,1EEF,1EF1,1EF3,1EF5,1EF7,1EF9,1EFB,1EFD,1EFF,1F00-1F07,1F10,1F11,1F12,1F13,1F14,1F15,1F20-1F27,1F30-1F37,1F40,1F41,1F42,1F43,1F44,1F45,1F50-1F57,1F60-1F67,1F70-1F77,1F78,1F79,1F7A,1F7B,1F7C,1F7D,1F80-1F87,1F90-1F97,1FA0-1FA7,1FB0,1FB1,1FB2,1FB3,1FB4,1FB6,1FB7,1FBE,1FC2,1FC3,1FC4,1FC6,1FC7,1FD0,1FD1,1FD2,1FD3,1FD6,1FD7,1FE0-1FE7,1FF2,1FF3,1FF4,1FF6,1FF7," + +// Lu +>> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, + If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Lu}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, + If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) +"0041,0042,0043,0044,0045,0046,0047,0048-004F,0050-0057,0058,0059,005A,00C0-00C7,00C8-00CF,00D0,00D1,00D2,00D3,00D4,00D5,00D6,00D8,00D9,00DA,00DB,00DC,00DD,00DE,0100,0102,0104,0106,0108,010A,010C,010E,0110,0112,0114,0116,0118,011A,011C,011E,0120,0122,0124,0126,0128,012A,012C,012E,0130,0132,0134,0136,0139,013B,013D,013F,0141,0143,0145,0147,014A,014C,014E,0150,0152,0154,0156,0158,015A,015C,015E,0160,0162,0164,0166,0168,016A,016C,016E,0170,0172,0174,0176,0178,0179,017B,017D,0181,0182,0184,0186,0187,0189,018A,018B,018E,018F,0190,0191,0193,0194,0196,0197,0198,019C,019D,019F,01A0,01A2,01A4,01A6,01A7,01A9,01AC,01AE,01AF,01B1,01B2,01B3,01B5,01B7,01B8,01BC,01C4,01C7,01CA,01CD,01CF,01D1,01D3,01D5,01D7,01D9,01DB,01DE,01E0,01E2,01E4,01E6,01E8,01EA,01EC,01EE,01F1,01F4,01F6,01F7,01F8,01FA,01FC,01FE,0200,0202,0204,0206,0208,020A,020C,020E,0210,0212,0214,0216,0218,021A,021C,021E,0220,0222,0224,0226,0228,022A,022C,022E,0230,0232,023A,023B,023D,023E,0241,0243,0244,0245,0246,0248,024A,024C,024E,0370,0372,0376,037F,0386,0388,0389,038A,038C,038E,038F,0391,0392,0393,0394,0395,0396,0397,0398-039F,03A0,03A1,03A3,03A4,03A5,03A6,03A7,03A8,03A9,03AA,03AB,03CF,03D2,03D3,03D4,03D8,03DA,03DC,03DE,03E0,03E2,03E4,03E6,03E8,03EA,03EC,03EE,03F4,03F7,03F9,03FA,03FD,03FE,03FF,0400-0407,0408-040F,0410-0417,0418-041F,0420-0427,0428-042F,0460,0462,0464,0466,0468,046A,046C,046E,0470,0472,0474,0476,0478,047A,047C,047E,0480,048A,048C,048E,0490,0492,0494,0496,0498,049A,049C,049E,04A0,04A2,04A4,04A6,04A8,04AA,04AC,04AE,04B0,04B2,04B4,04B6,04B8,04BA,04BC,04BE,04C0,04C1,04C3,04C5,04C7,04C9,04CB,04CD,04D0,04D2,04D4,04D6,04D8,04DA,04DC,04DE,04E0,04E2,04E4,04E6,04E8,04EA,04EC,04EE,04F0,04F2,04F4,04F6,04F8,04FA,04FC,04FE,0500,0502,0504,0506,0508,050A,050C,050E,0510,0512,0514,0516,0518,051A,051C,051E,0520,0522,0524,0526,0528,052A,052C,052E,0531,0532,0533,0534,0535,0536,0537,0538-053F,0540-0547,0548-054F,0550,0551,0552,0553,0554,0555,0556,10A0-10A7,10A8-10AF,10B0-10B7,10B8-10BF,10C0,10C1,10C2,10C3,10C4,10C5,10C7,10CD,13A0-13A7,13A8-13AF,13B0-13B7,13B8-13BF,13C0-13C7,13C8-13CF,13D0-13D7,13D8-13DF,13E0-13E7,13E8-13EF,13F0,13F1,13F2,13F3,13F4,13F5,1C90-1C97,1C98-1C9F,1CA0-1CA7,1CA8-1CAF,1CB0-1CB7,1CB8,1CB9,1CBA,1CBD,1CBE,1CBF,1E00,1E02,1E04,1E06,1E08,1E0A,1E0C,1E0E,1E10,1E12,1E14,1E16,1E18,1E1A,1E1C,1E1E,1E20,1E22,1E24,1E26,1E28,1E2A,1E2C,1E2E,1E30,1E32,1E34,1E36,1E38,1E3A,1E3C,1E3E,1E40,1E42,1E44,1E46,1E48,1E4A,1E4C,1E4E,1E50,1E52,1E54,1E56,1E58,1E5A,1E5C,1E5E,1E60,1E62,1E64,1E66,1E68,1E6A,1E6C,1E6E,1E70,1E72,1E74,1E76,1E78,1E7A,1E7C,1E7E,1E80,1E82,1E84,1E86,1E88,1E8A,1E8C,1E8E,1E90,1E92,1E94,1E9E,1EA0,1EA2,1EA4,1EA6,1EA8,1EAA,1EAC,1EAE,1EB0,1EB2,1EB4,1EB6,1EB8,1EBA,1EBC,1EBE,1EC0,1EC2,1EC4,1EC6,1EC8,1ECA,1ECC,1ECE,1ED0,1ED2,1ED4,1ED6,1ED8,1EDA,1EDC,1EDE,1EE0,1EE2,1EE4,1EE6,1EE8,1EEA,1EEC,1EEE,1EF0,1EF2,1EF4,1EF6,1EF8,1EFA,1EFC,1EFE,1F08-1F0F,1F18,1F19,1F1A,1F1B,1F1C,1F1D,1F28-1F2F,1F38-1F3F,1F48,1F49,1F4A,1F4B,1F4C,1F4D,1F59,1F5B,1F5D,1F5F,1F68-1F6F,1FB8,1FB9,1FBA,1FBB,1FC8,1FC9,1FCA,1FCB,1FD8,1FD9,1FDA,1FDB,1FE8,1FE9,1FEA,1FEB,1FEC,1FF8,1FF9,1FFA,1FFB," + +// Lt +>> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, + If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Lt}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, + If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) +"01C5,01C8,01CB,01F2,1F88-1F8F,1F98-1F9F,1FA8-1FAF,1FBC,1FCC,1FFC," + +// Lm +>> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, + If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Lm}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, + If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) +"02B0-02B7,02B8-02BF,02C0,02C1,02C6,02C7,02C8-02CF,02D0,02D1,02E0,02E1,02E2,02E3,02E4,02EC,02EE,0374,037A,0559,0640,06E5,06E6,07F4,07F5,07FA,081A,0824,0828,08C9,0971,0E46,0EC6,10FC,17D7,1843,1AA7,1C78,1C79,1C7A,1C7B,1C7C,1C7D,1D2C,1D2D,1D2E,1D2F,1D30-1D37,1D38-1D3F,1D40-1D47,1D48-1D4F,1D50-1D57,1D58-1D5F,1D60-1D67,1D68,1D69,1D6A,1D78,1D9B,1D9C,1D9D,1D9E,1D9F,1DA0-1DA7,1DA8-1DAF,1DB0-1DB7,1DB8-1DBF," + +// Lo +>> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, + If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Lo}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, + If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) +"00AA,00BA,01BB,01C0,01C1,01C2,01C3,0294,05D0-05D7,05D8-05DF,05E0-05E7,05E8,05E9,05EA,05EF,05F0,05F1,05F2,0620-0627,0628-062F,0630-0637,0638-063F,0641,0642,0643,0644,0645,0646,0647,0648,0649,064A,066E,066F,0671,0672,0673,0674,0675,0676,0677,0678-067F,0680-0687,0688-068F,0690-0697,0698-069F,06A0-06A7,06A8-06AF,06B0-06B7,06B8-06BF,06C0-06C7,06C8-06CF,06D0,06D1,06D2,06D3,06D5,06EE,06EF,06FA,06FB,06FC,06FF,0710,0712,0713,0714,0715,0716,0717,0718-071F,0720-0727,0728-072F,074D,074E,074F,0750-0757,0758-075F,0760-0767,0768-076F,0770-0777,0778-077F,0780-0787,0788-078F,0790-0797,0798-079F,07A0,07A1,07A2,07A3,07A4,07A5,07B1,07CA,07CB,07CC,07CD,07CE,07CF,07D0-07D7,07D8-07DF,07E0-07E7,07E8,07E9,07EA,0800-0807,0808-080F,0810,0811,0812,0813,0814,0815,0840-0847,0848-084F,0850-0857,0858,0860-0867,0868,0869,086A,0870-0877,0878-087F,0880-0887,0889,088A,088B,088C,088D,088E,08A0-08A7,08A8-08AF,08B0-08B7,08B8-08BF,08C0-08C7,08C8,0904,0905,0906,0907,0908-090F,0910-0917,0918-091F,0920-0927,0928-092F,0930-0937,0938,0939,093D,0950,0958-095F,0960,0961,0972,0973,0974,0975,0976,0977,0978-097F,0980,0985,0986,0987,0988,0989,098A,098B,098C,098F,0990,0993,0994,0995,0996,0997,0998-099F,09A0-09A7,09A8,09AA,09AB,09AC,09AD,09AE,09AF,09B0,09B2,09B6,09B7,09B8,09B9,09BD,09CE,09DC,09DD,09DF,09E0,09E1,09F0,09F1,09FC,0A05,0A06,0A07,0A08,0A09,0A0A,0A0F,0A10,0A13,0A14,0A15,0A16,0A17,0A18-0A1F,0A20-0A27,0A28,0A2A,0A2B,0A2C,0A2D,0A2E,0A2F,0A30,0A32,0A33,0A35,0A36,0A38,0A39,0A59,0A5A,0A5B,0A5C,0A5E,0A72,0A73,0A74,0A85,0A86,0A87,0A88,0A89,0A8A,0A8B,0A8C,0A8D,0A8F,0A90,0A91,0A93,0A94,0A95,0A96,0A97,0A98-0A9F,0AA0-0AA7,0AA8,0AAA,0AAB,0AAC,0AAD,0AAE,0AAF,0AB0,0AB2,0AB3,0AB5,0AB6,0AB7,0AB8,0AB9,0ABD,0AD0,0AE0,0AE1,0AF9,0B05,0B06,0B07,0B08,0B09,0B0A,0B0B,0B0C,0B0F,0B10,0B13,0B14,0B15,0B16,0B17,0B18-0B1F,0B20-0B27,0B28,0B2A,0B2B,0B2C,0B2D,0B2E,0B2F,0B30,0B32,0B33,0B35,0B36,0B37,0B38,0B39,0B3D,0B5C,0B5D,0B5F,0B60,0B61,0B71,0B83,0B85,0B86,0B87,0B88,0B89,0B8A,0B8E,0B8F,0B90,0B92,0B93,0B94,0B95,0B99,0B9A,0B9C,0B9E,0B9F,0BA3,0BA4,0BA8,0BA9,0BAA,0BAE,0BAF,0BB0-0BB7,0BB8,0BB9,0BD0,0C05,0C06,0C07,0C08,0C09,0C0A,0C0B,0C0C,0C0E,0C0F,0C10,0C12,0C13,0C14,0C15,0C16,0C17,0C18-0C1F,0C20-0C27,0C28,0C2A,0C2B,0C2C,0C2D,0C2E,0C2F,0C30-0C37,0C38,0C39,0C3D,0C58,0C59,0C5A,0C5D,0C60,0C61,0C80,0C85,0C86,0C87,0C88,0C89,0C8A,0C8B,0C8C,0C8E,0C8F,0C90,0C92,0C93,0C94,0C95,0C96,0C97,0C98-0C9F,0CA0-0CA7,0CA8,0CAA,0CAB,0CAC,0CAD,0CAE,0CAF,0CB0,0CB1,0CB2,0CB3,0CB5,0CB6,0CB7,0CB8,0CB9,0CBD,0CDD,0CDE,0CE0,0CE1,0CF1,0CF2,0D04,0D05,0D06,0D07,0D08,0D09,0D0A,0D0B,0D0C,0D0E,0D0F,0D10,0D12,0D13,0D14,0D15,0D16,0D17,0D18-0D1F,0D20-0D27,0D28-0D2F,0D30-0D37,0D38,0D39,0D3A,0D3D,0D4E,0D54,0D55,0D56,0D5F,0D60,0D61,0D7A,0D7B,0D7C,0D7D,0D7E,0D7F,0D85,0D86,0D87,0D88-0D8F,0D90,0D91,0D92,0D93,0D94,0D95,0D96,0D9A,0D9B,0D9C,0D9D,0D9E,0D9F,0DA0-0DA7,0DA8-0DAF,0DB0,0DB1,0DB3,0DB4,0DB5,0DB6,0DB7,0DB8,0DB9,0DBA,0DBB,0DBD,0DC0,0DC1,0DC2,0DC3,0DC4,0DC5,0DC6,0E01,0E02,0E03,0E04,0E05,0E06,0E07,0E08-0E0F,0E10-0E17,0E18-0E1F,0E20-0E27,0E28-0E2F,0E30,0E32,0E33,0E40,0E41,0E42,0E43,0E44,0E45,0E81,0E82,0E84,0E86,0E87,0E88,0E89,0E8A,0E8C,0E8D,0E8E,0E8F,0E90-0E97,0E98-0E9F,0EA0,0EA1,0EA2,0EA3,0EA5,0EA7,0EA8-0EAF,0EB0,0EB2,0EB3,0EBD,0EC0,0EC1,0EC2,0EC3,0EC4,0EDC,0EDD,0EDE,0EDF,0F00,0F40-0F47,0F49,0F4A,0F4B,0F4C,0F4D,0F4E,0F4F,0F50-0F57,0F58-0F5F,0F60-0F67,0F68,0F69,0F6A,0F6B,0F6C,0F88,0F89,0F8A,0F8B,0F8C,1000-1007,1008-100F,1010-1017,1018-101F,1020-1027,1028,1029,102A,103F,1050,1051,1052,1053,1054,1055,105A,105B,105C,105D,1061,1065,1066,106E,106F,1070,1075,1076,1077,1078-107F,1080,1081,108E,1100-1107,1108-110F,1110-1117,1118-111F,1120-1127,1128-112F,1130-1137,1138-113F,1140-1147,1148-114F,1150-1157,1158-115F,1160-1167,1168-116F,1170-1177,1178-117F,1180-1187,1188-118F,1190-1197,1198-119F,11A0-11A7,11A8-11AF,11B0-11B7,11B8-11BF,11C0-11C7,11C8-11CF,11D0-11D7,11D8-11DF,11E0-11E7,11E8-11EF,11F0-11F7,11F8-11FF,1200-1207,1208-120F,1210-1217,1218-121F,1220-1227,1228-122F,1230-1237,1238-123F,1240-1247,1248,124A,124B,124C,124D,1250,1251,1252,1253,1254,1255,1256,1258,125A,125B,125C,125D,1260-1267,1268-126F,1270-1277,1278-127F,1280-1287,1288,128A,128B,128C,128D,1290-1297,1298-129F,12A0-12A7,12A8-12AF,12B0,12B2,12B3,12B4,12B5,12B8,12B9,12BA,12BB,12BC,12BD,12BE,12C0,12C2,12C3,12C4,12C5,12C8-12CF,12D0,12D1,12D2,12D3,12D4,12D5,12D6,12D8-12DF,12E0-12E7,12E8-12EF,12F0-12F7,12F8-12FF,1300-1307,1308-130F,1310,1312,1313,1314,1315,1318-131F,1320-1327,1328-132F,1330-1337,1338-133F,1340-1347,1348-134F,1350-1357,1358,1359,135A,1380-1387,1388-138F,1401,1402,1403,1404,1405,1406,1407,1408-140F,1410-1417,1418-141F,1420-1427,1428-142F,1430-1437,1438-143F,1440-1447,1448-144F,1450-1457,1458-145F,1460-1467,1468-146F,1470-1477,1478-147F,1480-1487,1488-148F,1490-1497,1498-149F,14A0-14A7,14A8-14AF,14B0-14B7,14B8-14BF,14C0-14C7,14C8-14CF,14D0-14D7,14D8-14DF,14E0-14E7,14E8-14EF,14F0-14F7,14F8-14FF,1500-1507,1508-150F,1510-1517,1518-151F,1520-1527,1528-152F,1530-1537,1538-153F,1540-1547,1548-154F,1550-1557,1558-155F,1560-1567,1568-156F,1570-1577,1578-157F,1580-1587,1588-158F,1590-1597,1598-159F,15A0-15A7,15A8-15AF,15B0-15B7,15B8-15BF,15C0-15C7,15C8-15CF,15D0-15D7,15D8-15DF,15E0-15E7,15E8-15EF,15F0-15F7,15F8-15FF,1600-1607,1608-160F,1610-1617,1618-161F,1620-1627,1628-162F,1630-1637,1638-163F,1640-1647,1648-164F,1650-1657,1658-165F,1660-1667,1668,1669,166A,166B,166C,166F,1670-1677,1678-167F,1681,1682,1683,1684,1685,1686,1687,1688-168F,1690-1697,1698,1699,169A,16A0-16A7,16A8-16AF,16B0-16B7,16B8-16BF,16C0-16C7,16C8-16CF,16D0-16D7,16D8-16DF,16E0-16E7,16E8,16E9,16EA,16F1,16F2,16F3,16F4,16F5,16F6,16F7,16F8,1700-1707,1708-170F,1710,1711,171F,1720-1727,1728-172F,1730,1731,1740-1747,1748-174F,1750,1751,1760-1767,1768,1769,176A,176B,176C,176E,176F,1770,1780-1787,1788-178F,1790-1797,1798-179F,17A0-17A7,17A8-17AF,17B0,17B1,17B2,17B3,17DC,1820-1827,1828-182F,1830-1837,1838-183F,1840,1841,1842,1844,1845,1846,1847,1848-184F,1850-1857,1858-185F,1860-1867,1868-186F,1870-1877,1878,1880,1881,1882,1883,1884,1887,1888-188F,1890-1897,1898-189F,18A0-18A7,18A8,18AA,18B0-18B7,18B8-18BF,18C0-18C7,18C8-18CF,18D0-18D7,18D8-18DF,18E0-18E7,18E8-18EF,18F0,18F1,18F2,18F3,18F4,18F5,1900-1907,1908-190F,1910-1917,1918,1919,191A,191B,191C,191D,191E,1950-1957,1958-195F,1960-1967,1968,1969,196A,196B,196C,196D,1970,1971,1972,1973,1974,1980-1987,1988-198F,1990-1997,1998-199F,19A0-19A7,19A8,19A9,19AA,19AB,19B0-19B7,19B8-19BF,19C0-19C7,19C8,19C9,1A00-1A07,1A08-1A0F,1A10,1A11,1A12,1A13,1A14,1A15,1A16,1A20-1A27,1A28-1A2F,1A30-1A37,1A38-1A3F,1A40-1A47,1A48-1A4F,1A50,1A51,1A52,1A53,1A54,1B05,1B06,1B07,1B08-1B0F,1B10-1B17,1B18-1B1F,1B20-1B27,1B28-1B2F,1B30,1B31,1B32,1B33,1B45,1B46,1B47,1B48,1B49,1B4A,1B4B,1B4C,1B83,1B84,1B85,1B86,1B87,1B88-1B8F,1B90-1B97,1B98-1B9F,1BA0,1BAE,1BAF,1BBA,1BBB,1BBC,1BBD,1BBE,1BBF,1BC0-1BC7,1BC8-1BCF,1BD0-1BD7,1BD8-1BDF,1BE0,1BE1,1BE2,1BE3,1BE4,1BE5,1C00-1C07,1C08-1C0F,1C10-1C17,1C18-1C1F,1C20,1C21,1C22,1C23,1C4D,1C4E,1C4F,1C5A,1C5B,1C5C,1C5D,1C5E,1C5F,1C60-1C67,1C68-1C6F,1C70-1C77,1CE9,1CEA,1CEB,1CEC,1CEE,1CEF,1CF0,1CF1,1CF2,1CF3,1CF5,1CF6,1CFA," + +// M +>> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, + If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{M}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, + If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) + +// Mn +>> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, + If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Mn}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, + If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) + +// Mc +>> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, + If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Mc}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, + If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) + +// Me +>> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, + If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Me}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, + If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) + +// N +>> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, + If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{N}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, + If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) +"0030-0037,0038,0039,00B2,00B3,00B9,00BC,00BD,00BE,0660-0667,0668,0669,06F0-06F7,06F8,06F9,07C0-07C7,07C8,07C9,0966,0967,0968-096F,09E6,09E7,09E8-09EF,09F4,09F5,09F6,09F7,09F8,09F9,0A66,0A67,0A68-0A6F,0AE6,0AE7,0AE8-0AEF,0B66,0B67,0B68-0B6F,0B72,0B73,0B74,0B75,0B76,0B77,0BE6,0BE7,0BE8-0BEF,0BF0,0BF1,0BF2,0C66,0C67,0C68-0C6F,0C78,0C79,0C7A,0C7B,0C7C,0C7D,0C7E,0CE6,0CE7,0CE8-0CEF,0D58,0D59,0D5A,0D5B,0D5C,0D5D,0D5E,0D66,0D67,0D68-0D6F,0D70-0D77,0D78,0DE6,0DE7,0DE8-0DEF,0E50-0E57,0E58,0E59,0ED0-0ED7,0ED8,0ED9,0F20-0F27,0F28-0F2F,0F30,0F31,0F32,0F33,1040-1047,1048,1049,1090-1097,1098,1099,1369,136A,136B,136C,136D,136E,136F,1370-1377,1378,1379,137A,137B,137C,16EE,16EF,16F0,17E0-17E7,17E8,17E9,17F0-17F7,17F8,17F9,1810-1817,1818,1819,1946,1947,1948-194F,19D0-19D7,19D8,19D9,19DA,1A80-1A87,1A88,1A89,1A90-1A97,1A98,1A99,1B50-1B57,1B58,1B59,1BB0-1BB7,1BB8,1BB9,1C40-1C47,1C48,1C49,1C50-1C57,1C58,1C59," + +// Nd +>> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, + If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Nd}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, + If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) +"0030-0037,0038,0039,0660-0667,0668,0669,06F0-06F7,06F8,06F9,07C0-07C7,07C8,07C9,0966,0967,0968-096F,09E6,09E7,09E8-09EF,0A66,0A67,0A68-0A6F,0AE6,0AE7,0AE8-0AEF,0B66,0B67,0B68-0B6F,0BE6,0BE7,0BE8-0BEF,0C66,0C67,0C68-0C6F,0CE6,0CE7,0CE8-0CEF,0D66,0D67,0D68-0D6F,0DE6,0DE7,0DE8-0DEF,0E50-0E57,0E58,0E59,0ED0-0ED7,0ED8,0ED9,0F20-0F27,0F28,0F29,1040-1047,1048,1049,1090-1097,1098,1099,17E0-17E7,17E8,17E9,1810-1817,1818,1819,1946,1947,1948-194F,19D0-19D7,19D8,19D9,1A80-1A87,1A88,1A89,1A90-1A97,1A98,1A99,1B50-1B57,1B58,1B59,1BB0-1BB7,1BB8,1BB9,1C40-1C47,1C48,1C49,1C50-1C57,1C58,1C59," + +// Nl +>> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, + If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Nl}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, + If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) +"16EE,16EF,16F0," + +// No +>> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, + If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{No}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, + If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) + +// P +>> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, + If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{P}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, + If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) +"0021,0022,0023,0025,0026,0027,0028,0029,002A,002C,002D,002E,002F,003A,003B,003F,0040,005B,005C,005D,005F,007B,007D,00A1,00A7,00AB,00B6,00B7,00BB,00BF,037E,0387,055A,055B,055C,055D,055E,055F,0589,058A,05BE,05C0,05C3,05C6,05F3,05F4,0609,060A,060C,060D,061B,061D,061E,061F,066A,066B,066C,066D,06D4,0700-0707,0708,0709,070A,070B,070C,070D,07F7,07F8,07F9,0830-0837,0838,0839,083A,083B,083C,083D,083E,085E,0964,0965,0970,09FD,0A76,0AF0,0C77,0C84,0DF4,0E4F,0E5A,0E5B,0F04,0F05,0F06,0F07,0F08-0F0F,0F10,0F11,0F12,0F14,0F3A,0F3B,0F3C,0F3D,0F85,0FD0,0FD1,0FD2,0FD3,0FD4,0FD9,0FDA,104A,104B,104C,104D,104E,104F,10FB,1360-1367,1368,1400,166E,169B,169C,16EB,16EC,16ED,1735,1736,17D4,17D5,17D6,17D8,17D9,17DA,1800-1807,1808,1809,180A,1944,1945,1A1E,1A1F,1AA0,1AA1,1AA2,1AA3,1AA4,1AA5,1AA6,1AA8,1AA9,1AAA,1AAB,1AAC,1AAD,1B5A,1B5B,1B5C,1B5D,1B5E,1B5F,1B60,1B7D,1B7E,1BFC,1BFD,1BFE,1BFF,1C3B,1C3C,1C3D,1C3E,1C3F,1C7E,1C7F,1CC0-1CC7,1CD3," + +// Pc +>> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, + If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Pc}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, + If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) + +// Pd +>> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, + If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Pd}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, + If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) + +// Ps +>> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, + If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Ps}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, + If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) + +// Pe +>> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, + If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Pe}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, + If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) + +// Pi +>> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, + If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Pi}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, + If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) + +// Pf +>> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, + If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Pf}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, + If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) + +// Po +>> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, + If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Po}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, + If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs index 23145bb7ff..a013e83ece 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs @@ -10,27 +10,67 @@ using System.Linq; using System.Runtime.Serialization; using System.Text; +using System.Text.Json; using System.Text.RegularExpressions; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.Differencing; using Microsoft.PowerFx.Core.Functions; using Microsoft.PowerFx.Core.IR; using Microsoft.PowerFx.Core.Texl.Builtins; +using Microsoft.PowerFx.Syntax; using Microsoft.PowerFx.Types; +using Newtonsoft.Json.Linq; namespace Microsoft.PowerFx.Functions { public class RegEx_NodeJS { + private static Process node; + + private static readonly StringBuilder OutputSB = new StringBuilder(); + private static readonly StringBuilder ErrorSB = new StringBuilder(); + private static TaskCompletionSource readTask = null; + + private static void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine) + { + OutputSB.Append(outLine.Data); + if (outLine.Data.Contains("%%end%%")) + { + readTask.TrySetResult(true); + } + } + + private static void ErrorHandler(object sendingProcess, DataReceivedEventArgs outLine) + { + ErrorSB.Append(outLine.Data); + readTask.TrySetResult(true); + } + + private class JSMatch + { + public int Index { get; set; } + + public string[] Numbered { get; set; } + + public Dictionary Named { get; set; } + } + internal abstract class NodeJS_RegexCommonImplementation : Library.RegexCommonImplementation { internal static FormulaValue Match(string subject, string pattern, string flags, bool matchAll = false) + { + Task task = Task.Run(async () => await MatchAsync(subject, pattern, flags, matchAll)); + return task.Result; + } + + internal static async Task MatchAsync(string subject, string pattern, string flags, bool matchAll = false) { var js = new StringBuilder(); - js.AppendLine($"const subject='{subject.Replace("\\", "\\\\").Replace("\r", "\\r").Replace("\n", "\\n").Replace("'", "\\'")}';"); - js.AppendLine($"const pattern='{pattern.Replace("\\", "\\\\").Replace("\r", "\\r").Replace("\n", "\\n").Replace("'", "\\'")}';"); - js.AppendLine($"const flags='{flags}';"); - js.AppendLine($"const matchAll={(matchAll ? "true" : "false")};"); + js.Append($"MatchTest('{subject.Replace("\\", "\\\\").Replace("\r", "\\r").Replace("\n", "\\n").Replace("'", "\\'")}',"); + js.Append($"'{pattern.Replace("\\", "\\\\").Replace("\r", "\\r").Replace("\n", "\\n").Replace("'", "\\'")}',"); + js.Append($"'{flags}',"); + js.Append($"{(matchAll ? "true" : "false")});"); #if false // for debugging unicode passing of strings to Node, output ignored by deserializer but visible in the debugger @@ -42,152 +82,130 @@ internal static FormulaValue Match(string subject, string pattern, string flags, "); #endif - js.AppendLine(@" - const [alteredPattern, alteredFlags] = AlterRegex_JavaScript( pattern, flags ); - const regex = RegExp(alteredPattern, alteredFlags.concat(matchAll ? 'g' : '')); - const matches = matchAll ? [...subject.matchAll(regex)] : [subject.match(regex)]; - - for(const match of matches) - { - if (match != null) + if (node == null) + { + string js2 = @" + function MatchTest( subject, pattern, flags, matchAll ) { - console.log('%start%:' + match.index); - for(var group in match.groups) - { - var val = match.groups[group]; - if (val !== undefined) - { - val = '""' + val.replace( /""/g, '""""') + '""' - } - console.log(group + ':' + val); - } - for (var num = 0; num < match.length; num++) + const [alteredPattern, alteredFlags] = AlterRegex_JavaScript( pattern, flags ); + const regex = RegExp(alteredPattern, alteredFlags.concat(matchAll ? 'g' : '')); + const matches = matchAll ? [...subject.matchAll(regex)] : [subject.match(regex)]; + console.log('%%begin%%'); + if (matches.length != 0 && matches[0] != null) { - var val = match[num]; - if (val !== undefined) + var arr = new Array(); + for (const match of matches) { - val = '""' + val.replace( /""/g, '""""') + '""' + var o = new Object(); + o.Index = match.index; + o.Named = match.groups; + o.Numbered = match; + arr.push(o); } - console.log(num + ':' + val); + console.log(JSON.stringify(arr)); } - console.log('%end%:'); + console.log('%%end%%'); } - } - console.log('%done%:'); - "); + "; + + node = new Process(); + node.StartInfo.FileName = "node.exe"; + node.StartInfo.Arguments = "-i"; + node.StartInfo.RedirectStandardInput = true; + node.StartInfo.RedirectStandardOutput = true; + node.StartInfo.RedirectStandardError = true; + node.StartInfo.CreateNoWindow = true; + node.StartInfo.UseShellExecute = false; + node.StartInfo.StandardOutputEncoding = System.Text.Encoding.UTF8; - var node = new Process(); - node.StartInfo.FileName = "node.exe"; - node.StartInfo.RedirectStandardInput = true; - node.StartInfo.RedirectStandardOutput = true; - node.StartInfo.RedirectStandardError = true; - node.StartInfo.CreateNoWindow = true; - node.StartInfo.UseShellExecute = false; - node.StartInfo.StandardOutputEncoding = System.Text.Encoding.UTF8; + // Not supported by .NET framework 4.6.2, we need to use the manual GetBytes method below + // node.StartInfo.StandardInputEncoding = System.Text.Encoding.UTF8; - // Not supported by .NET framework 4.6.2, we need to use the manual GetBytes method below - // node.StartInfo.StandardInputEncoding = System.Text.Encoding.UTF8; + node.OutputDataReceived += OutputHandler; + node.ErrorDataReceived += ErrorHandler; + + node.Start(); + + node.BeginOutputReadLine(); + node.BeginErrorReadLine(); + + await node.StandardInput.WriteLineAsync(RegEx_JavaScript.AlterRegex_JavaScript); + await node.StandardInput.WriteLineAsync(js2); + } - node.Start(); + OutputSB.Clear(); + ErrorSB.Clear(); + readTask = new TaskCompletionSource(); var jsString = js.ToString(); - var bytes = Encoding.UTF8.GetBytes(RegEx_JavaScript.AlterRegex_JavaScript + jsString); - node.StandardInput.BaseStream.Write(bytes, 0, bytes.Length); - node.StandardInput.WriteLine(); - node.StandardInput.Close(); + var bytes = Encoding.UTF8.GetBytes(jsString); + await node.StandardInput.BaseStream.WriteAsync(bytes, 0, bytes.Length); + await node.StandardInput.WriteLineAsync(); - string output = node.StandardOutput.ReadToEnd(); - string error = node.StandardError.ReadToEnd(); + await node.StandardInput.FlushAsync(); - node.WaitForExit(); - node.Dispose(); + await readTask.Task; + + string output = OutputSB.ToString(); + string error = ErrorSB.ToString(); if (error.Length > 0) { throw new InvalidOperationException(error); } - var outputRE = new Regex( - @" - ^%start%:(?[-\d]+)$ | - ^(?%end%): | - ^(?%done%): | - ^(?\d+):""(?(""""|[^""])*)""$ | - ^(?[^:]+):""(?(""""|[^""])*)""$ | - ^(?\d+):undefined$ | - ^(?[^:]+):undefined$ - ", RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace); - - List subMatches = new List(); - Dictionary fields = new (); + int begin = output.IndexOf("%%begin%%"); + int end = output.IndexOf("%%end%%"); + + var type = new KnownRecordType(GetRecordTypeFromRegularExpression(pattern, flags.Contains('N') ? RegexOptions.None : RegexOptions.ExplicitCapture)); + + if (end == begin + 9) + { + return matchAll ? FormulaValue.NewTable(type) : new BlankValue(IRContext.NotInSource(type)); + } + + string json = output.Substring(begin + 9, end - begin - 9); + var result = JsonSerializer.Deserialize(json); + List allMatches = new (); - foreach (Match token in outputRE.Matches(output)) + foreach (JSMatch match in result) { - if (token.Groups["start"].Success) - { - fields = new (); - subMatches = new (); - fields.Add(STARTMATCH, new NamedValue(STARTMATCH, NumberValue.New(Convert.ToDouble(token.Groups["start"].Value) + 1))); - } - else if (token.Groups["end"].Success) + Dictionary fields = new Dictionary() { - if (flags.Contains('N')) - { - var recordType = RecordType.Empty().Add(TableValue.ValueName, FormulaType.String); - fields.Add(SUBMATCHES, new NamedValue(SUBMATCHES, TableValue.NewTable(recordType, subMatches))); - } + { STARTMATCH, new NamedValue(STARTMATCH, NumberValue.New(Convert.ToDouble(match.Index) + 1)) }, + { FULLMATCH, new NamedValue(FULLMATCH, match.Numbered[0] == null ? BlankValue.NewBlank(FormulaType.String) : StringValue.New(match.Numbered[0])) }, + }; - allMatches.Add(RecordValue.NewRecordFromFields(fields.Values)); - } - else if (token.Groups["done"].Success) - { - if (allMatches.Count == 0) - { - return matchAll ? FormulaValue.NewTable(new KnownRecordType(GetRecordTypeFromRegularExpression(pattern, flags.Contains('N') ? RegexOptions.None : RegexOptions.ExplicitCapture))) - : new BlankValue(IRContext.NotInSource(new KnownRecordType(GetRecordTypeFromRegularExpression(pattern, flags.Contains('N') ? RegexOptions.None : RegexOptions.ExplicitCapture)))); - } - else - { - return matchAll ? FormulaValue.NewTable(allMatches.First().Type, allMatches) - : allMatches.First(); - } - } - else if (token.Groups["name"].Success) - { - fields.Add(token.Groups["name"].Value, new NamedValue(token.Groups["name"].Value, StringValue.New(token.Groups["nameMatch"].Value.Replace(@"""""", @"""")))); - } - else if (token.Groups["nameBlank"].Success) + if (match.Named != null) { - fields.Add(token.Groups["nameBlank"].Value, new NamedValue(token.Groups["nameBlank"].Value, BlankValue.NewBlank(FormulaType.String))); - } - else if (token.Groups["num"].Success) - { - var num = Convert.ToInt32(token.Groups["num"].Value); - if (num == 0) - { - fields.Add(FULLMATCH, new NamedValue(FULLMATCH, StringValue.New(token.Groups["numMatch"].Value.Replace(@"""""", @"""")))); - } - else + foreach (var name in type.FieldNames) { - subMatches.Add(FormulaValue.NewRecordFromFields(new NamedValue(TableValue.ValueName, StringValue.New(token.Groups["numMatch"].Value.Replace(@"""""", @""""))))); + if (name != STARTMATCH && name != FULLMATCH && name != SUBMATCHES) + { + fields.Add(name, new NamedValue(name, match.Named.ContainsKey(name) ? StringValue.New(match.Named[name]) : BlankValue.NewBlank(FormulaType.String))); + } } } - else if (token.Groups["numBlank"].Success) + + if (flags.Contains('N')) { - var num = Convert.ToInt32(token.Groups["numBlank"].Value); - if (num == 0) - { - fields.Add(FULLMATCH, new NamedValue(FULLMATCH, BlankValue.NewBlank(FormulaType.String))); - } - else + List subMatches = new List(); + + for (int i = 1; i < match.Numbered.Count(); i++) { - subMatches.Add(FormulaValue.NewRecordFromFields(new NamedValue(TableValue.ValueName, BlankValue.NewBlank(FormulaType.String)))); + var n = match.Numbered[i]; + subMatches.Add(FormulaValue.NewRecordFromFields(new NamedValue(TableValue.ValueName, n == null ? BlankValue.NewBlank(FormulaType.String) : StringValue.New(n)))); } + + var recordType = RecordType.Empty().Add(TableValue.ValueName, FormulaType.String); + fields.Add(SUBMATCHES, new NamedValue(SUBMATCHES, TableValue.NewTable(recordType, subMatches))); } + + allMatches.Add(RecordValue.NewRecordFromFields(fields.Values)); } - throw new Exception("%done% marker not found"); + return matchAll ? FormulaValue.NewTable(allMatches.First().Type, allMatches) : allMatches.First(); } } From d8774a1d4144dd2f54d0e9ff0aa937a043b8bfbd Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Thu, 19 Sep 2024 23:30:10 -0700 Subject: [PATCH 49/61] Updates --- .../Helpers/LibraryRegEx_NodeJS.cs | 158 ++++++++++++------ 1 file changed, 105 insertions(+), 53 deletions(-) diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs index 23145bb7ff..00bce162f9 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs @@ -10,7 +10,9 @@ using System.Linq; using System.Runtime.Serialization; using System.Text; +using System.Text.Json; using System.Text.RegularExpressions; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.Differencing; using Microsoft.PowerFx.Core.Functions; using Microsoft.PowerFx.Core.IR; @@ -21,16 +23,57 @@ namespace Microsoft.PowerFx.Functions { public class RegEx_NodeJS { + private static Process node; + + private static readonly StringBuilder OutputSB = new StringBuilder(); + private static readonly StringBuilder ErrorSB = new StringBuilder(); + private static TaskCompletionSource readTask = null; + + private static void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine) + { + OutputSB.Append(outLine.Data); + if (outLine.Data.Contains("%%end%%")) + { + readTask.TrySetResult(true); + } + } + + private static void ErrorHandler(object sendingProcess, DataReceivedEventArgs outLine) + { + ErrorSB.Append(outLine.Data); + readTask.TrySetResult(true); + } + + private class JSResult + { + public JSMatch[] Matches { get; set; } + } + + private class JSMatch + { + public int Index { get; set; } + + public string[] Numbered { get; set; } + + public Dictionary Named { get; set; } + } + internal abstract class NodeJS_RegexCommonImplementation : Library.RegexCommonImplementation { internal static FormulaValue Match(string subject, string pattern, string flags, bool matchAll = false) + { + Task task = Task.Run(async () => await MatchAsync(subject, pattern, flags, matchAll)); + return task.Result; + } + + internal static async Task MatchAsync(string subject, string pattern, string flags, bool matchAll = false) { var js = new StringBuilder(); - js.AppendLine($"const subject='{subject.Replace("\\", "\\\\").Replace("\r", "\\r").Replace("\n", "\\n").Replace("'", "\\'")}';"); - js.AppendLine($"const pattern='{pattern.Replace("\\", "\\\\").Replace("\r", "\\r").Replace("\n", "\\n").Replace("'", "\\'")}';"); - js.AppendLine($"const flags='{flags}';"); - js.AppendLine($"const matchAll={(matchAll ? "true" : "false")};"); + js.Append($"MatchTest('{subject.Replace("\\", "\\\\").Replace("\r", "\\r").Replace("\n", "\\n").Replace("'", "\\'")}',"); + js.Append($"'{pattern.Replace("\\", "\\\\").Replace("\r", "\\r").Replace("\n", "\\n").Replace("'", "\\'")}',"); + js.Append($"'{flags}',"); + js.Append($"{(matchAll ? "true" : "false")});"); #if false // for debugging unicode passing of strings to Node, output ignored by deserializer but visible in the debugger @@ -42,71 +85,80 @@ internal static FormulaValue Match(string subject, string pattern, string flags, "); #endif - js.AppendLine(@" - const [alteredPattern, alteredFlags] = AlterRegex_JavaScript( pattern, flags ); - const regex = RegExp(alteredPattern, alteredFlags.concat(matchAll ? 'g' : '')); - const matches = matchAll ? [...subject.matchAll(regex)] : [subject.match(regex)]; - - for(const match of matches) - { - if (match != null) + if (node == null) + { + string js2 = @" + function MatchTest( subject, pattern, flags, matchAll ) { - console.log('%start%:' + match.index); - for(var group in match.groups) - { - var val = match.groups[group]; - if (val !== undefined) - { - val = '""' + val.replace( /""/g, '""""') + '""' - } - console.log(group + ':' + val); - } - for (var num = 0; num < match.length; num++) + const [alteredPattern, alteredFlags] = AlterRegex_JavaScript( pattern, flags ); + const regex = RegExp(alteredPattern, alteredFlags.concat(matchAll ? 'g' : '')); + const matches = matchAll ? [...subject.matchAll(regex)] : [subject.match(regex)]; + var arr = new Array(); + for (const m in matches) { - var val = match[num]; - if (val !== undefined) - { - val = '""' + val.replace( /""/g, '""""') + '""' - } - console.log(num + ':' + val); + var o = new Object(); + o.Index = m.index; + o.Named = m.groups; + o.Numbered = m; + arr.push(o); } - console.log('%end%:'); + console.log('%%begin%%'); + console.log(JSON.stringify(arr)); + console.log('%%end%%'); } - } - console.log('%done%:'); - "); + "; + + node = new Process(); + node.StartInfo.FileName = "node.exe"; + node.StartInfo.Arguments = "-i"; + node.StartInfo.RedirectStandardInput = true; + node.StartInfo.RedirectStandardOutput = true; + node.StartInfo.RedirectStandardError = true; + node.StartInfo.CreateNoWindow = true; + node.StartInfo.UseShellExecute = false; + node.StartInfo.StandardOutputEncoding = System.Text.Encoding.UTF8; - var node = new Process(); - node.StartInfo.FileName = "node.exe"; - node.StartInfo.RedirectStandardInput = true; - node.StartInfo.RedirectStandardOutput = true; - node.StartInfo.RedirectStandardError = true; - node.StartInfo.CreateNoWindow = true; - node.StartInfo.UseShellExecute = false; - node.StartInfo.StandardOutputEncoding = System.Text.Encoding.UTF8; + // Not supported by .NET framework 4.6.2, we need to use the manual GetBytes method below + // node.StartInfo.StandardInputEncoding = System.Text.Encoding.UTF8; - // Not supported by .NET framework 4.6.2, we need to use the manual GetBytes method below - // node.StartInfo.StandardInputEncoding = System.Text.Encoding.UTF8; + node.OutputDataReceived += OutputHandler; + node.ErrorDataReceived += ErrorHandler; - node.Start(); + node.Start(); + + node.BeginOutputReadLine(); + node.BeginErrorReadLine(); + + await node.StandardInput.WriteLineAsync(RegEx_JavaScript.AlterRegex_JavaScript); + await node.StandardInput.WriteLineAsync(js2); + } + + OutputSB.Clear(); + ErrorSB.Clear(); + readTask = new TaskCompletionSource(); var jsString = js.ToString(); - var bytes = Encoding.UTF8.GetBytes(RegEx_JavaScript.AlterRegex_JavaScript + jsString); - node.StandardInput.BaseStream.Write(bytes, 0, bytes.Length); - node.StandardInput.WriteLine(); - node.StandardInput.Close(); + var bytes = Encoding.UTF8.GetBytes(jsString); + await node.StandardInput.BaseStream.WriteAsync(bytes, 0, bytes.Length); + await node.StandardInput.WriteLineAsync(); - string output = node.StandardOutput.ReadToEnd(); - string error = node.StandardError.ReadToEnd(); + await node.StandardInput.FlushAsync(); - node.WaitForExit(); - node.Dispose(); + await readTask.Task; + + string output = OutputSB.ToString(); + string error = ErrorSB.ToString(); if (error.Length > 0) { throw new InvalidOperationException(error); } + int begin = output.IndexOf("%%begin%%"); + int end = output.IndexOf("%%end%%"); + string json = output.Substring(begin + 9, end - begin - 9); + + var result = JsonSerializer.Deserialize(json); var outputRE = new Regex( @" ^%start%:(?[-\d]+)$ | @@ -122,7 +174,7 @@ internal static FormulaValue Match(string subject, string pattern, string flags, Dictionary fields = new (); List allMatches = new (); - foreach (Match token in outputRE.Matches(output)) + foreach (Match token in outputRE.Matches(output.ToString())) { if (token.Groups["start"].Success) { From 5615760984a0bc79ba321f202cc7adf3c140fec5 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Mon, 21 Oct 2024 23:35:27 -0700 Subject: [PATCH 50/61] updates --- .../Localization/Strings.cs | 1 + .../Texl/Builtins/Match.cs | 23 +- src/strings/PowerFxResources.en-US.resx | 4 + .../ExpressionTestCases/Match_Limited.txt | 132 ++++- .../ExpressionTestCases/Match_Unicode.txt | 551 ++++++++++++++---- .../ExpressionTestCases/Match_V1Compat.txt | 2 +- .../Helpers/RegEx_JavaScript.cs | 70 ++- .../FileExpressionEvaluationTests.cs | 6 +- .../Helpers/LibraryRegEx_NodeJS.cs | 1 + src/tools/Repl/Program.cs | 14 +- 10 files changed, 646 insertions(+), 158 deletions(-) diff --git a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs index f95bacbbc7..a4a55fbfa3 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs @@ -739,6 +739,7 @@ internal static class TexlStrings public static ErrorResourceKey ErrInvalidRegExBadSquare = new ErrorResourceKey("ErrInvalidRegExBadSquare"); public static ErrorResourceKey ErrInvalidRegExBadParen = new ErrorResourceKey("ErrInvalidRegExBadParen"); public static ErrorResourceKey ErrInvalidRegExBadEscapeInsideCharacterClass = new ErrorResourceKey("ErrInvalidRegExBadEscapeInsideCharacterClass"); + public static ErrorResourceKey ErrInvalidRegExBadEscapeInsideNegativeCharacterClass = new ErrorResourceKey("ErrInvalidRegExBadEscapeInsideNegativeCharacterClass"); public static ErrorResourceKey ErrInvalidRegExBadEscapeOutsideCharacterClass = new ErrorResourceKey("ErrInvalidRegExBadEscapeOutsideCharacterClass"); public static ErrorResourceKey ErrInvalidRegExRepeatInCharClass = new ErrorResourceKey("ErrInvalidRegExRepeatInCharClass"); public static ErrorResourceKey ErrInvalidRegExRepeatedInlineOption = new ErrorResourceKey("ErrInvalidRegExRepeatedInlineOption"); diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index 04afc7b7c2..1bf8a97481 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -146,7 +146,9 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp "P", "Pc", "Pd", "Ps", "Pe", "Pi", "Pf", "Po", "S", "Sm", "Sc", "Sk", "So", "Z", "Zs", "Zl", "Zp", - "C", "Cc", "Cf", "Cs", "Co", "Cn", + "Cc", "Cf", + + // "C", "Cs", "Co", "Cn", are left out for now until we have a good scenario for them, as they differ between implementations }; // Limit regular expressions to common features that are supported, with consistent semantics, by both canonical .NET and XRegExp. @@ -200,7 +202,8 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter x[0-9a-fA-F]{2} | # hex character, must be exactly 2 hex digits u[0-9a-fA-F]{4})) | # Unicode characters, must be exactly 4 hex digits \\[pP]\{(?[\w=:-]+)\} | # Unicode chaeracter classes, extra characters here for a better error message - (?\\[bBWDS]) | # acceptable outside a character class, includes negative classes until we have character class subtraction, include \P for future MatchOptions.LocaleAware + (?\\[DWS]) | + (?\\[bB]) | # acceptable outside a character class, includes negative classes until we have character class subtraction, include \P for future MatchOptions.LocaleAware (?\\[\-]) | # needed for /v compatibility with ECMAScript (?\\.) | # all other escaped characters are invalid and reserved for future use @@ -248,6 +251,7 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter bool openPoundComment = false; // there is an open end-of-line pound comment, only in freeFormMode bool openInlineComment = false; // there is an open inline comment bool openCharacterClass = false; // are we defining a character class? + bool openCharacterClassNegative = false; int openCharacterClassStart = -1; foreach (Match token in tokenRE.Matches(regexPattern)) @@ -276,6 +280,14 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter return false; } } + else if (token.Groups["goodEscapeInsidePositive"].Success) + { + if (openCharacterClass && openCharacterClassNegative) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadEscapeInsideNegativeCharacterClass, token.Index >= regexPattern.Length - 5 ? regexPattern.Substring(token.Index) : regexPattern.Substring(token.Index, 5) + "..."); + return false; + } + } else if (token.Groups["goodEscapeInside"].Success) { if (!openCharacterClass) @@ -286,6 +298,12 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter } else if (token.Groups["goodUnicodeCategory"].Success) { + if (openCharacterClass && openCharacterClassNegative) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadEscapeInsideNegativeCharacterClass, token.Index >= regexPattern.Length - 5 ? regexPattern.Substring(token.Index) : regexPattern.Substring(token.Index, 5) + "..."); + return false; + } + if (!UnicodeCategories.Contains(token.Groups["goodUnicodeCategory"].Value)) { errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadUnicodeCategory, token.Value); @@ -311,6 +329,7 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter { openCharacterClassStart = token.Index; openCharacterClass = true; + openCharacterClassNegative = token.Index + 1 < regexPattern.Length && regexPattern[token.Index + 1] == '^'; } } else if (token.Groups["closeCharClass"].Success) diff --git a/src/strings/PowerFxResources.en-US.resx b/src/strings/PowerFxResources.en-US.resx index 47ff561df8..12eee9a9fe 100644 --- a/src/strings/PowerFxResources.en-US.resx +++ b/src/strings/PowerFxResources.en-US.resx @@ -4531,6 +4531,10 @@ Invalid regular expression: Escape character not permitted within character class, found "{0}". Error message indicating that the regular expression has an escape character within a character class. + + Invalid regular expression: Negative escape character not permitted within negated character class, found "{0}". + Error message indicating that the regular expression has an escape character within a negated character class. + Invalid regular expression: Escape character not permitted outside a character class, found "{0}". Error message indicating that the regular expression has an escape character outside a character class. diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt index 18bcdb178d..34ad933b15 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt @@ -513,19 +513,31 @@ Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\_" Errors: Error 35-45: Invalid regular expression: Escape character not permitted within character class, found "\b]te...".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "$test" & Char(8) & "test", "[\B]test" ) -Errors: Error 35-45: Invalid regular expression: Escape character not permitted within character class, found "[\B]te...".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 35-45: Invalid regular expression: Escape character not permitted within character class, found "\B]te...".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test123bed", "[\D]+" ) -Errors: Error 21-28: Invalid regular expression: Escape character not permitted within character class, found "[\D]+".|Error 0-5: The function 'Match' has some invalid arguments. +{FullMatch:"test",StartMatch:1} + +>> Match( "test123bed", "[^\D]+" ) +Errors: Error 21-29: Invalid regular expression: Negative escape character not permitted within negated character class, found "\D]+".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "$test" & Char(8) & "test", "[\W]test" ) -Errors: Error 35-45: Invalid regular expression: Escape character not permitted within character class, found "[\W]te...".|Error 0-5: The function 'Match' has some invalid arguments. +{FullMatch:"$test",StartMatch:1} + +>> Match( "$test" & Char(8) & "test", "[^\W]test" ) +Errors: Error 35-46: Invalid regular expression: Negative escape character not permitted within negated character class, found "\W]te...".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "$test" & Char(8) & "test", "[\S]test" ) -Errors: Error 35-45: Invalid regular expression: Escape character not permitted within character class, found "\S]te...".|Error 0-5: The function 'Match' has some invalid arguments. +{FullMatch:"$test",StartMatch:1} + +>> Match( "$test" & Char(8) & "test", "[^\S]test" ) +Errors: Error 35-46: Invalid regular expression: Negative escape character not permitted within negated character class, found "\S]te...".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "foo123test456", "[\P{L}]+" ) +{FullMatch:"123",StartMatch:4} ->> Match( "foo123test456", "[\P{L}]+" ) // would be problematic if we wanted to implement MatchOptions.LocaleAware in the future -Errors: Error 24-34: Invalid regular expression: Escape character not permitted within character class, found "\P{L}...".|Error 0-5: The function 'Match' has some invalid arguments. +>> Match( "foo123test456", "[^\P{L}]+") // would be problematic if we wanted to implement MatchOptions.LocaleAware in the future +Errors: Error 24-34: Invalid regular expression: Negative escape character not permitted within negated character class, found "\P{L}...".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "$test" & Char(8) & "test", "[\w]test" ) // \w is OK Blank() @@ -588,7 +600,7 @@ Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\&" Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\=".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "!@#%&=-`~><';:,""", "\-" ) -Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\-".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 28-32: Invalid regular expression: Escape character not permitted outside a character class, found "\-".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "!@#%&=-`~><';:,""", "\`" ) Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\`".|Error 0-5: The function 'Match' has some invalid arguments. @@ -787,6 +799,112 @@ Errors: Error 17-26: Invalid regular expression.|Error 0-5: The function 'Match' >> Match( "abcdef", "\w{2,4}+" ).FullMatch Errors: Error 17-27: Invalid regular expression.|Error 0-5: The function 'Match' has some invalid arguments.|Error 29-39: Name isn't valid. 'FullMatch' isn't recognized. +// +// UNICODE +// + +// Unicode letters as word characters are matched + +>> Match( "the whole world", "\b(\w+\s*)+" ) +{FullMatch:"the whole world",StartMatch:1} + +>> Match( "целый мир", "\b(\w+\s*)+" ) +{FullMatch:"целый мир",StartMatch:1} + +>> Match( "el niño", "\b(\w+\s*)+" ) +{FullMatch:"el niño",StartMatch:1} + +>> Match( "Müller", "^\w+$" ) +{FullMatch:"Müller",StartMatch:1} + +// Unicode numbers as digits are matched + +>> Match( "12345", "^\d+$" ) +{FullMatch:"12345",StartMatch:1} + +>> Match( "12٤45", "^\d+$" ) +{FullMatch:"12٤45",StartMatch:1} + +>> Match( "123४5", "^\d+$" ) +{FullMatch:"123४5",StartMatch:1} + +>> Match( "abc3d", "^\D+" ) +{FullMatch:"abc",StartMatch:1} + +>> Match( "abc٤45", "^\D+" ) +{FullMatch:"abc",StartMatch:1} + +>> Match( "abc४5", "^\D+" ) +{FullMatch:"abc",StartMatch:1} + +// See Match_Unicode for character class consistency tests + +>> Match( "1aBc2+", "\p{L}") +{FullMatch:"a",StartMatch:2} + +>> Match( "1Abc2+", "\p{L}") +{FullMatch:"A",StartMatch:2} + +>> Match( "aBc2+", "\P{L}") +{FullMatch:"2",StartMatch:4} + +>> Match( "1aBc2+", "\p{Ll}") +{FullMatch:"a",StartMatch:2} + +>> Match( "aBc2+", "\P{Ll}") +{FullMatch:"B",StartMatch:2} + +>> Match( "1aBc2+", "\p{Lu}") +{FullMatch:"B",StartMatch:3} + +>> Match( "Bc2+", "\P{Lu}") +{FullMatch:"c",StartMatch:2} + +>> Match( "1ῼa", "\p{Lt}" ) // Unicode Character “ῼ” (U+1FFC), Greek Capital Letter Omega with Prosgegrammeni +{FullMatch:"ῼ",StartMatch:2} + +>> Match( "ῼa", "\P{Lt}" ) // Unicode Character “ῼ” (U+1FFC), Greek Capital Letter Omega with Prosgegrammeni +{FullMatch:"a",StartMatch:2} + +>> Match( "1ˁa", "\p{Lm}" ) // Unicode Character “ˁ” (U+02C1), Modifier Letter Reversed Glottal Stop +{FullMatch:"ˁ",StartMatch:2} + +>> Match( "ˁa1", "\P{Lm}" ) // Unicode Character “ˁ” (U+02C1), Modifier Letter Reversed Glottal Stop +{FullMatch:"a",StartMatch:2} + +>> Match( "1ǂa1", "\p{Lo}" ) // Unicode Character “ǂ” (U+01C2), Latin Letter Alveolar Click +{FullMatch:"ǂ",StartMatch:2} + +>> Match( "ǂa1", "\P{Lo}" ) // Unicode Character “ǂ” (U+01C2), Latin Letter Alveolar Click +{FullMatch:"a",StartMatch:2} + +>> Match( "1҉a1", "\p{Me}" ) // Unicode Character “҉” (U+0489), Combining Cyrillic Millions Sign +{FullMatch:"҉",StartMatch:2} + +>> Match( "҉a1", "\P{Me}" ) // Unicode Character “҉” (U+0489), Combining Cyrillic Millions Sign +{FullMatch:"a",StartMatch:2} + +>> Match( "1◌̃a1", "\p{Mn}" ) // Unicode Character “◌̃” (U+0303), Combining Tilde +{FullMatch:"̃",StartMatch:3} + +>> Match( "◌̃a1", "\P{Mn}" ) // Unicode Character “◌̃” (U+0303), Combining Tilde +{FullMatch:"◌",StartMatch:1} + +>> Match( "1ைa1", "\p{Mc}" ) // Unicode Character “ை” (U+0BC8), Tamil Vowel Sign Ai +{FullMatch:"ை",StartMatch:2} + +>> Match( "ைa1", "\P{Mc}" ) // Unicode Character “ை” (U+0BC8), Tamil Vowel Sign Ai +{FullMatch:"a",StartMatch:2} + +>> Match( "1aBc2+", "\P{Cs}") +Errors: Error 17-25: Invalid regular expression: Invalid Unicode category name, found "\P{Cs}".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "1aBc2+", "\P{Co}") +Errors: Error 17-25: Invalid regular expression: Invalid Unicode category name, found "\P{Co}".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "1aBc2+", "\P{Cn}") +Errors: Error 17-25: Invalid regular expression: Invalid Unicode category name, found "\P{Cn}".|Error 0-5: The function 'Match' has some invalid arguments. + // // OTHER // diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Unicode.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Unicode.txt index 1119d1f7bb..34ec85f3c8 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Unicode.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Unicode.txt @@ -1,51 +1,17 @@ -#SETUP: RegEx,PowerFxV1CompatibilityRules,SupportColumnNamesAsIdentifiers +#SETUP: RegEx,PowerFxV1CompatibilityRules,SupportColumnNamesAsIdentifiers,DisableMemChecks // Unicode character behavior in Power Fx regular expressions. // -// Effective Usage .NET ECMAScript PCRE2 +// Effective Usage .NET ECMAScript PCRE2 Power Fx // ===================================================================================================================================== -// \p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Lm}\p{Nd}\p{Pc} \w, \W, \b, \B Yes No Yes -// \p{Nd} \d, \D Yes No Yes -// \p{Category} \p, \P Yes Yes Yes -// \p{Script} \p, \P Yes Yes Yes +// \p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Lm}\p{Nd}\p{Pc} \w, \W, \b, \B Yes No Yes Yes +// \p{Nd} \d, \D Yes No Yes Yes +// \p{Category} \p, \P Yes Yes Yes Yes +// \p{Script} \p, \P Yes Yes Yes No (syntax varies) // // We chose to use canonical .NET instead of RegexOptions.ECMAScript because we wanted the unicode definitions for words. // See https://learn.microsoft.com/dotnet/standard/base-types/regular-expression-options#ecmascript-matching-behavior for more details -// Unicode letters as word characters are matched - ->> Match( "the whole world", "\b(\w+\s*)+" ) -{FullMatch:"the whole world",StartMatch:1} - ->> Match( "целый мир", "\b(\w+\s*)+" ) -{FullMatch:"целый мир",StartMatch:1} - ->> Match( "el niño", "\b(\w+\s*)+" ) -{FullMatch:"el niño",StartMatch:1} - ->> Match( "Müller", "^\w+$" ) -{FullMatch:"Müller",StartMatch:1} - -// Unicode numbers as digits are matched - ->> Match( "12345", "^\d+$" ) -{FullMatch:"12345",StartMatch:1} - ->> Match( "12٤45", "^\d+$" ) -{FullMatch:"12٤45",StartMatch:1} - ->> Match( "123४5", "^\d+$" ) -{FullMatch:"123४5",StartMatch:1} - ->> Match( "abc3d", "^\D+" ) -{FullMatch:"abc",StartMatch:1} - ->> Match( "abc٤45", "^\D+" ) -{FullMatch:"abc",StartMatch:1} - ->> Match( "abc४5", "^\D+" ) -{FullMatch:"abc",StartMatch:1} - // Changes in case insensitive matching in .NET 7 causes different answers that are consistent with PCRE2 and Node // See https://devblogs.microsoft.com/dotnet/regular-expression-improvements-in-dotnet-7/#case-insensitive-matching-and-regexoptions-ignorecase @@ -71,122 +37,475 @@ >> Match( UniChar(Hex2Dec("2126")), "\u03a9", MatchOptions.IgnoreCase ).FullMatch "Ω" +// w +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\w" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"003_,0038,0039,0041,0042,0043,0044,0045,0046,0047,004^,005_,0058,0059,005A,005F,0061,0062,0063,0064,0065,0066,0067,006^,007_,0078,0079,007A,00AA,00B5,00BA,00C*,00D0,00D1,00D2,00D3,00D4,00D5,00D6,00D^,00E*,00F0,00F1,00F2,00F3,00F4,00F5,00F6,00F^,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C0,02C1,02C6,02C7,02C^,02D0,02D1,02E0,02E1,02E2,02E3,02E4,02EC,02EE,030*,031*,032*,033*,034*,035*,036*,0370,0371,0372,0373,0374,0376,0377,037A,037B,037C,037D,037F,0386,0388,0389,038A,038C,038E,038F,039*,03A0,03A1,03A3,03A4,03A5,03A6,03A7,03A^,03B*,03C*,03D*,03E*,03F0,03F1,03F2,03F3,03F4,03F5,03F7,03F^,040*,041*,042*,043*,044*,045*,046*,047*,0480,0481,0483,0484,0485,0486,0487,048A,048B,048C,048D,048E,048F,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,0531,0532,0533,0534,0535,0536,0537,053^,054*,0550,0551,0552,0553,0554,0555,0556,0559,056*,057*,058_,0588,0591,0592,0593,0594,0595,0596,0597,059^,05A*,05B_,05B8,05B9,05BA,05BB,05BC,05BD,05BF,05C1,05C2,05C4,05C5,05C7,05D*,05E_,05E8,05E9,05EA,05EF,05F0,05F1,05F2,061_,0618,0619,061A,062*,063*,064*,065*,066_,0668,0669,066E,066F,067*,068*,069*,06A*,06B*,06C*,06D0,06D1,06D2,06D3,06D5,06D6,06D7,06D8,06D9,06DA,06DB,06DC,06DF,06E_,06E8,06EA,06EB,06EC,06ED,06EE,06EF,06F_,06F8,06F9,06FA,06FB,06FC,06FF,071*,072*,073*,074_,0748,0749,074A,074D,074E,074F,075*,076*,077*,078*,079*,07A*,07B0,07B1,07C*,07D*,07E*,07F0,07F1,07F2,07F3,07F4,07F5,07FA,07FD,080*,081*,082_,0828,0829,082A,082B,082C,082D,084*,085_,0858,0859,085A,085B,086_,0868,0869,086A,087*,088_,0889,088A,088B,088C,088D,088E,089^,08A*,08B*,08C*,08D*,08E0,08E1,08E3,08E4,08E5,08E6,08E7,08E^,08F*,0900,0901,0902,0904,0905,0906,0907,090^,091*,092*,093_,0938,0939,093A,093C,093D,0941,0942,0943,0944,0945,0946,0947,0948,094D,095*,0960,0961,0962,0963,0966,0967,096^,0971,0972,0973,0974,0975,0976,0977,097^,0980,0981,0985,0986,0987,0988,0989,098A,098B,098C,098F,0990,0993,0994,0995,0996,0997,099^,09A_,09A8,09AA,09AB,09AC,09AD,09AE,09AF,09B0,09B2,09B6,09B7,09B8,09B9,09BC,09BD,09C1,09C2,09C3,09C4,09CD,09CE,09DC,09DD,09DF,09E0,09E1,09E2,09E3,09E6,09E7,09E^,09F0,09F1,09FC,09FE,0A01,0A02,0A05,0A06,0A07,0A08,0A09,0A0A,0A0F,0A10,0A13,0A14,0A15,0A16,0A17,0A1^,0A2_,0A28,0A2A,0A2B,0A2C,0A2D,0A2E,0A2F,0A30,0A32,0A33,0A35,0A36,0A38,0A39,0A3C,0A41,0A42,0A47,0A48,0A4B,0A4C,0A4D,0A51,0A59,0A5A,0A5B,0A5C,0A5E,0A66,0A67,0A6^,0A70,0A71,0A72,0A73,0A74,0A75,0A81,0A82,0A85,0A86,0A87,0A88,0A89,0A8A,0A8B,0A8C,0A8D,0A8F,0A90,0A91,0A93,0A94,0A95,0A96,0A97,0A9^,0AA_,0AA8,0AAA,0AAB,0AAC,0AAD,0AAE,0AAF,0AB0,0AB2,0AB3,0AB5,0AB6,0AB7,0AB8,0AB9,0ABC,0ABD,0AC1,0AC2,0AC3,0AC4,0AC5,0AC7,0AC8,0ACD,0AD0,0AE0,0AE1,0AE2,0AE3,0AE6,0AE7,0AE^,0AF9,0AFA,0AFB,0AFC,0AFD,0AFE,0AFF,0B01,0B05,0B06,0B07,0B08,0B09,0B0A,0B0B,0B0C,0B0F,0B10,0B13,0B14,0B15,0B16,0B17,0B1^,0B2_,0B28,0B2A,0B2B,0B2C,0B2D,0B2E,0B2F,0B30,0B32,0B33,0B35,0B36,0B37,0B38,0B39,0B3C,0B3D,0B3F,0B41,0B42,0B43,0B44,0B4D,0B55,0B56,0B5C,0B5D,0B5F,0B60,0B61,0B62,0B63,0B66,0B67,0B6^,0B71,0B82,0B83,0B85,0B86,0B87,0B88,0B89,0B8A,0B8E,0B8F,0B90,0B92,0B93,0B94,0B95,0B99,0B9A,0B9C,0B9E,0B9F,0BA3,0BA4,0BA8,0BA9,0BAA,0BAE,0BAF,0BB_,0BB8,0BB9,0BC0,0BCD,0BD0,0BE6,0BE7,0BE^,0C00,0C04,0C05,0C06,0C07,0C08,0C09,0C0A,0C0B,0C0C,0C0E,0C0F,0C10,0C12,0C13,0C14,0C15,0C16,0C17,0C1^,0C2_,0C28,0C2A,0C2B,0C2C,0C2D,0C2E,0C2F,0C3_,0C38,0C39,0C3C,0C3D,0C3E,0C3F,0C40,0C46,0C47,0C48,0C4A,0C4B,0C4C,0C4D,0C55,0C56,0C58,0C59,0C5A,0C5D,0C60,0C61,0C62,0C63,0C66,0C67,0C6^,0C80,0C81,0C85,0C86,0C87,0C88,0C89,0C8A,0C8B,0C8C,0C8E,0C8F,0C90,0C92,0C93,0C94,0C95,0C96,0C97,0C9^,0CA_,0CA8,0CAA,0CAB,0CAC,0CAD,0CAE,0CAF,0CB0,0CB1,0CB2,0CB3,0CB5,0CB6,0CB7,0CB8,0CB9,0CBC,0CBD,0CBF,0CC6,0CCC,0CCD,0CDD,0CDE,0CE0,0CE1,0CE2,0CE3,0CE6,0CE7,0CE^,0CF1,0CF2,0D00,0D01,0D04,0D05,0D06,0D07,0D08,0D09,0D0A,0D0B,0D0C,0D0E,0D0F,0D10,0D12,0D13,0D14,0D15,0D16,0D17,0D1^,0D2*,0D3_,0D38,0D39,0D3A,0D3B,0D3C,0D3D,0D41,0D42,0D43,0D44,0D4D,0D4E,0D54,0D55,0D56,0D5F,0D60,0D61,0D62,0D63,0D66,0D67,0D6^,0D7A,0D7B,0D7C,0D7D,0D7E,0D7F,0D81,0D85,0D86,0D87,0D8^,0D90,0D91,0D92,0D93,0D94,0D95,0D96,0D9A,0D9B,0D9C,0D9D,0D9E,0D9F,0DA*,0DB0,0DB1,0DB3,0DB4,0DB5,0DB6,0DB7,0DB8,0DB9,0DBA,0DBB,0DBD,0DC0,0DC1,0DC2,0DC3,0DC4,0DC5,0DC6,0DCA,0DD2,0DD3,0DD4,0DD6,0DE6,0DE7,0DE^,0E01,0E02,0E03,0E04,0E05,0E06,0E07,0E0^,0E1*,0E2*,0E3_,0E38,0E39,0E3A,0E4_,0E48,0E49,0E4A,0E4B,0E4C,0E4D,0E4E,0E5_,0E58,0E59,0E81,0E82,0E84,0E86,0E87,0E88,0E89,0E8A,0E8C,0E8D,0E8E,0E8F,0E9*,0EA0,0EA1,0EA2,0EA3,0EA5,0EA7,0EA^,0EB_,0EB8,0EB9,0EBA,0EBB,0EBC,0EBD,0EC0,0EC1,0EC2,0EC3,0EC4,0EC6,0EC8,0EC9,0ECA,0ECB,0ECC,0ECD,0ED_,0ED8,0ED9,0EDC,0EDD,0EDE,0EDF,0F00,0F18,0F19,0F2_,0F28,0F29,0F35,0F37,0F39,0F4_,0F49,0F4A,0F4B,0F4C,0F4D,0F4E,0F4F,0F5*,0F6_,0F68,0F69,0F6A,0F6B,0F6C,0F71,0F72,0F73,0F74,0F75,0F76,0F77,0F78,0F79,0F7A,0F7B,0F7C,0F7D,0F7E,0F80,0F81,0F82,0F83,0F84,0F86,0F87,0F8^,0F9_,0F99,0F9A,0F9B,0F9C,0F9D,0F9E,0F9F,0FA*,0FB_,0FB8,0FB9,0FBA,0FBB,0FBC,0FC6,100*,101*,102_,1028,1029,102A,102D,102E,102F,1030,1032,1033,1034,1035,1036,1037,1039,103A,103D,103E,103F,104_,1048,1049,1050,1051,1052,1053,1054,1055,105^,1060,1061,1065,1066,106E,106F,107*,1080,1081,1082,1085,1086,108D,108E,109_,1098,1099,109D,10A*,10B*,10C0,10C1,10C2,10C3,10C4,10C5,10C7,10CD,10D*,10E*,10F_,10F8,10F9,10FA,10FC,10FD,10FE,10FF,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124_,1248,124A,124B,124C,124D,1250,1251,1252,1253,1254,1255,1256,1258,125A,125B,125C,125D,126*,127*,128_,1288,128A,128B,128C,128D,129*,12A*,12B0,12B2,12B3,12B4,12B5,12B8,12B9,12BA,12BB,12BC,12BD,12BE,12C0,12C2,12C3,12C4,12C5,12C^,12D0,12D1,12D2,12D3,12D4,12D5,12D6,12D^,12E*,12F*,130*,1310,1312,1313,1314,1315,131^,132*,133*,134*,135_,1358,1359,135A,135D,135E,135F,138*,13A*,13B*,13C*,13D*,13E*,13F0,13F1,13F2,13F3,13F4,13F5,13F8,13F9,13FA,13FB,13FC,13FD,1401,1402,1403,1404,1405,1406,1407,140^,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166_,1668,1669,166A,166B,166C,166F,167*,1681,1682,1683,1684,1685,1686,1687,168^,169_,1698,1699,169A,16A*,16B*,16C*,16D*,16E_,16E8,16E9,16EA,16F1,16F2,16F3,16F4,16F5,16F6,16F7,16F8,170*,1710,1711,1712,1713,1714,171F,172*,1730,1731,1732,1733,174*,1750,1751,1752,1753,176_,1768,1769,176A,176B,176C,176E,176F,1770,1772,1773,178*,179*,17A*,17B0,17B1,17B2,17B3,17B4,17B5,17B7,17B8,17B9,17BA,17BB,17BC,17BD,17C6,17C9,17CA,17CB,17CC,17CD,17CE,17CF,17D0,17D1,17D2,17D3,17D7,17DC,17DD,17E_,17E8,17E9,180B,180C,180D,180F,181_,1818,1819,182*,183*,184*,185*,186*,187_,1878,188*,189*,18A_,18A8,18A9,18AA,18B*,18C*,18D*,18E*,18F0,18F1,18F2,18F3,18F4,18F5,190*,191_,1918,1919,191A,191B,191C,191D,191E,1920,1921,1922,1927,1928,1932,1939,193A,193B,1946,1947,194^,195*,196_,1968,1969,196A,196B,196C,196D,1970,1971,1972,1973,1974,198*,199*,19A_,19A8,19A9,19AA,19AB,19B*,19C_,19C8,19C9,19D_,19D8,19D9,1A0*,1A1_,1A18,1A1B,1A2*,1A3*,1A4*,1A50,1A51,1A52,1A53,1A54,1A56,1A58,1A59,1A5A,1A5B,1A5C,1A5D,1A5E,1A60,1A62,1A65,1A66,1A67,1A68,1A69,1A6A,1A6B,1A6C,1A73,1A74,1A75,1A76,1A77,1A78,1A79,1A7A,1A7B,1A7C,1A7F,1A8_,1A88,1A89,1A9_,1A98,1A99,1AA7,1AB_,1AB8,1AB9,1ABA,1ABB,1ABC,1ABD,1ABF,1AC_,1AC8,1AC9,1ACA,1ACB,1ACC,1ACD,1ACE,1B00,1B01,1B02,1B03,1B05,1B06,1B07,1B0^,1B1*,1B2*,1B30,1B31,1B32,1B33,1B34,1B36,1B37,1B38,1B39,1B3A,1B3C,1B42,1B45,1B46,1B47,1B48,1B49,1B4A,1B4B,1B4C,1B5_,1B58,1B59,1B6B,1B6C,1B6D,1B6E,1B6F,1B70,1B71,1B72,1B73,1B80,1B81,1B83,1B84,1B85,1B86,1B87,1B8^,1B9*,1BA0,1BA2,1BA3,1BA4,1BA5,1BA8,1BA9,1BAB,1BAC,1BAD,1BAE,1BAF,1BB*,1BC*,1BD*,1BE0,1BE1,1BE2,1BE3,1BE4,1BE5,1BE6,1BE8,1BE9,1BED,1BEF,1BF0,1BF1,1C0*,1C1*,1C20,1C21,1C22,1C23,1C2C,1C2D,1C2E,1C2F,1C30,1C31,1C32,1C33,1C36,1C37,1C4_,1C48,1C49,1C4D,1C4E,1C4F,1C5*,1C6*,1C7_,1C78,1C79,1C7A,1C7B,1C7C,1C7D,1C8_,1C88,1C9*,1CA*,1CB_,1CB8,1CB9,1CBA,1CBD,1CBE,1CBF,1CD0,1CD1,1CD2,1CD4,1CD5,1CD6,1CD7,1CD^,1CE0,1CE2,1CE3,1CE4,1CE5,1CE6,1CE7,1CE^,1CF0,1CF1,1CF2,1CF3,1CF4,1CF5,1CF6,1CF8,1CF9,1CFA,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F10,1F11,1F12,1F13,1F14,1F15,1F18,1F19,1F1A,1F1B,1F1C,1F1D,1F2*,1F3*,1F40,1F41,1F42,1F43,1F44,1F45,1F48,1F49,1F4A,1F4B,1F4C,1F4D,1F5_,1F59,1F5B,1F5D,1F5F,1F6*,1F7_,1F78,1F79,1F7A,1F7B,1F7C,1F7D,1F8*,1F9*,1FA*,1FB0,1FB1,1FB2,1FB3,1FB4,1FB6,1FB7,1FB8,1FB9,1FBA,1FBB,1FBC,1FBE,1FC2,1FC3,1FC4,1FC6,1FC7,1FC8,1FC9,1FCA,1FCB,1FCC,1FD0,1FD1,1FD2,1FD3,1FD6,1FD7,1FD8,1FD9,1FDA,1FDB,1FE_,1FE8,1FE9,1FEA,1FEB,1FEC,1FF2,1FF3,1FF4,1FF6,1FF7,1FF8,1FF9,1FFA,1FFB,1FFC,203F,2040,2054,2071,207F,209_,2098,2099,209A,209B,209C,20D_,20D8,20D9,20DA,20DB,20DC,20E1,20E5,20E6,20E7,20E^,20F0,2102,2107,210A,210B,210C,210D,210E,210F,2110,2111,2112,2113,2115,2119,211A,211B,211C,211D,2124,2126,2128,212A,212B,212C,212D,212F,213_,2138,2139,213C,213D,213E,213F,2145,2146,2147,2148,2149,214E,2183,2184,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE0,2CE1,2CE2,2CE3,2CE4,2CEB,2CEC,2CED,2CEE,2CEF,2CF0,2CF1,2CF2,2CF3,2D0*,2D1*,2D20,2D21,2D22,2D23,2D24,2D25,2D27,2D2D,2D3*,2D4*,2D5*,2D6_,2D6F,2D7F,2D8*,2D90,2D91,2D92,2D93,2D94,2D95,2D96,2DA0,2DA1,2DA2,2DA3,2DA4,2DA5,2DA6,2DA8,2DA9,2DAA,2DAB,2DAC,2DAD,2DAE,2DB0,2DB1,2DB2,2DB3,2DB4,2DB5,2DB6,2DB8,2DB9,2DBA,2DBB,2DBC,2DBD,2DBE,2DC0,2DC1,2DC2,2DC3,2DC4,2DC5,2DC6,2DC8,2DC9,2DCA,2DCB,2DCC,2DCD,2DCE,2DD0,2DD1,2DD2,2DD3,2DD4,2DD5,2DD6,2DD8,2DD9,2DDA,2DDB,2DDC,2DDD,2DDE,2DE*,2DF*,2E2F,3005,3006,302A,302B,302C,302D,3031,3032,3033,3034,3035,303B,303C,3041,3042,3043,3044,3045,3046,3047,304^,305*,306*,307*,308*,3090,3091,3092,3093,3094,3095,3096,3099,309A,309D,309E,309F,30A1,30A2,30A3,30A4,30A5,30A6,30A7,30A^,30B*,30C*,30D*,30E*,30F_,30F8,30F9,30FA,30FC,30FD,30FE,30FF,3105,3106,3107,310^,311*,312*,3131,3132,3133,3134,3135,3136,3137,313^,314*,315*,316*,317*,318_,3188,3189,318A,318B,318C,318D,318E,31A*,31B*,31F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\W" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003A,003B,003C,003D,003E,003F,0040,005B,005C,005D,005E,0060,007B,007C,007D,007E,007F,008*,009*,00A_,00A8,00A9,00AB,00AC,00AD,00AE,00AF,00B0,00B1,00B2,00B3,00B4,00B6,00B7,00B8,00B9,00BB,00BC,00BD,00BE,00BF,00D7,00F7,02C2,02C3,02C4,02C5,02D2,02D3,02D4,02D5,02D6,02D7,02D^,02E5,02E6,02E7,02E8,02E9,02EA,02EB,02ED,02EF,02F*,0375,0378,0379,037E,0380,0381,0382,0383,0384,0385,0387,038B,038D,03A2,03F6,0482,0488,0489,0530,0557,0558,055A,055B,055C,055D,055E,055F,0589,058A,058B,058C,058D,058E,058F,0590,05BE,05C0,05C3,05C6,05C^,05EB,05EC,05ED,05EE,05F3,05F4,05F5,05F6,05F7,05F^,060*,061B,061C,061D,061E,061F,066A,066B,066C,066D,06D4,06DD,06DE,06E9,06FD,06FE,070*,074B,074C,07B2,07B3,07B4,07B5,07B6,07B7,07B^,07F6,07F7,07F8,07F9,07FB,07FC,07FE,07FF,082E,082F,083*,085C,085D,085E,085F,086B,086C,086D,086E,086F,0888,088F,089_,08E2,0903,093B,093E,093F,0940,0949,094A,094B,094C,094E,094F,0964,0965,0970,0982,0983,0984,098D,098E,0991,0992,09A9,09B1,09B3,09B4,09B5,09BA,09BB,09BE,09BF,09C0,09C5,09C6,09C7,09C8,09C9,09CA,09CB,09CC,09CF,09D_,09D8,09D9,09DA,09DB,09DE,09E4,09E5,09F2,09F3,09F4,09F5,09F6,09F7,09F8,09F9,09FA,09FB,09FD,09FF,0A00,0A03,0A04,0A0B,0A0C,0A0D,0A0E,0A11,0A12,0A29,0A31,0A34,0A37,0A3A,0A3B,0A3D,0A3E,0A3F,0A40,0A43,0A44,0A45,0A46,0A49,0A4A,0A4E,0A4F,0A50,0A52,0A53,0A54,0A55,0A56,0A57,0A58,0A5D,0A5F,0A60,0A61,0A62,0A63,0A64,0A65,0A76,0A77,0A7^,0A80,0A83,0A84,0A8E,0A92,0AA9,0AB1,0AB4,0ABA,0ABB,0ABE,0ABF,0AC0,0AC6,0AC9,0ACA,0ACB,0ACC,0ACE,0ACF,0AD1,0AD2,0AD3,0AD4,0AD5,0AD6,0AD7,0AD^,0AE4,0AE5,0AF_,0AF8,0B00,0B02,0B03,0B04,0B0D,0B0E,0B11,0B12,0B29,0B31,0B34,0B3A,0B3B,0B3E,0B40,0B45,0B46,0B47,0B48,0B49,0B4A,0B4B,0B4C,0B4E,0B4F,0B50,0B51,0B52,0B53,0B54,0B57,0B58,0B59,0B5A,0B5B,0B5E,0B64,0B65,0B70,0B72,0B73,0B74,0B75,0B76,0B77,0B7^,0B80,0B81,0B84,0B8B,0B8C,0B8D,0B91,0B96,0B97,0B98,0B9B,0B9D,0BA0,0BA1,0BA2,0BA5,0BA6,0BA7,0BAB,0BAC,0BAD,0BBA,0BBB,0BBC,0BBD,0BBE,0BBF,0BC1,0BC2,0BC3,0BC4,0BC5,0BC6,0BC7,0BC8,0BC9,0BCA,0BCB,0BCC,0BCE,0BCF,0BD1,0BD2,0BD3,0BD4,0BD5,0BD6,0BD7,0BD^,0BE0,0BE1,0BE2,0BE3,0BE4,0BE5,0BF*,0C01,0C02,0C03,0C0D,0C11,0C29,0C3A,0C3B,0C41,0C42,0C43,0C44,0C45,0C49,0C4E,0C4F,0C50,0C51,0C52,0C53,0C54,0C57,0C5B,0C5C,0C5E,0C5F,0C64,0C65,0C7*,0C82,0C83,0C84,0C8D,0C91,0CA9,0CB4,0CBA,0CBB,0CBE,0CC0,0CC1,0CC2,0CC3,0CC4,0CC5,0CC7,0CC8,0CC9,0CCA,0CCB,0CCE,0CCF,0CD_,0CD8,0CD9,0CDA,0CDB,0CDC,0CDF,0CE4,0CE5,0CF0,0CF3,0CF4,0CF5,0CF6,0CF7,0CF^,0D02,0D03,0D0D,0D11,0D3E,0D3F,0D40,0D45,0D46,0D47,0D48,0D49,0D4A,0D4B,0D4C,0D4F,0D50,0D51,0D52,0D53,0D57,0D58,0D59,0D5A,0D5B,0D5C,0D5D,0D5E,0D64,0D65,0D7_,0D78,0D79,0D80,0D82,0D83,0D84,0D97,0D98,0D99,0DB2,0DBC,0DBE,0DBF,0DC7,0DC8,0DC9,0DCB,0DCC,0DCD,0DCE,0DCF,0DD0,0DD1,0DD5,0DD7,0DD^,0DE0,0DE1,0DE2,0DE3,0DE4,0DE5,0DF*,0E00,0E3B,0E3C,0E3D,0E3E,0E3F,0E4F,0E5A,0E5B,0E5C,0E5D,0E5E,0E5F,0E6*,0E7*,0E80,0E83,0E85,0E8B,0EA4,0EA6,0EBE,0EBF,0EC5,0EC7,0ECE,0ECF,0EDA,0EDB,0EE*,0EF*,0F01,0F02,0F03,0F04,0F05,0F06,0F07,0F0^,0F1_,0F1A,0F1B,0F1C,0F1D,0F1E,0F1F,0F2A,0F2B,0F2C,0F2D,0F2E,0F2F,0F30,0F31,0F32,0F33,0F34,0F36,0F38,0F3A,0F3B,0F3C,0F3D,0F3E,0F3F,0F48,0F6D,0F6E,0F6F,0F70,0F7F,0F85,0F98,0FBD,0FBE,0FBF,0FC0,0FC1,0FC2,0FC3,0FC4,0FC5,0FC7,0FC^,0FD*,0FE*,0FF*,102B,102C,1031,1038,103B,103C,104A,104B,104C,104D,104E,104F,1056,1057,1062,1063,1064,1067,1068,1069,106A,106B,106C,106D,1083,1084,1087,1088,1089,108A,108B,108C,108F,109A,109B,109C,109E,109F,10C6,10C8,10C9,10CA,10CB,10CC,10CE,10CF,10FB,1249,124E,124F,1257,1259,125E,125F,1289,128E,128F,12B1,12B6,12B7,12BF,12C1,12C6,12C7,12D7,1311,1316,1317,135B,135C,136*,137*,139*,13F6,13F7,13FE,13FF,1400,166D,166E,1680,169B,169C,169D,169E,169F,16EB,16EC,16ED,16EE,16EF,16F0,16F9,16FA,16FB,16FC,16FD,16FE,16FF,1715,1716,1717,1718,1719,171A,171B,171C,171D,171E,1734,1735,1736,1737,173^,1754,1755,1756,1757,175^,176D,1771,1774,1775,1776,1777,177^,17B6,17BE,17BF,17C0,17C1,17C2,17C3,17C4,17C5,17C7,17C8,17D4,17D5,17D6,17D8,17D9,17DA,17DB,17DE,17DF,17EA,17EB,17EC,17ED,17EE,17EF,17F*,180_,1808,1809,180A,180E,181A,181B,181C,181D,181E,181F,1879,187A,187B,187C,187D,187E,187F,18AB,18AC,18AD,18AE,18AF,18F6,18F7,18F^,191F,1923,1924,1925,1926,1929,192A,192B,192C,192D,192E,192F,1930,1931,1933,1934,1935,1936,1937,1938,193C,193D,193E,193F,1940,1941,1942,1943,1944,1945,196E,196F,1975,1976,1977,197^,19AC,19AD,19AE,19AF,19CA,19CB,19CC,19CD,19CE,19CF,19DA,19DB,19DC,19DD,19DE,19DF,19E*,19F*,1A19,1A1A,1A1C,1A1D,1A1E,1A1F,1A55,1A57,1A5F,1A61,1A63,1A64,1A6D,1A6E,1A6F,1A70,1A71,1A72,1A7D,1A7E,1A8A,1A8B,1A8C,1A8D,1A8E,1A8F,1A9A,1A9B,1A9C,1A9D,1A9E,1A9F,1AA0,1AA1,1AA2,1AA3,1AA4,1AA5,1AA6,1AA^,1ABE,1ACF,1AD*,1AE*,1AF*,1B04,1B35,1B3B,1B3D,1B3E,1B3F,1B40,1B41,1B43,1B44,1B4D,1B4E,1B4F,1B5A,1B5B,1B5C,1B5D,1B5E,1B5F,1B6_,1B68,1B69,1B6A,1B74,1B75,1B76,1B77,1B7^,1B82,1BA1,1BA6,1BA7,1BAA,1BE7,1BEA,1BEB,1BEC,1BEE,1BF2,1BF3,1BF4,1BF5,1BF6,1BF7,1BF^,1C24,1C25,1C26,1C27,1C28,1C29,1C2A,1C2B,1C34,1C35,1C3^,1C4A,1C4B,1C4C,1C7E,1C7F,1C89,1C8A,1C8B,1C8C,1C8D,1C8E,1C8F,1CBB,1CBC,1CC*,1CD3,1CE1,1CF7,1CFB,1CFC,1CFD,1CFE,1CFF,1F16,1F17,1F1E,1F1F,1F46,1F47,1F4E,1F4F,1F58,1F5A,1F5C,1F5E,1F7E,1F7F,1FB5,1FBD,1FBF,1FC0,1FC1,1FC5,1FCD,1FCE,1FCF,1FD4,1FD5,1FDC,1FDD,1FDE,1FDF,1FED,1FEE,1FEF,1FF0,1FF1,1FF5,1FFD,1FFE,1FFF,200*,201*,202*,203_,2038,2039,203A,203B,203C,203D,203E,2041,2042,2043,2044,2045,2046,2047,204^,2050,2051,2052,2053,2055,2056,2057,205^,206*,2070,2072,2073,2074,2075,2076,2077,2078,2079,207A,207B,207C,207D,207E,208*,209D,209E,209F,20A*,20B*,20C*,20DD,20DE,20DF,20E0,20E2,20E3,20E4,20F1,20F2,20F3,20F4,20F5,20F6,20F7,20F^,2100,2101,2103,2104,2105,2106,2108,2109,2114,2116,2117,2118,211E,211F,2120,2121,2122,2123,2125,2127,2129,212E,213A,213B,2140,2141,2142,2143,2144,214A,214B,214C,214D,214F,215*,216*,217*,2180,2181,2182,2185,2186,2187,218^,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2CE5,2CE6,2CE7,2CE8,2CE9,2CEA,2CF4,2CF5,2CF6,2CF7,2CF^,2D26,2D28,2D29,2D2A,2D2B,2D2C,2D2E,2D2F,2D68,2D69,2D6A,2D6B,2D6C,2D6D,2D6E,2D7_,2D78,2D79,2D7A,2D7B,2D7C,2D7D,2D7E,2D97,2D9^,2DA7,2DAF,2DB7,2DBF,2DC7,2DCF,2DD7,2DDF,2E0*,2E1*,2E2_,2E28,2E29,2E2A,2E2B,2E2C,2E2D,2E2E,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,3000,3001,3002,3003,3004,3007,300^,301*,302_,3028,3029,302E,302F,3030,3036,3037,3038,3039,303A,303D,303E,303F,3040,3097,3098,309B,309C,30A0,30FB,3100,3101,3102,3103,3104,3130,318F,319*,31C*,31D*,31E*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*," + +// d +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\d" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"003_,0038,0039,066_,0668,0669,06F_,06F8,06F9,07C_,07C8,07C9,0966,0967,096^,09E6,09E7,09E^,0A66,0A67,0A6^,0AE6,0AE7,0AE^,0B66,0B67,0B6^,0BE6,0BE7,0BE^,0C66,0C67,0C6^,0CE6,0CE7,0CE^,0D66,0D67,0D6^,0DE6,0DE7,0DE^,0E5_,0E58,0E59,0ED_,0ED8,0ED9,0F2_,0F28,0F29,104_,1048,1049,109_,1098,1099,17E_,17E8,17E9,181_,1818,1819,1946,1947,194^,19D_,19D8,19D9,1A8_,1A88,1A89,1A9_,1A98,1A99,1B5_,1B58,1B59,1BB_,1BB8,1BB9,1C4_,1C48,1C49,1C5_,1C58,1C59," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\D" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003A,003B,003C,003D,003E,003F,004*,005*,006*,007*,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066A,066B,066C,066D,066E,066F,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06FA,06FB,06FC,06FD,06FE,06FF,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07CA,07CB,07CC,07CD,07CE,07CF,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,0960,0961,0962,0963,0964,0965,097*,098*,099*,09A*,09B*,09C*,09D*,09E0,09E1,09E2,09E3,09E4,09E5,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A60,0A61,0A62,0A63,0A64,0A65,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE0,0AE1,0AE2,0AE3,0AE4,0AE5,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B60,0B61,0B62,0B63,0B64,0B65,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE0,0BE1,0BE2,0BE3,0BE4,0BE5,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C60,0C61,0C62,0C63,0C64,0C65,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE0,0CE1,0CE2,0CE3,0CE4,0CE5,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D60,0D61,0D62,0D63,0D64,0D65,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE0,0DE1,0DE2,0DE3,0DE4,0DE5,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5A,0E5B,0E5C,0E5D,0E5E,0E5F,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0EDA,0EDB,0EDC,0EDD,0EDE,0EDF,0EE*,0EF*,0F0*,0F1*,0F2A,0F2B,0F2C,0F2D,0F2E,0F2F,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104A,104B,104C,104D,104E,104F,105*,106*,107*,108*,109A,109B,109C,109D,109E,109F,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17EA,17EB,17EC,17ED,17EE,17EF,17F*,180*,181A,181B,181C,181D,181E,181F,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,1940,1941,1942,1943,1944,1945,195*,196*,197*,198*,199*,19A*,19B*,19C*,19DA,19DB,19DC,19DD,19DE,19DF,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8A,1A8B,1A8C,1A8D,1A8E,1A8F,1A9A,1A9B,1A9C,1A9D,1A9E,1A9F,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5A,1B5B,1B5C,1B5D,1B5E,1B5F,1B6*,1B7*,1B8*,1B9*,1BA*,1BBA,1BBB,1BBC,1BBD,1BBE,1BBF,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4A,1C4B,1C4C,1C4D,1C4E,1C4F,1C5A,1C5B,1C5C,1C5D,1C5E,1C5F,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," + +// s +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\s" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0009,000A,000B,000C,000D,0020,0085,00A0,1680,200_,2008,2009,200A,2028,2029,202F,205F,3000," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\S" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,0008,000E,000F,001*,0021,0022,0023,0024,0025,0026,0027,002^,003*,004*,005*,006*,007*,0080,0081,0082,0083,0084,0086,0087,008^,009*,00A1,00A2,00A3,00A4,00A5,00A6,00A7,00A^,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,1681,1682,1683,1684,1685,1686,1687,168^,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200B,200C,200D,200E,200F,201*,202_,202A,202B,202C,202D,202E,203*,204*,205_,2058,2059,205A,205B,205C,205D,205E,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,3001,3002,3003,3004,3005,3006,3007,300^,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," + // L ->> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, - If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{L}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, - If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) -"0041,0042,0043,0044,0045,0046,0047,0048-004F,0050-0057,0058,0059,005A,0061,0062,0063,0064,0065,0066,0067,0068-006F,0070-0077,0078,0079,007A,00AA,00B5,00BA,00C0-00C7,00C8-00CF,00D0,00D1,00D2,00D3,00D4,00D5,00D6,00D8-00DF,00E0-00E7,00E8-00EF,00F0,00F1,00F2,00F3,00F4,00F5,00F6,00F8-00FF,0100-0107,0108-010F,0110-0117,0118-011F,0120-0127,0128-012F,0130-0137,0138-013F,0140-0147,0148-014F,0150-0157,0158-015F,0160-0167,0168-016F,0170-0177,0178-017F,0180-0187,0188-018F,0190-0197,0198-019F,01A0-01A7,01A8-01AF,01B0-01B7,01B8-01BF,01C0-01C7,01C8-01CF,01D0-01D7,01D8-01DF,01E0-01E7,01E8-01EF,01F0-01F7,01F8-01FF,0200-0207,0208-020F,0210-0217,0218-021F,0220-0227,0228-022F,0230-0237,0238-023F,0240-0247,0248-024F,0250-0257,0258-025F,0260-0267,0268-026F,0270-0277,0278-027F,0280-0287,0288-028F,0290-0297,0298-029F,02A0-02A7,02A8-02AF,02B0-02B7,02B8-02BF,02C0,02C1,02C6,02C7,02C8-02CF,02D0,02D1,02E0,02E1,02E2,02E3,02E4,02EC,02EE,0370,0371,0372,0373,0374,0376,0377,037A,037B,037C,037D,037F,0386,0388,0389,038A,038C,038E,038F,0390-0397,0398-039F,03A0,03A1,03A3,03A4,03A5,03A6,03A7,03A8-03AF,03B0-03B7,03B8-03BF,03C0-03C7,03C8-03CF,03D0-03D7,03D8-03DF,03E0-03E7,03E8-03EF,03F0,03F1,03F2,03F3,03F4,03F5,03F7,03F8-03FF,0400-0407,0408-040F,0410-0417,0418-041F,0420-0427,0428-042F,0430-0437,0438-043F,0440-0447,0448-044F,0450-0457,0458-045F,0460-0467,0468-046F,0470-0477,0478-047F,0480,0481,048A,048B,048C,048D,048E,048F,0490-0497,0498-049F,04A0-04A7,04A8-04AF,04B0-04B7,04B8-04BF,04C0-04C7,04C8-04CF,04D0-04D7,04D8-04DF,04E0-04E7,04E8-04EF,04F0-04F7,04F8-04FF,0500-0507,0508-050F,0510-0517,0518-051F,0520-0527,0528-052F,0531,0532,0533,0534,0535,0536,0537,0538-053F,0540-0547,0548-054F,0550,0551,0552,0553,0554,0555,0556,0559,0560-0567,0568-056F,0570-0577,0578-057F,0580-0587,0588,05D0-05D7,05D8-05DF,05E0-05E7,05E8,05E9,05EA,05EF,05F0,05F1,05F2,0620-0627,0628-062F,0630-0637,0638-063F,0640-0647,0648,0649,064A,066E,066F,0671,0672,0673,0674,0675,0676,0677,0678-067F,0680-0687,0688-068F,0690-0697,0698-069F,06A0-06A7,06A8-06AF,06B0-06B7,06B8-06BF,06C0-06C7,06C8-06CF,06D0,06D1,06D2,06D3,06D5,06E5,06E6,06EE,06EF,06FA,06FB,06FC,06FF,0710,0712,0713,0714,0715,0716,0717,0718-071F,0720-0727,0728-072F,074D,074E,074F,0750-0757,0758-075F,0760-0767,0768-076F,0770-0777,0778-077F,0780-0787,0788-078F,0790-0797,0798-079F,07A0,07A1,07A2,07A3,07A4,07A5,07B1,07CA,07CB,07CC,07CD,07CE,07CF,07D0-07D7,07D8-07DF,07E0-07E7,07E8,07E9,07EA,07F4,07F5,07FA,0800-0807,0808-080F,0810,0811,0812,0813,0814,0815,081A,0824,0828,0840-0847,0848-084F,0850-0857,0858,0860-0867,0868,0869,086A,0870-0877,0878-087F,0880-0887,0889,088A,088B,088C,088D,088E,08A0-08A7,08A8-08AF,08B0-08B7,08B8-08BF,08C0-08C7,08C8,08C9,0904,0905,0906,0907,0908-090F,0910-0917,0918-091F,0920-0927,0928-092F,0930-0937,0938,0939,093D,0950,0958-095F,0960,0961,0971,0972,0973,0974,0975,0976,0977,0978-097F,0980,0985,0986,0987,0988,0989,098A,098B,098C,098F,0990,0993,0994,0995,0996,0997,0998-099F,09A0-09A7,09A8,09AA,09AB,09AC,09AD,09AE,09AF,09B0,09B2,09B6,09B7,09B8,09B9,09BD,09CE,09DC,09DD,09DF,09E0,09E1,09F0,09F1,09FC,0A05,0A06,0A07,0A08,0A09,0A0A,0A0F,0A10,0A13,0A14,0A15,0A16,0A17,0A18-0A1F,0A20-0A27,0A28,0A2A,0A2B,0A2C,0A2D,0A2E,0A2F,0A30,0A32,0A33,0A35,0A36,0A38,0A39,0A59,0A5A,0A5B,0A5C,0A5E,0A72,0A73,0A74,0A85,0A86,0A87,0A88,0A89,0A8A,0A8B,0A8C,0A8D,0A8F,0A90,0A91,0A93,0A94,0A95,0A96,0A97,0A98-0A9F,0AA0-0AA7,0AA8,0AAA,0AAB,0AAC,0AAD,0AAE,0AAF,0AB0,0AB2,0AB3,0AB5,0AB6,0AB7,0AB8,0AB9,0ABD,0AD0,0AE0,0AE1,0AF9,0B05,0B06,0B07,0B08,0B09,0B0A,0B0B,0B0C,0B0F,0B10,0B13,0B14,0B15,0B16,0B17,0B18-0B1F,0B20-0B27,0B28,0B2A,0B2B,0B2C,0B2D,0B2E,0B2F,0B30,0B32,0B33,0B35,0B36,0B37,0B38,0B39,0B3D,0B5C,0B5D,0B5F,0B60,0B61,0B71,0B83,0B85,0B86,0B87,0B88,0B89,0B8A,0B8E,0B8F,0B90,0B92,0B93,0B94,0B95,0B99,0B9A,0B9C,0B9E,0B9F,0BA3,0BA4,0BA8,0BA9,0BAA,0BAE,0BAF,0BB0-0BB7,0BB8,0BB9,0BD0,0C05,0C06,0C07,0C08,0C09,0C0A,0C0B,0C0C,0C0E,0C0F,0C10,0C12,0C13,0C14,0C15,0C16,0C17,0C18-0C1F,0C20-0C27,0C28,0C2A,0C2B,0C2C,0C2D,0C2E,0C2F,0C30-0C37,0C38,0C39,0C3D,0C58,0C59,0C5A,0C5D,0C60,0C61,0C80,0C85,0C86,0C87,0C88,0C89,0C8A,0C8B,0C8C,0C8E,0C8F,0C90,0C92,0C93,0C94,0C95,0C96,0C97,0C98-0C9F,0CA0-0CA7,0CA8,0CAA,0CAB,0CAC,0CAD,0CAE,0CAF,0CB0,0CB1,0CB2,0CB3,0CB5,0CB6,0CB7,0CB8,0CB9,0CBD,0CDD,0CDE,0CE0,0CE1,0CF1,0CF2,0D04,0D05,0D06,0D07,0D08,0D09,0D0A,0D0B,0D0C,0D0E,0D0F,0D10,0D12,0D13,0D14,0D15,0D16,0D17,0D18-0D1F,0D20-0D27,0D28-0D2F,0D30-0D37,0D38,0D39,0D3A,0D3D,0D4E,0D54,0D55,0D56,0D5F,0D60,0D61,0D7A,0D7B,0D7C,0D7D,0D7E,0D7F,0D85,0D86,0D87,0D88-0D8F,0D90,0D91,0D92,0D93,0D94,0D95,0D96,0D9A,0D9B,0D9C,0D9D,0D9E,0D9F,0DA0-0DA7,0DA8-0DAF,0DB0,0DB1,0DB3,0DB4,0DB5,0DB6,0DB7,0DB8,0DB9,0DBA,0DBB,0DBD,0DC0,0DC1,0DC2,0DC3,0DC4,0DC5,0DC6,0E01,0E02,0E03,0E04,0E05,0E06,0E07,0E08-0E0F,0E10-0E17,0E18-0E1F,0E20-0E27,0E28-0E2F,0E30,0E32,0E33,0E40,0E41,0E42,0E43,0E44,0E45,0E46,0E81,0E82,0E84,0E86,0E87,0E88,0E89,0E8A,0E8C,0E8D,0E8E,0E8F,0E90-0E97,0E98-0E9F,0EA0,0EA1,0EA2,0EA3,0EA5,0EA7,0EA8-0EAF,0EB0,0EB2,0EB3,0EBD,0EC0,0EC1,0EC2,0EC3,0EC4,0EC6,0EDC,0EDD,0EDE,0EDF,0F00,0F40-0F47,0F49,0F4A,0F4B,0F4C,0F4D,0F4E,0F4F,0F50-0F57,0F58-0F5F,0F60-0F67,0F68,0F69,0F6A,0F6B,0F6C,0F88,0F89,0F8A,0F8B,0F8C,1000-1007,1008-100F,1010-1017,1018-101F,1020-1027,1028,1029,102A,103F,1050,1051,1052,1053,1054,1055,105A,105B,105C,105D,1061,1065,1066,106E,106F,1070,1075,1076,1077,1078-107F,1080,1081,108E,10A0-10A7,10A8-10AF,10B0-10B7,10B8-10BF,10C0,10C1,10C2,10C3,10C4,10C5,10C7,10CD,10D0-10D7,10D8-10DF,10E0-10E7,10E8-10EF,10F0-10F7,10F8,10F9,10FA,10FC,10FD,10FE,10FF,1100-1107,1108-110F,1110-1117,1118-111F,1120-1127,1128-112F,1130-1137,1138-113F,1140-1147,1148-114F,1150-1157,1158-115F,1160-1167,1168-116F,1170-1177,1178-117F,1180-1187,1188-118F,1190-1197,1198-119F,11A0-11A7,11A8-11AF,11B0-11B7,11B8-11BF,11C0-11C7,11C8-11CF,11D0-11D7,11D8-11DF,11E0-11E7,11E8-11EF,11F0-11F7,11F8-11FF,1200-1207,1208-120F,1210-1217,1218-121F,1220-1227,1228-122F,1230-1237,1238-123F,1240-1247,1248,124A,124B,124C,124D,1250,1251,1252,1253,1254,1255,1256,1258,125A,125B,125C,125D,1260-1267,1268-126F,1270-1277,1278-127F,1280-1287,1288,128A,128B,128C,128D,1290-1297,1298-129F,12A0-12A7,12A8-12AF,12B0,12B2,12B3,12B4,12B5,12B8,12B9,12BA,12BB,12BC,12BD,12BE,12C0,12C2,12C3,12C4,12C5,12C8-12CF,12D0,12D1,12D2,12D3,12D4,12D5,12D6,12D8-12DF,12E0-12E7,12E8-12EF,12F0-12F7,12F8-12FF,1300-1307,1308-130F,1310,1312,1313,1314,1315,1318-131F,1320-1327,1328-132F,1330-1337,1338-133F,1340-1347,1348-134F,1350-1357,1358,1359,135A,1380-1387,1388-138F,13A0-13A7,13A8-13AF,13B0-13B7,13B8-13BF,13C0-13C7,13C8-13CF,13D0-13D7,13D8-13DF,13E0-13E7,13E8-13EF,13F0,13F1,13F2,13F3,13F4,13F5,13F8,13F9,13FA,13FB,13FC,13FD,1401,1402,1403,1404,1405,1406,1407,1408-140F,1410-1417,1418-141F,1420-1427,1428-142F,1430-1437,1438-143F,1440-1447,1448-144F,1450-1457,1458-145F,1460-1467,1468-146F,1470-1477,1478-147F,1480-1487,1488-148F,1490-1497,1498-149F,14A0-14A7,14A8-14AF,14B0-14B7,14B8-14BF,14C0-14C7,14C8-14CF,14D0-14D7,14D8-14DF,14E0-14E7,14E8-14EF,14F0-14F7,14F8-14FF,1500-1507,1508-150F,1510-1517,1518-151F,1520-1527,1528-152F,1530-1537,1538-153F,1540-1547,1548-154F,1550-1557,1558-155F,1560-1567,1568-156F,1570-1577,1578-157F,1580-1587,1588-158F,1590-1597,1598-159F,15A0-15A7,15A8-15AF,15B0-15B7,15B8-15BF,15C0-15C7,15C8-15CF,15D0-15D7,15D8-15DF,15E0-15E7,15E8-15EF,15F0-15F7,15F8-15FF,1600-1607,1608-160F,1610-1617,1618-161F,1620-1627,1628-162F,1630-1637,1638-163F,1640-1647,1648-164F,1650-1657,1658-165F,1660-1667,1668,1669,166A,166B,166C,166F,1670-1677,1678-167F,1681,1682,1683,1684,1685,1686,1687,1688-168F,1690-1697,1698,1699,169A,16A0-16A7,16A8-16AF,16B0-16B7,16B8-16BF,16C0-16C7,16C8-16CF,16D0-16D7,16D8-16DF,16E0-16E7,16E8,16E9,16EA,16F1,16F2,16F3,16F4,16F5,16F6,16F7,16F8,1700-1707,1708-170F,1710,1711,171F,1720-1727,1728-172F,1730,1731,1740-1747,1748-174F,1750,1751,1760-1767,1768,1769,176A,176B,176C,176E,176F,1770,1780-1787,1788-178F,1790-1797,1798-179F,17A0-17A7,17A8-17AF,17B0,17B1,17B2,17B3,17D7,17DC,1820-1827,1828-182F,1830-1837,1838-183F,1840-1847,1848-184F,1850-1857,1858-185F,1860-1867,1868-186F,1870-1877,1878,1880,1881,1882,1883,1884,1887,1888-188F,1890-1897,1898-189F,18A0-18A7,18A8,18AA,18B0-18B7,18B8-18BF,18C0-18C7,18C8-18CF,18D0-18D7,18D8-18DF,18E0-18E7,18E8-18EF,18F0,18F1,18F2,18F3,18F4,18F5,1900-1907,1908-190F,1910-1917,1918,1919,191A,191B,191C,191D,191E,1950-1957,1958-195F,1960-1967,1968,1969,196A,196B,196C,196D,1970,1971,1972,1973,1974,1980-1987,1988-198F,1990-1997,1998-199F,19A0-19A7,19A8,19A9,19AA,19AB,19B0-19B7,19B8-19BF,19C0-19C7,19C8,19C9,1A00-1A07,1A08-1A0F,1A10,1A11,1A12,1A13,1A14,1A15,1A16,1A20-1A27,1A28-1A2F,1A30-1A37,1A38-1A3F,1A40-1A47,1A48-1A4F,1A50,1A51,1A52,1A53,1A54,1AA7,1B05,1B06,1B07,1B08-1B0F,1B10-1B17,1B18-1B1F,1B20-1B27,1B28-1B2F,1B30,1B31,1B32,1B33,1B45,1B46,1B47,1B48,1B49,1B4A,1B4B,1B4C,1B83,1B84,1B85,1B86,1B87,1B88-1B8F,1B90-1B97,1B98-1B9F,1BA0,1BAE,1BAF,1BBA,1BBB,1BBC,1BBD,1BBE,1BBF,1BC0-1BC7,1BC8-1BCF,1BD0-1BD7,1BD8-1BDF,1BE0,1BE1,1BE2,1BE3,1BE4,1BE5,1C00-1C07,1C08-1C0F,1C10-1C17,1C18-1C1F,1C20,1C21,1C22,1C23,1C4D,1C4E,1C4F,1C5A,1C5B,1C5C,1C5D,1C5E,1C5F,1C60-1C67,1C68-1C6F,1C70-1C77,1C78,1C79,1C7A,1C7B,1C7C,1C7D,1C80-1C87,1C88,1C90-1C97,1C98-1C9F,1CA0-1CA7,1CA8-1CAF,1CB0-1CB7,1CB8,1CB9,1CBA,1CBD,1CBE,1CBF,1CE9,1CEA,1CEB,1CEC,1CEE,1CEF,1CF0,1CF1,1CF2,1CF3,1CF5,1CF6,1CFA,1D00-1D07,1D08-1D0F,1D10-1D17,1D18-1D1F,1D20-1D27,1D28-1D2F,1D30-1D37,1D38-1D3F,1D40-1D47,1D48-1D4F,1D50-1D57,1D58-1D5F,1D60-1D67,1D68-1D6F,1D70-1D77,1D78-1D7F,1D80-1D87,1D88-1D8F,1D90-1D97,1D98-1D9F,1DA0-1DA7,1DA8-1DAF,1DB0-1DB7,1DB8-1DBF,1E00-1E07,1E08-1E0F,1E10-1E17,1E18-1E1F,1E20-1E27,1E28-1E2F,1E30-1E37,1E38-1E3F,1E40-1E47,1E48-1E4F,1E50-1E57,1E58-1E5F,1E60-1E67,1E68-1E6F,1E70-1E77,1E78-1E7F,1E80-1E87,1E88-1E8F,1E90-1E97,1E98-1E9F,1EA0-1EA7,1EA8-1EAF,1EB0-1EB7,1EB8-1EBF,1EC0-1EC7,1EC8-1ECF,1ED0-1ED7,1ED8-1EDF,1EE0-1EE7,1EE8-1EEF,1EF0-1EF7,1EF8-1EFF,1F00-1F07,1F08-1F0F,1F10,1F11,1F12,1F13,1F14,1F15,1F18,1F19,1F1A,1F1B,1F1C,1F1D,1F20-1F27,1F28-1F2F,1F30-1F37,1F38-1F3F,1F40,1F41,1F42,1F43,1F44,1F45,1F48,1F49,1F4A,1F4B,1F4C,1F4D,1F50-1F57,1F59,1F5B,1F5D,1F5F,1F60-1F67,1F68-1F6F,1F70-1F77,1F78,1F79,1F7A,1F7B,1F7C,1F7D,1F80-1F87,1F88-1F8F,1F90-1F97,1F98-1F9F,1FA0-1FA7,1FA8-1FAF,1FB0,1FB1,1FB2,1FB3,1FB4,1FB6,1FB7,1FB8,1FB9,1FBA,1FBB,1FBC,1FBE,1FC2,1FC3,1FC4,1FC6,1FC7,1FC8,1FC9,1FCA,1FCB,1FCC,1FD0,1FD1,1FD2,1FD3,1FD6,1FD7,1FD8,1FD9,1FDA,1FDB,1FE0-1FE7,1FE8,1FE9,1FEA,1FEB,1FEC,1FF2,1FF3,1FF4,1FF6,1FF7,1FF8,1FF9,1FFA,1FFB,1FFC," +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{L}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0041,0042,0043,0044,0045,0046,0047,004^,005_,0058,0059,005A,0061,0062,0063,0064,0065,0066,0067,006^,007_,0078,0079,007A,00AA,00B5,00BA,00C*,00D0,00D1,00D2,00D3,00D4,00D5,00D6,00D^,00E*,00F0,00F1,00F2,00F3,00F4,00F5,00F6,00F^,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C0,02C1,02C6,02C7,02C^,02D0,02D1,02E0,02E1,02E2,02E3,02E4,02EC,02EE,0370,0371,0372,0373,0374,0376,0377,037A,037B,037C,037D,037F,0386,0388,0389,038A,038C,038E,038F,039*,03A0,03A1,03A3,03A4,03A5,03A6,03A7,03A^,03B*,03C*,03D*,03E*,03F0,03F1,03F2,03F3,03F4,03F5,03F7,03F^,040*,041*,042*,043*,044*,045*,046*,047*,0480,0481,048A,048B,048C,048D,048E,048F,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,0531,0532,0533,0534,0535,0536,0537,053^,054*,0550,0551,0552,0553,0554,0555,0556,0559,056*,057*,058_,0588,05D*,05E_,05E8,05E9,05EA,05EF,05F0,05F1,05F2,062*,063*,064_,0648,0649,064A,066E,066F,0671,0672,0673,0674,0675,0676,0677,067^,068*,069*,06A*,06B*,06C*,06D0,06D1,06D2,06D3,06D5,06E5,06E6,06EE,06EF,06FA,06FB,06FC,06FF,0710,0712,0713,0714,0715,0716,0717,071^,072*,074D,074E,074F,075*,076*,077*,078*,079*,07A0,07A1,07A2,07A3,07A4,07A5,07B1,07CA,07CB,07CC,07CD,07CE,07CF,07D*,07E_,07E8,07E9,07EA,07F4,07F5,07FA,080*,0810,0811,0812,0813,0814,0815,081A,0824,0828,084*,085_,0858,086_,0868,0869,086A,087*,088_,0889,088A,088B,088C,088D,088E,08A*,08B*,08C_,08C8,08C9,0904,0905,0906,0907,090^,091*,092*,093_,0938,0939,093D,0950,095^,0960,0961,0971,0972,0973,0974,0975,0976,0977,097^,0980,0985,0986,0987,0988,0989,098A,098B,098C,098F,0990,0993,0994,0995,0996,0997,099^,09A_,09A8,09AA,09AB,09AC,09AD,09AE,09AF,09B0,09B2,09B6,09B7,09B8,09B9,09BD,09CE,09DC,09DD,09DF,09E0,09E1,09F0,09F1,09FC,0A05,0A06,0A07,0A08,0A09,0A0A,0A0F,0A10,0A13,0A14,0A15,0A16,0A17,0A1^,0A2_,0A28,0A2A,0A2B,0A2C,0A2D,0A2E,0A2F,0A30,0A32,0A33,0A35,0A36,0A38,0A39,0A59,0A5A,0A5B,0A5C,0A5E,0A72,0A73,0A74,0A85,0A86,0A87,0A88,0A89,0A8A,0A8B,0A8C,0A8D,0A8F,0A90,0A91,0A93,0A94,0A95,0A96,0A97,0A9^,0AA_,0AA8,0AAA,0AAB,0AAC,0AAD,0AAE,0AAF,0AB0,0AB2,0AB3,0AB5,0AB6,0AB7,0AB8,0AB9,0ABD,0AD0,0AE0,0AE1,0AF9,0B05,0B06,0B07,0B08,0B09,0B0A,0B0B,0B0C,0B0F,0B10,0B13,0B14,0B15,0B16,0B17,0B1^,0B2_,0B28,0B2A,0B2B,0B2C,0B2D,0B2E,0B2F,0B30,0B32,0B33,0B35,0B36,0B37,0B38,0B39,0B3D,0B5C,0B5D,0B5F,0B60,0B61,0B71,0B83,0B85,0B86,0B87,0B88,0B89,0B8A,0B8E,0B8F,0B90,0B92,0B93,0B94,0B95,0B99,0B9A,0B9C,0B9E,0B9F,0BA3,0BA4,0BA8,0BA9,0BAA,0BAE,0BAF,0BB_,0BB8,0BB9,0BD0,0C05,0C06,0C07,0C08,0C09,0C0A,0C0B,0C0C,0C0E,0C0F,0C10,0C12,0C13,0C14,0C15,0C16,0C17,0C1^,0C2_,0C28,0C2A,0C2B,0C2C,0C2D,0C2E,0C2F,0C3_,0C38,0C39,0C3D,0C58,0C59,0C5A,0C5D,0C60,0C61,0C80,0C85,0C86,0C87,0C88,0C89,0C8A,0C8B,0C8C,0C8E,0C8F,0C90,0C92,0C93,0C94,0C95,0C96,0C97,0C9^,0CA_,0CA8,0CAA,0CAB,0CAC,0CAD,0CAE,0CAF,0CB0,0CB1,0CB2,0CB3,0CB5,0CB6,0CB7,0CB8,0CB9,0CBD,0CDD,0CDE,0CE0,0CE1,0CF1,0CF2,0D04,0D05,0D06,0D07,0D08,0D09,0D0A,0D0B,0D0C,0D0E,0D0F,0D10,0D12,0D13,0D14,0D15,0D16,0D17,0D1^,0D2*,0D3_,0D38,0D39,0D3A,0D3D,0D4E,0D54,0D55,0D56,0D5F,0D60,0D61,0D7A,0D7B,0D7C,0D7D,0D7E,0D7F,0D85,0D86,0D87,0D8^,0D90,0D91,0D92,0D93,0D94,0D95,0D96,0D9A,0D9B,0D9C,0D9D,0D9E,0D9F,0DA*,0DB0,0DB1,0DB3,0DB4,0DB5,0DB6,0DB7,0DB8,0DB9,0DBA,0DBB,0DBD,0DC0,0DC1,0DC2,0DC3,0DC4,0DC5,0DC6,0E01,0E02,0E03,0E04,0E05,0E06,0E07,0E0^,0E1*,0E2*,0E30,0E32,0E33,0E40,0E41,0E42,0E43,0E44,0E45,0E46,0E81,0E82,0E84,0E86,0E87,0E88,0E89,0E8A,0E8C,0E8D,0E8E,0E8F,0E9*,0EA0,0EA1,0EA2,0EA3,0EA5,0EA7,0EA^,0EB0,0EB2,0EB3,0EBD,0EC0,0EC1,0EC2,0EC3,0EC4,0EC6,0EDC,0EDD,0EDE,0EDF,0F00,0F4_,0F49,0F4A,0F4B,0F4C,0F4D,0F4E,0F4F,0F5*,0F6_,0F68,0F69,0F6A,0F6B,0F6C,0F88,0F89,0F8A,0F8B,0F8C,100*,101*,102_,1028,1029,102A,103F,1050,1051,1052,1053,1054,1055,105A,105B,105C,105D,1061,1065,1066,106E,106F,1070,1075,1076,1077,107^,1080,1081,108E,10A*,10B*,10C0,10C1,10C2,10C3,10C4,10C5,10C7,10CD,10D*,10E*,10F_,10F8,10F9,10FA,10FC,10FD,10FE,10FF,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124_,1248,124A,124B,124C,124D,1250,1251,1252,1253,1254,1255,1256,1258,125A,125B,125C,125D,126*,127*,128_,1288,128A,128B,128C,128D,129*,12A*,12B0,12B2,12B3,12B4,12B5,12B8,12B9,12BA,12BB,12BC,12BD,12BE,12C0,12C2,12C3,12C4,12C5,12C^,12D0,12D1,12D2,12D3,12D4,12D5,12D6,12D^,12E*,12F*,130*,1310,1312,1313,1314,1315,131^,132*,133*,134*,135_,1358,1359,135A,138*,13A*,13B*,13C*,13D*,13E*,13F0,13F1,13F2,13F3,13F4,13F5,13F8,13F9,13FA,13FB,13FC,13FD,1401,1402,1403,1404,1405,1406,1407,140^,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166_,1668,1669,166A,166B,166C,166F,167*,1681,1682,1683,1684,1685,1686,1687,168^,169_,1698,1699,169A,16A*,16B*,16C*,16D*,16E_,16E8,16E9,16EA,16F1,16F2,16F3,16F4,16F5,16F6,16F7,16F8,170*,1710,1711,171F,172*,1730,1731,174*,1750,1751,176_,1768,1769,176A,176B,176C,176E,176F,1770,178*,179*,17A*,17B0,17B1,17B2,17B3,17D7,17DC,182*,183*,184*,185*,186*,187_,1878,1880,1881,1882,1883,1884,1887,188^,189*,18A_,18A8,18AA,18B*,18C*,18D*,18E*,18F0,18F1,18F2,18F3,18F4,18F5,190*,191_,1918,1919,191A,191B,191C,191D,191E,195*,196_,1968,1969,196A,196B,196C,196D,1970,1971,1972,1973,1974,198*,199*,19A_,19A8,19A9,19AA,19AB,19B*,19C_,19C8,19C9,1A0*,1A10,1A11,1A12,1A13,1A14,1A15,1A16,1A2*,1A3*,1A4*,1A50,1A51,1A52,1A53,1A54,1AA7,1B05,1B06,1B07,1B0^,1B1*,1B2*,1B30,1B31,1B32,1B33,1B45,1B46,1B47,1B48,1B49,1B4A,1B4B,1B4C,1B83,1B84,1B85,1B86,1B87,1B8^,1B9*,1BA0,1BAE,1BAF,1BBA,1BBB,1BBC,1BBD,1BBE,1BBF,1BC*,1BD*,1BE0,1BE1,1BE2,1BE3,1BE4,1BE5,1C0*,1C1*,1C20,1C21,1C22,1C23,1C4D,1C4E,1C4F,1C5A,1C5B,1C5C,1C5D,1C5E,1C5F,1C6*,1C7_,1C78,1C79,1C7A,1C7B,1C7C,1C7D,1C8_,1C88,1C9*,1CA*,1CB_,1CB8,1CB9,1CBA,1CBD,1CBE,1CBF,1CE9,1CEA,1CEB,1CEC,1CEE,1CEF,1CF0,1CF1,1CF2,1CF3,1CF5,1CF6,1CFA,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F10,1F11,1F12,1F13,1F14,1F15,1F18,1F19,1F1A,1F1B,1F1C,1F1D,1F2*,1F3*,1F40,1F41,1F42,1F43,1F44,1F45,1F48,1F49,1F4A,1F4B,1F4C,1F4D,1F5_,1F59,1F5B,1F5D,1F5F,1F6*,1F7_,1F78,1F79,1F7A,1F7B,1F7C,1F7D,1F8*,1F9*,1FA*,1FB0,1FB1,1FB2,1FB3,1FB4,1FB6,1FB7,1FB8,1FB9,1FBA,1FBB,1FBC,1FBE,1FC2,1FC3,1FC4,1FC6,1FC7,1FC8,1FC9,1FCA,1FCB,1FCC,1FD0,1FD1,1FD2,1FD3,1FD6,1FD7,1FD8,1FD9,1FDA,1FDB,1FE_,1FE8,1FE9,1FEA,1FEB,1FEC,1FF2,1FF3,1FF4,1FF6,1FF7,1FF8,1FF9,1FFA,1FFB,1FFC,2071,207F,209_,2098,2099,209A,209B,209C,2102,2107,210A,210B,210C,210D,210E,210F,2110,2111,2112,2113,2115,2119,211A,211B,211C,211D,2124,2126,2128,212A,212B,212C,212D,212F,213_,2138,2139,213C,213D,213E,213F,2145,2146,2147,2148,2149,214E,2183,2184,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE0,2CE1,2CE2,2CE3,2CE4,2CEB,2CEC,2CED,2CEE,2CF2,2CF3,2D0*,2D1*,2D20,2D21,2D22,2D23,2D24,2D25,2D27,2D2D,2D3*,2D4*,2D5*,2D6_,2D6F,2D8*,2D90,2D91,2D92,2D93,2D94,2D95,2D96,2DA0,2DA1,2DA2,2DA3,2DA4,2DA5,2DA6,2DA8,2DA9,2DAA,2DAB,2DAC,2DAD,2DAE,2DB0,2DB1,2DB2,2DB3,2DB4,2DB5,2DB6,2DB8,2DB9,2DBA,2DBB,2DBC,2DBD,2DBE,2DC0,2DC1,2DC2,2DC3,2DC4,2DC5,2DC6,2DC8,2DC9,2DCA,2DCB,2DCC,2DCD,2DCE,2DD0,2DD1,2DD2,2DD3,2DD4,2DD5,2DD6,2DD8,2DD9,2DDA,2DDB,2DDC,2DDD,2DDE,2E2F,3005,3006,3031,3032,3033,3034,3035,303B,303C,3041,3042,3043,3044,3045,3046,3047,304^,305*,306*,307*,308*,3090,3091,3092,3093,3094,3095,3096,309D,309E,309F,30A1,30A2,30A3,30A4,30A5,30A6,30A7,30A^,30B*,30C*,30D*,30E*,30F_,30F8,30F9,30FA,30FC,30FD,30FE,30FF,3105,3106,3107,310^,311*,312*,3131,3132,3133,3134,3135,3136,3137,313^,314*,315*,316*,317*,318_,3188,3189,318A,318B,318C,318D,318E,31A*,31B*,31F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{L}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,0040,005B,005C,005D,005E,005F,0060,007B,007C,007D,007E,007F,008*,009*,00A_,00A8,00A9,00AB,00AC,00AD,00AE,00AF,00B0,00B1,00B2,00B3,00B4,00B6,00B7,00B8,00B9,00BB,00BC,00BD,00BE,00BF,00D7,00F7,02C2,02C3,02C4,02C5,02D2,02D3,02D4,02D5,02D6,02D7,02D^,02E5,02E6,02E7,02E8,02E9,02EA,02EB,02ED,02EF,02F*,030*,031*,032*,033*,034*,035*,036*,0375,0378,0379,037E,0380,0381,0382,0383,0384,0385,0387,038B,038D,03A2,03F6,0482,0483,0484,0485,0486,0487,0488,0489,0530,0557,0558,055A,055B,055C,055D,055E,055F,0589,058A,058B,058C,058D,058E,058F,059*,05A*,05B*,05C*,05EB,05EC,05ED,05EE,05F3,05F4,05F5,05F6,05F7,05F^,060*,061*,064B,064C,064D,064E,064F,065*,066_,0668,0669,066A,066B,066C,066D,0670,06D4,06D6,06D7,06D^,06E0,06E1,06E2,06E3,06E4,06E7,06E8,06E9,06EA,06EB,06EC,06ED,06F_,06F8,06F9,06FD,06FE,070*,0711,073*,074_,0748,0749,074A,074B,074C,07A6,07A7,07A^,07B0,07B2,07B3,07B4,07B5,07B6,07B7,07B^,07C_,07C8,07C9,07EB,07EC,07ED,07EE,07EF,07F0,07F1,07F2,07F3,07F6,07F7,07F8,07F9,07FB,07FC,07FD,07FE,07FF,0816,0817,0818,0819,081B,081C,081D,081E,081F,0820,0821,0822,0823,0825,0826,0827,0829,082A,082B,082C,082D,082E,082F,083*,0859,085A,085B,085C,085D,085E,085F,086B,086C,086D,086E,086F,0888,088F,089*,08CA,08CB,08CC,08CD,08CE,08CF,08D*,08E*,08F*,0900,0901,0902,0903,093A,093B,093C,093E,093F,094*,0951,0952,0953,0954,0955,0956,0957,0962,0963,0964,0965,0966,0967,096^,0970,0981,0982,0983,0984,098D,098E,0991,0992,09A9,09B1,09B3,09B4,09B5,09BA,09BB,09BC,09BE,09BF,09C_,09C8,09C9,09CA,09CB,09CC,09CD,09CF,09D_,09D8,09D9,09DA,09DB,09DE,09E2,09E3,09E4,09E5,09E6,09E7,09E^,09F2,09F3,09F4,09F5,09F6,09F7,09F8,09F9,09FA,09FB,09FD,09FE,09FF,0A00,0A01,0A02,0A03,0A04,0A0B,0A0C,0A0D,0A0E,0A11,0A12,0A29,0A31,0A34,0A37,0A3A,0A3B,0A3C,0A3D,0A3E,0A3F,0A4*,0A5_,0A58,0A5D,0A5F,0A6*,0A70,0A71,0A75,0A76,0A77,0A7^,0A80,0A81,0A82,0A83,0A84,0A8E,0A92,0AA9,0AB1,0AB4,0ABA,0ABB,0ABC,0ABE,0ABF,0AC*,0AD1,0AD2,0AD3,0AD4,0AD5,0AD6,0AD7,0AD^,0AE2,0AE3,0AE4,0AE5,0AE6,0AE7,0AE^,0AF_,0AF8,0AFA,0AFB,0AFC,0AFD,0AFE,0AFF,0B00,0B01,0B02,0B03,0B04,0B0D,0B0E,0B11,0B12,0B29,0B31,0B34,0B3A,0B3B,0B3C,0B3E,0B3F,0B4*,0B5_,0B58,0B59,0B5A,0B5B,0B5E,0B62,0B63,0B64,0B65,0B66,0B67,0B6^,0B70,0B72,0B73,0B74,0B75,0B76,0B77,0B7^,0B80,0B81,0B82,0B84,0B8B,0B8C,0B8D,0B91,0B96,0B97,0B98,0B9B,0B9D,0BA0,0BA1,0BA2,0BA5,0BA6,0BA7,0BAB,0BAC,0BAD,0BBA,0BBB,0BBC,0BBD,0BBE,0BBF,0BC*,0BD1,0BD2,0BD3,0BD4,0BD5,0BD6,0BD7,0BD^,0BE*,0BF*,0C00,0C01,0C02,0C03,0C04,0C0D,0C11,0C29,0C3A,0C3B,0C3C,0C3E,0C3F,0C4*,0C5_,0C5B,0C5C,0C5E,0C5F,0C62,0C63,0C64,0C65,0C66,0C67,0C6^,0C7*,0C81,0C82,0C83,0C84,0C8D,0C91,0CA9,0CB4,0CBA,0CBB,0CBC,0CBE,0CBF,0CC*,0CD_,0CD8,0CD9,0CDA,0CDB,0CDC,0CDF,0CE2,0CE3,0CE4,0CE5,0CE6,0CE7,0CE^,0CF0,0CF3,0CF4,0CF5,0CF6,0CF7,0CF^,0D00,0D01,0D02,0D03,0D0D,0D11,0D3B,0D3C,0D3E,0D3F,0D4_,0D48,0D49,0D4A,0D4B,0D4C,0D4D,0D4F,0D50,0D51,0D52,0D53,0D57,0D58,0D59,0D5A,0D5B,0D5C,0D5D,0D5E,0D62,0D63,0D64,0D65,0D66,0D67,0D6^,0D7_,0D78,0D79,0D80,0D81,0D82,0D83,0D84,0D97,0D98,0D99,0DB2,0DBC,0DBE,0DBF,0DC7,0DC^,0DD*,0DE*,0DF*,0E00,0E31,0E34,0E35,0E36,0E37,0E3^,0E47,0E4^,0E5*,0E6*,0E7*,0E80,0E83,0E85,0E8B,0EA4,0EA6,0EB1,0EB4,0EB5,0EB6,0EB7,0EB8,0EB9,0EBA,0EBB,0EBC,0EBE,0EBF,0EC5,0EC7,0EC^,0ED_,0ED8,0ED9,0EDA,0EDB,0EE*,0EF*,0F01,0F02,0F03,0F04,0F05,0F06,0F07,0F0^,0F1*,0F2*,0F3*,0F48,0F6D,0F6E,0F6F,0F7*,0F8_,0F8D,0F8E,0F8F,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,102B,102C,102D,102E,102F,103_,1038,1039,103A,103B,103C,103D,103E,104*,1056,1057,1058,1059,105E,105F,1060,1062,1063,1064,1067,1068,1069,106A,106B,106C,106D,1071,1072,1073,1074,1082,1083,1084,1085,1086,1087,1088,1089,108A,108B,108C,108D,108F,109*,10C6,10C8,10C9,10CA,10CB,10CC,10CE,10CF,10FB,1249,124E,124F,1257,1259,125E,125F,1289,128E,128F,12B1,12B6,12B7,12BF,12C1,12C6,12C7,12D7,1311,1316,1317,135B,135C,135D,135E,135F,136*,137*,139*,13F6,13F7,13FE,13FF,1400,166D,166E,1680,169B,169C,169D,169E,169F,16EB,16EC,16ED,16EE,16EF,16F0,16F9,16FA,16FB,16FC,16FD,16FE,16FF,1712,1713,1714,1715,1716,1717,1718,1719,171A,171B,171C,171D,171E,1732,1733,1734,1735,1736,1737,173^,1752,1753,1754,1755,1756,1757,175^,176D,1771,1772,1773,1774,1775,1776,1777,177^,17B4,17B5,17B6,17B7,17B^,17C*,17D0,17D1,17D2,17D3,17D4,17D5,17D6,17D8,17D9,17DA,17DB,17DD,17DE,17DF,17E*,17F*,180*,181*,1879,187A,187B,187C,187D,187E,187F,1885,1886,18A9,18AB,18AC,18AD,18AE,18AF,18F6,18F7,18F^,191F,192*,193*,194*,196E,196F,1975,1976,1977,197^,19AC,19AD,19AE,19AF,19CA,19CB,19CC,19CD,19CE,19CF,19D*,19E*,19F*,1A17,1A1^,1A55,1A56,1A57,1A5^,1A6*,1A7*,1A8*,1A9*,1AA0,1AA1,1AA2,1AA3,1AA4,1AA5,1AA6,1AA^,1AB*,1AC*,1AD*,1AE*,1AF*,1B00,1B01,1B02,1B03,1B04,1B34,1B35,1B36,1B37,1B3^,1B40,1B41,1B42,1B43,1B44,1B4D,1B4E,1B4F,1B5*,1B6*,1B7*,1B80,1B81,1B82,1BA1,1BA2,1BA3,1BA4,1BA5,1BA6,1BA7,1BA8,1BA9,1BAA,1BAB,1BAC,1BAD,1BB_,1BB8,1BB9,1BE6,1BE7,1BE^,1BF*,1C24,1C25,1C26,1C27,1C2^,1C3*,1C4_,1C48,1C49,1C4A,1C4B,1C4C,1C5_,1C58,1C59,1C7E,1C7F,1C89,1C8A,1C8B,1C8C,1C8D,1C8E,1C8F,1CBB,1CBC,1CC*,1CD*,1CE_,1CE8,1CED,1CF4,1CF7,1CF8,1CF9,1CFB,1CFC,1CFD,1CFE,1CFF,1DC*,1DD*,1DE*,1DF*,1F16,1F17,1F1E,1F1F,1F46,1F47,1F4E,1F4F,1F58,1F5A,1F5C,1F5E,1F7E,1F7F,1FB5,1FBD,1FBF,1FC0,1FC1,1FC5,1FCD,1FCE,1FCF,1FD4,1FD5,1FDC,1FDD,1FDE,1FDF,1FED,1FEE,1FEF,1FF0,1FF1,1FF5,1FFD,1FFE,1FFF,200*,201*,202*,203*,204*,205*,206*,2070,2072,2073,2074,2075,2076,2077,2078,2079,207A,207B,207C,207D,207E,208*,209D,209E,209F,20A*,20B*,20C*,20D*,20E*,20F*,2100,2101,2103,2104,2105,2106,2108,2109,2114,2116,2117,2118,211E,211F,2120,2121,2122,2123,2125,2127,2129,212E,213A,213B,2140,2141,2142,2143,2144,214A,214B,214C,214D,214F,215*,216*,217*,2180,2181,2182,2185,2186,2187,218^,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2CE5,2CE6,2CE7,2CE8,2CE9,2CEA,2CEF,2CF0,2CF1,2CF4,2CF5,2CF6,2CF7,2CF^,2D26,2D28,2D29,2D2A,2D2B,2D2C,2D2E,2D2F,2D68,2D69,2D6A,2D6B,2D6C,2D6D,2D6E,2D7*,2D97,2D9^,2DA7,2DAF,2DB7,2DBF,2DC7,2DCF,2DD7,2DDF,2DE*,2DF*,2E0*,2E1*,2E2_,2E28,2E29,2E2A,2E2B,2E2C,2E2D,2E2E,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,3000,3001,3002,3003,3004,3007,300^,301*,302*,3030,3036,3037,3038,3039,303A,303D,303E,303F,3040,3097,3098,3099,309A,309B,309C,30A0,30FB,3100,3101,3102,3103,3104,3130,318F,319*,31C*,31D*,31E*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*," // Ll ->> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, - If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Ll}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, - If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) -"0061,0062,0063,0064,0065,0066,0067,0068-006F,0070-0077,0078,0079,007A,00B5,00DF,00E0-00E7,00E8-00EF,00F0,00F1,00F2,00F3,00F4,00F5,00F6,00F8-00FF,0101,0103,0105,0107,0109,010B,010D,010F,0111,0113,0115,0117,0119,011B,011D,011F,0121,0123,0125,0127,0129,012B,012D,012F,0131,0133,0135,0137,0138,013A,013C,013E,0140,0142,0144,0146,0148,0149,014B,014D,014F,0151,0153,0155,0157,0159,015B,015D,015F,0161,0163,0165,0167,0169,016B,016D,016F,0171,0173,0175,0177,017A,017C,017E,017F,0180,0183,0185,0188,018C,018D,0192,0195,0199,019A,019B,019E,01A1,01A3,01A5,01A8,01AA,01AB,01AD,01B0,01B4,01B6,01B9,01BA,01BD,01BE,01BF,01C6,01C9,01CC,01CE,01D0,01D2,01D4,01D6,01D8,01DA,01DC,01DD,01DF,01E1,01E3,01E5,01E7,01E9,01EB,01ED,01EF,01F0,01F3,01F5,01F9,01FB,01FD,01FF,0201,0203,0205,0207,0209,020B,020D,020F,0211,0213,0215,0217,0219,021B,021D,021F,0221,0223,0225,0227,0229,022B,022D,022F,0231,0233,0234,0235,0236,0237,0238,0239,023C,023F,0240,0242,0247,0249,024B,024D,024F,0250-0257,0258-025F,0260-0267,0268-026F,0270-0277,0278-027F,0280-0287,0288-028F,0290,0291,0292,0293,0295,0296,0297,0298-029F,02A0-02A7,02A8-02AF,0371,0373,0377,037B,037C,037D,0390,03AC,03AD,03AE,03AF,03B0-03B7,03B8-03BF,03C0-03C7,03C8,03C9,03CA,03CB,03CC,03CD,03CE,03D0,03D1,03D5,03D6,03D7,03D9,03DB,03DD,03DF,03E1,03E3,03E5,03E7,03E9,03EB,03ED,03EF,03F0,03F1,03F2,03F3,03F5,03F8,03FB,03FC,0430-0437,0438-043F,0440-0447,0448-044F,0450-0457,0458-045F,0461,0463,0465,0467,0469,046B,046D,046F,0471,0473,0475,0477,0479,047B,047D,047F,0481,048B,048D,048F,0491,0493,0495,0497,0499,049B,049D,049F,04A1,04A3,04A5,04A7,04A9,04AB,04AD,04AF,04B1,04B3,04B5,04B7,04B9,04BB,04BD,04BF,04C2,04C4,04C6,04C8,04CA,04CC,04CE,04CF,04D1,04D3,04D5,04D7,04D9,04DB,04DD,04DF,04E1,04E3,04E5,04E7,04E9,04EB,04ED,04EF,04F1,04F3,04F5,04F7,04F9,04FB,04FD,04FF,0501,0503,0505,0507,0509,050B,050D,050F,0511,0513,0515,0517,0519,051B,051D,051F,0521,0523,0525,0527,0529,052B,052D,052F,0560-0567,0568-056F,0570-0577,0578-057F,0580-0587,0588,10D0-10D7,10D8-10DF,10E0-10E7,10E8-10EF,10F0-10F7,10F8,10F9,10FA,10FD,10FE,10FF,13F8,13F9,13FA,13FB,13FC,13FD,1C80-1C87,1C88,1D00-1D07,1D08-1D0F,1D10-1D17,1D18-1D1F,1D20-1D27,1D28,1D29,1D2A,1D2B,1D6B,1D6C,1D6D,1D6E,1D6F,1D70-1D77,1D79,1D7A,1D7B,1D7C,1D7D,1D7E,1D7F,1D80-1D87,1D88-1D8F,1D90-1D97,1D98,1D99,1D9A,1E01,1E03,1E05,1E07,1E09,1E0B,1E0D,1E0F,1E11,1E13,1E15,1E17,1E19,1E1B,1E1D,1E1F,1E21,1E23,1E25,1E27,1E29,1E2B,1E2D,1E2F,1E31,1E33,1E35,1E37,1E39,1E3B,1E3D,1E3F,1E41,1E43,1E45,1E47,1E49,1E4B,1E4D,1E4F,1E51,1E53,1E55,1E57,1E59,1E5B,1E5D,1E5F,1E61,1E63,1E65,1E67,1E69,1E6B,1E6D,1E6F,1E71,1E73,1E75,1E77,1E79,1E7B,1E7D,1E7F,1E81,1E83,1E85,1E87,1E89,1E8B,1E8D,1E8F,1E91,1E93,1E95,1E96,1E97,1E98,1E99,1E9A,1E9B,1E9C,1E9D,1E9F,1EA1,1EA3,1EA5,1EA7,1EA9,1EAB,1EAD,1EAF,1EB1,1EB3,1EB5,1EB7,1EB9,1EBB,1EBD,1EBF,1EC1,1EC3,1EC5,1EC7,1EC9,1ECB,1ECD,1ECF,1ED1,1ED3,1ED5,1ED7,1ED9,1EDB,1EDD,1EDF,1EE1,1EE3,1EE5,1EE7,1EE9,1EEB,1EED,1EEF,1EF1,1EF3,1EF5,1EF7,1EF9,1EFB,1EFD,1EFF,1F00-1F07,1F10,1F11,1F12,1F13,1F14,1F15,1F20-1F27,1F30-1F37,1F40,1F41,1F42,1F43,1F44,1F45,1F50-1F57,1F60-1F67,1F70-1F77,1F78,1F79,1F7A,1F7B,1F7C,1F7D,1F80-1F87,1F90-1F97,1FA0-1FA7,1FB0,1FB1,1FB2,1FB3,1FB4,1FB6,1FB7,1FBE,1FC2,1FC3,1FC4,1FC6,1FC7,1FD0,1FD1,1FD2,1FD3,1FD6,1FD7,1FE0-1FE7,1FF2,1FF3,1FF4,1FF6,1FF7," +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Ll}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0061,0062,0063,0064,0065,0066,0067,006^,007_,0078,0079,007A,00B5,00DF,00E*,00F0,00F1,00F2,00F3,00F4,00F5,00F6,00F^,0101,0103,0105,0107,0109,010B,010D,010F,0111,0113,0115,0117,0119,011B,011D,011F,0121,0123,0125,0127,0129,012B,012D,012F,0131,0133,0135,0137,0138,013A,013C,013E,0140,0142,0144,0146,0148,0149,014B,014D,014F,0151,0153,0155,0157,0159,015B,015D,015F,0161,0163,0165,0167,0169,016B,016D,016F,0171,0173,0175,0177,017A,017C,017E,017F,0180,0183,0185,0188,018C,018D,0192,0195,0199,019A,019B,019E,01A1,01A3,01A5,01A8,01AA,01AB,01AD,01B0,01B4,01B6,01B9,01BA,01BD,01BE,01BF,01C6,01C9,01CC,01CE,01D0,01D2,01D4,01D6,01D8,01DA,01DC,01DD,01DF,01E1,01E3,01E5,01E7,01E9,01EB,01ED,01EF,01F0,01F3,01F5,01F9,01FB,01FD,01FF,0201,0203,0205,0207,0209,020B,020D,020F,0211,0213,0215,0217,0219,021B,021D,021F,0221,0223,0225,0227,0229,022B,022D,022F,0231,0233,0234,0235,0236,0237,0238,0239,023C,023F,0240,0242,0247,0249,024B,024D,024F,025*,026*,027*,028*,0290,0291,0292,0293,0295,0296,0297,029^,02A*,0371,0373,0377,037B,037C,037D,0390,03AC,03AD,03AE,03AF,03B*,03C_,03C8,03C9,03CA,03CB,03CC,03CD,03CE,03D0,03D1,03D5,03D6,03D7,03D9,03DB,03DD,03DF,03E1,03E3,03E5,03E7,03E9,03EB,03ED,03EF,03F0,03F1,03F2,03F3,03F5,03F8,03FB,03FC,043*,044*,045*,0461,0463,0465,0467,0469,046B,046D,046F,0471,0473,0475,0477,0479,047B,047D,047F,0481,048B,048D,048F,0491,0493,0495,0497,0499,049B,049D,049F,04A1,04A3,04A5,04A7,04A9,04AB,04AD,04AF,04B1,04B3,04B5,04B7,04B9,04BB,04BD,04BF,04C2,04C4,04C6,04C8,04CA,04CC,04CE,04CF,04D1,04D3,04D5,04D7,04D9,04DB,04DD,04DF,04E1,04E3,04E5,04E7,04E9,04EB,04ED,04EF,04F1,04F3,04F5,04F7,04F9,04FB,04FD,04FF,0501,0503,0505,0507,0509,050B,050D,050F,0511,0513,0515,0517,0519,051B,051D,051F,0521,0523,0525,0527,0529,052B,052D,052F,056*,057*,058_,0588,10D*,10E*,10F_,10F8,10F9,10FA,10FD,10FE,10FF,13F8,13F9,13FA,13FB,13FC,13FD,1C8_,1C88,1D0*,1D1*,1D2_,1D28,1D29,1D2A,1D2B,1D6B,1D6C,1D6D,1D6E,1D6F,1D7_,1D79,1D7A,1D7B,1D7C,1D7D,1D7E,1D7F,1D8*,1D9_,1D98,1D99,1D9A,1E01,1E03,1E05,1E07,1E09,1E0B,1E0D,1E0F,1E11,1E13,1E15,1E17,1E19,1E1B,1E1D,1E1F,1E21,1E23,1E25,1E27,1E29,1E2B,1E2D,1E2F,1E31,1E33,1E35,1E37,1E39,1E3B,1E3D,1E3F,1E41,1E43,1E45,1E47,1E49,1E4B,1E4D,1E4F,1E51,1E53,1E55,1E57,1E59,1E5B,1E5D,1E5F,1E61,1E63,1E65,1E67,1E69,1E6B,1E6D,1E6F,1E71,1E73,1E75,1E77,1E79,1E7B,1E7D,1E7F,1E81,1E83,1E85,1E87,1E89,1E8B,1E8D,1E8F,1E91,1E93,1E95,1E96,1E97,1E98,1E99,1E9A,1E9B,1E9C,1E9D,1E9F,1EA1,1EA3,1EA5,1EA7,1EA9,1EAB,1EAD,1EAF,1EB1,1EB3,1EB5,1EB7,1EB9,1EBB,1EBD,1EBF,1EC1,1EC3,1EC5,1EC7,1EC9,1ECB,1ECD,1ECF,1ED1,1ED3,1ED5,1ED7,1ED9,1EDB,1EDD,1EDF,1EE1,1EE3,1EE5,1EE7,1EE9,1EEB,1EED,1EEF,1EF1,1EF3,1EF5,1EF7,1EF9,1EFB,1EFD,1EFF,1F0_,1F10,1F11,1F12,1F13,1F14,1F15,1F2_,1F3_,1F40,1F41,1F42,1F43,1F44,1F45,1F5_,1F6_,1F7_,1F78,1F79,1F7A,1F7B,1F7C,1F7D,1F8_,1F9_,1FA_,1FB0,1FB1,1FB2,1FB3,1FB4,1FB6,1FB7,1FBE,1FC2,1FC3,1FC4,1FC6,1FC7,1FD0,1FD1,1FD2,1FD3,1FD6,1FD7,1FE_,1FF2,1FF3,1FF4,1FF6,1FF7,210A,210E,210F,2113,212F,2134,2139,213C,213D,2146,2147,2148,2149,214E,2184,2C3*,2C4*,2C5*,2C61,2C65,2C66,2C68,2C6A,2C6C,2C71,2C73,2C74,2C76,2C77,2C78,2C79,2C7A,2C7B,2C81,2C83,2C85,2C87,2C89,2C8B,2C8D,2C8F,2C91,2C93,2C95,2C97,2C99,2C9B,2C9D,2C9F,2CA1,2CA3,2CA5,2CA7,2CA9,2CAB,2CAD,2CAF,2CB1,2CB3,2CB5,2CB7,2CB9,2CBB,2CBD,2CBF,2CC1,2CC3,2CC5,2CC7,2CC9,2CCB,2CCD,2CCF,2CD1,2CD3,2CD5,2CD7,2CD9,2CDB,2CDD,2CDF,2CE1,2CE3,2CE4,2CEC,2CEE,2CF3,2D0*,2D1*,2D20,2D21,2D22,2D23,2D24,2D25,2D27,2D2D," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Ll}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,0060,007B,007C,007D,007E,007F,008*,009*,00A*,00B0,00B1,00B2,00B3,00B4,00B6,00B7,00B^,00C*,00D_,00D8,00D9,00DA,00DB,00DC,00DD,00DE,00F7,0100,0102,0104,0106,0108,010A,010C,010E,0110,0112,0114,0116,0118,011A,011C,011E,0120,0122,0124,0126,0128,012A,012C,012E,0130,0132,0134,0136,0139,013B,013D,013F,0141,0143,0145,0147,014A,014C,014E,0150,0152,0154,0156,0158,015A,015C,015E,0160,0162,0164,0166,0168,016A,016C,016E,0170,0172,0174,0176,0178,0179,017B,017D,0181,0182,0184,0186,0187,0189,018A,018B,018E,018F,0190,0191,0193,0194,0196,0197,0198,019C,019D,019F,01A0,01A2,01A4,01A6,01A7,01A9,01AC,01AE,01AF,01B1,01B2,01B3,01B5,01B7,01B8,01BB,01BC,01C0,01C1,01C2,01C3,01C4,01C5,01C7,01C8,01CA,01CB,01CD,01CF,01D1,01D3,01D5,01D7,01D9,01DB,01DE,01E0,01E2,01E4,01E6,01E8,01EA,01EC,01EE,01F1,01F2,01F4,01F6,01F7,01F8,01FA,01FC,01FE,0200,0202,0204,0206,0208,020A,020C,020E,0210,0212,0214,0216,0218,021A,021C,021E,0220,0222,0224,0226,0228,022A,022C,022E,0230,0232,023A,023B,023D,023E,0241,0243,0244,0245,0246,0248,024A,024C,024E,0294,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,0370,0372,0374,0375,0376,0378,0379,037A,037E,037F,038*,0391,0392,0393,0394,0395,0396,0397,039^,03A_,03A8,03A9,03AA,03AB,03CF,03D2,03D3,03D4,03D8,03DA,03DC,03DE,03E0,03E2,03E4,03E6,03E8,03EA,03EC,03EE,03F4,03F6,03F7,03F9,03FA,03FD,03FE,03FF,040*,041*,042*,0460,0462,0464,0466,0468,046A,046C,046E,0470,0472,0474,0476,0478,047A,047C,047E,0480,0482,0483,0484,0485,0486,0487,0488,0489,048A,048C,048E,0490,0492,0494,0496,0498,049A,049C,049E,04A0,04A2,04A4,04A6,04A8,04AA,04AC,04AE,04B0,04B2,04B4,04B6,04B8,04BA,04BC,04BE,04C0,04C1,04C3,04C5,04C7,04C9,04CB,04CD,04D0,04D2,04D4,04D6,04D8,04DA,04DC,04DE,04E0,04E2,04E4,04E6,04E8,04EA,04EC,04EE,04F0,04F2,04F4,04F6,04F8,04FA,04FC,04FE,0500,0502,0504,0506,0508,050A,050C,050E,0510,0512,0514,0516,0518,051A,051C,051E,0520,0522,0524,0526,0528,052A,052C,052E,053*,054*,055*,0589,058A,058B,058C,058D,058E,058F,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10FB,10FC,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F_,13FE,13FF,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C89,1C8A,1C8B,1C8C,1C8D,1C8E,1C8F,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D2C,1D2D,1D2E,1D2F,1D3*,1D4*,1D5*,1D6_,1D68,1D69,1D6A,1D78,1D9B,1D9C,1D9D,1D9E,1D9F,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E00,1E02,1E04,1E06,1E08,1E0A,1E0C,1E0E,1E10,1E12,1E14,1E16,1E18,1E1A,1E1C,1E1E,1E20,1E22,1E24,1E26,1E28,1E2A,1E2C,1E2E,1E30,1E32,1E34,1E36,1E38,1E3A,1E3C,1E3E,1E40,1E42,1E44,1E46,1E48,1E4A,1E4C,1E4E,1E50,1E52,1E54,1E56,1E58,1E5A,1E5C,1E5E,1E60,1E62,1E64,1E66,1E68,1E6A,1E6C,1E6E,1E70,1E72,1E74,1E76,1E78,1E7A,1E7C,1E7E,1E80,1E82,1E84,1E86,1E88,1E8A,1E8C,1E8E,1E90,1E92,1E94,1E9E,1EA0,1EA2,1EA4,1EA6,1EA8,1EAA,1EAC,1EAE,1EB0,1EB2,1EB4,1EB6,1EB8,1EBA,1EBC,1EBE,1EC0,1EC2,1EC4,1EC6,1EC8,1ECA,1ECC,1ECE,1ED0,1ED2,1ED4,1ED6,1ED8,1EDA,1EDC,1EDE,1EE0,1EE2,1EE4,1EE6,1EE8,1EEA,1EEC,1EEE,1EF0,1EF2,1EF4,1EF6,1EF8,1EFA,1EFC,1EFE,1F0^,1F16,1F17,1F1^,1F2^,1F3^,1F46,1F47,1F4^,1F5^,1F6^,1F7E,1F7F,1F8^,1F9^,1FA^,1FB5,1FB8,1FB9,1FBA,1FBB,1FBC,1FBD,1FBF,1FC0,1FC1,1FC5,1FC^,1FD4,1FD5,1FD^,1FE^,1FF0,1FF1,1FF5,1FF^,200*,201*,202*,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210_,2108,2109,210B,210C,210D,2110,2111,2112,2114,2115,2116,2117,211^,212_,2128,2129,212A,212B,212C,212D,212E,2130,2131,2132,2133,2135,2136,2137,2138,213A,213B,213E,213F,2140,2141,2142,2143,2144,2145,214A,214B,214C,214D,214F,215*,216*,217*,2180,2181,2182,2183,2185,2186,2187,218^,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C60,2C62,2C63,2C64,2C67,2C69,2C6B,2C6D,2C6E,2C6F,2C70,2C72,2C75,2C7C,2C7D,2C7E,2C7F,2C80,2C82,2C84,2C86,2C88,2C8A,2C8C,2C8E,2C90,2C92,2C94,2C96,2C98,2C9A,2C9C,2C9E,2CA0,2CA2,2CA4,2CA6,2CA8,2CAA,2CAC,2CAE,2CB0,2CB2,2CB4,2CB6,2CB8,2CBA,2CBC,2CBE,2CC0,2CC2,2CC4,2CC6,2CC8,2CCA,2CCC,2CCE,2CD0,2CD2,2CD4,2CD6,2CD8,2CDA,2CDC,2CDE,2CE0,2CE2,2CE5,2CE6,2CE7,2CE8,2CE9,2CEA,2CEB,2CED,2CEF,2CF0,2CF1,2CF2,2CF4,2CF5,2CF6,2CF7,2CF^,2D26,2D28,2D29,2D2A,2D2B,2D2C,2D2E,2D2F,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," // Lu ->> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, - If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Lu}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, - If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) -"0041,0042,0043,0044,0045,0046,0047,0048-004F,0050-0057,0058,0059,005A,00C0-00C7,00C8-00CF,00D0,00D1,00D2,00D3,00D4,00D5,00D6,00D8,00D9,00DA,00DB,00DC,00DD,00DE,0100,0102,0104,0106,0108,010A,010C,010E,0110,0112,0114,0116,0118,011A,011C,011E,0120,0122,0124,0126,0128,012A,012C,012E,0130,0132,0134,0136,0139,013B,013D,013F,0141,0143,0145,0147,014A,014C,014E,0150,0152,0154,0156,0158,015A,015C,015E,0160,0162,0164,0166,0168,016A,016C,016E,0170,0172,0174,0176,0178,0179,017B,017D,0181,0182,0184,0186,0187,0189,018A,018B,018E,018F,0190,0191,0193,0194,0196,0197,0198,019C,019D,019F,01A0,01A2,01A4,01A6,01A7,01A9,01AC,01AE,01AF,01B1,01B2,01B3,01B5,01B7,01B8,01BC,01C4,01C7,01CA,01CD,01CF,01D1,01D3,01D5,01D7,01D9,01DB,01DE,01E0,01E2,01E4,01E6,01E8,01EA,01EC,01EE,01F1,01F4,01F6,01F7,01F8,01FA,01FC,01FE,0200,0202,0204,0206,0208,020A,020C,020E,0210,0212,0214,0216,0218,021A,021C,021E,0220,0222,0224,0226,0228,022A,022C,022E,0230,0232,023A,023B,023D,023E,0241,0243,0244,0245,0246,0248,024A,024C,024E,0370,0372,0376,037F,0386,0388,0389,038A,038C,038E,038F,0391,0392,0393,0394,0395,0396,0397,0398-039F,03A0,03A1,03A3,03A4,03A5,03A6,03A7,03A8,03A9,03AA,03AB,03CF,03D2,03D3,03D4,03D8,03DA,03DC,03DE,03E0,03E2,03E4,03E6,03E8,03EA,03EC,03EE,03F4,03F7,03F9,03FA,03FD,03FE,03FF,0400-0407,0408-040F,0410-0417,0418-041F,0420-0427,0428-042F,0460,0462,0464,0466,0468,046A,046C,046E,0470,0472,0474,0476,0478,047A,047C,047E,0480,048A,048C,048E,0490,0492,0494,0496,0498,049A,049C,049E,04A0,04A2,04A4,04A6,04A8,04AA,04AC,04AE,04B0,04B2,04B4,04B6,04B8,04BA,04BC,04BE,04C0,04C1,04C3,04C5,04C7,04C9,04CB,04CD,04D0,04D2,04D4,04D6,04D8,04DA,04DC,04DE,04E0,04E2,04E4,04E6,04E8,04EA,04EC,04EE,04F0,04F2,04F4,04F6,04F8,04FA,04FC,04FE,0500,0502,0504,0506,0508,050A,050C,050E,0510,0512,0514,0516,0518,051A,051C,051E,0520,0522,0524,0526,0528,052A,052C,052E,0531,0532,0533,0534,0535,0536,0537,0538-053F,0540-0547,0548-054F,0550,0551,0552,0553,0554,0555,0556,10A0-10A7,10A8-10AF,10B0-10B7,10B8-10BF,10C0,10C1,10C2,10C3,10C4,10C5,10C7,10CD,13A0-13A7,13A8-13AF,13B0-13B7,13B8-13BF,13C0-13C7,13C8-13CF,13D0-13D7,13D8-13DF,13E0-13E7,13E8-13EF,13F0,13F1,13F2,13F3,13F4,13F5,1C90-1C97,1C98-1C9F,1CA0-1CA7,1CA8-1CAF,1CB0-1CB7,1CB8,1CB9,1CBA,1CBD,1CBE,1CBF,1E00,1E02,1E04,1E06,1E08,1E0A,1E0C,1E0E,1E10,1E12,1E14,1E16,1E18,1E1A,1E1C,1E1E,1E20,1E22,1E24,1E26,1E28,1E2A,1E2C,1E2E,1E30,1E32,1E34,1E36,1E38,1E3A,1E3C,1E3E,1E40,1E42,1E44,1E46,1E48,1E4A,1E4C,1E4E,1E50,1E52,1E54,1E56,1E58,1E5A,1E5C,1E5E,1E60,1E62,1E64,1E66,1E68,1E6A,1E6C,1E6E,1E70,1E72,1E74,1E76,1E78,1E7A,1E7C,1E7E,1E80,1E82,1E84,1E86,1E88,1E8A,1E8C,1E8E,1E90,1E92,1E94,1E9E,1EA0,1EA2,1EA4,1EA6,1EA8,1EAA,1EAC,1EAE,1EB0,1EB2,1EB4,1EB6,1EB8,1EBA,1EBC,1EBE,1EC0,1EC2,1EC4,1EC6,1EC8,1ECA,1ECC,1ECE,1ED0,1ED2,1ED4,1ED6,1ED8,1EDA,1EDC,1EDE,1EE0,1EE2,1EE4,1EE6,1EE8,1EEA,1EEC,1EEE,1EF0,1EF2,1EF4,1EF6,1EF8,1EFA,1EFC,1EFE,1F08-1F0F,1F18,1F19,1F1A,1F1B,1F1C,1F1D,1F28-1F2F,1F38-1F3F,1F48,1F49,1F4A,1F4B,1F4C,1F4D,1F59,1F5B,1F5D,1F5F,1F68-1F6F,1FB8,1FB9,1FBA,1FBB,1FC8,1FC9,1FCA,1FCB,1FD8,1FD9,1FDA,1FDB,1FE8,1FE9,1FEA,1FEB,1FEC,1FF8,1FF9,1FFA,1FFB," +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Lu}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0041,0042,0043,0044,0045,0046,0047,004^,005_,0058,0059,005A,00C*,00D0,00D1,00D2,00D3,00D4,00D5,00D6,00D8,00D9,00DA,00DB,00DC,00DD,00DE,0100,0102,0104,0106,0108,010A,010C,010E,0110,0112,0114,0116,0118,011A,011C,011E,0120,0122,0124,0126,0128,012A,012C,012E,0130,0132,0134,0136,0139,013B,013D,013F,0141,0143,0145,0147,014A,014C,014E,0150,0152,0154,0156,0158,015A,015C,015E,0160,0162,0164,0166,0168,016A,016C,016E,0170,0172,0174,0176,0178,0179,017B,017D,0181,0182,0184,0186,0187,0189,018A,018B,018E,018F,0190,0191,0193,0194,0196,0197,0198,019C,019D,019F,01A0,01A2,01A4,01A6,01A7,01A9,01AC,01AE,01AF,01B1,01B2,01B3,01B5,01B7,01B8,01BC,01C4,01C7,01CA,01CD,01CF,01D1,01D3,01D5,01D7,01D9,01DB,01DE,01E0,01E2,01E4,01E6,01E8,01EA,01EC,01EE,01F1,01F4,01F6,01F7,01F8,01FA,01FC,01FE,0200,0202,0204,0206,0208,020A,020C,020E,0210,0212,0214,0216,0218,021A,021C,021E,0220,0222,0224,0226,0228,022A,022C,022E,0230,0232,023A,023B,023D,023E,0241,0243,0244,0245,0246,0248,024A,024C,024E,0370,0372,0376,037F,0386,0388,0389,038A,038C,038E,038F,0391,0392,0393,0394,0395,0396,0397,039^,03A0,03A1,03A3,03A4,03A5,03A6,03A7,03A8,03A9,03AA,03AB,03CF,03D2,03D3,03D4,03D8,03DA,03DC,03DE,03E0,03E2,03E4,03E6,03E8,03EA,03EC,03EE,03F4,03F7,03F9,03FA,03FD,03FE,03FF,040*,041*,042*,0460,0462,0464,0466,0468,046A,046C,046E,0470,0472,0474,0476,0478,047A,047C,047E,0480,048A,048C,048E,0490,0492,0494,0496,0498,049A,049C,049E,04A0,04A2,04A4,04A6,04A8,04AA,04AC,04AE,04B0,04B2,04B4,04B6,04B8,04BA,04BC,04BE,04C0,04C1,04C3,04C5,04C7,04C9,04CB,04CD,04D0,04D2,04D4,04D6,04D8,04DA,04DC,04DE,04E0,04E2,04E4,04E6,04E8,04EA,04EC,04EE,04F0,04F2,04F4,04F6,04F8,04FA,04FC,04FE,0500,0502,0504,0506,0508,050A,050C,050E,0510,0512,0514,0516,0518,051A,051C,051E,0520,0522,0524,0526,0528,052A,052C,052E,0531,0532,0533,0534,0535,0536,0537,053^,054*,0550,0551,0552,0553,0554,0555,0556,10A*,10B*,10C0,10C1,10C2,10C3,10C4,10C5,10C7,10CD,13A*,13B*,13C*,13D*,13E*,13F0,13F1,13F2,13F3,13F4,13F5,1C9*,1CA*,1CB_,1CB8,1CB9,1CBA,1CBD,1CBE,1CBF,1E00,1E02,1E04,1E06,1E08,1E0A,1E0C,1E0E,1E10,1E12,1E14,1E16,1E18,1E1A,1E1C,1E1E,1E20,1E22,1E24,1E26,1E28,1E2A,1E2C,1E2E,1E30,1E32,1E34,1E36,1E38,1E3A,1E3C,1E3E,1E40,1E42,1E44,1E46,1E48,1E4A,1E4C,1E4E,1E50,1E52,1E54,1E56,1E58,1E5A,1E5C,1E5E,1E60,1E62,1E64,1E66,1E68,1E6A,1E6C,1E6E,1E70,1E72,1E74,1E76,1E78,1E7A,1E7C,1E7E,1E80,1E82,1E84,1E86,1E88,1E8A,1E8C,1E8E,1E90,1E92,1E94,1E9E,1EA0,1EA2,1EA4,1EA6,1EA8,1EAA,1EAC,1EAE,1EB0,1EB2,1EB4,1EB6,1EB8,1EBA,1EBC,1EBE,1EC0,1EC2,1EC4,1EC6,1EC8,1ECA,1ECC,1ECE,1ED0,1ED2,1ED4,1ED6,1ED8,1EDA,1EDC,1EDE,1EE0,1EE2,1EE4,1EE6,1EE8,1EEA,1EEC,1EEE,1EF0,1EF2,1EF4,1EF6,1EF8,1EFA,1EFC,1EFE,1F0^,1F18,1F19,1F1A,1F1B,1F1C,1F1D,1F2^,1F3^,1F48,1F49,1F4A,1F4B,1F4C,1F4D,1F59,1F5B,1F5D,1F5F,1F6^,1FB8,1FB9,1FBA,1FBB,1FC8,1FC9,1FCA,1FCB,1FD8,1FD9,1FDA,1FDB,1FE8,1FE9,1FEA,1FEB,1FEC,1FF8,1FF9,1FFA,1FFB,2102,2107,210B,210C,210D,2110,2111,2112,2115,2119,211A,211B,211C,211D,2124,2126,2128,212A,212B,212C,212D,2130,2131,2132,2133,213E,213F,2145,2183,2C0*,2C1*,2C2*,2C60,2C62,2C63,2C64,2C67,2C69,2C6B,2C6D,2C6E,2C6F,2C70,2C72,2C75,2C7E,2C7F,2C80,2C82,2C84,2C86,2C88,2C8A,2C8C,2C8E,2C90,2C92,2C94,2C96,2C98,2C9A,2C9C,2C9E,2CA0,2CA2,2CA4,2CA6,2CA8,2CAA,2CAC,2CAE,2CB0,2CB2,2CB4,2CB6,2CB8,2CBA,2CBC,2CBE,2CC0,2CC2,2CC4,2CC6,2CC8,2CCA,2CCC,2CCE,2CD0,2CD2,2CD4,2CD6,2CD8,2CDA,2CDC,2CDE,2CE0,2CE2,2CEB,2CED,2CF2," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Lu}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,0040,005B,005C,005D,005E,005F,006*,007*,008*,009*,00A*,00B*,00D7,00DF,00E*,00F*,0101,0103,0105,0107,0109,010B,010D,010F,0111,0113,0115,0117,0119,011B,011D,011F,0121,0123,0125,0127,0129,012B,012D,012F,0131,0133,0135,0137,0138,013A,013C,013E,0140,0142,0144,0146,0148,0149,014B,014D,014F,0151,0153,0155,0157,0159,015B,015D,015F,0161,0163,0165,0167,0169,016B,016D,016F,0171,0173,0175,0177,017A,017C,017E,017F,0180,0183,0185,0188,018C,018D,0192,0195,0199,019A,019B,019E,01A1,01A3,01A5,01A8,01AA,01AB,01AD,01B0,01B4,01B6,01B9,01BA,01BB,01BD,01BE,01BF,01C0,01C1,01C2,01C3,01C5,01C6,01C8,01C9,01CB,01CC,01CE,01D0,01D2,01D4,01D6,01D8,01DA,01DC,01DD,01DF,01E1,01E3,01E5,01E7,01E9,01EB,01ED,01EF,01F0,01F2,01F3,01F5,01F9,01FB,01FD,01FF,0201,0203,0205,0207,0209,020B,020D,020F,0211,0213,0215,0217,0219,021B,021D,021F,0221,0223,0225,0227,0229,022B,022D,022F,0231,0233,0234,0235,0236,0237,0238,0239,023C,023F,0240,0242,0247,0249,024B,024D,024F,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,0371,0373,0374,0375,0377,0378,0379,037A,037B,037C,037D,037E,0380,0381,0382,0383,0384,0385,0387,038B,038D,0390,03A2,03AC,03AD,03AE,03AF,03B*,03C_,03C8,03C9,03CA,03CB,03CC,03CD,03CE,03D0,03D1,03D5,03D6,03D7,03D9,03DB,03DD,03DF,03E1,03E3,03E5,03E7,03E9,03EB,03ED,03EF,03F0,03F1,03F2,03F3,03F5,03F6,03F8,03FB,03FC,043*,044*,045*,0461,0463,0465,0467,0469,046B,046D,046F,0471,0473,0475,0477,0479,047B,047D,047F,0481,0482,0483,0484,0485,0486,0487,0488,0489,048B,048D,048F,0491,0493,0495,0497,0499,049B,049D,049F,04A1,04A3,04A5,04A7,04A9,04AB,04AD,04AF,04B1,04B3,04B5,04B7,04B9,04BB,04BD,04BF,04C2,04C4,04C6,04C8,04CA,04CC,04CE,04CF,04D1,04D3,04D5,04D7,04D9,04DB,04DD,04DF,04E1,04E3,04E5,04E7,04E9,04EB,04ED,04EF,04F1,04F3,04F5,04F7,04F9,04FB,04FD,04FF,0501,0503,0505,0507,0509,050B,050D,050F,0511,0513,0515,0517,0519,051B,051D,051F,0521,0523,0525,0527,0529,052B,052D,052F,0530,0557,055^,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10C6,10C8,10C9,10CA,10CB,10CC,10CE,10CF,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13F6,13F7,13F^,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1CBB,1CBC,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E01,1E03,1E05,1E07,1E09,1E0B,1E0D,1E0F,1E11,1E13,1E15,1E17,1E19,1E1B,1E1D,1E1F,1E21,1E23,1E25,1E27,1E29,1E2B,1E2D,1E2F,1E31,1E33,1E35,1E37,1E39,1E3B,1E3D,1E3F,1E41,1E43,1E45,1E47,1E49,1E4B,1E4D,1E4F,1E51,1E53,1E55,1E57,1E59,1E5B,1E5D,1E5F,1E61,1E63,1E65,1E67,1E69,1E6B,1E6D,1E6F,1E71,1E73,1E75,1E77,1E79,1E7B,1E7D,1E7F,1E81,1E83,1E85,1E87,1E89,1E8B,1E8D,1E8F,1E91,1E93,1E95,1E96,1E97,1E98,1E99,1E9A,1E9B,1E9C,1E9D,1E9F,1EA1,1EA3,1EA5,1EA7,1EA9,1EAB,1EAD,1EAF,1EB1,1EB3,1EB5,1EB7,1EB9,1EBB,1EBD,1EBF,1EC1,1EC3,1EC5,1EC7,1EC9,1ECB,1ECD,1ECF,1ED1,1ED3,1ED5,1ED7,1ED9,1EDB,1EDD,1EDF,1EE1,1EE3,1EE5,1EE7,1EE9,1EEB,1EED,1EEF,1EF1,1EF3,1EF5,1EF7,1EF9,1EFB,1EFD,1EFF,1F0_,1F1_,1F1E,1F1F,1F2_,1F3_,1F4_,1F4E,1F4F,1F5_,1F58,1F5A,1F5C,1F5E,1F6_,1F7*,1F8*,1F9*,1FA*,1FB_,1FBC,1FBD,1FBE,1FBF,1FC_,1FCC,1FCD,1FCE,1FCF,1FD_,1FDC,1FDD,1FDE,1FDF,1FE_,1FED,1FEE,1FEF,1FF_,1FFC,1FFD,1FFE,1FFF,200*,201*,202*,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,2100,2101,2103,2104,2105,2106,2108,2109,210A,210E,210F,2113,2114,2116,2117,2118,211E,211F,2120,2121,2122,2123,2125,2127,2129,212E,212F,2134,2135,2136,2137,2138,2139,213A,213B,213C,213D,2140,2141,2142,2143,2144,2146,2147,214^,215*,216*,217*,2180,2181,2182,2184,2185,2186,2187,218^,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C3*,2C4*,2C5*,2C61,2C65,2C66,2C68,2C6A,2C6C,2C71,2C73,2C74,2C76,2C77,2C78,2C79,2C7A,2C7B,2C7C,2C7D,2C81,2C83,2C85,2C87,2C89,2C8B,2C8D,2C8F,2C91,2C93,2C95,2C97,2C99,2C9B,2C9D,2C9F,2CA1,2CA3,2CA5,2CA7,2CA9,2CAB,2CAD,2CAF,2CB1,2CB3,2CB5,2CB7,2CB9,2CBB,2CBD,2CBF,2CC1,2CC3,2CC5,2CC7,2CC9,2CCB,2CCD,2CCF,2CD1,2CD3,2CD5,2CD7,2CD9,2CDB,2CDD,2CDF,2CE1,2CE3,2CE4,2CE5,2CE6,2CE7,2CE8,2CE9,2CEA,2CEC,2CEE,2CEF,2CF0,2CF1,2CF3,2CF4,2CF5,2CF6,2CF7,2CF^,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," // Lt ->> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, - If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Lt}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, - If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) -"01C5,01C8,01CB,01F2,1F88-1F8F,1F98-1F9F,1FA8-1FAF,1FBC,1FCC,1FFC," +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Lt}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"01C5,01C8,01CB,01F2,1F8^,1F9^,1FA^,1FBC,1FCC,1FFC," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Lt}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C0,01C1,01C2,01C3,01C4,01C6,01C7,01C9,01CA,01CC,01CD,01CE,01CF,01D*,01E*,01F0,01F1,01F3,01F4,01F5,01F6,01F7,01F^,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8_,1F9_,1FA_,1FB_,1FB8,1FB9,1FBA,1FBB,1FBD,1FBE,1FBF,1FC_,1FC8,1FC9,1FCA,1FCB,1FCD,1FCE,1FCF,1FD*,1FE*,1FF_,1FF8,1FF9,1FFA,1FFB,1FFD,1FFE,1FFF,200*,201*,202*,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," // Lm ->> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, - If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Lm}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, - If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) -"02B0-02B7,02B8-02BF,02C0,02C1,02C6,02C7,02C8-02CF,02D0,02D1,02E0,02E1,02E2,02E3,02E4,02EC,02EE,0374,037A,0559,0640,06E5,06E6,07F4,07F5,07FA,081A,0824,0828,08C9,0971,0E46,0EC6,10FC,17D7,1843,1AA7,1C78,1C79,1C7A,1C7B,1C7C,1C7D,1D2C,1D2D,1D2E,1D2F,1D30-1D37,1D38-1D3F,1D40-1D47,1D48-1D4F,1D50-1D57,1D58-1D5F,1D60-1D67,1D68,1D69,1D6A,1D78,1D9B,1D9C,1D9D,1D9E,1D9F,1DA0-1DA7,1DA8-1DAF,1DB0-1DB7,1DB8-1DBF," +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Lm}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"02B*,02C0,02C1,02C6,02C7,02C^,02D0,02D1,02E0,02E1,02E2,02E3,02E4,02EC,02EE,0374,037A,0559,0640,06E5,06E6,07F4,07F5,07FA,081A,0824,0828,08C9,0971,0E46,0EC6,10FC,17D7,1843,1AA7,1C78,1C79,1C7A,1C7B,1C7C,1C7D,1D2C,1D2D,1D2E,1D2F,1D3*,1D4*,1D5*,1D6_,1D68,1D69,1D6A,1D78,1D9B,1D9C,1D9D,1D9E,1D9F,1DA*,1DB*,2071,207F,209_,2098,2099,209A,209B,209C,2C7C,2C7D,2D6F,2E2F,3005,3031,3032,3033,3034,3035,303B,309D,309E,30FC,30FD,30FE," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Lm}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02C2,02C3,02C4,02C5,02D2,02D3,02D4,02D5,02D6,02D7,02D^,02E5,02E6,02E7,02E8,02E9,02EA,02EB,02ED,02EF,02F*,030*,031*,032*,033*,034*,035*,036*,0370,0371,0372,0373,0375,0376,0377,0378,0379,037B,037C,037D,037E,037F,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055_,0558,055A,055B,055C,055D,055E,055F,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,0641,0642,0643,0644,0645,0646,0647,064^,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E0,06E1,06E2,06E3,06E4,06E7,06E^,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F0,07F1,07F2,07F3,07F6,07F7,07F8,07F9,07FB,07FC,07FD,07FE,07FF,080*,081_,0818,0819,081B,081C,081D,081E,081F,0820,0821,0822,0823,0825,0826,0827,0829,082A,082B,082C,082D,082E,082F,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C_,08C8,08CA,08CB,08CC,08CD,08CE,08CF,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,0970,0972,0973,0974,0975,0976,0977,097^,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E40,0E41,0E42,0E43,0E44,0E45,0E47,0E4^,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC0,0EC1,0EC2,0EC3,0EC4,0EC5,0EC7,0EC^,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F_,10F8,10F9,10FA,10FB,10FD,10FE,10FF,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D0,17D1,17D2,17D3,17D4,17D5,17D6,17D^,17E*,17F*,180*,181*,182*,183*,1840,1841,1842,1844,1845,1846,1847,184^,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA0,1AA1,1AA2,1AA3,1AA4,1AA5,1AA6,1AA^,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7_,1C7E,1C7F,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2_,1D28,1D29,1D2A,1D2B,1D6B,1D6C,1D6D,1D6E,1D6F,1D7_,1D79,1D7A,1D7B,1D7C,1D7D,1D7E,1D7F,1D8*,1D9_,1D98,1D99,1D9A,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,204*,205*,206*,2070,2072,2073,2074,2075,2076,2077,2078,2079,207A,207B,207C,207D,207E,208*,209D,209E,209F,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7_,2C78,2C79,2C7A,2C7B,2C7E,2C7F,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6_,2D68,2D69,2D6A,2D6B,2D6C,2D6D,2D6E,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2_,2E28,2E29,2E2A,2E2B,2E2C,2E2D,2E2E,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,3000,3001,3002,3003,3004,3006,3007,300^,301*,302*,3030,3036,3037,3038,3039,303A,303C,303D,303E,303F,304*,305*,306*,307*,308*,309_,3098,3099,309A,309B,309C,309F,30A*,30B*,30C*,30D*,30E*,30F_,30F8,30F9,30FA,30FB,30FF,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," // Lo ->> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, - If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Lo}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, - If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) -"00AA,00BA,01BB,01C0,01C1,01C2,01C3,0294,05D0-05D7,05D8-05DF,05E0-05E7,05E8,05E9,05EA,05EF,05F0,05F1,05F2,0620-0627,0628-062F,0630-0637,0638-063F,0641,0642,0643,0644,0645,0646,0647,0648,0649,064A,066E,066F,0671,0672,0673,0674,0675,0676,0677,0678-067F,0680-0687,0688-068F,0690-0697,0698-069F,06A0-06A7,06A8-06AF,06B0-06B7,06B8-06BF,06C0-06C7,06C8-06CF,06D0,06D1,06D2,06D3,06D5,06EE,06EF,06FA,06FB,06FC,06FF,0710,0712,0713,0714,0715,0716,0717,0718-071F,0720-0727,0728-072F,074D,074E,074F,0750-0757,0758-075F,0760-0767,0768-076F,0770-0777,0778-077F,0780-0787,0788-078F,0790-0797,0798-079F,07A0,07A1,07A2,07A3,07A4,07A5,07B1,07CA,07CB,07CC,07CD,07CE,07CF,07D0-07D7,07D8-07DF,07E0-07E7,07E8,07E9,07EA,0800-0807,0808-080F,0810,0811,0812,0813,0814,0815,0840-0847,0848-084F,0850-0857,0858,0860-0867,0868,0869,086A,0870-0877,0878-087F,0880-0887,0889,088A,088B,088C,088D,088E,08A0-08A7,08A8-08AF,08B0-08B7,08B8-08BF,08C0-08C7,08C8,0904,0905,0906,0907,0908-090F,0910-0917,0918-091F,0920-0927,0928-092F,0930-0937,0938,0939,093D,0950,0958-095F,0960,0961,0972,0973,0974,0975,0976,0977,0978-097F,0980,0985,0986,0987,0988,0989,098A,098B,098C,098F,0990,0993,0994,0995,0996,0997,0998-099F,09A0-09A7,09A8,09AA,09AB,09AC,09AD,09AE,09AF,09B0,09B2,09B6,09B7,09B8,09B9,09BD,09CE,09DC,09DD,09DF,09E0,09E1,09F0,09F1,09FC,0A05,0A06,0A07,0A08,0A09,0A0A,0A0F,0A10,0A13,0A14,0A15,0A16,0A17,0A18-0A1F,0A20-0A27,0A28,0A2A,0A2B,0A2C,0A2D,0A2E,0A2F,0A30,0A32,0A33,0A35,0A36,0A38,0A39,0A59,0A5A,0A5B,0A5C,0A5E,0A72,0A73,0A74,0A85,0A86,0A87,0A88,0A89,0A8A,0A8B,0A8C,0A8D,0A8F,0A90,0A91,0A93,0A94,0A95,0A96,0A97,0A98-0A9F,0AA0-0AA7,0AA8,0AAA,0AAB,0AAC,0AAD,0AAE,0AAF,0AB0,0AB2,0AB3,0AB5,0AB6,0AB7,0AB8,0AB9,0ABD,0AD0,0AE0,0AE1,0AF9,0B05,0B06,0B07,0B08,0B09,0B0A,0B0B,0B0C,0B0F,0B10,0B13,0B14,0B15,0B16,0B17,0B18-0B1F,0B20-0B27,0B28,0B2A,0B2B,0B2C,0B2D,0B2E,0B2F,0B30,0B32,0B33,0B35,0B36,0B37,0B38,0B39,0B3D,0B5C,0B5D,0B5F,0B60,0B61,0B71,0B83,0B85,0B86,0B87,0B88,0B89,0B8A,0B8E,0B8F,0B90,0B92,0B93,0B94,0B95,0B99,0B9A,0B9C,0B9E,0B9F,0BA3,0BA4,0BA8,0BA9,0BAA,0BAE,0BAF,0BB0-0BB7,0BB8,0BB9,0BD0,0C05,0C06,0C07,0C08,0C09,0C0A,0C0B,0C0C,0C0E,0C0F,0C10,0C12,0C13,0C14,0C15,0C16,0C17,0C18-0C1F,0C20-0C27,0C28,0C2A,0C2B,0C2C,0C2D,0C2E,0C2F,0C30-0C37,0C38,0C39,0C3D,0C58,0C59,0C5A,0C5D,0C60,0C61,0C80,0C85,0C86,0C87,0C88,0C89,0C8A,0C8B,0C8C,0C8E,0C8F,0C90,0C92,0C93,0C94,0C95,0C96,0C97,0C98-0C9F,0CA0-0CA7,0CA8,0CAA,0CAB,0CAC,0CAD,0CAE,0CAF,0CB0,0CB1,0CB2,0CB3,0CB5,0CB6,0CB7,0CB8,0CB9,0CBD,0CDD,0CDE,0CE0,0CE1,0CF1,0CF2,0D04,0D05,0D06,0D07,0D08,0D09,0D0A,0D0B,0D0C,0D0E,0D0F,0D10,0D12,0D13,0D14,0D15,0D16,0D17,0D18-0D1F,0D20-0D27,0D28-0D2F,0D30-0D37,0D38,0D39,0D3A,0D3D,0D4E,0D54,0D55,0D56,0D5F,0D60,0D61,0D7A,0D7B,0D7C,0D7D,0D7E,0D7F,0D85,0D86,0D87,0D88-0D8F,0D90,0D91,0D92,0D93,0D94,0D95,0D96,0D9A,0D9B,0D9C,0D9D,0D9E,0D9F,0DA0-0DA7,0DA8-0DAF,0DB0,0DB1,0DB3,0DB4,0DB5,0DB6,0DB7,0DB8,0DB9,0DBA,0DBB,0DBD,0DC0,0DC1,0DC2,0DC3,0DC4,0DC5,0DC6,0E01,0E02,0E03,0E04,0E05,0E06,0E07,0E08-0E0F,0E10-0E17,0E18-0E1F,0E20-0E27,0E28-0E2F,0E30,0E32,0E33,0E40,0E41,0E42,0E43,0E44,0E45,0E81,0E82,0E84,0E86,0E87,0E88,0E89,0E8A,0E8C,0E8D,0E8E,0E8F,0E90-0E97,0E98-0E9F,0EA0,0EA1,0EA2,0EA3,0EA5,0EA7,0EA8-0EAF,0EB0,0EB2,0EB3,0EBD,0EC0,0EC1,0EC2,0EC3,0EC4,0EDC,0EDD,0EDE,0EDF,0F00,0F40-0F47,0F49,0F4A,0F4B,0F4C,0F4D,0F4E,0F4F,0F50-0F57,0F58-0F5F,0F60-0F67,0F68,0F69,0F6A,0F6B,0F6C,0F88,0F89,0F8A,0F8B,0F8C,1000-1007,1008-100F,1010-1017,1018-101F,1020-1027,1028,1029,102A,103F,1050,1051,1052,1053,1054,1055,105A,105B,105C,105D,1061,1065,1066,106E,106F,1070,1075,1076,1077,1078-107F,1080,1081,108E,1100-1107,1108-110F,1110-1117,1118-111F,1120-1127,1128-112F,1130-1137,1138-113F,1140-1147,1148-114F,1150-1157,1158-115F,1160-1167,1168-116F,1170-1177,1178-117F,1180-1187,1188-118F,1190-1197,1198-119F,11A0-11A7,11A8-11AF,11B0-11B7,11B8-11BF,11C0-11C7,11C8-11CF,11D0-11D7,11D8-11DF,11E0-11E7,11E8-11EF,11F0-11F7,11F8-11FF,1200-1207,1208-120F,1210-1217,1218-121F,1220-1227,1228-122F,1230-1237,1238-123F,1240-1247,1248,124A,124B,124C,124D,1250,1251,1252,1253,1254,1255,1256,1258,125A,125B,125C,125D,1260-1267,1268-126F,1270-1277,1278-127F,1280-1287,1288,128A,128B,128C,128D,1290-1297,1298-129F,12A0-12A7,12A8-12AF,12B0,12B2,12B3,12B4,12B5,12B8,12B9,12BA,12BB,12BC,12BD,12BE,12C0,12C2,12C3,12C4,12C5,12C8-12CF,12D0,12D1,12D2,12D3,12D4,12D5,12D6,12D8-12DF,12E0-12E7,12E8-12EF,12F0-12F7,12F8-12FF,1300-1307,1308-130F,1310,1312,1313,1314,1315,1318-131F,1320-1327,1328-132F,1330-1337,1338-133F,1340-1347,1348-134F,1350-1357,1358,1359,135A,1380-1387,1388-138F,1401,1402,1403,1404,1405,1406,1407,1408-140F,1410-1417,1418-141F,1420-1427,1428-142F,1430-1437,1438-143F,1440-1447,1448-144F,1450-1457,1458-145F,1460-1467,1468-146F,1470-1477,1478-147F,1480-1487,1488-148F,1490-1497,1498-149F,14A0-14A7,14A8-14AF,14B0-14B7,14B8-14BF,14C0-14C7,14C8-14CF,14D0-14D7,14D8-14DF,14E0-14E7,14E8-14EF,14F0-14F7,14F8-14FF,1500-1507,1508-150F,1510-1517,1518-151F,1520-1527,1528-152F,1530-1537,1538-153F,1540-1547,1548-154F,1550-1557,1558-155F,1560-1567,1568-156F,1570-1577,1578-157F,1580-1587,1588-158F,1590-1597,1598-159F,15A0-15A7,15A8-15AF,15B0-15B7,15B8-15BF,15C0-15C7,15C8-15CF,15D0-15D7,15D8-15DF,15E0-15E7,15E8-15EF,15F0-15F7,15F8-15FF,1600-1607,1608-160F,1610-1617,1618-161F,1620-1627,1628-162F,1630-1637,1638-163F,1640-1647,1648-164F,1650-1657,1658-165F,1660-1667,1668,1669,166A,166B,166C,166F,1670-1677,1678-167F,1681,1682,1683,1684,1685,1686,1687,1688-168F,1690-1697,1698,1699,169A,16A0-16A7,16A8-16AF,16B0-16B7,16B8-16BF,16C0-16C7,16C8-16CF,16D0-16D7,16D8-16DF,16E0-16E7,16E8,16E9,16EA,16F1,16F2,16F3,16F4,16F5,16F6,16F7,16F8,1700-1707,1708-170F,1710,1711,171F,1720-1727,1728-172F,1730,1731,1740-1747,1748-174F,1750,1751,1760-1767,1768,1769,176A,176B,176C,176E,176F,1770,1780-1787,1788-178F,1790-1797,1798-179F,17A0-17A7,17A8-17AF,17B0,17B1,17B2,17B3,17DC,1820-1827,1828-182F,1830-1837,1838-183F,1840,1841,1842,1844,1845,1846,1847,1848-184F,1850-1857,1858-185F,1860-1867,1868-186F,1870-1877,1878,1880,1881,1882,1883,1884,1887,1888-188F,1890-1897,1898-189F,18A0-18A7,18A8,18AA,18B0-18B7,18B8-18BF,18C0-18C7,18C8-18CF,18D0-18D7,18D8-18DF,18E0-18E7,18E8-18EF,18F0,18F1,18F2,18F3,18F4,18F5,1900-1907,1908-190F,1910-1917,1918,1919,191A,191B,191C,191D,191E,1950-1957,1958-195F,1960-1967,1968,1969,196A,196B,196C,196D,1970,1971,1972,1973,1974,1980-1987,1988-198F,1990-1997,1998-199F,19A0-19A7,19A8,19A9,19AA,19AB,19B0-19B7,19B8-19BF,19C0-19C7,19C8,19C9,1A00-1A07,1A08-1A0F,1A10,1A11,1A12,1A13,1A14,1A15,1A16,1A20-1A27,1A28-1A2F,1A30-1A37,1A38-1A3F,1A40-1A47,1A48-1A4F,1A50,1A51,1A52,1A53,1A54,1B05,1B06,1B07,1B08-1B0F,1B10-1B17,1B18-1B1F,1B20-1B27,1B28-1B2F,1B30,1B31,1B32,1B33,1B45,1B46,1B47,1B48,1B49,1B4A,1B4B,1B4C,1B83,1B84,1B85,1B86,1B87,1B88-1B8F,1B90-1B97,1B98-1B9F,1BA0,1BAE,1BAF,1BBA,1BBB,1BBC,1BBD,1BBE,1BBF,1BC0-1BC7,1BC8-1BCF,1BD0-1BD7,1BD8-1BDF,1BE0,1BE1,1BE2,1BE3,1BE4,1BE5,1C00-1C07,1C08-1C0F,1C10-1C17,1C18-1C1F,1C20,1C21,1C22,1C23,1C4D,1C4E,1C4F,1C5A,1C5B,1C5C,1C5D,1C5E,1C5F,1C60-1C67,1C68-1C6F,1C70-1C77,1CE9,1CEA,1CEB,1CEC,1CEE,1CEF,1CF0,1CF1,1CF2,1CF3,1CF5,1CF6,1CFA," +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Lo}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"00AA,00BA,01BB,01C0,01C1,01C2,01C3,0294,05D*,05E_,05E8,05E9,05EA,05EF,05F0,05F1,05F2,062*,063*,0641,0642,0643,0644,0645,0646,0647,0648,0649,064A,066E,066F,0671,0672,0673,0674,0675,0676,0677,067^,068*,069*,06A*,06B*,06C*,06D0,06D1,06D2,06D3,06D5,06EE,06EF,06FA,06FB,06FC,06FF,0710,0712,0713,0714,0715,0716,0717,071^,072*,074D,074E,074F,075*,076*,077*,078*,079*,07A0,07A1,07A2,07A3,07A4,07A5,07B1,07CA,07CB,07CC,07CD,07CE,07CF,07D*,07E_,07E8,07E9,07EA,080*,0810,0811,0812,0813,0814,0815,084*,085_,0858,086_,0868,0869,086A,087*,088_,0889,088A,088B,088C,088D,088E,08A*,08B*,08C_,08C8,0904,0905,0906,0907,090^,091*,092*,093_,0938,0939,093D,0950,095^,0960,0961,0972,0973,0974,0975,0976,0977,097^,0980,0985,0986,0987,0988,0989,098A,098B,098C,098F,0990,0993,0994,0995,0996,0997,099^,09A_,09A8,09AA,09AB,09AC,09AD,09AE,09AF,09B0,09B2,09B6,09B7,09B8,09B9,09BD,09CE,09DC,09DD,09DF,09E0,09E1,09F0,09F1,09FC,0A05,0A06,0A07,0A08,0A09,0A0A,0A0F,0A10,0A13,0A14,0A15,0A16,0A17,0A1^,0A2_,0A28,0A2A,0A2B,0A2C,0A2D,0A2E,0A2F,0A30,0A32,0A33,0A35,0A36,0A38,0A39,0A59,0A5A,0A5B,0A5C,0A5E,0A72,0A73,0A74,0A85,0A86,0A87,0A88,0A89,0A8A,0A8B,0A8C,0A8D,0A8F,0A90,0A91,0A93,0A94,0A95,0A96,0A97,0A9^,0AA_,0AA8,0AAA,0AAB,0AAC,0AAD,0AAE,0AAF,0AB0,0AB2,0AB3,0AB5,0AB6,0AB7,0AB8,0AB9,0ABD,0AD0,0AE0,0AE1,0AF9,0B05,0B06,0B07,0B08,0B09,0B0A,0B0B,0B0C,0B0F,0B10,0B13,0B14,0B15,0B16,0B17,0B1^,0B2_,0B28,0B2A,0B2B,0B2C,0B2D,0B2E,0B2F,0B30,0B32,0B33,0B35,0B36,0B37,0B38,0B39,0B3D,0B5C,0B5D,0B5F,0B60,0B61,0B71,0B83,0B85,0B86,0B87,0B88,0B89,0B8A,0B8E,0B8F,0B90,0B92,0B93,0B94,0B95,0B99,0B9A,0B9C,0B9E,0B9F,0BA3,0BA4,0BA8,0BA9,0BAA,0BAE,0BAF,0BB_,0BB8,0BB9,0BD0,0C05,0C06,0C07,0C08,0C09,0C0A,0C0B,0C0C,0C0E,0C0F,0C10,0C12,0C13,0C14,0C15,0C16,0C17,0C1^,0C2_,0C28,0C2A,0C2B,0C2C,0C2D,0C2E,0C2F,0C3_,0C38,0C39,0C3D,0C58,0C59,0C5A,0C5D,0C60,0C61,0C80,0C85,0C86,0C87,0C88,0C89,0C8A,0C8B,0C8C,0C8E,0C8F,0C90,0C92,0C93,0C94,0C95,0C96,0C97,0C9^,0CA_,0CA8,0CAA,0CAB,0CAC,0CAD,0CAE,0CAF,0CB0,0CB1,0CB2,0CB3,0CB5,0CB6,0CB7,0CB8,0CB9,0CBD,0CDD,0CDE,0CE0,0CE1,0CF1,0CF2,0D04,0D05,0D06,0D07,0D08,0D09,0D0A,0D0B,0D0C,0D0E,0D0F,0D10,0D12,0D13,0D14,0D15,0D16,0D17,0D1^,0D2*,0D3_,0D38,0D39,0D3A,0D3D,0D4E,0D54,0D55,0D56,0D5F,0D60,0D61,0D7A,0D7B,0D7C,0D7D,0D7E,0D7F,0D85,0D86,0D87,0D8^,0D90,0D91,0D92,0D93,0D94,0D95,0D96,0D9A,0D9B,0D9C,0D9D,0D9E,0D9F,0DA*,0DB0,0DB1,0DB3,0DB4,0DB5,0DB6,0DB7,0DB8,0DB9,0DBA,0DBB,0DBD,0DC0,0DC1,0DC2,0DC3,0DC4,0DC5,0DC6,0E01,0E02,0E03,0E04,0E05,0E06,0E07,0E0^,0E1*,0E2*,0E30,0E32,0E33,0E40,0E41,0E42,0E43,0E44,0E45,0E81,0E82,0E84,0E86,0E87,0E88,0E89,0E8A,0E8C,0E8D,0E8E,0E8F,0E9*,0EA0,0EA1,0EA2,0EA3,0EA5,0EA7,0EA^,0EB0,0EB2,0EB3,0EBD,0EC0,0EC1,0EC2,0EC3,0EC4,0EDC,0EDD,0EDE,0EDF,0F00,0F4_,0F49,0F4A,0F4B,0F4C,0F4D,0F4E,0F4F,0F5*,0F6_,0F68,0F69,0F6A,0F6B,0F6C,0F88,0F89,0F8A,0F8B,0F8C,100*,101*,102_,1028,1029,102A,103F,1050,1051,1052,1053,1054,1055,105A,105B,105C,105D,1061,1065,1066,106E,106F,1070,1075,1076,1077,107^,1080,1081,108E,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124_,1248,124A,124B,124C,124D,1250,1251,1252,1253,1254,1255,1256,1258,125A,125B,125C,125D,126*,127*,128_,1288,128A,128B,128C,128D,129*,12A*,12B0,12B2,12B3,12B4,12B5,12B8,12B9,12BA,12BB,12BC,12BD,12BE,12C0,12C2,12C3,12C4,12C5,12C^,12D0,12D1,12D2,12D3,12D4,12D5,12D6,12D^,12E*,12F*,130*,1310,1312,1313,1314,1315,131^,132*,133*,134*,135_,1358,1359,135A,138*,1401,1402,1403,1404,1405,1406,1407,140^,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166_,1668,1669,166A,166B,166C,166F,167*,1681,1682,1683,1684,1685,1686,1687,168^,169_,1698,1699,169A,16A*,16B*,16C*,16D*,16E_,16E8,16E9,16EA,16F1,16F2,16F3,16F4,16F5,16F6,16F7,16F8,170*,1710,1711,171F,172*,1730,1731,174*,1750,1751,176_,1768,1769,176A,176B,176C,176E,176F,1770,178*,179*,17A*,17B0,17B1,17B2,17B3,17DC,182*,183*,1840,1841,1842,1844,1845,1846,1847,184^,185*,186*,187_,1878,1880,1881,1882,1883,1884,1887,188^,189*,18A_,18A8,18AA,18B*,18C*,18D*,18E*,18F0,18F1,18F2,18F3,18F4,18F5,190*,191_,1918,1919,191A,191B,191C,191D,191E,195*,196_,1968,1969,196A,196B,196C,196D,1970,1971,1972,1973,1974,198*,199*,19A_,19A8,19A9,19AA,19AB,19B*,19C_,19C8,19C9,1A0*,1A10,1A11,1A12,1A13,1A14,1A15,1A16,1A2*,1A3*,1A4*,1A50,1A51,1A52,1A53,1A54,1B05,1B06,1B07,1B0^,1B1*,1B2*,1B30,1B31,1B32,1B33,1B45,1B46,1B47,1B48,1B49,1B4A,1B4B,1B4C,1B83,1B84,1B85,1B86,1B87,1B8^,1B9*,1BA0,1BAE,1BAF,1BBA,1BBB,1BBC,1BBD,1BBE,1BBF,1BC*,1BD*,1BE0,1BE1,1BE2,1BE3,1BE4,1BE5,1C0*,1C1*,1C20,1C21,1C22,1C23,1C4D,1C4E,1C4F,1C5A,1C5B,1C5C,1C5D,1C5E,1C5F,1C6*,1C7_,1CE9,1CEA,1CEB,1CEC,1CEE,1CEF,1CF0,1CF1,1CF2,1CF3,1CF5,1CF6,1CFA,2135,2136,2137,2138,2D3*,2D4*,2D5*,2D6_,2D8*,2D90,2D91,2D92,2D93,2D94,2D95,2D96,2DA0,2DA1,2DA2,2DA3,2DA4,2DA5,2DA6,2DA8,2DA9,2DAA,2DAB,2DAC,2DAD,2DAE,2DB0,2DB1,2DB2,2DB3,2DB4,2DB5,2DB6,2DB8,2DB9,2DBA,2DBB,2DBC,2DBD,2DBE,2DC0,2DC1,2DC2,2DC3,2DC4,2DC5,2DC6,2DC8,2DC9,2DCA,2DCB,2DCC,2DCD,2DCE,2DD0,2DD1,2DD2,2DD3,2DD4,2DD5,2DD6,2DD8,2DD9,2DDA,2DDB,2DDC,2DDD,2DDE,3006,303C,3041,3042,3043,3044,3045,3046,3047,304^,305*,306*,307*,308*,3090,3091,3092,3093,3094,3095,3096,309F,30A1,30A2,30A3,30A4,30A5,30A6,30A7,30A^,30B*,30C*,30D*,30E*,30F_,30F8,30F9,30FA,30FF,3105,3106,3107,310^,311*,312*,3131,3132,3133,3134,3135,3136,3137,313^,314*,315*,316*,317*,318_,3188,3189,318A,318B,318C,318D,318E,31A*,31B*,31F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Lo}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A_,00A8,00A9,00AB,00AC,00AD,00AE,00AF,00B_,00B8,00B9,00BB,00BC,00BD,00BE,00BF,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B_,01B8,01B9,01BA,01BC,01BD,01BE,01BF,01C4,01C5,01C6,01C7,01C^,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,0290,0291,0292,0293,0295,0296,0297,029^,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05EB,05EC,05ED,05EE,05F3,05F4,05F5,05F6,05F7,05F^,060*,061*,0640,064B,064C,064D,064E,064F,065*,066_,0668,0669,066A,066B,066C,066D,0670,06D4,06D6,06D7,06D^,06E_,06E8,06E9,06EA,06EB,06EC,06ED,06F_,06F8,06F9,06FD,06FE,070*,0711,073*,074_,0748,0749,074A,074B,074C,07A6,07A7,07A^,07B0,07B2,07B3,07B4,07B5,07B6,07B7,07B^,07C_,07C8,07C9,07EB,07EC,07ED,07EE,07EF,07F*,0816,0817,081^,082*,083*,0859,085A,085B,085C,085D,085E,085F,086B,086C,086D,086E,086F,0888,088F,089*,08C9,08CA,08CB,08CC,08CD,08CE,08CF,08D*,08E*,08F*,0900,0901,0902,0903,093A,093B,093C,093E,093F,094*,0951,0952,0953,0954,0955,0956,0957,0962,0963,0964,0965,0966,0967,096^,0970,0971,0981,0982,0983,0984,098D,098E,0991,0992,09A9,09B1,09B3,09B4,09B5,09BA,09BB,09BC,09BE,09BF,09C_,09C8,09C9,09CA,09CB,09CC,09CD,09CF,09D_,09D8,09D9,09DA,09DB,09DE,09E2,09E3,09E4,09E5,09E6,09E7,09E^,09F2,09F3,09F4,09F5,09F6,09F7,09F8,09F9,09FA,09FB,09FD,09FE,09FF,0A00,0A01,0A02,0A03,0A04,0A0B,0A0C,0A0D,0A0E,0A11,0A12,0A29,0A31,0A34,0A37,0A3A,0A3B,0A3C,0A3D,0A3E,0A3F,0A4*,0A5_,0A58,0A5D,0A5F,0A6*,0A70,0A71,0A75,0A76,0A77,0A7^,0A80,0A81,0A82,0A83,0A84,0A8E,0A92,0AA9,0AB1,0AB4,0ABA,0ABB,0ABC,0ABE,0ABF,0AC*,0AD1,0AD2,0AD3,0AD4,0AD5,0AD6,0AD7,0AD^,0AE2,0AE3,0AE4,0AE5,0AE6,0AE7,0AE^,0AF_,0AF8,0AFA,0AFB,0AFC,0AFD,0AFE,0AFF,0B00,0B01,0B02,0B03,0B04,0B0D,0B0E,0B11,0B12,0B29,0B31,0B34,0B3A,0B3B,0B3C,0B3E,0B3F,0B4*,0B5_,0B58,0B59,0B5A,0B5B,0B5E,0B62,0B63,0B64,0B65,0B66,0B67,0B6^,0B70,0B72,0B73,0B74,0B75,0B76,0B77,0B7^,0B80,0B81,0B82,0B84,0B8B,0B8C,0B8D,0B91,0B96,0B97,0B98,0B9B,0B9D,0BA0,0BA1,0BA2,0BA5,0BA6,0BA7,0BAB,0BAC,0BAD,0BBA,0BBB,0BBC,0BBD,0BBE,0BBF,0BC*,0BD1,0BD2,0BD3,0BD4,0BD5,0BD6,0BD7,0BD^,0BE*,0BF*,0C00,0C01,0C02,0C03,0C04,0C0D,0C11,0C29,0C3A,0C3B,0C3C,0C3E,0C3F,0C4*,0C5_,0C5B,0C5C,0C5E,0C5F,0C62,0C63,0C64,0C65,0C66,0C67,0C6^,0C7*,0C81,0C82,0C83,0C84,0C8D,0C91,0CA9,0CB4,0CBA,0CBB,0CBC,0CBE,0CBF,0CC*,0CD_,0CD8,0CD9,0CDA,0CDB,0CDC,0CDF,0CE2,0CE3,0CE4,0CE5,0CE6,0CE7,0CE^,0CF0,0CF3,0CF4,0CF5,0CF6,0CF7,0CF^,0D00,0D01,0D02,0D03,0D0D,0D11,0D3B,0D3C,0D3E,0D3F,0D4_,0D48,0D49,0D4A,0D4B,0D4C,0D4D,0D4F,0D50,0D51,0D52,0D53,0D57,0D58,0D59,0D5A,0D5B,0D5C,0D5D,0D5E,0D62,0D63,0D64,0D65,0D66,0D67,0D6^,0D7_,0D78,0D79,0D80,0D81,0D82,0D83,0D84,0D97,0D98,0D99,0DB2,0DBC,0DBE,0DBF,0DC7,0DC^,0DD*,0DE*,0DF*,0E00,0E31,0E34,0E35,0E36,0E37,0E3^,0E46,0E47,0E4^,0E5*,0E6*,0E7*,0E80,0E83,0E85,0E8B,0EA4,0EA6,0EB1,0EB4,0EB5,0EB6,0EB7,0EB8,0EB9,0EBA,0EBB,0EBC,0EBE,0EBF,0EC5,0EC6,0EC7,0EC^,0ED_,0ED8,0ED9,0EDA,0EDB,0EE*,0EF*,0F01,0F02,0F03,0F04,0F05,0F06,0F07,0F0^,0F1*,0F2*,0F3*,0F48,0F6D,0F6E,0F6F,0F7*,0F8_,0F8D,0F8E,0F8F,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,102B,102C,102D,102E,102F,103_,1038,1039,103A,103B,103C,103D,103E,104*,1056,1057,1058,1059,105E,105F,1060,1062,1063,1064,1067,1068,1069,106A,106B,106C,106D,1071,1072,1073,1074,1082,1083,1084,1085,1086,1087,1088,1089,108A,108B,108C,108D,108F,109*,10A*,10B*,10C*,10D*,10E*,10F*,1249,124E,124F,1257,1259,125E,125F,1289,128E,128F,12B1,12B6,12B7,12BF,12C1,12C6,12C7,12D7,1311,1316,1317,135B,135C,135D,135E,135F,136*,137*,139*,13A*,13B*,13C*,13D*,13E*,13F*,1400,166D,166E,1680,169B,169C,169D,169E,169F,16EB,16EC,16ED,16EE,16EF,16F0,16F9,16FA,16FB,16FC,16FD,16FE,16FF,1712,1713,1714,1715,1716,1717,1718,1719,171A,171B,171C,171D,171E,1732,1733,1734,1735,1736,1737,173^,1752,1753,1754,1755,1756,1757,175^,176D,1771,1772,1773,1774,1775,1776,1777,177^,17B4,17B5,17B6,17B7,17B^,17C*,17D_,17D8,17D9,17DA,17DB,17DD,17DE,17DF,17E*,17F*,180*,181*,1843,1879,187A,187B,187C,187D,187E,187F,1885,1886,18A9,18AB,18AC,18AD,18AE,18AF,18F6,18F7,18F^,191F,192*,193*,194*,196E,196F,1975,1976,1977,197^,19AC,19AD,19AE,19AF,19CA,19CB,19CC,19CD,19CE,19CF,19D*,19E*,19F*,1A17,1A1^,1A55,1A56,1A57,1A5^,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B00,1B01,1B02,1B03,1B04,1B34,1B35,1B36,1B37,1B3^,1B40,1B41,1B42,1B43,1B44,1B4D,1B4E,1B4F,1B5*,1B6*,1B7*,1B80,1B81,1B82,1BA1,1BA2,1BA3,1BA4,1BA5,1BA6,1BA7,1BA8,1BA9,1BAA,1BAB,1BAC,1BAD,1BB_,1BB8,1BB9,1BE6,1BE7,1BE^,1BF*,1C24,1C25,1C26,1C27,1C2^,1C3*,1C4_,1C48,1C49,1C4A,1C4B,1C4C,1C5_,1C58,1C59,1C7^,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE_,1CE8,1CED,1CF4,1CF7,1CF8,1CF9,1CFB,1CFC,1CFD,1CFE,1CFF,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,2130,2131,2132,2133,2134,2139,213A,213B,213C,213D,213E,213F,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D6^,2D7*,2D97,2D9^,2DA7,2DAF,2DB7,2DBF,2DC7,2DCF,2DD7,2DDF,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,3000,3001,3002,3003,3004,3005,3007,300^,301*,302*,303_,3038,3039,303A,303B,303D,303E,303F,3040,3097,3098,3099,309A,309B,309C,309D,309E,30A0,30FB,30FC,30FD,30FE,3100,3101,3102,3103,3104,3130,318F,319*,31C*,31D*,31E*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*," // M ->> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, - If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{M}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, - If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) +// \u0cf3 reports as false in .NET 4.7 & .NET 7, but true in .NET 8, PCRE2, and JavaScript +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{M}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"030*,031*,032*,033*,034*,035*,036*,0483,0484,0485,0486,0487,0488,0489,0591,0592,0593,0594,0595,0596,0597,059^,05A*,05B_,05B8,05B9,05BA,05BB,05BC,05BD,05BF,05C1,05C2,05C4,05C5,05C7,061_,0618,0619,061A,064B,064C,064D,064E,064F,065*,0670,06D6,06D7,06D8,06D9,06DA,06DB,06DC,06DF,06E0,06E1,06E2,06E3,06E4,06E7,06E8,06EA,06EB,06EC,06ED,0711,073*,074_,0748,0749,074A,07A6,07A7,07A^,07B0,07EB,07EC,07ED,07EE,07EF,07F0,07F1,07F2,07F3,07FD,0816,0817,0818,0819,081B,081C,081D,081E,081F,0820,0821,0822,0823,0825,0826,0827,0829,082A,082B,082C,082D,0859,085A,085B,089^,08CA,08CB,08CC,08CD,08CE,08CF,08D*,08E0,08E1,08E3,08E4,08E5,08E6,08E7,08E^,08F*,0900,0901,0902,0903,093A,093B,093C,093E,093F,094*,0951,0952,0953,0954,0955,0956,0957,0962,0963,0981,0982,0983,09BC,09BE,09BF,09C0,09C1,09C2,09C3,09C4,09C7,09C8,09CB,09CC,09CD,09D7,09E2,09E3,09FE,0A01,0A02,0A03,0A3C,0A3E,0A3F,0A40,0A41,0A42,0A47,0A48,0A4B,0A4C,0A4D,0A51,0A70,0A71,0A75,0A81,0A82,0A83,0ABC,0ABE,0ABF,0AC0,0AC1,0AC2,0AC3,0AC4,0AC5,0AC7,0AC8,0AC9,0ACB,0ACC,0ACD,0AE2,0AE3,0AFA,0AFB,0AFC,0AFD,0AFE,0AFF,0B01,0B02,0B03,0B3C,0B3E,0B3F,0B40,0B41,0B42,0B43,0B44,0B47,0B48,0B4B,0B4C,0B4D,0B55,0B56,0B57,0B62,0B63,0B82,0BBE,0BBF,0BC0,0BC1,0BC2,0BC6,0BC7,0BC8,0BCA,0BCB,0BCC,0BCD,0BD7,0C00,0C01,0C02,0C03,0C04,0C3C,0C3E,0C3F,0C40,0C41,0C42,0C43,0C44,0C46,0C47,0C48,0C4A,0C4B,0C4C,0C4D,0C55,0C56,0C62,0C63,0C81,0C82,0C83,0CBC,0CBE,0CBF,0CC0,0CC1,0CC2,0CC3,0CC4,0CC6,0CC7,0CC8,0CCA,0CCB,0CCC,0CCD,0CD5,0CD6,0CE2,0CE3,0D00,0D01,0D02,0D03,0D3B,0D3C,0D3E,0D3F,0D40,0D41,0D42,0D43,0D44,0D46,0D47,0D48,0D4A,0D4B,0D4C,0D4D,0D57,0D62,0D63,0D81,0D82,0D83,0DCA,0DCF,0DD0,0DD1,0DD2,0DD3,0DD4,0DD6,0DD^,0DF2,0DF3,0E31,0E34,0E35,0E36,0E37,0E38,0E39,0E3A,0E47,0E48,0E49,0E4A,0E4B,0E4C,0E4D,0E4E,0EB1,0EB4,0EB5,0EB6,0EB7,0EB8,0EB9,0EBA,0EBB,0EBC,0EC8,0EC9,0ECA,0ECB,0ECC,0ECD,0F18,0F19,0F35,0F37,0F39,0F3E,0F3F,0F71,0F72,0F73,0F74,0F75,0F76,0F77,0F7^,0F80,0F81,0F82,0F83,0F84,0F86,0F87,0F8D,0F8E,0F8F,0F9_,0F99,0F9A,0F9B,0F9C,0F9D,0F9E,0F9F,0FA*,0FB_,0FB8,0FB9,0FBA,0FBB,0FBC,0FC6,102B,102C,102D,102E,102F,103_,1038,1039,103A,103B,103C,103D,103E,1056,1057,1058,1059,105E,105F,1060,1062,1063,1064,1067,1068,1069,106A,106B,106C,106D,1071,1072,1073,1074,1082,1083,1084,1085,1086,1087,1088,1089,108A,108B,108C,108D,108F,109A,109B,109C,109D,135D,135E,135F,1712,1713,1714,1715,1732,1733,1734,1752,1753,1772,1773,17B4,17B5,17B6,17B7,17B^,17C*,17D0,17D1,17D2,17D3,17DD,180B,180C,180D,180F,1885,1886,18A9,192_,1928,1929,192A,192B,193_,1938,1939,193A,193B,1A17,1A18,1A19,1A1A,1A1B,1A55,1A56,1A57,1A58,1A59,1A5A,1A5B,1A5C,1A5D,1A5E,1A6*,1A7_,1A78,1A79,1A7A,1A7B,1A7C,1A7F,1AB*,1AC_,1AC8,1AC9,1ACA,1ACB,1ACC,1ACD,1ACE,1B00,1B01,1B02,1B03,1B04,1B34,1B35,1B36,1B37,1B3^,1B40,1B41,1B42,1B43,1B44,1B6B,1B6C,1B6D,1B6E,1B6F,1B70,1B71,1B72,1B73,1B80,1B81,1B82,1BA1,1BA2,1BA3,1BA4,1BA5,1BA6,1BA7,1BA8,1BA9,1BAA,1BAB,1BAC,1BAD,1BE6,1BE7,1BE^,1BF0,1BF1,1BF2,1BF3,1C24,1C25,1C26,1C27,1C2^,1C3_,1CD0,1CD1,1CD2,1CD4,1CD5,1CD6,1CD7,1CD^,1CE_,1CE8,1CED,1CF4,1CF7,1CF8,1CF9,1DC*,1DD*,1DE*,1DF*,20D*,20E*,20F0,2CEF,2CF0,2CF1,2D7F,2DE*,2DF*,302A,302B,302C,302D,302E,302F,3099,309A," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{M}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,0480,0481,0482,048A,048B,048C,048D,048E,048F,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,0590,05BE,05C0,05C3,05C6,05C^,05D*,05E*,05F*,060*,061B,061C,061D,061E,061F,062*,063*,064_,0648,0649,064A,066*,0671,0672,0673,0674,0675,0676,0677,067^,068*,069*,06A*,06B*,06C*,06D0,06D1,06D2,06D3,06D4,06D5,06DD,06DE,06E5,06E6,06E9,06EE,06EF,06F*,070*,0710,0712,0713,0714,0715,0716,0717,071^,072*,074B,074C,074D,074E,074F,075*,076*,077*,078*,079*,07A0,07A1,07A2,07A3,07A4,07A5,07B1,07B2,07B3,07B4,07B5,07B6,07B7,07B^,07C*,07D*,07E_,07E8,07E9,07EA,07F4,07F5,07F6,07F7,07F8,07F9,07FA,07FB,07FC,07FE,07FF,080*,0810,0811,0812,0813,0814,0815,081A,0824,0828,082E,082F,083*,084*,085_,0858,085C,085D,085E,085F,086*,087*,088*,089_,08A*,08B*,08C_,08C8,08C9,08E2,0904,0905,0906,0907,090^,091*,092*,093_,0938,0939,093D,0950,095^,0960,0961,0964,0965,0966,0967,096^,097*,0980,0984,0985,0986,0987,098^,099*,09A*,09B_,09B8,09B9,09BA,09BB,09BD,09C5,09C6,09C9,09CA,09CE,09CF,09D0,09D1,09D2,09D3,09D4,09D5,09D6,09D^,09E0,09E1,09E4,09E5,09E6,09E7,09E^,09F_,09F8,09F9,09FA,09FB,09FC,09FD,09FF,0A00,0A04,0A05,0A06,0A07,0A0^,0A1*,0A2*,0A3_,0A38,0A39,0A3A,0A3B,0A3D,0A43,0A44,0A45,0A46,0A49,0A4A,0A4E,0A4F,0A50,0A52,0A53,0A54,0A55,0A56,0A57,0A5^,0A6*,0A72,0A73,0A74,0A76,0A77,0A7^,0A80,0A84,0A85,0A86,0A87,0A8^,0A9*,0AA*,0AB_,0AB8,0AB9,0ABA,0ABB,0ABD,0AC6,0ACA,0ACE,0ACF,0AD*,0AE0,0AE1,0AE4,0AE5,0AE6,0AE7,0AE^,0AF_,0AF8,0AF9,0B00,0B04,0B05,0B06,0B07,0B0^,0B1*,0B2*,0B3_,0B38,0B39,0B3A,0B3B,0B3D,0B45,0B46,0B49,0B4A,0B4E,0B4F,0B50,0B51,0B52,0B53,0B54,0B5^,0B60,0B61,0B64,0B65,0B66,0B67,0B6^,0B7*,0B80,0B81,0B83,0B84,0B85,0B86,0B87,0B8^,0B9*,0BA*,0BB_,0BB8,0BB9,0BBA,0BBB,0BBC,0BBD,0BC3,0BC4,0BC5,0BC9,0BCE,0BCF,0BD0,0BD1,0BD2,0BD3,0BD4,0BD5,0BD6,0BD^,0BE*,0BF*,0C05,0C06,0C07,0C0^,0C1*,0C2*,0C3_,0C38,0C39,0C3A,0C3B,0C3D,0C45,0C49,0C4E,0C4F,0C50,0C51,0C52,0C53,0C54,0C57,0C5^,0C60,0C61,0C64,0C65,0C66,0C67,0C6^,0C7*,0C80,0C84,0C85,0C86,0C87,0C8^,0C9*,0CA*,0CB_,0CB8,0CB9,0CBA,0CBB,0CBD,0CC5,0CC9,0CCE,0CCF,0CD0,0CD1,0CD2,0CD3,0CD4,0CD7,0CD^,0CE0,0CE1,0CE4,0CE5,0CE6,0CE7,0CE^,0CF*,0D04,0D05,0D06,0D07,0D0^,0D1*,0D2*,0D3_,0D38,0D39,0D3A,0D3D,0D45,0D49,0D4E,0D4F,0D50,0D51,0D52,0D53,0D54,0D55,0D56,0D5^,0D60,0D61,0D64,0D65,0D66,0D67,0D6^,0D7*,0D80,0D84,0D85,0D86,0D87,0D8^,0D9*,0DA*,0DB*,0DC_,0DC8,0DC9,0DCB,0DCC,0DCD,0DCE,0DD5,0DD7,0DE*,0DF0,0DF1,0DF4,0DF5,0DF6,0DF7,0DF^,0E0*,0E1*,0E2*,0E30,0E32,0E33,0E3B,0E3C,0E3D,0E3E,0E3F,0E40,0E41,0E42,0E43,0E44,0E45,0E46,0E4F,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB0,0EB2,0EB3,0EBD,0EBE,0EBF,0EC_,0ECE,0ECF,0ED*,0EE*,0EF*,0F0*,0F1_,0F1A,0F1B,0F1C,0F1D,0F1E,0F1F,0F2*,0F30,0F31,0F32,0F33,0F34,0F36,0F38,0F3A,0F3B,0F3C,0F3D,0F4*,0F5*,0F6*,0F70,0F85,0F88,0F89,0F8A,0F8B,0F8C,0F98,0FBD,0FBE,0FBF,0FC0,0FC1,0FC2,0FC3,0FC4,0FC5,0FC7,0FC^,0FD*,0FE*,0FF*,100*,101*,102_,1028,1029,102A,103F,104*,1050,1051,1052,1053,1054,1055,105A,105B,105C,105D,1061,1065,1066,106E,106F,1070,1075,1076,1077,107^,1080,1081,108E,109_,1098,1099,109E,109F,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135_,1358,1359,135A,135B,135C,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,1710,1711,1716,1717,171^,172*,1730,1731,1735,1736,1737,173^,174*,1750,1751,1754,1755,1756,1757,175^,176*,1770,1771,1774,1775,1776,1777,177^,178*,179*,17A*,17B0,17B1,17B2,17B3,17D4,17D5,17D6,17D7,17D8,17D9,17DA,17DB,17DC,17DE,17DF,17E*,17F*,180_,1808,1809,180A,180E,181*,182*,183*,184*,185*,186*,187*,1880,1881,1882,1883,1884,1887,188^,189*,18A_,18A8,18AA,18AB,18AC,18AD,18AE,18AF,18B*,18C*,18D*,18E*,18F*,190*,191*,192C,192D,192E,192F,193C,193D,193E,193F,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A10,1A11,1A12,1A13,1A14,1A15,1A16,1A1C,1A1D,1A1E,1A1F,1A2*,1A3*,1A4*,1A50,1A51,1A52,1A53,1A54,1A5F,1A7D,1A7E,1A8*,1A9*,1AA*,1ACF,1AD*,1AE*,1AF*,1B05,1B06,1B07,1B0^,1B1*,1B2*,1B30,1B31,1B32,1B33,1B45,1B46,1B47,1B4^,1B5*,1B6_,1B68,1B69,1B6A,1B74,1B75,1B76,1B77,1B7^,1B83,1B84,1B85,1B86,1B87,1B8^,1B9*,1BA0,1BAE,1BAF,1BB*,1BC*,1BD*,1BE0,1BE1,1BE2,1BE3,1BE4,1BE5,1BF4,1BF5,1BF6,1BF7,1BF^,1C0*,1C1*,1C20,1C21,1C22,1C23,1C3^,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD3,1CE9,1CEA,1CEB,1CEC,1CEE,1CEF,1CF0,1CF1,1CF2,1CF3,1CF5,1CF6,1CFA,1CFB,1CFC,1CFD,1CFE,1CFF,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20F1,20F2,20F3,20F4,20F5,20F6,20F7,20F^,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE_,2CE8,2CE9,2CEA,2CEB,2CEC,2CED,2CEE,2CF2,2CF3,2CF4,2CF5,2CF6,2CF7,2CF^,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7_,2D78,2D79,2D7A,2D7B,2D7C,2D7D,2D7E,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302_,3028,3029,303*,304*,305*,306*,307*,308*,309_,3098,309B,309C,309D,309E,309F,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," // Mn ->> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, - If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Mn}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, - If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Mn}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"030*,031*,032*,033*,034*,035*,036*,0483,0484,0485,0486,0487,0591,0592,0593,0594,0595,0596,0597,059^,05A*,05B_,05B8,05B9,05BA,05BB,05BC,05BD,05BF,05C1,05C2,05C4,05C5,05C7,061_,0618,0619,061A,064B,064C,064D,064E,064F,065*,0670,06D6,06D7,06D8,06D9,06DA,06DB,06DC,06DF,06E0,06E1,06E2,06E3,06E4,06E7,06E8,06EA,06EB,06EC,06ED,0711,073*,074_,0748,0749,074A,07A6,07A7,07A^,07B0,07EB,07EC,07ED,07EE,07EF,07F0,07F1,07F2,07F3,07FD,0816,0817,0818,0819,081B,081C,081D,081E,081F,0820,0821,0822,0823,0825,0826,0827,0829,082A,082B,082C,082D,0859,085A,085B,089^,08CA,08CB,08CC,08CD,08CE,08CF,08D*,08E0,08E1,08E3,08E4,08E5,08E6,08E7,08E^,08F*,0900,0901,0902,093A,093C,0941,0942,0943,0944,0945,0946,0947,0948,094D,0951,0952,0953,0954,0955,0956,0957,0962,0963,0981,09BC,09C1,09C2,09C3,09C4,09CD,09E2,09E3,09FE,0A01,0A02,0A3C,0A41,0A42,0A47,0A48,0A4B,0A4C,0A4D,0A51,0A70,0A71,0A75,0A81,0A82,0ABC,0AC1,0AC2,0AC3,0AC4,0AC5,0AC7,0AC8,0ACD,0AE2,0AE3,0AFA,0AFB,0AFC,0AFD,0AFE,0AFF,0B01,0B3C,0B3F,0B41,0B42,0B43,0B44,0B4D,0B55,0B56,0B62,0B63,0B82,0BC0,0BCD,0C00,0C04,0C3C,0C3E,0C3F,0C40,0C46,0C47,0C48,0C4A,0C4B,0C4C,0C4D,0C55,0C56,0C62,0C63,0C81,0CBC,0CBF,0CC6,0CCC,0CCD,0CE2,0CE3,0D00,0D01,0D3B,0D3C,0D41,0D42,0D43,0D44,0D4D,0D62,0D63,0D81,0DCA,0DD2,0DD3,0DD4,0DD6,0E31,0E34,0E35,0E36,0E37,0E38,0E39,0E3A,0E47,0E48,0E49,0E4A,0E4B,0E4C,0E4D,0E4E,0EB1,0EB4,0EB5,0EB6,0EB7,0EB8,0EB9,0EBA,0EBB,0EBC,0EC8,0EC9,0ECA,0ECB,0ECC,0ECD,0F18,0F19,0F35,0F37,0F39,0F71,0F72,0F73,0F74,0F75,0F76,0F77,0F78,0F79,0F7A,0F7B,0F7C,0F7D,0F7E,0F80,0F81,0F82,0F83,0F84,0F86,0F87,0F8D,0F8E,0F8F,0F9_,0F99,0F9A,0F9B,0F9C,0F9D,0F9E,0F9F,0FA*,0FB_,0FB8,0FB9,0FBA,0FBB,0FBC,0FC6,102D,102E,102F,1030,1032,1033,1034,1035,1036,1037,1039,103A,103D,103E,1058,1059,105E,105F,1060,1071,1072,1073,1074,1082,1085,1086,108D,109D,135D,135E,135F,1712,1713,1714,1732,1733,1752,1753,1772,1773,17B4,17B5,17B7,17B8,17B9,17BA,17BB,17BC,17BD,17C6,17C9,17CA,17CB,17CC,17CD,17CE,17CF,17D0,17D1,17D2,17D3,17DD,180B,180C,180D,180F,1885,1886,18A9,1920,1921,1922,1927,1928,1932,1939,193A,193B,1A17,1A18,1A1B,1A56,1A58,1A59,1A5A,1A5B,1A5C,1A5D,1A5E,1A60,1A62,1A65,1A66,1A67,1A68,1A69,1A6A,1A6B,1A6C,1A73,1A74,1A75,1A76,1A77,1A78,1A79,1A7A,1A7B,1A7C,1A7F,1AB_,1AB8,1AB9,1ABA,1ABB,1ABC,1ABD,1ABF,1AC_,1AC8,1AC9,1ACA,1ACB,1ACC,1ACD,1ACE,1B00,1B01,1B02,1B03,1B34,1B36,1B37,1B38,1B39,1B3A,1B3C,1B42,1B6B,1B6C,1B6D,1B6E,1B6F,1B70,1B71,1B72,1B73,1B80,1B81,1BA2,1BA3,1BA4,1BA5,1BA8,1BA9,1BAB,1BAC,1BAD,1BE6,1BE8,1BE9,1BED,1BEF,1BF0,1BF1,1C2C,1C2D,1C2E,1C2F,1C30,1C31,1C32,1C33,1C36,1C37,1CD0,1CD1,1CD2,1CD4,1CD5,1CD6,1CD7,1CD^,1CE0,1CE2,1CE3,1CE4,1CE5,1CE6,1CE7,1CE8,1CED,1CF4,1CF8,1CF9,1DC*,1DD*,1DE*,1DF*,20D_,20D8,20D9,20DA,20DB,20DC,20E1,20E5,20E6,20E7,20E^,20F0,2CEF,2CF0,2CF1,2D7F,2DE*,2DF*,302A,302B,302C,302D,3099,309A," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Mn}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,0480,0481,0482,048^,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,0590,05BE,05C0,05C3,05C6,05C^,05D*,05E*,05F*,060*,061B,061C,061D,061E,061F,062*,063*,064_,0648,0649,064A,066*,0671,0672,0673,0674,0675,0676,0677,067^,068*,069*,06A*,06B*,06C*,06D0,06D1,06D2,06D3,06D4,06D5,06DD,06DE,06E5,06E6,06E9,06EE,06EF,06F*,070*,0710,0712,0713,0714,0715,0716,0717,071^,072*,074B,074C,074D,074E,074F,075*,076*,077*,078*,079*,07A0,07A1,07A2,07A3,07A4,07A5,07B1,07B2,07B3,07B4,07B5,07B6,07B7,07B^,07C*,07D*,07E_,07E8,07E9,07EA,07F4,07F5,07F6,07F7,07F8,07F9,07FA,07FB,07FC,07FE,07FF,080*,0810,0811,0812,0813,0814,0815,081A,0824,0828,082E,082F,083*,084*,085_,0858,085C,085D,085E,085F,086*,087*,088*,089_,08A*,08B*,08C_,08C8,08C9,08E2,0903,0904,0905,0906,0907,090^,091*,092*,093_,0938,0939,093B,093D,093E,093F,0940,0949,094A,094B,094C,094E,094F,0950,095^,0960,0961,0964,0965,0966,0967,096^,097*,0980,0982,0983,0984,0985,0986,0987,098^,099*,09A*,09B_,09B8,09B9,09BA,09BB,09BD,09BE,09BF,09C0,09C5,09C6,09C7,09C8,09C9,09CA,09CB,09CC,09CE,09CF,09D*,09E0,09E1,09E4,09E5,09E6,09E7,09E^,09F_,09F8,09F9,09FA,09FB,09FC,09FD,09FF,0A00,0A03,0A04,0A05,0A06,0A07,0A0^,0A1*,0A2*,0A3_,0A38,0A39,0A3A,0A3B,0A3D,0A3E,0A3F,0A40,0A43,0A44,0A45,0A46,0A49,0A4A,0A4E,0A4F,0A50,0A52,0A53,0A54,0A55,0A56,0A57,0A5^,0A6*,0A72,0A73,0A74,0A76,0A77,0A7^,0A80,0A83,0A84,0A85,0A86,0A87,0A8^,0A9*,0AA*,0AB_,0AB8,0AB9,0ABA,0ABB,0ABD,0ABE,0ABF,0AC0,0AC6,0AC9,0ACA,0ACB,0ACC,0ACE,0ACF,0AD*,0AE0,0AE1,0AE4,0AE5,0AE6,0AE7,0AE^,0AF_,0AF8,0AF9,0B00,0B02,0B03,0B04,0B05,0B06,0B07,0B0^,0B1*,0B2*,0B3_,0B38,0B39,0B3A,0B3B,0B3D,0B3E,0B40,0B45,0B46,0B47,0B48,0B49,0B4A,0B4B,0B4C,0B4E,0B4F,0B50,0B51,0B52,0B53,0B54,0B57,0B5^,0B60,0B61,0B64,0B65,0B66,0B67,0B6^,0B7*,0B80,0B81,0B83,0B84,0B85,0B86,0B87,0B8^,0B9*,0BA*,0BB*,0BC1,0BC2,0BC3,0BC4,0BC5,0BC6,0BC7,0BC8,0BC9,0BCA,0BCB,0BCC,0BCE,0BCF,0BD*,0BE*,0BF*,0C01,0C02,0C03,0C05,0C06,0C07,0C0^,0C1*,0C2*,0C3_,0C38,0C39,0C3A,0C3B,0C3D,0C41,0C42,0C43,0C44,0C45,0C49,0C4E,0C4F,0C50,0C51,0C52,0C53,0C54,0C57,0C5^,0C60,0C61,0C64,0C65,0C66,0C67,0C6^,0C7*,0C80,0C82,0C83,0C84,0C85,0C86,0C87,0C8^,0C9*,0CA*,0CB_,0CB8,0CB9,0CBA,0CBB,0CBD,0CBE,0CC0,0CC1,0CC2,0CC3,0CC4,0CC5,0CC7,0CC8,0CC9,0CCA,0CCB,0CCE,0CCF,0CD*,0CE0,0CE1,0CE4,0CE5,0CE6,0CE7,0CE^,0CF*,0D02,0D03,0D04,0D05,0D06,0D07,0D0^,0D1*,0D2*,0D3_,0D38,0D39,0D3A,0D3D,0D3E,0D3F,0D40,0D45,0D46,0D47,0D48,0D49,0D4A,0D4B,0D4C,0D4E,0D4F,0D5*,0D60,0D61,0D64,0D65,0D66,0D67,0D6^,0D7*,0D80,0D82,0D83,0D84,0D85,0D86,0D87,0D8^,0D9*,0DA*,0DB*,0DC_,0DC8,0DC9,0DCB,0DCC,0DCD,0DCE,0DCF,0DD0,0DD1,0DD5,0DD7,0DD^,0DE*,0DF*,0E0*,0E1*,0E2*,0E30,0E32,0E33,0E3B,0E3C,0E3D,0E3E,0E3F,0E40,0E41,0E42,0E43,0E44,0E45,0E46,0E4F,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB0,0EB2,0EB3,0EBD,0EBE,0EBF,0EC_,0ECE,0ECF,0ED*,0EE*,0EF*,0F0*,0F1_,0F1A,0F1B,0F1C,0F1D,0F1E,0F1F,0F2*,0F30,0F31,0F32,0F33,0F34,0F36,0F38,0F3A,0F3B,0F3C,0F3D,0F3E,0F3F,0F4*,0F5*,0F6*,0F70,0F7F,0F85,0F88,0F89,0F8A,0F8B,0F8C,0F98,0FBD,0FBE,0FBF,0FC0,0FC1,0FC2,0FC3,0FC4,0FC5,0FC7,0FC^,0FD*,0FE*,0FF*,100*,101*,102_,1028,1029,102A,102B,102C,1031,1038,103B,103C,103F,104*,105_,105A,105B,105C,105D,1061,1062,1063,1064,1065,1066,1067,106^,1070,1075,1076,1077,107^,1080,1081,1083,1084,1087,1088,1089,108A,108B,108C,108E,108F,109_,1098,1099,109A,109B,109C,109E,109F,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135_,1358,1359,135A,135B,135C,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,1710,1711,1715,1716,1717,171^,172*,1730,1731,1734,1735,1736,1737,173^,174*,1750,1751,1754,1755,1756,1757,175^,176*,1770,1771,1774,1775,1776,1777,177^,178*,179*,17A*,17B0,17B1,17B2,17B3,17B6,17BE,17BF,17C0,17C1,17C2,17C3,17C4,17C5,17C7,17C8,17D4,17D5,17D6,17D7,17D8,17D9,17DA,17DB,17DC,17DE,17DF,17E*,17F*,180_,1808,1809,180A,180E,181*,182*,183*,184*,185*,186*,187*,1880,1881,1882,1883,1884,1887,188^,189*,18A_,18A8,18AA,18AB,18AC,18AD,18AE,18AF,18B*,18C*,18D*,18E*,18F*,190*,191*,1923,1924,1925,1926,1929,192A,192B,192C,192D,192E,192F,1930,1931,1933,1934,1935,1936,1937,1938,193C,193D,193E,193F,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A10,1A11,1A12,1A13,1A14,1A15,1A16,1A19,1A1A,1A1C,1A1D,1A1E,1A1F,1A2*,1A3*,1A4*,1A50,1A51,1A52,1A53,1A54,1A55,1A57,1A5F,1A61,1A63,1A64,1A6D,1A6E,1A6F,1A70,1A71,1A72,1A7D,1A7E,1A8*,1A9*,1AA*,1ABE,1ACF,1AD*,1AE*,1AF*,1B04,1B05,1B06,1B07,1B0^,1B1*,1B2*,1B30,1B31,1B32,1B33,1B35,1B3B,1B3D,1B3E,1B3F,1B40,1B41,1B43,1B44,1B45,1B46,1B47,1B4^,1B5*,1B6_,1B68,1B69,1B6A,1B74,1B75,1B76,1B77,1B7^,1B82,1B83,1B84,1B85,1B86,1B87,1B8^,1B9*,1BA0,1BA1,1BA6,1BA7,1BAA,1BAE,1BAF,1BB*,1BC*,1BD*,1BE0,1BE1,1BE2,1BE3,1BE4,1BE5,1BE7,1BEA,1BEB,1BEC,1BEE,1BF2,1BF3,1BF4,1BF5,1BF6,1BF7,1BF^,1C0*,1C1*,1C2_,1C28,1C29,1C2A,1C2B,1C34,1C35,1C3^,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD3,1CE1,1CE9,1CEA,1CEB,1CEC,1CEE,1CEF,1CF0,1CF1,1CF2,1CF3,1CF5,1CF6,1CF7,1CFA,1CFB,1CFC,1CFD,1CFE,1CFF,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20DD,20DE,20DF,20E0,20E2,20E3,20E4,20F1,20F2,20F3,20F4,20F5,20F6,20F7,20F^,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE_,2CE8,2CE9,2CEA,2CEB,2CEC,2CED,2CEE,2CF2,2CF3,2CF4,2CF5,2CF6,2CF7,2CF^,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7_,2D78,2D79,2D7A,2D7B,2D7C,2D7D,2D7E,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302_,3028,3029,302E,302F,303*,304*,305*,306*,307*,308*,309_,3098,309B,309C,309D,309E,309F,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," // Mc ->> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, - If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Mc}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, - If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) +// \u0cf3 reports as false in .NET 4.7 & .NET 7, but true in .NET 8, PCRE2, and JavaScript +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Mc}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0903,093B,093E,093F,0940,0949,094A,094B,094C,094E,094F,0982,0983,09BE,09BF,09C0,09C7,09C8,09CB,09CC,09D7,0A03,0A3E,0A3F,0A40,0A83,0ABE,0ABF,0AC0,0AC9,0ACB,0ACC,0B02,0B03,0B3E,0B40,0B47,0B48,0B4B,0B4C,0B57,0BBE,0BBF,0BC1,0BC2,0BC6,0BC7,0BC8,0BCA,0BCB,0BCC,0BD7,0C01,0C02,0C03,0C41,0C42,0C43,0C44,0C82,0C83,0CBE,0CC0,0CC1,0CC2,0CC3,0CC4,0CC7,0CC8,0CCA,0CCB,0CD5,0CD6,0D02,0D03,0D3E,0D3F,0D40,0D46,0D47,0D48,0D4A,0D4B,0D4C,0D57,0D82,0D83,0DCF,0DD0,0DD1,0DD^,0DF2,0DF3,0F3E,0F3F,0F7F,102B,102C,1031,1038,103B,103C,1056,1057,1062,1063,1064,1067,1068,1069,106A,106B,106C,106D,1083,1084,1087,1088,1089,108A,108B,108C,108F,109A,109B,109C,1715,1734,17B6,17BE,17BF,17C0,17C1,17C2,17C3,17C4,17C5,17C7,17C8,1923,1924,1925,1926,1929,192A,192B,1930,1931,1933,1934,1935,1936,1937,1938,1A19,1A1A,1A55,1A57,1A61,1A63,1A64,1A6D,1A6E,1A6F,1A70,1A71,1A72,1B04,1B35,1B3B,1B3D,1B3E,1B3F,1B40,1B41,1B43,1B44,1B82,1BA1,1BA6,1BA7,1BAA,1BE7,1BEA,1BEB,1BEC,1BEE,1BF2,1BF3,1C24,1C25,1C26,1C27,1C28,1C29,1C2A,1C2B,1C34,1C35,1CE1,1CF7,302E,302F," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Mc}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,0900,0901,0902,0904,0905,0906,0907,090^,091*,092*,093_,0938,0939,093A,093C,093D,0941,0942,0943,0944,0945,0946,0947,0948,094D,095*,096*,097*,0980,0981,0984,0985,0986,0987,098^,099*,09A*,09B_,09B8,09B9,09BA,09BB,09BC,09BD,09C1,09C2,09C3,09C4,09C5,09C6,09C9,09CA,09CD,09CE,09CF,09D0,09D1,09D2,09D3,09D4,09D5,09D6,09D^,09E*,09F*,0A00,0A01,0A02,0A04,0A05,0A06,0A07,0A0^,0A1*,0A2*,0A3_,0A38,0A39,0A3A,0A3B,0A3C,0A3D,0A41,0A42,0A43,0A44,0A45,0A46,0A47,0A4^,0A5*,0A6*,0A7*,0A80,0A81,0A82,0A84,0A85,0A86,0A87,0A8^,0A9*,0AA*,0AB_,0AB8,0AB9,0ABA,0ABB,0ABC,0ABD,0AC1,0AC2,0AC3,0AC4,0AC5,0AC6,0AC7,0AC8,0ACA,0ACD,0ACE,0ACF,0AD*,0AE*,0AF*,0B00,0B01,0B04,0B05,0B06,0B07,0B0^,0B1*,0B2*,0B3_,0B38,0B39,0B3A,0B3B,0B3C,0B3D,0B3F,0B41,0B42,0B43,0B44,0B45,0B46,0B49,0B4A,0B4D,0B4E,0B4F,0B50,0B51,0B52,0B53,0B54,0B55,0B56,0B5^,0B6*,0B7*,0B8*,0B9*,0BA*,0BB_,0BB8,0BB9,0BBA,0BBB,0BBC,0BBD,0BC0,0BC3,0BC4,0BC5,0BC9,0BCD,0BCE,0BCF,0BD0,0BD1,0BD2,0BD3,0BD4,0BD5,0BD6,0BD^,0BE*,0BF*,0C00,0C04,0C05,0C06,0C07,0C0^,0C1*,0C2*,0C3*,0C40,0C45,0C46,0C47,0C4^,0C5*,0C6*,0C7*,0C80,0C81,0C84,0C85,0C86,0C87,0C8^,0C9*,0CA*,0CB_,0CB8,0CB9,0CBA,0CBB,0CBC,0CBD,0CBF,0CC5,0CC6,0CC9,0CCC,0CCD,0CCE,0CCF,0CD0,0CD1,0CD2,0CD3,0CD4,0CD7,0CD^,0CE*,0CF*,0D00,0D01,0D04,0D05,0D06,0D07,0D0^,0D1*,0D2*,0D3_,0D38,0D39,0D3A,0D3B,0D3C,0D3D,0D41,0D42,0D43,0D44,0D45,0D49,0D4D,0D4E,0D4F,0D50,0D51,0D52,0D53,0D54,0D55,0D56,0D5^,0D6*,0D7*,0D80,0D81,0D84,0D85,0D86,0D87,0D8^,0D9*,0DA*,0DB*,0DC_,0DC8,0DC9,0DCA,0DCB,0DCC,0DCD,0DCE,0DD2,0DD3,0DD4,0DD5,0DD6,0DD7,0DE*,0DF0,0DF1,0DF4,0DF5,0DF6,0DF7,0DF^,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3_,0F38,0F39,0F3A,0F3B,0F3C,0F3D,0F4*,0F5*,0F6*,0F7_,0F78,0F79,0F7A,0F7B,0F7C,0F7D,0F7E,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102_,1028,1029,102A,102D,102E,102F,1030,1032,1033,1034,1035,1036,1037,1039,103A,103D,103E,103F,104*,1050,1051,1052,1053,1054,1055,105^,1060,1061,1065,1066,106E,106F,107*,1080,1081,1082,1085,1086,108D,108E,109_,1098,1099,109D,109E,109F,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,1710,1711,1712,1713,1714,1716,1717,171^,172*,1730,1731,1732,1733,1735,1736,1737,173^,174*,175*,176*,177*,178*,179*,17A*,17B0,17B1,17B2,17B3,17B4,17B5,17B7,17B8,17B9,17BA,17BB,17BC,17BD,17C6,17C9,17CA,17CB,17CC,17CD,17CE,17CF,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,1920,1921,1922,1927,1928,192C,192D,192E,192F,1932,1939,193A,193B,193C,193D,193E,193F,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1_,1A18,1A1B,1A1C,1A1D,1A1E,1A1F,1A2*,1A3*,1A4*,1A50,1A51,1A52,1A53,1A54,1A56,1A5^,1A60,1A62,1A65,1A66,1A67,1A68,1A69,1A6A,1A6B,1A6C,1A73,1A74,1A75,1A76,1A77,1A7^,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B00,1B01,1B02,1B03,1B05,1B06,1B07,1B0^,1B1*,1B2*,1B30,1B31,1B32,1B33,1B34,1B36,1B37,1B38,1B39,1B3A,1B3C,1B42,1B45,1B46,1B47,1B4^,1B5*,1B6*,1B7*,1B80,1B81,1B83,1B84,1B85,1B86,1B87,1B8^,1B9*,1BA0,1BA2,1BA3,1BA4,1BA5,1BA8,1BA9,1BAB,1BAC,1BAD,1BAE,1BAF,1BB*,1BC*,1BD*,1BE0,1BE1,1BE2,1BE3,1BE4,1BE5,1BE6,1BE8,1BE9,1BED,1BEF,1BF0,1BF1,1BF4,1BF5,1BF6,1BF7,1BF^,1C0*,1C1*,1C20,1C21,1C22,1C23,1C2C,1C2D,1C2E,1C2F,1C30,1C31,1C32,1C33,1C36,1C37,1C3^,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE0,1CE2,1CE3,1CE4,1CE5,1CE6,1CE7,1CE^,1CF0,1CF1,1CF2,1CF3,1CF4,1CF5,1CF6,1CF^,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302_,3028,3029,302A,302B,302C,302D,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," // Me ->> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, - If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Me}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, - If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Me}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0488,0489,1ABE,20DD,20DE,20DF,20E0,20E2,20E3,20E4," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Me}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048_,048A,048B,048C,048D,048E,048F,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB_,1AB8,1AB9,1ABA,1ABB,1ABC,1ABD,1ABF,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D_,20D8,20D9,20DA,20DB,20DC,20E1,20E5,20E6,20E7,20E^,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," // N ->> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, - If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{N}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, - If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) -"0030-0037,0038,0039,00B2,00B3,00B9,00BC,00BD,00BE,0660-0667,0668,0669,06F0-06F7,06F8,06F9,07C0-07C7,07C8,07C9,0966,0967,0968-096F,09E6,09E7,09E8-09EF,09F4,09F5,09F6,09F7,09F8,09F9,0A66,0A67,0A68-0A6F,0AE6,0AE7,0AE8-0AEF,0B66,0B67,0B68-0B6F,0B72,0B73,0B74,0B75,0B76,0B77,0BE6,0BE7,0BE8-0BEF,0BF0,0BF1,0BF2,0C66,0C67,0C68-0C6F,0C78,0C79,0C7A,0C7B,0C7C,0C7D,0C7E,0CE6,0CE7,0CE8-0CEF,0D58,0D59,0D5A,0D5B,0D5C,0D5D,0D5E,0D66,0D67,0D68-0D6F,0D70-0D77,0D78,0DE6,0DE7,0DE8-0DEF,0E50-0E57,0E58,0E59,0ED0-0ED7,0ED8,0ED9,0F20-0F27,0F28-0F2F,0F30,0F31,0F32,0F33,1040-1047,1048,1049,1090-1097,1098,1099,1369,136A,136B,136C,136D,136E,136F,1370-1377,1378,1379,137A,137B,137C,16EE,16EF,16F0,17E0-17E7,17E8,17E9,17F0-17F7,17F8,17F9,1810-1817,1818,1819,1946,1947,1948-194F,19D0-19D7,19D8,19D9,19DA,1A80-1A87,1A88,1A89,1A90-1A97,1A98,1A99,1B50-1B57,1B58,1B59,1BB0-1BB7,1BB8,1BB9,1C40-1C47,1C48,1C49,1C50-1C57,1C58,1C59," +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{N}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"003_,0038,0039,00B2,00B3,00B9,00BC,00BD,00BE,066_,0668,0669,06F_,06F8,06F9,07C_,07C8,07C9,0966,0967,096^,09E6,09E7,09E^,09F4,09F5,09F6,09F7,09F8,09F9,0A66,0A67,0A6^,0AE6,0AE7,0AE^,0B66,0B67,0B6^,0B72,0B73,0B74,0B75,0B76,0B77,0BE6,0BE7,0BE^,0BF0,0BF1,0BF2,0C66,0C67,0C6^,0C78,0C79,0C7A,0C7B,0C7C,0C7D,0C7E,0CE6,0CE7,0CE^,0D58,0D59,0D5A,0D5B,0D5C,0D5D,0D5E,0D66,0D67,0D6^,0D7_,0D78,0DE6,0DE7,0DE^,0E5_,0E58,0E59,0ED_,0ED8,0ED9,0F2*,0F30,0F31,0F32,0F33,104_,1048,1049,109_,1098,1099,1369,136A,136B,136C,136D,136E,136F,137_,1378,1379,137A,137B,137C,16EE,16EF,16F0,17E_,17E8,17E9,17F_,17F8,17F9,181_,1818,1819,1946,1947,194^,19D_,19D8,19D9,19DA,1A8_,1A88,1A89,1A9_,1A98,1A99,1B5_,1B58,1B59,1BB_,1BB8,1BB9,1C4_,1C48,1C49,1C5_,1C58,1C59,2070,2074,2075,2076,2077,2078,2079,208_,2088,2089,215*,216*,217*,2180,2181,2182,2185,2186,2187,2188,2189,246*,247*,248*,249_,2498,2499,249A,249B,24EA,24EB,24EC,24ED,24EE,24EF,24F*,2776,2777,277^,278*,2790,2791,2792,2793,2CFD,3007,3021,3022,3023,3024,3025,3026,3027,3028,3029,3038,3039,303A,3192,3193,3194,3195,322_,3228,3229,324^,3251,3252,3253,3254,3255,3256,3257,325^,328_,3288,3289,32B1,32B2,32B3,32B4,32B5,32B6,32B7,32B^," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{N}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003A,003B,003C,003D,003E,003F,004*,005*,006*,007*,008*,009*,00A*,00B0,00B1,00B4,00B5,00B6,00B7,00B8,00BA,00BB,00BF,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066A,066B,066C,066D,066E,066F,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06FA,06FB,06FC,06FD,06FE,06FF,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07CA,07CB,07CC,07CD,07CE,07CF,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,0960,0961,0962,0963,0964,0965,097*,098*,099*,09A*,09B*,09C*,09D*,09E0,09E1,09E2,09E3,09E4,09E5,09F0,09F1,09F2,09F3,09FA,09FB,09FC,09FD,09FE,09FF,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A60,0A61,0A62,0A63,0A64,0A65,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE0,0AE1,0AE2,0AE3,0AE4,0AE5,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B60,0B61,0B62,0B63,0B64,0B65,0B70,0B71,0B7^,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE0,0BE1,0BE2,0BE3,0BE4,0BE5,0BF3,0BF4,0BF5,0BF6,0BF7,0BF^,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C60,0C61,0C62,0C63,0C64,0C65,0C7_,0C7F,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE0,0CE1,0CE2,0CE3,0CE4,0CE5,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5_,0D5F,0D60,0D61,0D62,0D63,0D64,0D65,0D79,0D7A,0D7B,0D7C,0D7D,0D7E,0D7F,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE0,0DE1,0DE2,0DE3,0DE4,0DE5,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5A,0E5B,0E5C,0E5D,0E5E,0E5F,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0EDA,0EDB,0EDC,0EDD,0EDE,0EDF,0EE*,0EF*,0F0*,0F1*,0F34,0F35,0F36,0F37,0F3^,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104A,104B,104C,104D,104E,104F,105*,106*,107*,108*,109A,109B,109C,109D,109E,109F,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136_,1368,137D,137E,137F,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E_,16E8,16E9,16EA,16EB,16EC,16ED,16F1,16F2,16F3,16F4,16F5,16F6,16F7,16F^,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17EA,17EB,17EC,17ED,17EE,17EF,17FA,17FB,17FC,17FD,17FE,17FF,180*,181A,181B,181C,181D,181E,181F,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,1940,1941,1942,1943,1944,1945,195*,196*,197*,198*,199*,19A*,19B*,19C*,19DB,19DC,19DD,19DE,19DF,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8A,1A8B,1A8C,1A8D,1A8E,1A8F,1A9A,1A9B,1A9C,1A9D,1A9E,1A9F,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5A,1B5B,1B5C,1B5D,1B5E,1B5F,1B6*,1B7*,1B8*,1B9*,1BA*,1BBA,1BBB,1BBC,1BBD,1BBE,1BBF,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4A,1C4B,1C4C,1C4D,1C4E,1C4F,1C5A,1C5B,1C5C,1C5D,1C5E,1C5F,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,204*,205*,206*,2071,2072,2073,207A,207B,207C,207D,207E,207F,208A,208B,208C,208D,208E,208F,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,2183,2184,218A,218B,218C,218D,218E,218F,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,249C,249D,249E,249F,24A*,24B*,24C*,24D*,24E_,24E8,24E9,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,2770,2771,2772,2773,2774,2775,2794,2795,2796,2797,279^,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF_,2CF8,2CF9,2CFA,2CFB,2CFC,2CFE,2CFF,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,3000,3001,3002,3003,3004,3005,3006,300^,301*,3020,302A,302B,302C,302D,302E,302F,303_,303B,303C,303D,303E,303F,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,3190,3191,3196,3197,319^,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322A,322B,322C,322D,322E,322F,323*,324_,3250,326*,327*,328A,328B,328C,328D,328E,328F,329*,32A*,32B0,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," // Nd ->> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, - If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Nd}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, - If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) -"0030-0037,0038,0039,0660-0667,0668,0669,06F0-06F7,06F8,06F9,07C0-07C7,07C8,07C9,0966,0967,0968-096F,09E6,09E7,09E8-09EF,0A66,0A67,0A68-0A6F,0AE6,0AE7,0AE8-0AEF,0B66,0B67,0B68-0B6F,0BE6,0BE7,0BE8-0BEF,0C66,0C67,0C68-0C6F,0CE6,0CE7,0CE8-0CEF,0D66,0D67,0D68-0D6F,0DE6,0DE7,0DE8-0DEF,0E50-0E57,0E58,0E59,0ED0-0ED7,0ED8,0ED9,0F20-0F27,0F28,0F29,1040-1047,1048,1049,1090-1097,1098,1099,17E0-17E7,17E8,17E9,1810-1817,1818,1819,1946,1947,1948-194F,19D0-19D7,19D8,19D9,1A80-1A87,1A88,1A89,1A90-1A97,1A98,1A99,1B50-1B57,1B58,1B59,1BB0-1BB7,1BB8,1BB9,1C40-1C47,1C48,1C49,1C50-1C57,1C58,1C59," +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Nd}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"003_,0038,0039,066_,0668,0669,06F_,06F8,06F9,07C_,07C8,07C9,0966,0967,096^,09E6,09E7,09E^,0A66,0A67,0A6^,0AE6,0AE7,0AE^,0B66,0B67,0B6^,0BE6,0BE7,0BE^,0C66,0C67,0C6^,0CE6,0CE7,0CE^,0D66,0D67,0D6^,0DE6,0DE7,0DE^,0E5_,0E58,0E59,0ED_,0ED8,0ED9,0F2_,0F28,0F29,104_,1048,1049,109_,1098,1099,17E_,17E8,17E9,181_,1818,1819,1946,1947,194^,19D_,19D8,19D9,1A8_,1A88,1A89,1A9_,1A98,1A99,1B5_,1B58,1B59,1BB_,1BB8,1BB9,1C4_,1C48,1C49,1C5_,1C58,1C59," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Nd}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003A,003B,003C,003D,003E,003F,004*,005*,006*,007*,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066A,066B,066C,066D,066E,066F,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06FA,06FB,06FC,06FD,06FE,06FF,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07CA,07CB,07CC,07CD,07CE,07CF,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,0960,0961,0962,0963,0964,0965,097*,098*,099*,09A*,09B*,09C*,09D*,09E0,09E1,09E2,09E3,09E4,09E5,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A60,0A61,0A62,0A63,0A64,0A65,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE0,0AE1,0AE2,0AE3,0AE4,0AE5,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B60,0B61,0B62,0B63,0B64,0B65,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE0,0BE1,0BE2,0BE3,0BE4,0BE5,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C60,0C61,0C62,0C63,0C64,0C65,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE0,0CE1,0CE2,0CE3,0CE4,0CE5,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D60,0D61,0D62,0D63,0D64,0D65,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE0,0DE1,0DE2,0DE3,0DE4,0DE5,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5A,0E5B,0E5C,0E5D,0E5E,0E5F,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0EDA,0EDB,0EDC,0EDD,0EDE,0EDF,0EE*,0EF*,0F0*,0F1*,0F2A,0F2B,0F2C,0F2D,0F2E,0F2F,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104A,104B,104C,104D,104E,104F,105*,106*,107*,108*,109A,109B,109C,109D,109E,109F,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17EA,17EB,17EC,17ED,17EE,17EF,17F*,180*,181A,181B,181C,181D,181E,181F,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,1940,1941,1942,1943,1944,1945,195*,196*,197*,198*,199*,19A*,19B*,19C*,19DA,19DB,19DC,19DD,19DE,19DF,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8A,1A8B,1A8C,1A8D,1A8E,1A8F,1A9A,1A9B,1A9C,1A9D,1A9E,1A9F,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5A,1B5B,1B5C,1B5D,1B5E,1B5F,1B6*,1B7*,1B8*,1B9*,1BA*,1BBA,1BBB,1BBC,1BBD,1BBE,1BBF,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4A,1C4B,1C4C,1C4D,1C4E,1C4F,1C5A,1C5B,1C5C,1C5D,1C5E,1C5F,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," // Nl ->> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, - If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Nl}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, - If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) -"16EE,16EF,16F0," +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Nl}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"16EE,16EF,16F0,216*,217*,2180,2181,2182,2185,2186,2187,2188,3007,3021,3022,3023,3024,3025,3026,3027,3028,3029,3038,3039,303A," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Nl}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E_,16E8,16E9,16EA,16EB,16EC,16ED,16F1,16F2,16F3,16F4,16F5,16F6,16F7,16F^,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,2183,2184,2189,218A,218B,218C,218D,218E,218F,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,3000,3001,3002,3003,3004,3005,3006,300^,301*,3020,302A,302B,302C,302D,302E,302F,303_,303B,303C,303D,303E,303F,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," // No ->> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, - If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{No}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, - If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{No}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"00B2,00B3,00B9,00BC,00BD,00BE,09F4,09F5,09F6,09F7,09F8,09F9,0B72,0B73,0B74,0B75,0B76,0B77,0BF0,0BF1,0BF2,0C78,0C79,0C7A,0C7B,0C7C,0C7D,0C7E,0D58,0D59,0D5A,0D5B,0D5C,0D5D,0D5E,0D7_,0D78,0F2A,0F2B,0F2C,0F2D,0F2E,0F2F,0F30,0F31,0F32,0F33,1369,136A,136B,136C,136D,136E,136F,137_,1378,1379,137A,137B,137C,17F_,17F8,17F9,19DA,2070,2074,2075,2076,2077,2078,2079,208_,2088,2089,215*,2189,246*,247*,248*,249_,2498,2499,249A,249B,24EA,24EB,24EC,24ED,24EE,24EF,24F*,2776,2777,277^,278*,2790,2791,2792,2793,2CFD,3192,3193,3194,3195,322_,3228,3229,324^,3251,3252,3253,3254,3255,3256,3257,325^,328_,3288,3289,32B1,32B2,32B3,32B4,32B5,32B6,32B7,32B^," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{No}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A*,00B0,00B1,00B4,00B5,00B6,00B7,00B8,00BA,00BB,00BF,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F0,09F1,09F2,09F3,09FA,09FB,09FC,09FD,09FE,09FF,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B70,0B71,0B7^,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF3,0BF4,0BF5,0BF6,0BF7,0BF^,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7_,0C7F,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5_,0D5F,0D6*,0D79,0D7A,0D7B,0D7C,0D7D,0D7E,0D7F,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2_,0F28,0F29,0F34,0F35,0F36,0F37,0F3^,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136_,1368,137D,137E,137F,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17FA,17FB,17FC,17FD,17FE,17FF,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D_,19D8,19D9,19DB,19DC,19DD,19DE,19DF,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,204*,205*,206*,2071,2072,2073,207A,207B,207C,207D,207E,207F,208A,208B,208C,208D,208E,208F,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,216*,217*,218_,2188,218A,218B,218C,218D,218E,218F,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,249C,249D,249E,249F,24A*,24B*,24C*,24D*,24E_,24E8,24E9,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,2770,2771,2772,2773,2774,2775,2794,2795,2796,2797,279^,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF_,2CF8,2CF9,2CFA,2CFB,2CFC,2CFE,2CFF,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,3190,3191,3196,3197,319^,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322A,322B,322C,322D,322E,322F,323*,324_,3250,326*,327*,328A,328B,328C,328D,328E,328F,329*,32A*,32B0,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," // P ->> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, - If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{P}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, - If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) -"0021,0022,0023,0025,0026,0027,0028,0029,002A,002C,002D,002E,002F,003A,003B,003F,0040,005B,005C,005D,005F,007B,007D,00A1,00A7,00AB,00B6,00B7,00BB,00BF,037E,0387,055A,055B,055C,055D,055E,055F,0589,058A,05BE,05C0,05C3,05C6,05F3,05F4,0609,060A,060C,060D,061B,061D,061E,061F,066A,066B,066C,066D,06D4,0700-0707,0708,0709,070A,070B,070C,070D,07F7,07F8,07F9,0830-0837,0838,0839,083A,083B,083C,083D,083E,085E,0964,0965,0970,09FD,0A76,0AF0,0C77,0C84,0DF4,0E4F,0E5A,0E5B,0F04,0F05,0F06,0F07,0F08-0F0F,0F10,0F11,0F12,0F14,0F3A,0F3B,0F3C,0F3D,0F85,0FD0,0FD1,0FD2,0FD3,0FD4,0FD9,0FDA,104A,104B,104C,104D,104E,104F,10FB,1360-1367,1368,1400,166E,169B,169C,16EB,16EC,16ED,1735,1736,17D4,17D5,17D6,17D8,17D9,17DA,1800-1807,1808,1809,180A,1944,1945,1A1E,1A1F,1AA0,1AA1,1AA2,1AA3,1AA4,1AA5,1AA6,1AA8,1AA9,1AAA,1AAB,1AAC,1AAD,1B5A,1B5B,1B5C,1B5D,1B5E,1B5F,1B60,1B7D,1B7E,1BFC,1BFD,1BFE,1BFF,1C3B,1C3C,1C3D,1C3E,1C3F,1C7E,1C7F,1CC0-1CC7,1CD3," +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{P}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0021,0022,0023,0025,0026,0027,0028,0029,002A,002C,002D,002E,002F,003A,003B,003F,0040,005B,005C,005D,005F,007B,007D,00A1,00A7,00AB,00B6,00B7,00BB,00BF,037E,0387,055A,055B,055C,055D,055E,055F,0589,058A,05BE,05C0,05C3,05C6,05F3,05F4,0609,060A,060C,060D,061B,061D,061E,061F,066A,066B,066C,066D,06D4,070_,0708,0709,070A,070B,070C,070D,07F7,07F8,07F9,083_,0838,0839,083A,083B,083C,083D,083E,085E,0964,0965,0970,09FD,0A76,0AF0,0C77,0C84,0DF4,0E4F,0E5A,0E5B,0F04,0F05,0F06,0F07,0F0^,0F10,0F11,0F12,0F14,0F3A,0F3B,0F3C,0F3D,0F85,0FD0,0FD1,0FD2,0FD3,0FD4,0FD9,0FDA,104A,104B,104C,104D,104E,104F,10FB,136_,1368,1400,166E,169B,169C,16EB,16EC,16ED,1735,1736,17D4,17D5,17D6,17D8,17D9,17DA,180_,1808,1809,180A,1944,1945,1A1E,1A1F,1AA0,1AA1,1AA2,1AA3,1AA4,1AA5,1AA6,1AA8,1AA9,1AAA,1AAB,1AAC,1AAD,1B5A,1B5B,1B5C,1B5D,1B5E,1B5F,1B60,1B7D,1B7E,1BFC,1BFD,1BFE,1BFF,1C3B,1C3C,1C3D,1C3E,1C3F,1C7E,1C7F,1CC_,1CD3,201*,202_,203*,2040,2041,2042,2043,2045,2046,2047,204^,2050,2051,2053,2054,2055,2056,2057,2058,2059,205A,205B,205C,205D,205E,207D,207E,208D,208E,2308,2309,230A,230B,2329,232A,276^,2770,2771,2772,2773,2774,2775,27C5,27C6,27E6,27E7,27E^,2983,2984,2985,2986,2987,298^,299_,2998,29D8,29D9,29DA,29DB,29FC,29FD,2CF9,2CFA,2CFB,2CFC,2CFE,2CFF,2D70,2E0*,2E1*,2E2_,2E28,2E29,2E2A,2E2B,2E2C,2E2D,2E2E,2E3*,2E4*,2E52,2E53,2E54,2E55,2E56,2E57,2E58,2E59,2E5A,2E5B,2E5C,2E5D,3001,3002,3003,300^,3010,3011,3014,3015,3016,3017,301^,3030,303D,30A0,30FB," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{P}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,0020,0024,002B,003_,0038,0039,003C,003D,003E,0041,0042,0043,0044,0045,0046,0047,004^,005_,0058,0059,005A,005E,006*,007_,0078,0079,007A,007C,007E,007F,008*,009*,00A0,00A2,00A3,00A4,00A5,00A6,00A8,00A9,00AA,00AC,00AD,00AE,00AF,00B0,00B1,00B2,00B3,00B4,00B5,00B8,00B9,00BA,00BC,00BD,00BE,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037_,0378,0379,037A,037B,037C,037D,037F,0380,0381,0382,0383,0384,0385,0386,038^,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055_,0558,0559,056*,057*,058_,0588,058B,058C,058D,058E,058F,059*,05A*,05B_,05B8,05B9,05BA,05BB,05BC,05BD,05BF,05C1,05C2,05C4,05C5,05C7,05C^,05D*,05E*,05F0,05F1,05F2,05F5,05F6,05F7,05F^,060_,0608,060B,060E,060F,061_,0618,0619,061A,061C,062*,063*,064*,065*,066_,0668,0669,066E,066F,067*,068*,069*,06A*,06B*,06C*,06D0,06D1,06D2,06D3,06D5,06D6,06D7,06D^,06E*,06F*,070E,070F,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F0,07F1,07F2,07F3,07F4,07F5,07F6,07FA,07FB,07FC,07FD,07FE,07FF,080*,081*,082*,083F,084*,085_,0858,0859,085A,085B,085C,085D,085F,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,0960,0961,0962,0963,0966,0967,096^,0971,0972,0973,0974,0975,0976,0977,097^,098*,099*,09A*,09B*,09C*,09D*,09E*,09F_,09F8,09F9,09FA,09FB,09FC,09FE,09FF,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A70,0A71,0A72,0A73,0A74,0A75,0A77,0A7^,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF1,0AF2,0AF3,0AF4,0AF5,0AF6,0AF7,0AF^,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C70,0C71,0C72,0C73,0C74,0C75,0C76,0C7^,0C80,0C81,0C82,0C83,0C85,0C86,0C87,0C8^,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF0,0DF1,0DF2,0DF3,0DF5,0DF6,0DF7,0DF^,0E0*,0E1*,0E2*,0E3*,0E4_,0E48,0E49,0E4A,0E4B,0E4C,0E4D,0E4E,0E5_,0E58,0E59,0E5C,0E5D,0E5E,0E5F,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F00,0F01,0F02,0F03,0F13,0F15,0F16,0F17,0F1^,0F2*,0F3_,0F38,0F39,0F3E,0F3F,0F4*,0F5*,0F6*,0F7*,0F80,0F81,0F82,0F83,0F84,0F86,0F87,0F8^,0F9*,0FA*,0FB*,0FC*,0FD5,0FD6,0FD7,0FD8,0FDB,0FDC,0FDD,0FDE,0FDF,0FE*,0FF*,100*,101*,102*,103*,104_,1048,1049,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F_,10F8,10F9,10FA,10FC,10FD,10FE,10FF,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,1369,136A,136B,136C,136D,136E,136F,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,1401,1402,1403,1404,1405,1406,1407,140^,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166_,1668,1669,166A,166B,166C,166D,166F,167*,168*,169_,1698,1699,169A,169D,169E,169F,16A*,16B*,16C*,16D*,16E_,16E8,16E9,16EA,16EE,16EF,16F*,170*,171*,172*,1730,1731,1732,1733,1734,1737,173^,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D0,17D1,17D2,17D3,17D7,17DB,17DC,17DD,17DE,17DF,17E*,17F*,180B,180C,180D,180E,180F,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,1940,1941,1942,1943,1946,1947,194^,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1_,1A18,1A19,1A1A,1A1B,1A1C,1A1D,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA7,1AAE,1AAF,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5_,1B58,1B59,1B61,1B62,1B63,1B64,1B65,1B66,1B67,1B6^,1B7_,1B78,1B79,1B7A,1B7B,1B7C,1B7F,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF_,1BF8,1BF9,1BFA,1BFB,1C0*,1C1*,1C2*,1C3_,1C38,1C39,1C3A,1C4*,1C5*,1C6*,1C7_,1C78,1C79,1C7A,1C7B,1C7C,1C7D,1C8*,1C9*,1CA*,1CB*,1CC^,1CD0,1CD1,1CD2,1CD4,1CD5,1CD6,1CD7,1CD^,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,202^,2044,2052,205F,206*,207_,2078,2079,207A,207B,207C,207F,208_,2088,2089,208A,208B,208C,208F,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230_,230C,230D,230E,230F,231*,232_,2328,232B,232C,232D,232E,232F,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276_,2776,2777,277^,278*,279*,27A*,27B*,27C0,27C1,27C2,27C3,27C4,27C7,27C^,27D*,27E0,27E1,27E2,27E3,27E4,27E5,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,2980,2981,2982,2999,299A,299B,299C,299D,299E,299F,29A*,29B*,29C*,29D_,29DC,29DD,29DE,29DF,29E*,29F_,29F8,29F9,29FA,29FB,29FE,29FF,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF_,2CF8,2CFD,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D71,2D72,2D73,2D74,2D75,2D76,2D77,2D7^,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E2F,2E50,2E51,2E5E,2E5F,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,3000,3004,3005,3006,3007,3012,3013,302*,3031,3032,3033,3034,3035,3036,3037,3038,3039,303A,303B,303C,303E,303F,304*,305*,306*,307*,308*,309*,30A1,30A2,30A3,30A4,30A5,30A6,30A7,30A^,30B*,30C*,30D*,30E*,30F_,30F8,30F9,30FA,30FC,30FD,30FE,30FF,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," // Pc ->> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, - If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Pc}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, - If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Pc}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"005F,203F,2040,2054," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Pc}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005_,0058,0059,005A,005B,005C,005D,005E,006*,007*,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203_,2038,2039,203A,203B,203C,203D,203E,2041,2042,2043,2044,2045,2046,2047,204^,2050,2051,2052,2053,2055,2056,2057,205^,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," // Pd ->> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, - If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Pd}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, - If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Pd}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"002D,058A,05BE,1400,1806,2010,2011,2012,2013,2014,2015,2E17,2E1A,2E3A,2E3B,2E40,2E5D,301C,3030,30A0," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Pd}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,002_,0028,0029,002A,002B,002C,002E,002F,003*,004*,005*,006*,007*,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058_,0588,0589,058B,058C,058D,058E,058F,059*,05A*,05B_,05B8,05B9,05BA,05BB,05BC,05BD,05BF,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,1401,1402,1403,1404,1405,1406,1407,140^,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,1800,1801,1802,1803,1804,1805,1807,180^,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,2016,2017,201^,202*,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E10,2E11,2E12,2E13,2E14,2E15,2E16,2E18,2E19,2E1B,2E1C,2E1D,2E1E,2E1F,2E2*,2E3_,2E38,2E39,2E3C,2E3D,2E3E,2E3F,2E41,2E42,2E43,2E44,2E45,2E46,2E47,2E4^,2E5_,2E58,2E59,2E5A,2E5B,2E5C,2E5E,2E5F,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301_,3018,3019,301A,301B,301D,301E,301F,302*,3031,3032,3033,3034,3035,3036,3037,303^,304*,305*,306*,307*,308*,309*,30A1,30A2,30A3,30A4,30A5,30A6,30A7,30A^,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," // Ps ->> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, - If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Ps}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, - If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Ps}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0028,005B,007B,0F3A,0F3C,169B,201A,201E,2045,207D,208D,2308,230A,2329,2768,276A,276C,276E,2770,2772,2774,27C5,27E6,27E8,27EA,27EC,27EE,2983,2985,2987,2989,298B,298D,298F,2991,2993,2995,2997,29D8,29DA,29FC,2E22,2E24,2E26,2E28,2E42,2E55,2E57,2E59,2E5B,3008,300A,300C,300E,3010,3014,3016,3018,301A,301D," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Ps}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,002_,0029,002A,002B,002C,002D,002E,002F,003*,004*,005_,0058,0059,005A,005C,005D,005E,005F,006*,007_,0078,0079,007A,007C,007D,007E,007F,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3_,0F38,0F39,0F3B,0F3D,0F3E,0F3F,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169_,1698,1699,169A,169C,169D,169E,169F,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201_,2018,2019,201B,201C,201D,201F,202*,203*,2040,2041,2042,2043,2044,2046,2047,204^,205*,206*,207_,2078,2079,207A,207B,207C,207E,207F,208_,2088,2089,208A,208B,208C,208E,208F,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230_,2309,230B,230C,230D,230E,230F,231*,232_,2328,232A,232B,232C,232D,232E,232F,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276_,2769,276B,276D,276F,2771,2773,2775,2776,2777,277^,278*,279*,27A*,27B*,27C0,27C1,27C2,27C3,27C4,27C6,27C7,27C^,27D*,27E0,27E1,27E2,27E3,27E4,27E5,27E7,27E9,27EB,27ED,27EF,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,2980,2981,2982,2984,2986,2988,298A,298C,298E,2990,2992,2994,2996,299^,29A*,29B*,29C*,29D_,29D9,29DB,29DC,29DD,29DE,29DF,29E*,29F_,29F8,29F9,29FA,29FB,29FD,29FE,29FF,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E20,2E21,2E23,2E25,2E27,2E29,2E2A,2E2B,2E2C,2E2D,2E2E,2E2F,2E3*,2E40,2E41,2E43,2E44,2E45,2E46,2E47,2E4^,2E50,2E51,2E52,2E53,2E54,2E56,2E58,2E5A,2E5C,2E5D,2E5E,2E5F,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300_,3009,300B,300D,300F,3011,3012,3013,3015,3017,3019,301B,301C,301E,301F,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," // Pe ->> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, - If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Pe}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, - If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Pe}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0029,005D,007D,0F3B,0F3D,169C,2046,207E,208E,2309,230B,232A,2769,276B,276D,276F,2771,2773,2775,27C6,27E7,27E9,27EB,27ED,27EF,2984,2986,2988,298A,298C,298E,2990,2992,2994,2996,2998,29D9,29DB,29FD,2E23,2E25,2E27,2E29,2E56,2E58,2E5A,2E5C,3009,300B,300D,300F,3011,3015,3017,3019,301B,301E,301F," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Pe}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,002_,0028,002A,002B,002C,002D,002E,002F,003*,004*,005_,0058,0059,005A,005B,005C,005E,005F,006*,007_,0078,0079,007A,007B,007C,007E,007F,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3_,0F38,0F39,0F3A,0F3C,0F3E,0F3F,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169_,1698,1699,169A,169B,169D,169E,169F,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,2040,2041,2042,2043,2044,2045,2047,204^,205*,206*,207_,2078,2079,207A,207B,207C,207D,207F,208_,2088,2089,208A,208B,208C,208D,208F,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230_,2308,230A,230C,230D,230E,230F,231*,232_,2328,2329,232B,232C,232D,232E,232F,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276_,2768,276A,276C,276E,2770,2772,2774,2776,2777,277^,278*,279*,27A*,27B*,27C0,27C1,27C2,27C3,27C4,27C5,27C7,27C^,27D*,27E0,27E1,27E2,27E3,27E4,27E5,27E6,27E8,27EA,27EC,27EE,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,2980,2981,2982,2983,2985,2987,2989,298B,298D,298F,2991,2993,2995,2997,2999,299A,299B,299C,299D,299E,299F,29A*,29B*,29C*,29D_,29D8,29DA,29DC,29DD,29DE,29DF,29E*,29F_,29F8,29F9,29FA,29FB,29FC,29FE,29FF,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E20,2E21,2E22,2E24,2E26,2E28,2E2A,2E2B,2E2C,2E2D,2E2E,2E2F,2E3*,2E4*,2E50,2E51,2E52,2E53,2E54,2E55,2E57,2E59,2E5B,2E5D,2E5E,2E5F,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300_,3008,300A,300C,300E,3010,3012,3013,3014,3016,3018,301A,301C,301D,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," // Pi ->> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, - If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Pi}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, - If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Pi}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"00AB,2018,201B,201C,201F,2039,2E02,2E04,2E09,2E0C,2E1C,2E20," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Pi}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A_,00A8,00A9,00AA,00AC,00AD,00AE,00AF,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201_,2019,201A,201D,201E,202*,203_,2038,203A,203B,203C,203D,203E,203F,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E00,2E01,2E03,2E05,2E06,2E07,2E08,2E0A,2E0B,2E0D,2E0E,2E0F,2E1_,2E18,2E19,2E1A,2E1B,2E1D,2E1E,2E1F,2E21,2E22,2E23,2E24,2E25,2E26,2E27,2E2^,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," // Pf ->> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, - If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Pf}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, - If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Pf}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"00BB,2019,201D,203A,2E03,2E05,2E0A,2E0D,2E1D,2E21," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Pf}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A*,00B_,00B8,00B9,00BA,00BC,00BD,00BE,00BF,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201_,2018,201A,201B,201C,201E,201F,202*,203_,2038,2039,203B,203C,203D,203E,203F,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E00,2E01,2E02,2E04,2E06,2E07,2E08,2E09,2E0B,2E0C,2E0E,2E0F,2E1_,2E18,2E19,2E1A,2E1B,2E1C,2E1E,2E1F,2E20,2E22,2E23,2E24,2E25,2E26,2E27,2E2^,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," // Po ->> Concat( ForAll( Sequence( 1024 ) As Outer, With( { s: Concat( ForAll( Sequence( 8, 0 ) As Inner, - If( IsMatch( UniChar(Outer.Value*8+Inner.Value), "\p{Po}" ), Dec2Hex( Outer.Value*8+Inner.Value, 4 ) & ",", "" ) ), Value ) }, - If( Len(s) = 40, Dec2Hex( Outer.Value*8, 4 ) & "-" & Dec2Hex(Outer.Value*8+7,4) & ",", s ) ) ), Value ) +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Po}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0021,0022,0023,0025,0026,0027,002A,002C,002E,002F,003A,003B,003F,0040,005C,00A1,00A7,00B6,00B7,00BF,037E,0387,055A,055B,055C,055D,055E,055F,0589,05C0,05C3,05C6,05F3,05F4,0609,060A,060C,060D,061B,061D,061E,061F,066A,066B,066C,066D,06D4,070_,0708,0709,070A,070B,070C,070D,07F7,07F8,07F9,083_,0838,0839,083A,083B,083C,083D,083E,085E,0964,0965,0970,09FD,0A76,0AF0,0C77,0C84,0DF4,0E4F,0E5A,0E5B,0F04,0F05,0F06,0F07,0F0^,0F10,0F11,0F12,0F14,0F85,0FD0,0FD1,0FD2,0FD3,0FD4,0FD9,0FDA,104A,104B,104C,104D,104E,104F,10FB,136_,1368,166E,16EB,16EC,16ED,1735,1736,17D4,17D5,17D6,17D8,17D9,17DA,1800,1801,1802,1803,1804,1805,1807,1808,1809,180A,1944,1945,1A1E,1A1F,1AA0,1AA1,1AA2,1AA3,1AA4,1AA5,1AA6,1AA8,1AA9,1AAA,1AAB,1AAC,1AAD,1B5A,1B5B,1B5C,1B5D,1B5E,1B5F,1B60,1B7D,1B7E,1BFC,1BFD,1BFE,1BFF,1C3B,1C3C,1C3D,1C3E,1C3F,1C7E,1C7F,1CC_,1CD3,2016,2017,202_,203_,2038,203B,203C,203D,203E,2041,2042,2043,2047,204^,2050,2051,2053,2055,2056,2057,2058,2059,205A,205B,205C,205D,205E,2CF9,2CFA,2CFB,2CFC,2CFE,2CFF,2D70,2E00,2E01,2E06,2E07,2E08,2E0B,2E0E,2E0F,2E10,2E11,2E12,2E13,2E14,2E15,2E16,2E18,2E19,2E1B,2E1E,2E1F,2E2A,2E2B,2E2C,2E2D,2E2E,2E3_,2E38,2E39,2E3C,2E3D,2E3E,2E3F,2E41,2E43,2E44,2E45,2E46,2E47,2E4^,2E52,2E53,2E54,3001,3002,3003,303D,30FB," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Po}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,0020,0024,0028,0029,002B,002D,003_,0038,0039,003C,003D,003E,0041,0042,0043,0044,0045,0046,0047,004^,005_,0058,0059,005A,005B,005D,005E,005F,006*,007*,008*,009*,00A0,00A2,00A3,00A4,00A5,00A6,00A^,00B0,00B1,00B2,00B3,00B4,00B5,00B8,00B9,00BA,00BB,00BC,00BD,00BE,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037_,0378,0379,037A,037B,037C,037D,037F,0380,0381,0382,0383,0384,0385,0386,038^,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055_,0558,0559,056*,057*,058_,0588,058A,058B,058C,058D,058E,058F,059*,05A*,05B*,05C1,05C2,05C4,05C5,05C7,05C^,05D*,05E*,05F0,05F1,05F2,05F5,05F6,05F7,05F^,060_,0608,060B,060E,060F,061_,0618,0619,061A,061C,062*,063*,064*,065*,066_,0668,0669,066E,066F,067*,068*,069*,06A*,06B*,06C*,06D0,06D1,06D2,06D3,06D5,06D6,06D7,06D^,06E*,06F*,070E,070F,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F0,07F1,07F2,07F3,07F4,07F5,07F6,07FA,07FB,07FC,07FD,07FE,07FF,080*,081*,082*,083F,084*,085_,0858,0859,085A,085B,085C,085D,085F,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,0960,0961,0962,0963,0966,0967,096^,0971,0972,0973,0974,0975,0976,0977,097^,098*,099*,09A*,09B*,09C*,09D*,09E*,09F_,09F8,09F9,09FA,09FB,09FC,09FE,09FF,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A70,0A71,0A72,0A73,0A74,0A75,0A77,0A7^,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF1,0AF2,0AF3,0AF4,0AF5,0AF6,0AF7,0AF^,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C70,0C71,0C72,0C73,0C74,0C75,0C76,0C7^,0C80,0C81,0C82,0C83,0C85,0C86,0C87,0C8^,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF0,0DF1,0DF2,0DF3,0DF5,0DF6,0DF7,0DF^,0E0*,0E1*,0E2*,0E3*,0E4_,0E48,0E49,0E4A,0E4B,0E4C,0E4D,0E4E,0E5_,0E58,0E59,0E5C,0E5D,0E5E,0E5F,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F00,0F01,0F02,0F03,0F13,0F15,0F16,0F17,0F1^,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F80,0F81,0F82,0F83,0F84,0F86,0F87,0F8^,0F9*,0FA*,0FB*,0FC*,0FD5,0FD6,0FD7,0FD8,0FDB,0FDC,0FDD,0FDE,0FDF,0FE*,0FF*,100*,101*,102*,103*,104_,1048,1049,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F_,10F8,10F9,10FA,10FC,10FD,10FE,10FF,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,1369,136A,136B,136C,136D,136E,136F,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166_,1668,1669,166A,166B,166C,166D,166F,167*,168*,169*,16A*,16B*,16C*,16D*,16E_,16E8,16E9,16EA,16EE,16EF,16F*,170*,171*,172*,1730,1731,1732,1733,1734,1737,173^,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D0,17D1,17D2,17D3,17D7,17DB,17DC,17DD,17DE,17DF,17E*,17F*,1806,180B,180C,180D,180E,180F,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,1940,1941,1942,1943,1946,1947,194^,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1_,1A18,1A19,1A1A,1A1B,1A1C,1A1D,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA7,1AAE,1AAF,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5_,1B58,1B59,1B61,1B62,1B63,1B64,1B65,1B66,1B67,1B6^,1B7_,1B78,1B79,1B7A,1B7B,1B7C,1B7F,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF_,1BF8,1BF9,1BFA,1BFB,1C0*,1C1*,1C2*,1C3_,1C38,1C39,1C3A,1C4*,1C5*,1C6*,1C7_,1C78,1C79,1C7A,1C7B,1C7C,1C7D,1C8*,1C9*,1CA*,1CB*,1CC^,1CD0,1CD1,1CD2,1CD4,1CD5,1CD6,1CD7,1CD^,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,2010,2011,2012,2013,2014,2015,201^,202^,2039,203A,203F,2040,2044,2045,2046,2052,2054,205F,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF_,2CF8,2CFD,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D71,2D72,2D73,2D74,2D75,2D76,2D77,2D7^,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E02,2E03,2E04,2E05,2E09,2E0A,2E0C,2E0D,2E17,2E1A,2E1C,2E1D,2E2_,2E28,2E29,2E2F,2E3A,2E3B,2E40,2E42,2E50,2E51,2E55,2E56,2E57,2E5^,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,3000,3004,3005,3006,3007,300^,301*,302*,303_,3038,3039,303A,303B,303C,303E,303F,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F_,30F8,30F9,30FA,30FC,30FD,30FE,30FF,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," + +// S +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{S}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0024,002B,003C,003D,003E,005E,0060,007C,007E,00A2,00A3,00A4,00A5,00A6,00A8,00A9,00AC,00AE,00AF,00B0,00B1,00B4,00B8,00D7,00F7,02C2,02C3,02C4,02C5,02D2,02D3,02D4,02D5,02D6,02D7,02D^,02E5,02E6,02E7,02E8,02E9,02EA,02EB,02ED,02EF,02F*,0375,0384,0385,03F6,0482,058D,058E,058F,0606,0607,0608,060B,060E,060F,06DE,06E9,06FD,06FE,07F6,07FE,07FF,0888,09F2,09F3,09FA,09FB,0AF1,0B70,0BF3,0BF4,0BF5,0BF6,0BF7,0BF8,0BF9,0BFA,0C7F,0D4F,0D79,0E3F,0F01,0F02,0F03,0F13,0F15,0F16,0F17,0F1A,0F1B,0F1C,0F1D,0F1E,0F1F,0F34,0F36,0F38,0FBE,0FBF,0FC0,0FC1,0FC2,0FC3,0FC4,0FC5,0FC7,0FC8,0FC9,0FCA,0FCB,0FCC,0FCE,0FCF,0FD5,0FD6,0FD7,0FD8,109E,109F,139_,1398,1399,166D,17DB,1940,19DE,19DF,19E*,19F*,1B61,1B62,1B63,1B64,1B65,1B66,1B67,1B68,1B69,1B6A,1B74,1B75,1B76,1B77,1B78,1B79,1B7A,1B7B,1B7C,1FBD,1FBF,1FC0,1FC1,1FCD,1FCE,1FCF,1FDD,1FDE,1FDF,1FED,1FEE,1FEF,1FFD,1FFE,2044,2052,207A,207B,207C,208A,208B,208C,20A*,20B*,20C0,2100,2101,2103,2104,2105,2106,2108,2109,2114,2116,2117,2118,211E,211F,2120,2121,2122,2123,2125,2127,2129,212E,213A,213B,2140,2141,2142,2143,2144,214A,214B,214C,214D,214F,218A,218B,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230_,230C,230D,230E,230F,231*,232_,2328,232B,232C,232D,232E,232F,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,2420,2421,2422,2423,2424,2425,2426,244_,2448,2449,244A,249C,249D,249E,249F,24A*,24B*,24C*,24D*,24E_,24E8,24E9,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276_,2794,2795,2796,2797,279^,27A*,27B*,27C0,27C1,27C2,27C3,27C4,27C7,27C^,27D*,27E0,27E1,27E2,27E3,27E4,27E5,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,2980,2981,2982,2999,299A,299B,299C,299D,299E,299F,29A*,29B*,29C*,29D_,29DC,29DD,29DE,29DF,29E*,29F_,29F8,29F9,29FA,29FB,29FE,29FF,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B70,2B71,2B72,2B73,2B76,2B77,2B7^,2B8*,2B90,2B91,2B92,2B93,2B94,2B95,2B97,2B9^,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2CE5,2CE6,2CE7,2CE8,2CE9,2CEA,2E50,2E51,2E8*,2E9_,2E98,2E99,2E9B,2E9C,2E9D,2E9E,2E9F,2EA*,2EB*,2EC*,2ED*,2EE*,2EF0,2EF1,2EF2,2EF3,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD0,2FD1,2FD2,2FD3,2FD4,2FD5,2FF_,2FF8,2FF9,2FFA,2FFB,3004,3012,3013,3020,3036,3037,303E,303F,309B,309C,3190,3191,3196,3197,319^,31C*,31D*,31E0,31E1,31E2,31E3,320*,321_,3218,3219,321A,321B,321C,321D,321E,322A,322B,322C,322D,322E,322F,323*,324_,3250,326*,327*,328A,328B,328C,328D,328E,328F,329*,32A*,32B0,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{S}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,0020,0021,0022,0023,0025,0026,0027,0028,0029,002A,002C,002D,002E,002F,003_,0038,0039,003A,003B,003F,004*,005_,0058,0059,005A,005B,005C,005D,005F,0061,0062,0063,0064,0065,0066,0067,006^,007_,0078,0079,007A,007B,007D,007F,008*,009*,00A0,00A1,00A7,00AA,00AB,00AD,00B2,00B3,00B5,00B6,00B7,00B9,00BA,00BB,00BC,00BD,00BE,00BF,00C*,00D0,00D1,00D2,00D3,00D4,00D5,00D6,00D^,00E*,00F0,00F1,00F2,00F3,00F4,00F5,00F6,00F^,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C0,02C1,02C6,02C7,02C^,02D0,02D1,02E0,02E1,02E2,02E3,02E4,02EC,02EE,030*,031*,032*,033*,034*,035*,036*,0370,0371,0372,0373,0374,0376,0377,037^,0380,0381,0382,0383,0386,0387,038^,039*,03A*,03B*,03C*,03D*,03E*,03F0,03F1,03F2,03F3,03F4,03F5,03F7,03F^,040*,041*,042*,043*,044*,045*,046*,047*,0480,0481,0483,0484,0485,0486,0487,048^,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058_,0588,0589,058A,058B,058C,059*,05A*,05B*,05C*,05D*,05E*,05F*,0600,0601,0602,0603,0604,0605,0609,060A,060C,060D,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D_,06D8,06D9,06DA,06DB,06DC,06DD,06DF,06E_,06E8,06EA,06EB,06EC,06ED,06EE,06EF,06F_,06F8,06F9,06FA,06FB,06FC,06FF,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F0,07F1,07F2,07F3,07F4,07F5,07F7,07F8,07F9,07FA,07FB,07FC,07FD,080*,081*,082*,083*,084*,085*,086*,087*,088_,0889,088A,088B,088C,088D,088E,088F,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F0,09F1,09F4,09F5,09F6,09F7,09F8,09F9,09FC,09FD,09FE,09FF,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF0,0AF2,0AF3,0AF4,0AF5,0AF6,0AF7,0AF^,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B71,0B72,0B73,0B74,0B75,0B76,0B77,0B7^,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF0,0BF1,0BF2,0BFB,0BFC,0BFD,0BFE,0BFF,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7_,0C78,0C79,0C7A,0C7B,0C7C,0C7D,0C7E,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4_,0D48,0D49,0D4A,0D4B,0D4C,0D4D,0D4E,0D5*,0D6*,0D7_,0D78,0D7A,0D7B,0D7C,0D7D,0D7E,0D7F,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3_,0E38,0E39,0E3A,0E3B,0E3C,0E3D,0E3E,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F00,0F04,0F05,0F06,0F07,0F0^,0F10,0F11,0F12,0F14,0F18,0F19,0F2*,0F30,0F31,0F32,0F33,0F35,0F37,0F39,0F3A,0F3B,0F3C,0F3D,0F3E,0F3F,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB_,0FB8,0FB9,0FBA,0FBB,0FBC,0FBD,0FC6,0FCD,0FD0,0FD1,0FD2,0FD3,0FD4,0FD9,0FDA,0FDB,0FDC,0FDD,0FDE,0FDF,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109_,1098,1099,109A,109B,109C,109D,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139A,139B,139C,139D,139E,139F,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166_,1668,1669,166A,166B,166C,166E,166F,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D_,17D8,17D9,17DA,17DC,17DD,17DE,17DF,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,1941,1942,1943,1944,1945,1946,1947,194^,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D_,19D8,19D9,19DA,19DB,19DC,19DD,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B60,1B6B,1B6C,1B6D,1B6E,1B6F,1B70,1B71,1B72,1B73,1B7D,1B7E,1B7F,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB_,1FB8,1FB9,1FBA,1FBB,1FBC,1FBE,1FC2,1FC3,1FC4,1FC5,1FC6,1FC7,1FC8,1FC9,1FCA,1FCB,1FCC,1FD_,1FD8,1FD9,1FDA,1FDB,1FDC,1FE_,1FE8,1FE9,1FEA,1FEB,1FEC,1FF_,1FF8,1FF9,1FFA,1FFB,1FFC,1FFF,200*,201*,202*,203*,2040,2041,2042,2043,2045,2046,2047,204^,2050,2051,2053,2054,2055,2056,2057,205^,206*,207_,2078,2079,207D,207E,207F,208_,2088,2089,208D,208E,208F,209*,20C1,20C2,20C3,20C4,20C5,20C6,20C7,20C^,20D*,20E*,20F*,2102,2107,210A,210B,210C,210D,210E,210F,2110,2111,2112,2113,2115,2119,211A,211B,211C,211D,2124,2126,2128,212A,212B,212C,212D,212F,213_,2138,2139,213C,213D,213E,213F,2145,2146,2147,2148,2149,214E,215*,216*,217*,218_,2188,2189,218C,218D,218E,218F,2308,2309,230A,230B,2329,232A,2427,242^,243*,244B,244C,244D,244E,244F,245*,246*,247*,248*,249_,2498,2499,249A,249B,24EA,24EB,24EC,24ED,24EE,24EF,24F*,276^,277*,278*,2790,2791,2792,2793,27C5,27C6,27E6,27E7,27E^,2983,2984,2985,2986,2987,298^,299_,2998,29D8,29D9,29DA,29DB,29FC,29FD,2B74,2B75,2B96,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE0,2CE1,2CE2,2CE3,2CE4,2CEB,2CEC,2CED,2CEE,2CEF,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E52,2E53,2E54,2E55,2E56,2E57,2E5^,2E6*,2E7*,2E9A,2EF4,2EF5,2EF6,2EF7,2EF^,2FD6,2FD7,2FD^,2FE*,2FFC,2FFD,2FFE,2FFF,3000,3001,3002,3003,3005,3006,3007,300^,3010,3011,3014,3015,3016,3017,301^,3021,3022,3023,3024,3025,3026,3027,302^,3030,3031,3032,3033,3034,3035,3038,3039,303A,303B,303C,303D,304*,305*,306*,307*,308*,309_,3098,3099,309A,309D,309E,309F,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,3192,3193,3194,3195,31A*,31B*,31E4,31E5,31E6,31E7,31E^,31F*,321F,322_,3228,3229,324^,3251,3252,3253,3254,3255,3256,3257,325^,328_,3288,3289,32B1,32B2,32B3,32B4,32B5,32B6,32B7,32B^,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," + +// Sm +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Sm}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"002B,003C,003D,003E,007C,007E,00AC,00B1,00D7,00F7,03F6,0606,0607,0608,2044,2052,207A,207B,207C,208A,208B,208C,2118,2140,2141,2142,2143,2144,214B,2190,2191,2192,2193,2194,219A,219B,21A0,21A3,21A6,21AE,21CE,21CF,21D2,21D4,21F4,21F5,21F6,21F7,21F^,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,2320,2321,237C,239B,239C,239D,239E,239F,23A*,23B0,23B1,23B2,23B3,23DC,23DD,23DE,23DF,23E0,23E1,25B7,25C1,25F^,266F,27C0,27C1,27C2,27C3,27C4,27C7,27C^,27D*,27E0,27E1,27E2,27E3,27E4,27E5,27F*,290*,291*,292*,293*,294*,295*,296*,297*,2980,2981,2982,2999,299A,299B,299C,299D,299E,299F,29A*,29B*,29C*,29D_,29DC,29DD,29DE,29DF,29E*,29F_,29F8,29F9,29FA,29FB,29FE,29FF,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B3*,2B40,2B41,2B42,2B43,2B44,2B47,2B48,2B49,2B4A,2B4B,2B4C," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Sm}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,002_,0028,0029,002A,002C,002D,002E,002F,003_,0038,0039,003A,003B,003F,004*,005*,006*,007_,0078,0079,007A,007B,007D,007F,008*,009*,00A_,00A8,00A9,00AA,00AB,00AD,00AE,00AF,00B0,00B2,00B3,00B4,00B5,00B6,00B7,00B^,00C*,00D0,00D1,00D2,00D3,00D4,00D5,00D6,00D^,00E*,00F0,00F1,00F2,00F3,00F4,00F5,00F6,00F^,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F0,03F1,03F2,03F3,03F4,03F5,03F7,03F^,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,0600,0601,0602,0603,0604,0605,0609,060A,060B,060C,060D,060E,060F,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,2040,2041,2042,2043,2045,2046,2047,204^,2050,2051,2053,2054,2055,2056,2057,205^,206*,207_,2078,2079,207D,207E,207F,208_,2088,2089,208D,208E,208F,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211_,2119,211A,211B,211C,211D,211E,211F,212*,213*,2145,2146,2147,2148,2149,214A,214C,214D,214E,214F,215*,216*,217*,218*,2195,2196,2197,2198,2199,219C,219D,219E,219F,21A1,21A2,21A4,21A5,21A7,21A8,21A9,21AA,21AB,21AC,21AD,21AF,21B*,21C_,21C8,21C9,21CA,21CB,21CC,21CD,21D0,21D1,21D3,21D5,21D6,21D7,21D^,21E*,21F0,21F1,21F2,21F3,230*,231*,2322,2323,2324,2325,2326,2327,232^,233*,234*,235*,236*,237_,2378,2379,237A,237B,237D,237E,237F,238*,239_,2398,2399,239A,23B4,23B5,23B6,23B7,23B^,23C*,23D_,23D8,23D9,23DA,23DB,23E2,23E3,23E4,23E5,23E6,23E7,23E^,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B0,25B1,25B2,25B3,25B4,25B5,25B6,25B^,25C0,25C2,25C3,25C4,25C5,25C6,25C7,25C^,25D*,25E*,25F_,260*,261*,262*,263*,264*,265*,266_,2668,2669,266A,266B,266C,266D,266E,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C5,27C6,27E6,27E7,27E^,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,2983,2984,2985,2986,2987,298^,299_,2998,29D8,29D9,29DA,29DB,29FC,29FD,2B0*,2B1*,2B2*,2B45,2B46,2B4D,2B4E,2B4F,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," + +// Sc +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Sc}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0024,00A2,00A3,00A4,00A5,058F,060B,07FE,07FF,09F2,09F3,09FB,0AF1,0BF9,0E3F,17DB,20A*,20B*,20C0," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Sc}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,0020,0021,0022,0023,0025,0026,0027,002^,003*,004*,005*,006*,007*,008*,009*,00A0,00A1,00A6,00A7,00A^,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058_,0588,0589,058A,058B,058C,058D,058E,059*,05A*,05B*,05C*,05D*,05E*,05F*,060_,0608,0609,060A,060C,060D,060E,060F,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F_,07F8,07F9,07FA,07FB,07FC,07FD,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F0,09F1,09F4,09F5,09F6,09F7,09F8,09F9,09FA,09FC,09FD,09FE,09FF,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF0,0AF2,0AF3,0AF4,0AF5,0AF6,0AF7,0AF^,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF_,0BF8,0BFA,0BFB,0BFC,0BFD,0BFE,0BFF,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3_,0E38,0E39,0E3A,0E3B,0E3C,0E3D,0E3E,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D_,17D8,17D9,17DA,17DC,17DD,17DE,17DF,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,204*,205*,206*,207*,208*,209*,20C1,20C2,20C3,20C4,20C5,20C6,20C7,20C^,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," + +// Sk +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Sk}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"005E,0060,00A8,00AF,00B4,00B8,02C2,02C3,02C4,02C5,02D2,02D3,02D4,02D5,02D6,02D7,02D^,02E5,02E6,02E7,02E8,02E9,02EA,02EB,02ED,02EF,02F*,0375,0384,0385,0888,1FBD,1FBF,1FC0,1FC1,1FCD,1FCE,1FCF,1FDD,1FDE,1FDF,1FED,1FEE,1FEF,1FFD,1FFE,309B,309C," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Sk}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005_,0058,0059,005A,005B,005C,005D,005F,0061,0062,0063,0064,0065,0066,0067,006^,007*,008*,009*,00A_,00A9,00AA,00AB,00AC,00AD,00AE,00B0,00B1,00B2,00B3,00B5,00B6,00B7,00B9,00BA,00BB,00BC,00BD,00BE,00BF,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C0,02C1,02C6,02C7,02C^,02D0,02D1,02E0,02E1,02E2,02E3,02E4,02EC,02EE,030*,031*,032*,033*,034*,035*,036*,0370,0371,0372,0373,0374,0376,0377,037^,0380,0381,0382,0383,0386,0387,038^,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088_,0889,088A,088B,088C,088D,088E,088F,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB_,1FB8,1FB9,1FBA,1FBB,1FBC,1FBE,1FC2,1FC3,1FC4,1FC5,1FC6,1FC7,1FC8,1FC9,1FCA,1FCB,1FCC,1FD_,1FD8,1FD9,1FDA,1FDB,1FDC,1FE_,1FE8,1FE9,1FEA,1FEB,1FEC,1FF_,1FF8,1FF9,1FFA,1FFB,1FFC,1FFF,200*,201*,202*,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309_,3098,3099,309A,309D,309E,309F,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," + +// So +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{So}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"00A6,00A9,00AE,00B0,0482,058D,058E,060E,060F,06DE,06E9,06FD,06FE,07F6,09FA,0B70,0BF3,0BF4,0BF5,0BF6,0BF7,0BF8,0BFA,0C7F,0D4F,0D79,0F01,0F02,0F03,0F13,0F15,0F16,0F17,0F1A,0F1B,0F1C,0F1D,0F1E,0F1F,0F34,0F36,0F38,0FBE,0FBF,0FC0,0FC1,0FC2,0FC3,0FC4,0FC5,0FC7,0FC8,0FC9,0FCA,0FCB,0FCC,0FCE,0FCF,0FD5,0FD6,0FD7,0FD8,109E,109F,139_,1398,1399,166D,1940,19DE,19DF,19E*,19F*,1B61,1B62,1B63,1B64,1B65,1B66,1B67,1B68,1B69,1B6A,1B74,1B75,1B76,1B77,1B78,1B79,1B7A,1B7B,1B7C,2100,2101,2103,2104,2105,2106,2108,2109,2114,2116,2117,211E,211F,2120,2121,2122,2123,2125,2127,2129,212E,213A,213B,214A,214C,214D,214F,218A,218B,2195,2196,2197,2198,2199,219C,219D,219E,219F,21A1,21A2,21A4,21A5,21A7,21A8,21A9,21AA,21AB,21AC,21AD,21AF,21B*,21C_,21C8,21C9,21CA,21CB,21CC,21CD,21D0,21D1,21D3,21D5,21D6,21D7,21D^,21E*,21F0,21F1,21F2,21F3,230_,230C,230D,230E,230F,231*,2322,2323,2324,2325,2326,2327,2328,232B,232C,232D,232E,232F,233*,234*,235*,236*,237_,2378,2379,237A,237B,237D,237E,237F,238*,239_,2398,2399,239A,23B4,23B5,23B6,23B7,23B^,23C*,23D_,23D8,23D9,23DA,23DB,23E2,23E3,23E4,23E5,23E6,23E7,23E^,23F*,240*,241*,2420,2421,2422,2423,2424,2425,2426,244_,2448,2449,244A,249C,249D,249E,249F,24A*,24B*,24C*,24D*,24E_,24E8,24E9,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B0,25B1,25B2,25B3,25B4,25B5,25B6,25B^,25C0,25C2,25C3,25C4,25C5,25C6,25C7,25C^,25D*,25E*,25F_,260*,261*,262*,263*,264*,265*,266_,2668,2669,266A,266B,266C,266D,266E,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276_,2794,2795,2796,2797,279^,27A*,27B*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,2B0*,2B1*,2B2*,2B45,2B46,2B4D,2B4E,2B4F,2B5*,2B6*,2B70,2B71,2B72,2B73,2B76,2B77,2B7^,2B8*,2B90,2B91,2B92,2B93,2B94,2B95,2B97,2B9^,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2CE5,2CE6,2CE7,2CE8,2CE9,2CEA,2E50,2E51,2E8*,2E9_,2E98,2E99,2E9B,2E9C,2E9D,2E9E,2E9F,2EA*,2EB*,2EC*,2ED*,2EE*,2EF0,2EF1,2EF2,2EF3,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD0,2FD1,2FD2,2FD3,2FD4,2FD5,2FF_,2FF8,2FF9,2FFA,2FFB,3004,3012,3013,3020,3036,3037,303E,303F,3190,3191,3196,3197,319^,31C*,31D*,31E0,31E1,31E2,31E3,320*,321_,3218,3219,321A,321B,321C,321D,321E,322A,322B,322C,322D,322E,322F,323*,324_,3250,326*,327*,328A,328B,328C,328D,328E,328F,329*,32A*,32B0,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{So}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A0,00A1,00A2,00A3,00A4,00A5,00A7,00A8,00AA,00AB,00AC,00AD,00AF,00B1,00B2,00B3,00B4,00B5,00B6,00B7,00B^,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,0480,0481,0483,0484,0485,0486,0487,048^,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058_,0588,0589,058A,058B,058C,058F,059*,05A*,05B*,05C*,05D*,05E*,05F*,060_,0608,0609,060A,060B,060C,060D,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D_,06D8,06D9,06DA,06DB,06DC,06DD,06DF,06E_,06E8,06EA,06EB,06EC,06ED,06EE,06EF,06F_,06F8,06F9,06FA,06FB,06FC,06FF,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F0,07F1,07F2,07F3,07F4,07F5,07F7,07F^,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F_,09F8,09F9,09FB,09FC,09FD,09FE,09FF,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B71,0B72,0B73,0B74,0B75,0B76,0B77,0B7^,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF0,0BF1,0BF2,0BF9,0BFB,0BFC,0BFD,0BFE,0BFF,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7_,0C78,0C79,0C7A,0C7B,0C7C,0C7D,0C7E,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4_,0D48,0D49,0D4A,0D4B,0D4C,0D4D,0D4E,0D5*,0D6*,0D7_,0D78,0D7A,0D7B,0D7C,0D7D,0D7E,0D7F,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F00,0F04,0F05,0F06,0F07,0F0^,0F10,0F11,0F12,0F14,0F18,0F19,0F2*,0F30,0F31,0F32,0F33,0F35,0F37,0F39,0F3A,0F3B,0F3C,0F3D,0F3E,0F3F,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB_,0FB8,0FB9,0FBA,0FBB,0FBC,0FBD,0FC6,0FCD,0FD0,0FD1,0FD2,0FD3,0FD4,0FD9,0FDA,0FDB,0FDC,0FDD,0FDE,0FDF,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109_,1098,1099,109A,109B,109C,109D,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139A,139B,139C,139D,139E,139F,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166_,1668,1669,166A,166B,166C,166E,166F,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,1941,1942,1943,1944,1945,1946,1947,194^,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D_,19D8,19D9,19DA,19DB,19DC,19DD,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B60,1B6B,1B6C,1B6D,1B6E,1B6F,1B70,1B71,1B72,1B73,1B7D,1B7E,1B7F,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,2102,2107,210A,210B,210C,210D,210E,210F,2110,2111,2112,2113,2115,2118,2119,211A,211B,211C,211D,2124,2126,2128,212A,212B,212C,212D,212F,213_,2138,2139,213C,213D,213E,213F,214_,2148,2149,214B,214E,215*,216*,217*,218_,2188,2189,218C,218D,218E,218F,2190,2191,2192,2193,2194,219A,219B,21A0,21A3,21A6,21AE,21CE,21CF,21D2,21D4,21F4,21F5,21F6,21F7,21F^,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,2308,2309,230A,230B,2320,2321,2329,232A,237C,239B,239C,239D,239E,239F,23A*,23B0,23B1,23B2,23B3,23DC,23DD,23DE,23DF,23E0,23E1,2427,242^,243*,244B,244C,244D,244E,244F,245*,246*,247*,248*,249_,2498,2499,249A,249B,24EA,24EB,24EC,24ED,24EE,24EF,24F*,25B7,25C1,25F^,266F,276^,277*,278*,2790,2791,2792,2793,27C*,27D*,27E*,27F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B3*,2B40,2B41,2B42,2B43,2B44,2B47,2B48,2B49,2B4A,2B4B,2B4C,2B74,2B75,2B96,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE0,2CE1,2CE2,2CE3,2CE4,2CEB,2CEC,2CED,2CEE,2CEF,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E52,2E53,2E54,2E55,2E56,2E57,2E5^,2E6*,2E7*,2E9A,2EF4,2EF5,2EF6,2EF7,2EF^,2FD6,2FD7,2FD^,2FE*,2FFC,2FFD,2FFE,2FFF,3000,3001,3002,3003,3005,3006,3007,300^,3010,3011,3014,3015,3016,3017,301^,3021,3022,3023,3024,3025,3026,3027,302^,3030,3031,3032,3033,3034,3035,3038,3039,303A,303B,303C,303D,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,3192,3193,3194,3195,31A*,31B*,31E4,31E5,31E6,31E7,31E^,31F*,321F,322_,3228,3229,324^,3251,3252,3253,3254,3255,3256,3257,325^,328_,3288,3289,32B1,32B2,32B3,32B4,32B5,32B6,32B7,32B^,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," + +// Z +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Z}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0020,00A0,1680,200_,2008,2009,200A,2028,2029,202F,205F,3000," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Z}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,0021,0022,0023,0024,0025,0026,0027,002^,003*,004*,005*,006*,007*,008*,009*,00A1,00A2,00A3,00A4,00A5,00A6,00A7,00A^,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,1681,1682,1683,1684,1685,1686,1687,168^,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200B,200C,200D,200E,200F,201*,202_,202A,202B,202C,202D,202E,203*,204*,205_,2058,2059,205A,205B,205C,205D,205E,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,3001,3002,3003,3004,3005,3006,3007,300^,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," + +// Zs +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Zs}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0020,00A0,1680,200_,2008,2009,200A,202F,205F,3000," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Zs}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,0021,0022,0023,0024,0025,0026,0027,002^,003*,004*,005*,006*,007*,008*,009*,00A1,00A2,00A3,00A4,00A5,00A6,00A7,00A^,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,1681,1682,1683,1684,1685,1686,1687,168^,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200B,200C,200D,200E,200F,201*,202_,2028,2029,202A,202B,202C,202D,202E,203*,204*,205_,2058,2059,205A,205B,205C,205D,205E,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,3001,3002,3003,3004,3005,3006,3007,300^,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," + +// Zl +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Zl}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"2028," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Zl}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202_,2029,202A,202B,202C,202D,202E,202F,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," + +// Zp +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Zp}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"2029," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Zp}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202_,2028,202A,202B,202C,202D,202E,202F,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," + +// Cc +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Cc}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,007F,008*,009*," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Cc}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"002*,003*,004*,005*,006*,007_,0078,0079,007A,007B,007C,007D,007E,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," + +// Cf +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Cf}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"00AD,0600,0601,0602,0603,0604,0605,061C,06DD,070F,0890,0891,08E2,180E,200B,200C,200D,200E,200F,202A,202B,202C,202D,202E,2060,2061,2062,2063,2064,2066,2067,206^," + +>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Cf}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), + "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") + As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A_,00A8,00A9,00AA,00AB,00AC,00AE,00AF,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,0606,0607,060^,061_,0618,0619,061A,061B,061D,061E,061F,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D_,06D8,06D9,06DA,06DB,06DC,06DE,06DF,06E*,06F*,070_,0708,0709,070A,070B,070C,070D,070E,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,0892,0893,0894,0895,0896,0897,089^,08A*,08B*,08C*,08D*,08E0,08E1,08E3,08E4,08E5,08E6,08E7,08E^,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180_,1808,1809,180A,180B,180C,180D,180F,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200_,2008,2009,200A,201*,202_,2028,2029,202F,203*,204*,205*,2065,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," + +// ====================================================================================================================================== +// C, Cs, Co, Cn are disabled for now, implementation variability and not sure how they would be used, wait for feedback + +// C +//>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{C}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), +// "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") +// As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +//"0001,0002,0003,0004,0005,0006,0007,000^,001*,007F,008*,009*,00AD,0378,0379,0380,0381,0382,0383,038B,038D,03A2,0530,0557,0558,058B,058C,0590,05C^,05EB,05EC,05ED,05EE,05F5,05F6,05F7,05F^,0600,0601,0602,0603,0604,0605,061C,06DD,070E,070F,074B,074C,07B2,07B3,07B4,07B5,07B6,07B7,07B^,07FB,07FC,082E,082F,083F,085C,085D,085F,086B,086C,086D,086E,086F,088F,089_,08E2,0984,098D,098E,0991,0992,09A9,09B1,09B3,09B4,09B5,09BA,09BB,09C5,09C6,09C9,09CA,09CF,09D0,09D1,09D2,09D3,09D4,09D5,09D6,09D8,09D9,09DA,09DB,09DE,09E4,09E5,09FF,0A00,0A04,0A0B,0A0C,0A0D,0A0E,0A11,0A12,0A29,0A31,0A34,0A37,0A3A,0A3B,0A3D,0A43,0A44,0A45,0A46,0A49,0A4A,0A4E,0A4F,0A50,0A52,0A53,0A54,0A55,0A56,0A57,0A58,0A5D,0A5F,0A60,0A61,0A62,0A63,0A64,0A65,0A77,0A7^,0A80,0A84,0A8E,0A92,0AA9,0AB1,0AB4,0ABA,0ABB,0AC6,0ACA,0ACE,0ACF,0AD1,0AD2,0AD3,0AD4,0AD5,0AD6,0AD7,0AD^,0AE4,0AE5,0AF2,0AF3,0AF4,0AF5,0AF6,0AF7,0AF8,0B00,0B04,0B0D,0B0E,0B11,0B12,0B29,0B31,0B34,0B3A,0B3B,0B45,0B46,0B49,0B4A,0B4E,0B4F,0B50,0B51,0B52,0B53,0B54,0B58,0B59,0B5A,0B5B,0B5E,0B64,0B65,0B7^,0B80,0B81,0B84,0B8B,0B8C,0B8D,0B91,0B96,0B97,0B98,0B9B,0B9D,0BA0,0BA1,0BA2,0BA5,0BA6,0BA7,0BAB,0BAC,0BAD,0BBA,0BBB,0BBC,0BBD,0BC3,0BC4,0BC5,0BC9,0BCE,0BCF,0BD1,0BD2,0BD3,0BD4,0BD5,0BD6,0BD^,0BE0,0BE1,0BE2,0BE3,0BE4,0BE5,0BFB,0BFC,0BFD,0BFE,0BFF,0C0D,0C11,0C29,0C3A,0C3B,0C45,0C49,0C4E,0C4F,0C50,0C51,0C52,0C53,0C54,0C57,0C5B,0C5C,0C5E,0C5F,0C64,0C65,0C70,0C71,0C72,0C73,0C74,0C75,0C76,0C8D,0C91,0CA9,0CB4,0CBA,0CBB,0CC5,0CC9,0CCE,0CCF,0CD0,0CD1,0CD2,0CD3,0CD4,0CD7,0CD8,0CD9,0CDA,0CDB,0CDC,0CDF,0CE4,0CE5,0CF0,0CF3,0CF4,0CF5,0CF6,0CF7,0CF^,0D0D,0D11,0D45,0D49,0D50,0D51,0D52,0D53,0D64,0D65,0D80,0D84,0D97,0D98,0D99,0DB2,0DBC,0DBE,0DBF,0DC7,0DC8,0DC9,0DCB,0DCC,0DCD,0DCE,0DD5,0DD7,0DE0,0DE1,0DE2,0DE3,0DE4,0DE5,0DF0,0DF1,0DF5,0DF6,0DF7,0DF^,0E00,0E3B,0E3C,0E3D,0E3E,0E5C,0E5D,0E5E,0E5F,0E6*,0E7*,0E80,0E83,0E85,0E8B,0EA4,0EA6,0EBE,0EBF,0EC5,0EC7,0ECE,0ECF,0EDA,0EDB,0EE*,0EF*,0F48,0F6D,0F6E,0F6F,0F70,0F98,0FBD,0FCD,0FDB,0FDC,0FDD,0FDE,0FDF,0FE*,0FF*,10C6,10C8,10C9,10CA,10CB,10CC,10CE,10CF,1249,124E,124F,1257,1259,125E,125F,1289,128E,128F,12B1,12B6,12B7,12BF,12C1,12C6,12C7,12D7,1311,1316,1317,135B,135C,137D,137E,137F,139A,139B,139C,139D,139E,139F,13F6,13F7,13FE,13FF,169D,169E,169F,16F9,16FA,16FB,16FC,16FD,16FE,16FF,1716,1717,1718,1719,171A,171B,171C,171D,171E,1737,173^,1754,1755,1756,1757,175^,176D,1771,1774,1775,1776,1777,177^,17DE,17DF,17EA,17EB,17EC,17ED,17EE,17EF,17FA,17FB,17FC,17FD,17FE,17FF,180E,181A,181B,181C,181D,181E,181F,1879,187A,187B,187C,187D,187E,187F,18AB,18AC,18AD,18AE,18AF,18F6,18F7,18F^,191F,192C,192D,192E,192F,193C,193D,193E,193F,1941,1942,1943,196E,196F,1975,1976,1977,197^,19AC,19AD,19AE,19AF,19CA,19CB,19CC,19CD,19CE,19CF,19DB,19DC,19DD,1A1C,1A1D,1A5F,1A7D,1A7E,1A8A,1A8B,1A8C,1A8D,1A8E,1A8F,1A9A,1A9B,1A9C,1A9D,1A9E,1A9F,1AAE,1AAF,1ACF,1AD*,1AE*,1AF*,1B4D,1B4E,1B4F,1B7F,1BF4,1BF5,1BF6,1BF7,1BF8,1BF9,1BFA,1BFB,1C38,1C39,1C3A,1C4A,1C4B,1C4C,1C89,1C8A,1C8B,1C8C,1C8D,1C8E,1C8F,1CBB,1CBC,1CC^,1CFB,1CFC,1CFD,1CFE,1CFF,1F16,1F17,1F1E,1F1F,1F46,1F47,1F4E,1F4F,1F58,1F5A,1F5C,1F5E,1F7E,1F7F,1FB5,1FC5,1FD4,1FD5,1FDC,1FF0,1FF1,1FF5,1FFF,200B,200C,200D,200E,200F,202A,202B,202C,202D,202E,206*,2072,2073,208F,209D,209E,209F,20C1,20C2,20C3,20C4,20C5,20C6,20C7,20C^,20F1,20F2,20F3,20F4,20F5,20F6,20F7,20F^,218C,218D,218E,218F,2427,242^,243*,244B,244C,244D,244E,244F,245*,2B74,2B75,2B96,2CF4,2CF5,2CF6,2CF7,2CF8,2D26,2D28,2D29,2D2A,2D2B,2D2C,2D2E,2D2F,2D68,2D69,2D6A,2D6B,2D6C,2D6D,2D6E,2D71,2D72,2D73,2D74,2D75,2D76,2D77,2D78,2D79,2D7A,2D7B,2D7C,2D7D,2D7E,2D97,2D9^,2DA7,2DAF,2DB7,2DBF,2DC7,2DCF,2DD7,2DDF,2E5E,2E5F,2E6*,2E7*,2E9A,2EF4,2EF5,2EF6,2EF7,2EF^,2FD6,2FD7,2FD^,2FE*,2FFC,2FFD,2FFE,2FFF,3040,3097,3098,3100,3101,3102,3103,3104,3130,318F,31E4,31E5,31E6,31E7,31E^,321F," + +//>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{C}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), +// "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") +// As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +//"002*,003*,004*,005*,006*,007_,0078,0079,007A,007B,007C,007D,007E,00A_,00A8,00A9,00AA,00AB,00AC,00AE,00AF,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037_,037A,037B,037C,037D,037E,037F,0384,0385,0386,0387,0388,0389,038A,038C,038E,038F,039*,03A0,03A1,03A3,03A4,03A5,03A6,03A7,03A^,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,0531,0532,0533,0534,0535,0536,0537,053^,054*,0550,0551,0552,0553,0554,0555,0556,0559,055A,055B,055C,055D,055E,055F,056*,057*,058_,0588,0589,058A,058D,058E,058F,0591,0592,0593,0594,0595,0596,0597,059^,05A*,05B*,05C_,05D*,05E_,05E8,05E9,05EA,05EF,05F0,05F1,05F2,05F3,05F4,0606,0607,060^,061_,0618,0619,061A,061B,061D,061E,061F,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D_,06D8,06D9,06DA,06DB,06DC,06DE,06DF,06E*,06F*,070_,0708,0709,070A,070B,070C,070D,071*,072*,073*,074_,0748,0749,074A,074D,074E,074F,075*,076*,077*,078*,079*,07A*,07B0,07B1,07C*,07D*,07E*,07F_,07F8,07F9,07FA,07FD,07FE,07FF,080*,081*,082_,0828,0829,082A,082B,082C,082D,083_,0838,0839,083A,083B,083C,083D,083E,084*,085_,0858,0859,085A,085B,085E,086_,0868,0869,086A,087*,088_,0888,0889,088A,088B,088C,088D,088E,089^,08A*,08B*,08C*,08D*,08E0,08E1,08E3,08E4,08E5,08E6,08E7,08E^,08F*,090*,091*,092*,093*,094*,095*,096*,097*,0980,0981,0982,0983,0985,0986,0987,0988,0989,098A,098B,098C,098F,0990,0993,0994,0995,0996,0997,099^,09A_,09A8,09AA,09AB,09AC,09AD,09AE,09AF,09B0,09B2,09B6,09B7,09B8,09B9,09BC,09BD,09BE,09BF,09C0,09C1,09C2,09C3,09C4,09C7,09C8,09CB,09CC,09CD,09CE,09D7,09DC,09DD,09DF,09E0,09E1,09E2,09E3,09E6,09E7,09E^,09F_,09F8,09F9,09FA,09FB,09FC,09FD,09FE,0A01,0A02,0A03,0A05,0A06,0A07,0A08,0A09,0A0A,0A0F,0A10,0A13,0A14,0A15,0A16,0A17,0A1^,0A2_,0A28,0A2A,0A2B,0A2C,0A2D,0A2E,0A2F,0A30,0A32,0A33,0A35,0A36,0A38,0A39,0A3C,0A3E,0A3F,0A40,0A41,0A42,0A47,0A48,0A4B,0A4C,0A4D,0A51,0A59,0A5A,0A5B,0A5C,0A5E,0A66,0A67,0A6^,0A70,0A71,0A72,0A73,0A74,0A75,0A76,0A81,0A82,0A83,0A85,0A86,0A87,0A88,0A89,0A8A,0A8B,0A8C,0A8D,0A8F,0A90,0A91,0A93,0A94,0A95,0A96,0A97,0A9^,0AA_,0AA8,0AAA,0AAB,0AAC,0AAD,0AAE,0AAF,0AB0,0AB2,0AB3,0AB5,0AB6,0AB7,0AB8,0AB9,0ABC,0ABD,0ABE,0ABF,0AC0,0AC1,0AC2,0AC3,0AC4,0AC5,0AC7,0AC8,0AC9,0ACB,0ACC,0ACD,0AD0,0AE0,0AE1,0AE2,0AE3,0AE6,0AE7,0AE^,0AF0,0AF1,0AF9,0AFA,0AFB,0AFC,0AFD,0AFE,0AFF,0B01,0B02,0B03,0B05,0B06,0B07,0B08,0B09,0B0A,0B0B,0B0C,0B0F,0B10,0B13,0B14,0B15,0B16,0B17,0B1^,0B2_,0B28,0B2A,0B2B,0B2C,0B2D,0B2E,0B2F,0B30,0B32,0B33,0B35,0B36,0B37,0B38,0B39,0B3C,0B3D,0B3E,0B3F,0B40,0B41,0B42,0B43,0B44,0B47,0B48,0B4B,0B4C,0B4D,0B55,0B56,0B57,0B5C,0B5D,0B5F,0B60,0B61,0B62,0B63,0B66,0B67,0B6^,0B7_,0B82,0B83,0B85,0B86,0B87,0B88,0B89,0B8A,0B8E,0B8F,0B90,0B92,0B93,0B94,0B95,0B99,0B9A,0B9C,0B9E,0B9F,0BA3,0BA4,0BA8,0BA9,0BAA,0BAE,0BAF,0BB_,0BB8,0BB9,0BBE,0BBF,0BC0,0BC1,0BC2,0BC6,0BC7,0BC8,0BCA,0BCB,0BCC,0BCD,0BD0,0BD7,0BE6,0BE7,0BE^,0BF_,0BF8,0BF9,0BFA,0C0_,0C08,0C09,0C0A,0C0B,0C0C,0C0E,0C0F,0C10,0C12,0C13,0C14,0C15,0C16,0C17,0C1^,0C2_,0C28,0C2A,0C2B,0C2C,0C2D,0C2E,0C2F,0C3_,0C38,0C39,0C3C,0C3D,0C3E,0C3F,0C40,0C41,0C42,0C43,0C44,0C46,0C47,0C48,0C4A,0C4B,0C4C,0C4D,0C55,0C56,0C58,0C59,0C5A,0C5D,0C60,0C61,0C62,0C63,0C66,0C67,0C6^,0C77,0C7^,0C8_,0C88,0C89,0C8A,0C8B,0C8C,0C8E,0C8F,0C90,0C92,0C93,0C94,0C95,0C96,0C97,0C9^,0CA_,0CA8,0CAA,0CAB,0CAC,0CAD,0CAE,0CAF,0CB0,0CB1,0CB2,0CB3,0CB5,0CB6,0CB7,0CB8,0CB9,0CBC,0CBD,0CBE,0CBF,0CC0,0CC1,0CC2,0CC3,0CC4,0CC6,0CC7,0CC8,0CCA,0CCB,0CCC,0CCD,0CD5,0CD6,0CDD,0CDE,0CE0,0CE1,0CE2,0CE3,0CE6,0CE7,0CE^,0CF1,0CF2,0D0_,0D08,0D09,0D0A,0D0B,0D0C,0D0E,0D0F,0D10,0D12,0D13,0D14,0D15,0D16,0D17,0D1^,0D2*,0D3*,0D40,0D41,0D42,0D43,0D44,0D46,0D47,0D48,0D4A,0D4B,0D4C,0D4D,0D4E,0D4F,0D54,0D55,0D56,0D57,0D5^,0D60,0D61,0D62,0D63,0D66,0D67,0D6^,0D7*,0D81,0D82,0D83,0D85,0D86,0D87,0D8^,0D90,0D91,0D92,0D93,0D94,0D95,0D96,0D9A,0D9B,0D9C,0D9D,0D9E,0D9F,0DA*,0DB0,0DB1,0DB3,0DB4,0DB5,0DB6,0DB7,0DB8,0DB9,0DBA,0DBB,0DBD,0DC0,0DC1,0DC2,0DC3,0DC4,0DC5,0DC6,0DCA,0DCF,0DD0,0DD1,0DD2,0DD3,0DD4,0DD6,0DD^,0DE6,0DE7,0DE^,0DF2,0DF3,0DF4,0E01,0E02,0E03,0E04,0E05,0E06,0E07,0E0^,0E1*,0E2*,0E3_,0E38,0E39,0E3A,0E3F,0E4*,0E5_,0E58,0E59,0E5A,0E5B,0E81,0E82,0E84,0E86,0E87,0E88,0E89,0E8A,0E8C,0E8D,0E8E,0E8F,0E9*,0EA0,0EA1,0EA2,0EA3,0EA5,0EA7,0EA^,0EB_,0EB8,0EB9,0EBA,0EBB,0EBC,0EBD,0EC0,0EC1,0EC2,0EC3,0EC4,0EC6,0EC8,0EC9,0ECA,0ECB,0ECC,0ECD,0ED_,0ED8,0ED9,0EDC,0EDD,0EDE,0EDF,0F0*,0F1*,0F2*,0F3*,0F4_,0F49,0F4A,0F4B,0F4C,0F4D,0F4E,0F4F,0F5*,0F6_,0F68,0F69,0F6A,0F6B,0F6C,0F71,0F72,0F73,0F74,0F75,0F76,0F77,0F7^,0F8*,0F9_,0F99,0F9A,0F9B,0F9C,0F9D,0F9E,0F9F,0FA*,0FB_,0FB8,0FB9,0FBA,0FBB,0FBC,0FBE,0FBF,0FC_,0FC8,0FC9,0FCA,0FCB,0FCC,0FCE,0FCF,0FD_,0FD8,0FD9,0FDA,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C0,10C1,10C2,10C3,10C4,10C5,10C7,10CD,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124_,1248,124A,124B,124C,124D,1250,1251,1252,1253,1254,1255,1256,1258,125A,125B,125C,125D,126*,127*,128_,1288,128A,128B,128C,128D,129*,12A*,12B0,12B2,12B3,12B4,12B5,12B8,12B9,12BA,12BB,12BC,12BD,12BE,12C0,12C2,12C3,12C4,12C5,12C^,12D0,12D1,12D2,12D3,12D4,12D5,12D6,12D^,12E*,12F*,130*,1310,1312,1313,1314,1315,131^,132*,133*,134*,135_,1358,1359,135A,135D,135E,135F,136*,137_,1378,1379,137A,137B,137C,138*,139_,1398,1399,13A*,13B*,13C*,13D*,13E*,13F0,13F1,13F2,13F3,13F4,13F5,13F8,13F9,13FA,13FB,13FC,13FD,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169_,1698,1699,169A,169B,169C,16A*,16B*,16C*,16D*,16E*,16F_,16F8,170*,1710,1711,1712,1713,1714,1715,171F,172*,1730,1731,1732,1733,1734,1735,1736,174*,1750,1751,1752,1753,176_,1768,1769,176A,176B,176C,176E,176F,1770,1772,1773,178*,179*,17A*,17B*,17C*,17D_,17D8,17D9,17DA,17DB,17DC,17DD,17E_,17E8,17E9,17F_,17F8,17F9,180_,1808,1809,180A,180B,180C,180D,180F,181_,1818,1819,182*,183*,184*,185*,186*,187_,1878,188*,189*,18A_,18A8,18A9,18AA,18B*,18C*,18D*,18E*,18F0,18F1,18F2,18F3,18F4,18F5,190*,191_,1918,1919,191A,191B,191C,191D,191E,192_,1928,1929,192A,192B,193_,1938,1939,193A,193B,1940,1944,1945,1946,1947,194^,195*,196_,1968,1969,196A,196B,196C,196D,1970,1971,1972,1973,1974,198*,199*,19A_,19A8,19A9,19AA,19AB,19B*,19C_,19C8,19C9,19D_,19D8,19D9,19DA,19DE,19DF,19E*,19F*,1A0*,1A1_,1A18,1A19,1A1A,1A1B,1A1E,1A1F,1A2*,1A3*,1A4*,1A5_,1A58,1A59,1A5A,1A5B,1A5C,1A5D,1A5E,1A6*,1A7_,1A78,1A79,1A7A,1A7B,1A7C,1A7F,1A8_,1A88,1A89,1A9_,1A98,1A99,1AA_,1AA8,1AA9,1AAA,1AAB,1AAC,1AAD,1AB*,1AC_,1AC8,1AC9,1ACA,1ACB,1ACC,1ACD,1ACE,1B0*,1B1*,1B2*,1B3*,1B4_,1B48,1B49,1B4A,1B4B,1B4C,1B5*,1B6*,1B7_,1B78,1B79,1B7A,1B7B,1B7C,1B7D,1B7E,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF0,1BF1,1BF2,1BF3,1BFC,1BFD,1BFE,1BFF,1C0*,1C1*,1C2*,1C3_,1C3B,1C3C,1C3D,1C3E,1C3F,1C4_,1C48,1C49,1C4D,1C4E,1C4F,1C5*,1C6*,1C7*,1C8_,1C88,1C9*,1CA*,1CB_,1CB8,1CB9,1CBA,1CBD,1CBE,1CBF,1CC_,1CD*,1CE*,1CF_,1CF8,1CF9,1CFA,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F10,1F11,1F12,1F13,1F14,1F15,1F18,1F19,1F1A,1F1B,1F1C,1F1D,1F2*,1F3*,1F40,1F41,1F42,1F43,1F44,1F45,1F48,1F49,1F4A,1F4B,1F4C,1F4D,1F5_,1F59,1F5B,1F5D,1F5F,1F6*,1F7_,1F78,1F79,1F7A,1F7B,1F7C,1F7D,1F8*,1F9*,1FA*,1FB0,1FB1,1FB2,1FB3,1FB4,1FB6,1FB7,1FB^,1FC0,1FC1,1FC2,1FC3,1FC4,1FC6,1FC7,1FC^,1FD0,1FD1,1FD2,1FD3,1FD6,1FD7,1FD8,1FD9,1FDA,1FDB,1FDD,1FDE,1FDF,1FE*,1FF2,1FF3,1FF4,1FF6,1FF7,1FF8,1FF9,1FFA,1FFB,1FFC,1FFD,1FFE,200_,2008,2009,200A,201*,202_,2028,2029,202F,203*,204*,205*,2070,2071,2074,2075,2076,2077,207^,208_,2088,2089,208A,208B,208C,208D,208E,209_,2098,2099,209A,209B,209C,20A*,20B*,20C0,20D*,20E*,20F0,210*,211*,212*,213*,214*,215*,216*,217*,218_,2188,2189,218A,218B,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,2420,2421,2422,2423,2424,2425,2426,244_,2448,2449,244A,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B70,2B71,2B72,2B73,2B76,2B77,2B7^,2B8*,2B90,2B91,2B92,2B93,2B94,2B95,2B97,2B9^,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF0,2CF1,2CF2,2CF3,2CF9,2CFA,2CFB,2CFC,2CFD,2CFE,2CFF,2D0*,2D1*,2D20,2D21,2D22,2D23,2D24,2D25,2D27,2D2D,2D3*,2D4*,2D5*,2D6_,2D6F,2D70,2D7F,2D8*,2D90,2D91,2D92,2D93,2D94,2D95,2D96,2DA0,2DA1,2DA2,2DA3,2DA4,2DA5,2DA6,2DA8,2DA9,2DAA,2DAB,2DAC,2DAD,2DAE,2DB0,2DB1,2DB2,2DB3,2DB4,2DB5,2DB6,2DB8,2DB9,2DBA,2DBB,2DBC,2DBD,2DBE,2DC0,2DC1,2DC2,2DC3,2DC4,2DC5,2DC6,2DC8,2DC9,2DCA,2DCB,2DCC,2DCD,2DCE,2DD0,2DD1,2DD2,2DD3,2DD4,2DD5,2DD6,2DD8,2DD9,2DDA,2DDB,2DDC,2DDD,2DDE,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5_,2E58,2E59,2E5A,2E5B,2E5C,2E5D,2E8*,2E9_,2E98,2E99,2E9B,2E9C,2E9D,2E9E,2E9F,2EA*,2EB*,2EC*,2ED*,2EE*,2EF0,2EF1,2EF2,2EF3,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD0,2FD1,2FD2,2FD3,2FD4,2FD5,2FF_,2FF8,2FF9,2FFA,2FFB,300*,301*,302*,303*,3041,3042,3043,3044,3045,3046,3047,304^,305*,306*,307*,308*,3090,3091,3092,3093,3094,3095,3096,3099,309A,309B,309C,309D,309E,309F,30A*,30B*,30C*,30D*,30E*,30F*,3105,3106,3107,310^,311*,312*,3131,3132,3133,3134,3135,3136,3137,313^,314*,315*,316*,317*,318_,3188,3189,318A,318B,318C,318D,318E,319*,31A*,31B*,31C*,31D*,31E0,31E1,31E2,31E3,31F*,320*,321_,3218,3219,321A,321B,321C,321D,321E,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000,""002*,003*,004*,005*,006*,007_,0078,0079,007A,007B,007C,007D,007E,00A_,00A8,00A9,00AA,00AB,00AC,00AE,00AF,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037_,037A,037B,037C,037D,037E,037F,0384,0385,0386,0387,0388,0389,038A,038C,038E,038F,039*,03A0,03A1,03A3,03A4,03A5,03A6,03A7,03A^,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,0531,0532,0533,0534,0535,0536,0537,053^,054*,0550,0551,0552,0553,0554,0555,0556,0559,055A,055B,055C,055D,055E,055F,056*,057*,058_,0588,0589,058A,058D,058E,058F,0591,0592,0593,0594,0595,0596,0597,059^,05A*,05B*,05C_,05D*,05E_,05E8,05E9,05EA,05EF,05F0,05F1,05F2,05F3,05F4,0606,0607,060^,061_,0618,0619,061A,061B,061D,061E,061F,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D_,06D8,06D9,06DA,06DB,06DC,06DE,06DF,06E*,06F*,070_,0708,0709,070A,070B,070C,070D,071*,072*,073*,074_,0748,0749,074A,074D,074E,074F,075*,076*,077*,078*,079*,07A*,07B0,07B1,07C*,07D*,07E*,07F_,07F8,07F9,07FA,07FD,07FE,07FF,080*,081*,082_,0828,0829,082A,082B,082C,082D,083_,0838,0839,083A,083B,083C,083D,083E,084*,085_,0858,0859,085A,085B,085E,086_,0868,0869,086A,087*,088_,0888,0889,088A,088B,088C,088D,088E,089^,08A*,08B*,08C*,08D*,08E0,08E1,08E3,08E4,08E5,08E6,08E7,08E^,08F*,090*,091*,092*,093*,094*,095*,096*,097*,0980,0981,0982,0983,0985,0986,0987,0988,0989,098A,098B,098C,098F,0990,0993,0994,0995,0996,0997,099^,09A_,09A8,09AA,09AB,09AC,09AD,09AE,09AF,09B0,09B2,09B6,09B7,09B8,09B9,09BC,09BD,09BE,09BF,09C0,09C1,09C2,09C3,09C4,09C7,09C8,09CB,09CC,09CD,09CE,09D7,09DC,09DD,09DF,09E0,09E1,09E2,09E3,09E6,09E7,09E^,09F_,09F8,09F9,09FA,09FB,09FC,09FD,09FE,0A01,0A02,0A03,0A05,0A06,0A07,0A08,0A09,0A0A,0A0F,0A10,0A13,0A14,0A15,0A16,0A17,0A1^,0A2_,0A28,0A2A,0A2B,0A2C,0A2D,0A2E,0A2F,0A30,0A32,0A33,0A35,0A36,0A38,0A39,0A3C,0A3E,0A3F,0A40,0A41,0A42,0A47,0A48,0A4B,0A4C,0A4D,0A51,0A59,0A5A,0A5B,0A5C,0A5E,0A66,0A67,0A6^,0A70,0A71,0A72,0A73,0A74,0A75,0A76,0A81,0A82,0A83,0A85,0A86,0A87,0A88,0A89,0A8A,0A8B,0A8C,0A8D,0A8F,0A90,0A91,0A93,0A94,0A95,0A96,0A97,0A9^,0AA_,0AA8,0AAA,0AAB,0AAC,0AAD,0AAE,0AAF,0AB0,0AB2,0AB3,0AB5,0AB6,0AB7,0AB8,0AB9,0ABC,0ABD,0ABE,0ABF,0AC0,0AC1,0AC2,0AC3,0AC4,0AC5,0AC7,0AC8,0AC9,0ACB,0ACC,0ACD,0AD0,0AE0,0AE1,0AE2,0AE3,0AE6,0AE7,0AE^,0AF0,0AF1,0AF9,0AFA,0AFB,0AFC,0AFD,0AFE,0AFF,0B01,0B02,0B03,0B05,0B06,0B07,0B08,0B09,0B0A,0B0B,0B0C,0B0F,0B10,0B13,0B14,0B15,0B16,0B17,0B1^,0B2_,0B28,0B2A,0B2B,0B2C,0B2D,0B2E,0B2F,0B30,0B32,0B33,0B35,0B36,0B37,0B38,0B39,0B3C,0B3D,0B3E,0B3F,0B40,0B41,0B42,0B43,0B44,0B47,0B48,0B4B,0B4C,0B4D,0B55,0B56,0B57,0B5C,0B5D,0B5F,0B60,0B61,0B62,0B63,0B66,0B67,0B6^,0B7_,0B82,0B83,0B85,0B86,0B87,0B88,0B89,0B8A,0B8E,0B8F,0B90,0B92,0B93,0B94,0B95,0B99,0B9A,0B9C,0B9E,0B9F,0BA3,0BA4,0BA8,0BA9,0BAA,0BAE,0BAF,0BB_,0BB8,0BB9,0BBE,0BBF,0BC0,0BC1,0BC2,0BC6,0BC7,0BC8,0BCA,0BCB,0BCC,0BCD,0BD0,0BD7,0BE6,0BE7,0BE^,0BF_,0BF8,0BF9,0BFA,0C0_,0C08,0C09,0C0A,0C0B,0C0C,0C0E,0C0F,0C10,0C12,0C13,0C14,0C15,0C16,0C17,0C1^,0C2_,0C28,0C2A,0C2B,0C2C,0C2D,0C2E,0C2F,0C3_,0C38,0C39,0C3C,0C3D,0C3E,0C3F,0C40,0C41,0C42,0C43,0C44,0C46,0C47,0C48,0C4A,0C4B,0C4C,0C4D,0C55,0C56,0C58,0C59,0C5A,0C5D,0C60,0C61,0C62,0C63,0C66,0C67,0C6^,0C77,0C7^,0C8_,0C88,0C89,0C8A,0C8B,0C8C,0C8E,0C8F,0C90,0C92,0C93,0C94,0C95,0C96,0C97,0C9^,0CA_,0CA8,0CAA,0CAB,0CAC,0CAD,0CAE,0CAF,0CB0,0CB1,0CB2,0CB3,0CB5,0CB6,0CB7,0CB8,0CB9,0CBC,0CBD,0CBE,0CBF,0CC0,0CC1,0CC2,0CC3,0CC4,0CC6,0CC7,0CC8,0CCA,0CCB,0CCC,0CCD,0CD5,0CD6,0CDD,0CDE,0CE0,0CE1,0CE2,0CE3,0CE6,0CE7,0CE^,0CF1,0CF2,0D0_,0D08,0D09,0D0A,0D0B,0D0C,0D0E,0D0F,0D10,0D12,0D13,0D14,0D15,0D16,0D17,0D1^,0D2*,0D3*,0D40,0D41,0D42,0D43,0D44,0D46,0D47,0D48,0D4A,0D4B,0D4C,0D4D,0D4E,0D4F,0D54,0D55,0D56,0D57,0D5^,0D60,0D61,0D62,0D63,0D66,0D67,0D6^,0D7*,0D81,0D82,0D83,0D85,0D86,0D87,0D8^,0D90,0D91,0D92,0D93,0D94,0D95,0D96,0D9A,0D9B,0D9C,0D9D,0D9E,0D9F,0DA*,0DB0,0DB1,0DB3,0DB4,0DB5,0DB6,0DB7,0DB8,0DB9,0DBA,0DBB,0DBD,0DC0,0DC1,0DC2,0DC3,0DC4,0DC5,0DC6,0DCA,0DCF,0DD0,0DD1,0DD2,0DD3,0DD4,0DD6,0DD^,0DE6,0DE7,0DE^,0DF2,0DF3,0DF4,0E01,0E02,0E03,0E04,0E05,0E06,0E07,0E0^,0E1*,0E2*,0E3_,0E38,0E39,0E3A,0E3F,0E4*,0E5_,0E58,0E59,0E5A,0E5B,0E81,0E82,0E84,0E86,0E87,0E88,0E89,0E8A,0E8C,0E8D,0E8E,0E8F,0E9*,0EA0,0EA1,0EA2,0EA3,0EA5,0EA7,0EA^,0EB_,0EB8,0EB9,0EBA,0EBB,0EBC,0EBD,0EC0,0EC1,0EC2,0EC3,0EC4,0EC6,0EC8,0EC9,0ECA,0ECB,0ECC,0ECD,0ED_,0ED8,0ED9,0EDC,0EDD,0EDE,0EDF,0F0*,0F1*,0F2*,0F3*,0F4_,0F49,0F4A,0F4B,0F4C,0F4D,0F4E,0F4F,0F5*,0F6_,0F68,0F69,0F6A,0F6B,0F6C,0F71,0F72,0F73,0F74,0F75,0F76,0F77,0F7^,0F8*,0F9_,0F99,0F9A,0F9B,0F9C,0F9D,0F9E,0F9F,0FA*,0FB_,0FB8,0FB9,0FBA,0FBB,0FBC,0FBE,0FBF,0FC_,0FC8,0FC9,0FCA,0FCB,0FCC,0FCE,0FCF,0FD_,0FD8,0FD9,0FDA,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C0,10C1,10C2,10C3,10C4,10C5,10C7,10CD,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124_,1248,124A,124B,124C,124D,1250,1251,1252,1253,1254,1255,1256,1258,125A,125B,125C,125D,126*,127*,128_,1288,128A,128B,128C,128D,129*,12A*,12B0,12B2,12B3,12B4,12B5,12B8,12B9,12BA,12BB,12BC,12BD,12BE,12C0,12C2,12C3,12C4,12C5,12C^,12D0,12D1,12D2,12D3,12D4,12D5,12D6,12D^,12E*,12F*,130*,1310,1312,1313,1314,1315,131^,132*,133*,134*,135_,1358,1359,135A,135D,135E,135F,136*,137_,1378,1379,137A,137B,137C,138*,139_,1398,1399,13A*,13B*,13C*,13D*,13E*,13F0,13F1,13F2,13F3,13F4,13F5,13F8,13F9,13FA,13FB,13FC,13FD,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169_,1698,1699,169A,169B,169C,16A*,16B*,16C*,16D*,16E*,16F_,16F8,170*,1710,1711,1712,1713,1714,1715,171F,172*,1730,1731,1732,1733,1734,1735,1736,174*,1750,1751,1752,1753,176_,1768,1769,176A,176B,176C,176E,176F,1770,1772,1773,178*,179*,17A*,17B*,17C*,17D_,17D8,17D9,17DA,17DB,17DC,17DD,17E_,17E8,17E9,17F_,17F8,17F9,180_,1808,1809,180A,180B,180C,180D,180F,181_,1818,1819,182*,183*,184*,185*,186*,187_,1878,188*,189*,18A_,18A8,18A9,18AA,18B*,18C*,18D*,18E*,18F0,18F1,18F2,18F3,18F4,18F5,190*,191_,1918,1919,191A,191B,191C,191D,191E,192_,1928,1929,192A,192B,193_,1938,1939,193A,193B,1940,1944,1945,1946,1947,194^,195*,196_,1968,1969,196A,196B,196C,196D,1970,1971,1972,1973,1974,198*,199*,19A_,19A8,19A9,19AA,19AB,19B*,19C_,19C8,19C9,19D_,19D8,19D9,19DA,19DE,19DF,19E*,19F*,1A0*,1A1_,1A18,1A19,1A1A,1A1B,1A1E,1A1F,1A2*,1A3*,1A4*,1A5_,1A58,1A59,1A5A,1A5B,1A5C,1A5D,1A5E,1A6*,1A7_,1A78,1A79,1A7A,1A7B,1A7C,1A7F,1A8_,1A88,1A89,1A9_,1A98,1A99,1AA_,1AA8,1AA9,1AAA,1AAB,1AAC,1AAD,1AB*,1AC_,1AC8,1AC9,1ACA,1ACB,1ACC,1ACD,1ACE,1B0*,1B1*,1B2*,1B3*,1B4_,1B48,1B49,1B4A,1B4B,1B4C,1B5*,1B6*,1B7_,1B78,1B79,1B7A,1B7B,1B7C,1B7D,1B7E,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF0,1BF1,1BF2,1BF3,1BFC,1BFD,1BFE,1BFF,1C0*,1C1*,1C2*,1C3_,1C3B,1C3C,1C3D,1C3E,1C3F,1C4_,1C48,1C49,1C4D,1C4E,1C4F,1C5*,1C6*,1C7*,1C8_,1C88,1C9*,1CA*,1CB_,1CB8,1CB9,1CBA,1CBD,1CBE,1CBF,1CC_,1CD*,1CE*,1CF_,1CF8,1CF9,1CFA,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F10,1F11,1F12,1F13,1F14,1F15,1F18,1F19,1F1A,1F1B,1F1C,1F1D,1F2*,1F3*,1F40,1F41,1F42,1F43,1F44,1F45,1F48,1F49,1F4A,1F4B,1F4C,1F4D,1F5_,1F59,1F5B,1F5D,1F5F,1F6*,1F7_,1F78,1F79,1F7A,1F7B,1F7C,1F7D,1F8*,1F9*,1FA*,1FB0,1FB1,1FB2,1FB3,1FB4,1FB6,1FB7,1FB^,1FC0,1FC1,1FC2,1FC3,1FC4,1FC6,1FC7,1FC^,1FD0,1FD1,1FD2,1FD3,1FD6,1FD7,1FD8,1FD9,1FDA,1FDB,1FDD,1FDE,1FDF,1FE*,1FF2,1FF3,1FF4,1FF6,1FF7,1FF8,1FF9,1FFA,1FFB,1FFC,1FFD,1FFE,200_,2008,2009,200A,201*,202_,2028,2029,202F,203*,204*,205*,2070,2071,2074,2075,2076,2077,207^,208_,2088,2089,208A,208B,208C,208D,208E,209_,2098,2099,209A,209B,209C,20A*,20B*,20C0,20D*,20E*,20F0,210*,211*,212*,213*,214*,215*,216*,217*,218_,2188,2189,218A,218B,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,2420,2421,2422,2423,2424,2425,2426,244_,2448,2449,244A,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B70,2B71,2B72,2B73,2B76,2B77,2B7^,2B8*,2B90,2B91,2B92,2B93,2B94,2B95,2B97,2B9^,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF0,2CF1,2CF2,2CF3,2CF9,2CFA,2CFB,2CFC,2CFD,2CFE,2CFF,2D0*,2D1*,2D20,2D21,2D22,2D23,2D24,2D25,2D27,2D2D,2D3*,2D4*,2D5*,2D6_,2D6F,2D70,2D7F,2D8*,2D90,2D91,2D92,2D93,2D94,2D95,2D96,2DA0,2DA1,2DA2,2DA3,2DA4,2DA5,2DA6,2DA8,2DA9,2DAA,2DAB,2DAC,2DAD,2DAE,2DB0,2DB1,2DB2,2DB3,2DB4,2DB5,2DB6,2DB8,2DB9,2DBA,2DBB,2DBC,2DBD,2DBE,2DC0,2DC1,2DC2,2DC3,2DC4,2DC5,2DC6,2DC8,2DC9,2DCA,2DCB,2DCC,2DCD,2DCE,2DD0,2DD1,2DD2,2DD3,2DD4,2DD5,2DD6,2DD8,2DD9,2DDA,2DDB,2DDC,2DDD,2DDE,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5_,2E58,2E59,2E5A,2E5B,2E5C,2E5D,2E8*,2E9_,2E98,2E99,2E9B,2E9C,2E9D,2E9E,2E9F,2EA*,2EB*,2EC*,2ED*,2EE*,2EF0,2EF1,2EF2,2EF3,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD0,2FD1,2FD2,2FD3,2FD4,2FD5,2FF_,2FF8,2FF9,2FFA,2FFB,300*,301*,302*,303*,3041,3042,3043,3044,3045,3046,3047,304^,305*,306*,307*,308*,3090,3091,3092,3093,3094,3095,3096,3099,309A,309B,309C,309D,309E,309F,30A*,30B*,30C*,30D*,30E*,30F*,3105,3106,3107,310^,311*,312*,3131,3132,3133,3134,3135,3136,3137,313^,314*,315*,316*,317*,318_,3188,3189,318A,318B,318C,318D,318E,319*,31A*,31B*,31C*,31D*,31E0,31E1,31E2,31E3,31F*,320*,321_,3218,3219,321A,321B,321C,321D,321E,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," + +// Cs - reserved for surrogates, \uD800-\uDFFF, which are illegal by themselves +//>> Concat(MatchAll( Concat(ForAll(Sequence(Hex2Dec("7ff"),Hex2Dec("D000")),If( IsMatch(UniChar(Value), "\p{Cs}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), +// "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") +// As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +//"" + +//>> Concat(MatchAll( Concat(ForAll(Sequence(Hex2Dec("7ff"),Hex2Dec("E000")),If( IsMatch(UniChar(Value), "\p{Cs}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), +// "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") +// As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +//"" + +//>> UniChar(Hex2Dec("D800")) +// + +//>> UniChar(Hex2Dec("D8FF")) +// + +//>> Concat(MatchAll( Concat(ForAll(Sequence(Hex2Dec("7ff"),Hex2Dec("D000")),If( IsMatch(UniChar(Value), "\P{Cs}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), +// "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") +// As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +//"D00*,D01*,D02*,D03*,D04*,D05*,D06*,D07*,D08*,D09*,D0A*,D0B*,D0C*,D0D*,D0E*,D0F*,D10*,D11*,D12*,D13*,D14*,D15*,D16*,D17*,D18*,D19*,D1A*,D1B*,D1C*,D1D*,D1E*,D1F*,D20*,D21*,D22*,D23*,D24*,D25*,D26*,D27*,D28*,D29*,D2A*,D2B*,D2C*,D2D*,D2E*,D2F*,D30*,D31*,D32*,D33*,D34*,D35*,D36*,D37*,D38*,D39*,D3A*,D3B*,D3C*,D3D*,D3E*,D3F*,D40*,D41*,D42*,D43*,D44*,D45*,D46*,D47*,D48*,D49*,D4A*,D4B*,D4C*,D4D*,D4E*,D4F*,D50*,D51*,D52*,D53*,D54*,D55*,D56*,D57*,D58*,D59*,D5A*,D5B*,D5C*,D5D*,D5E*,D5F*,D60*,D61*,D62*,D63*,D64*,D65*,D66*,D67*,D68*,D69*,D6A*,D6B*,D6C*,D6D*,D6E*,D6F*,D70*,D71*,D72*,D73*,D74*,D75*,D76*,D77*,D78*,D79*,D7A*,D7B*,D7C*,D7D*,D7E*,D7F_,D7F8,D7F9,D7FA,D7FB,D7FC,D7FD,D7FE," + +//>> Concat(MatchAll( Concat(ForAll(Sequence(Hex2Dec("7ff"),Hex2Dec("E000")),If( IsMatch(UniChar(Value), "\P{Cs}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), +// "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") +// As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +//"E00*,E01*,E02*,E03*,E04*,E05*,E06*,E07*,E08*,E09*,E0A*,E0B*,E0C*,E0D*,E0E*,E0F*,E10*,E11*,E12*,E13*,E14*,E15*,E16*,E17*,E18*,E19*,E1A*,E1B*,E1C*,E1D*,E1E*,E1F*,E20*,E21*,E22*,E23*,E24*,E25*,E26*,E27*,E28*,E29*,E2A*,E2B*,E2C*,E2D*,E2E*,E2F*,E30*,E31*,E32*,E33*,E34*,E35*,E36*,E37*,E38*,E39*,E3A*,E3B*,E3C*,E3D*,E3E*,E3F*,E40*,E41*,E42*,E43*,E44*,E45*,E46*,E47*,E48*,E49*,E4A*,E4B*,E4C*,E4D*,E4E*,E4F*,E50*,E51*,E52*,E53*,E54*,E55*,E56*,E57*,E58*,E59*,E5A*,E5B*,E5C*,E5D*,E5E*,E5F*,E60*,E61*,E62*,E63*,E64*,E65*,E66*,E67*,E68*,E69*,E6A*,E6B*,E6C*,E6D*,E6E*,E6F*,E70*,E71*,E72*,E73*,E74*,E75*,E76*,E77*,E78*,E79*,E7A*,E7B*,E7C*,E7D*,E7E*,E7F_,E7F8,E7F9,E7FA,E7FB,E7FC,E7FD,E7FE," + +// Co - reserved for private use, \uE000-\uF8FF, \uF0000-\uFFFFD, and \u100000-\u10FFFD +//>> Concat(MatchAll( Concat(ForAll(Sequence(Hex2Dec("1FFF"),Hex2Dec("E000")),If( IsMatch(UniChar(Value), "\p{Co}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), +// "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") +// As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +//"E00*,E01*,E02*,E03*,E04*,E05*,E06*,E07*,E08*,E09*,E0A*,E0B*,E0C*,E0D*,E0E*,E0F*,E10*,E11*,E12*,E13*,E14*,E15*,E16*,E17*,E18*,E19*,E1A*,E1B*,E1C*,E1D*,E1E*,E1F*,E20*,E21*,E22*,E23*,E24*,E25*,E26*,E27*,E28*,E29*,E2A*,E2B*,E2C*,E2D*,E2E*,E2F*,E30*,E31*,E32*,E33*,E34*,E35*,E36*,E37*,E38*,E39*,E3A*,E3B*,E3C*,E3D*,E3E*,E3F*,E40*,E41*,E42*,E43*,E44*,E45*,E46*,E47*,E48*,E49*,E4A*,E4B*,E4C*,E4D*,E4E*,E4F*,E50*,E51*,E52*,E53*,E54*,E55*,E56*,E57*,E58*,E59*,E5A*,E5B*,E5C*,E5D*,E5E*,E5F*,E60*,E61*,E62*,E63*,E64*,E65*,E66*,E67*,E68*,E69*,E6A*,E6B*,E6C*,E6D*,E6E*,E6F*,E70*,E71*,E72*,E73*,E74*,E75*,E76*,E77*,E78*,E79*,E7A*,E7B*,E7C*,E7D*,E7E*,E7F*,E80*,E81*,E82*,E83*,E84*,E85*,E86*,E87*,E88*,E89*,E8A*,E8B*,E8C*,E8D*,E8E*,E8F*,E90*,E91*,E92*,E93*,E94*,E95*,E96*,E97*,E98*,E99*,E9A*,E9B*,E9C*,E9D*,E9E*,E9F*,EA0*,EA1*,EA2*,EA3*,EA4*,EA5*,EA6*,EA7*,EA8*,EA9*,EAA*,EAB*,EAC*,EAD*,EAE*,EAF*,EB0*,EB1*,EB2*,EB3*,EB4*,EB5*,EB6*,EB7*,EB8*,EB9*,EBA*,EBB*,EBC*,EBD*,EBE*,EBF*,EC0*,EC1*,EC2*,EC3*,EC4*,EC5*,EC6*,EC7*,EC8*,EC9*,ECA*,ECB*,ECC*,ECD*,ECE*,ECF*,ED0*,ED1*,ED2*,ED3*,ED4*,ED5*,ED6*,ED7*,ED8*,ED9*,EDA*,EDB*,EDC*,EDD*,EDE*,EDF*,EE0*,EE1*,EE2*,EE3*,EE4*,EE5*,EE6*,EE7*,EE8*,EE9*,EEA*,EEB*,EEC*,EED*,EEE*,EEF*,EF0*,EF1*,EF2*,EF3*,EF4*,EF5*,EF6*,EF7*,EF8*,EF9*,EFA*,EFB*,EFC*,EFD*,EFE*,EFF*,F00*,F01*,F02*,F03*,F04*,F05*,F06*,F07*,F08*,F09*,F0A*,F0B*,F0C*,F0D*,F0E*,F0F*,F10*,F11*,F12*,F13*,F14*,F15*,F16*,F17*,F18*,F19*,F1A*,F1B*,F1C*,F1D*,F1E*,F1F*,F20*,F21*,F22*,F23*,F24*,F25*,F26*,F27*,F28*,F29*,F2A*,F2B*,F2C*,F2D*,F2E*,F2F*,F30*,F31*,F32*,F33*,F34*,F35*,F36*,F37*,F38*,F39*,F3A*,F3B*,F3C*,F3D*,F3E*,F3F*,F40*,F41*,F42*,F43*,F44*,F45*,F46*,F47*,F48*,F49*,F4A*,F4B*,F4C*,F4D*,F4E*,F4F*,F50*,F51*,F52*,F53*,F54*,F55*,F56*,F57*,F58*,F59*,F5A*,F5B*,F5C*,F5D*,F5E*,F5F*,F60*,F61*,F62*,F63*,F64*,F65*,F66*,F67*,F68*,F69*,F6A*,F6B*,F6C*,F6D*,F6E*,F6F*,F70*,F71*,F72*,F73*,F74*,F75*,F76*,F77*,F78*,F79*,F7A*,F7B*,F7C*,F7D*,F7E*,F7F*,F80*,F81*,F82*,F83*,F84*,F85*,F86*,F87*,F88*,F89*,F8A*,F8B*,F8C*,F8D*,F8E*,F8F*," + +//>> Concat(MatchAll( Concat(ForAll(Sequence(Hex2Dec(""),Hex2Dec("E000")),If( IsMatch(UniChar(Value), "\p{Co}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), +// "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") +// As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +//"E00*,E01*,E02*,E03*,E04*,E05*,E06*,E07*,E08*,E09*,E0A*,E0B*,E0C*,E0D*,E0E*,E0F*,E10*,E11*,E12*,E13*,E14*,E15*,E16*,E17*,E18*,E19*,E1A*,E1B*,E1C*,E1D*,E1E*,E1F*,E20*,E21*,E22*,E23*,E24*,E25*,E26*,E27*,E28*,E29*,E2A*,E2B*,E2C*,E2D*,E2E*,E2F*,E30*,E31*,E32*,E33*,E34*,E35*,E36*,E37*,E38*,E39*,E3A*,E3B*,E3C*,E3D*,E3E*,E3F*,E40*,E41*,E42*,E43*,E44*,E45*,E46*,E47*,E48*,E49*,E4A*,E4B*,E4C*,E4D*,E4E*,E4F*,E50*,E51*,E52*,E53*,E54*,E55*,E56*,E57*,E58*,E59*,E5A*,E5B*,E5C*,E5D*,E5E*,E5F*,E60*,E61*,E62*,E63*,E64*,E65*,E66*,E67*,E68*,E69*,E6A*,E6B*,E6C*,E6D*,E6E*,E6F*,E70*,E71*,E72*,E73*,E74*,E75*,E76*,E77*,E78*,E79*,E7A*,E7B*,E7C*,E7D*,E7E*,E7F*,E80*,E81*,E82*,E83*,E84*,E85*,E86*,E87*,E88*,E89*,E8A*,E8B*,E8C*,E8D*,E8E*,E8F*,E90*,E91*,E92*,E93*,E94*,E95*,E96*,E97*,E98*,E99*,E9A*,E9B*,E9C*,E9D*,E9E*,E9F*,EA0*,EA1*,EA2*,EA3*,EA4*,EA5*,EA6*,EA7*,EA8*,EA9*,EAA*,EAB*,EAC*,EAD*,EAE*,EAF*,EB0*,EB1*,EB2*,EB3*,EB4*,EB5*,EB6*,EB7*,EB8*,EB9*,EBA*,EBB*,EBC*,EBD*,EBE*,EBF*,EC0*,EC1*,EC2*,EC3*,EC4*,EC5*,EC6*,EC7*,EC8*,EC9*,ECA*,ECB*,ECC*,ECD*,ECE*,ECF*,ED0*,ED1*,ED2*,ED3*,ED4*,ED5*,ED6*,ED7*,ED8*,ED9*,EDA*,EDB*,EDC*,EDD*,EDE*,EDF*,EE0*,EE1*,EE2*,EE3*,EE4*,EE5*,EE6*,EE7*,EE8*,EE9*,EEA*,EEB*,EEC*,EED*,EEE*,EEF*,EF0*,EF1*,EF2*,EF3*,EF4*,EF5*,EF6*,EF7*,EF8*,EF9*,EFA*,EFB*,EFC*,EFD*,EFE*,EFF*,F00*,F01*,F02*,F03*,F04*,F05*,F06*,F07*,F08*,F09*,F0A*,F0B*,F0C*,F0D*,F0E*,F0F*,F10*,F11*,F12*,F13*,F14*,F15*,F16*,F17*,F18*,F19*,F1A*,F1B*,F1C*,F1D*,F1E*,F1F*,F20*,F21*,F22*,F23*,F24*,F25*,F26*,F27*,F28*,F29*,F2A*,F2B*,F2C*,F2D*,F2E*,F2F*,F30*,F31*,F32*,F33*,F34*,F35*,F36*,F37*,F38*,F39*,F3A*,F3B*,F3C*,F3D*,F3E*,F3F*,F40*,F41*,F42*,F43*,F44*,F45*,F46*,F47*,F48*,F49*,F4A*,F4B*,F4C*,F4D*,F4E*,F4F*,F50*,F51*,F52*,F53*,F54*,F55*,F56*,F57*,F58*,F59*,F5A*,F5B*,F5C*,F5D*,F5E*,F5F*,F60*,F61*,F62*,F63*,F64*,F65*,F66*,F67*,F68*,F69*,F6A*,F6B*,F6C*,F6D*,F6E*,F6F*,F70*,F71*,F72*,F73*,F74*,F75*,F76*,F77*,F78*,F79*,F7A*,F7B*,F7C*,F7D*,F7E*,F7F*,F80*,F81*,F82*,F83*,F84*,F85*,F86*,F87*,F88*,F89*,F8A*,F8B*,F8C*,F8D*,F8E*,F8F*," + +// above F0000, .NET 7 & 8 report false, PCRE2 and JavaScript report true +//>> Concat(MatchAll( Concat(ForAll(Sequence(Hex2Dec("2000"),Hex2Dec("EFF00")),If( IsMatch(UniChar(Value), "\p{Co}" ), Dec2Hex(Value,5) & ",", "" ) ),Value ), +// "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") +// As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +//"" + +// above 100000, .NET 7 & 8 report false, PCRE2 and JavaScript report true +//>> Concat(MatchAll( Concat(ForAll(Sequence(Hex2Dec("2000"),Hex2Dec("FFF00")),If( IsMatch(UniChar(Value), "\p{Co}" ), Dec2Hex(Value,5) & ",", "" ) ),Value ), +// "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") +// As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +//"" + +// Cn - not assigned +//>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Cn}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), +// "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") +// As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +//"0378,0379,0380,0381,0382,0383,038B,038D,03A2,0530,0557,0558,058B,058C,0590,05C^,05EB,05EC,05ED,05EE,05F5,05F6,05F7,05F^,070E,074B,074C,07B2,07B3,07B4,07B5,07B6,07B7,07B^,07FB,07FC,082E,082F,083F,085C,085D,085F,086B,086C,086D,086E,086F,088F,0892,0893,0894,0895,0896,0897,0984,098D,098E,0991,0992,09A9,09B1,09B3,09B4,09B5,09BA,09BB,09C5,09C6,09C9,09CA,09CF,09D0,09D1,09D2,09D3,09D4,09D5,09D6,09D8,09D9,09DA,09DB,09DE,09E4,09E5,09FF,0A00,0A04,0A0B,0A0C,0A0D,0A0E,0A11,0A12,0A29,0A31,0A34,0A37,0A3A,0A3B,0A3D,0A43,0A44,0A45,0A46,0A49,0A4A,0A4E,0A4F,0A50,0A52,0A53,0A54,0A55,0A56,0A57,0A58,0A5D,0A5F,0A60,0A61,0A62,0A63,0A64,0A65,0A77,0A7^,0A80,0A84,0A8E,0A92,0AA9,0AB1,0AB4,0ABA,0ABB,0AC6,0ACA,0ACE,0ACF,0AD1,0AD2,0AD3,0AD4,0AD5,0AD6,0AD7,0AD^,0AE4,0AE5,0AF2,0AF3,0AF4,0AF5,0AF6,0AF7,0AF8,0B00,0B04,0B0D,0B0E,0B11,0B12,0B29,0B31,0B34,0B3A,0B3B,0B45,0B46,0B49,0B4A,0B4E,0B4F,0B50,0B51,0B52,0B53,0B54,0B58,0B59,0B5A,0B5B,0B5E,0B64,0B65,0B7^,0B80,0B81,0B84,0B8B,0B8C,0B8D,0B91,0B96,0B97,0B98,0B9B,0B9D,0BA0,0BA1,0BA2,0BA5,0BA6,0BA7,0BAB,0BAC,0BAD,0BBA,0BBB,0BBC,0BBD,0BC3,0BC4,0BC5,0BC9,0BCE,0BCF,0BD1,0BD2,0BD3,0BD4,0BD5,0BD6,0BD^,0BE0,0BE1,0BE2,0BE3,0BE4,0BE5,0BFB,0BFC,0BFD,0BFE,0BFF,0C0D,0C11,0C29,0C3A,0C3B,0C45,0C49,0C4E,0C4F,0C50,0C51,0C52,0C53,0C54,0C57,0C5B,0C5C,0C5E,0C5F,0C64,0C65,0C70,0C71,0C72,0C73,0C74,0C75,0C76,0C8D,0C91,0CA9,0CB4,0CBA,0CBB,0CC5,0CC9,0CCE,0CCF,0CD0,0CD1,0CD2,0CD3,0CD4,0CD7,0CD8,0CD9,0CDA,0CDB,0CDC,0CDF,0CE4,0CE5,0CF0,0CF3,0CF4,0CF5,0CF6,0CF7,0CF^,0D0D,0D11,0D45,0D49,0D50,0D51,0D52,0D53,0D64,0D65,0D80,0D84,0D97,0D98,0D99,0DB2,0DBC,0DBE,0DBF,0DC7,0DC8,0DC9,0DCB,0DCC,0DCD,0DCE,0DD5,0DD7,0DE0,0DE1,0DE2,0DE3,0DE4,0DE5,0DF0,0DF1,0DF5,0DF6,0DF7,0DF^,0E00,0E3B,0E3C,0E3D,0E3E,0E5C,0E5D,0E5E,0E5F,0E6*,0E7*,0E80,0E83,0E85,0E8B,0EA4,0EA6,0EBE,0EBF,0EC5,0EC7,0ECE,0ECF,0EDA,0EDB,0EE*,0EF*,0F48,0F6D,0F6E,0F6F,0F70,0F98,0FBD,0FCD,0FDB,0FDC,0FDD,0FDE,0FDF,0FE*,0FF*,10C6,10C8,10C9,10CA,10CB,10CC,10CE,10CF,1249,124E,124F,1257,1259,125E,125F,1289,128E,128F,12B1,12B6,12B7,12BF,12C1,12C6,12C7,12D7,1311,1316,1317,135B,135C,137D,137E,137F,139A,139B,139C,139D,139E,139F,13F6,13F7,13FE,13FF,169D,169E,169F,16F9,16FA,16FB,16FC,16FD,16FE,16FF,1716,1717,1718,1719,171A,171B,171C,171D,171E,1737,173^,1754,1755,1756,1757,175^,176D,1771,1774,1775,1776,1777,177^,17DE,17DF,17EA,17EB,17EC,17ED,17EE,17EF,17FA,17FB,17FC,17FD,17FE,17FF,181A,181B,181C,181D,181E,181F,1879,187A,187B,187C,187D,187E,187F,18AB,18AC,18AD,18AE,18AF,18F6,18F7,18F^,191F,192C,192D,192E,192F,193C,193D,193E,193F,1941,1942,1943,196E,196F,1975,1976,1977,197^,19AC,19AD,19AE,19AF,19CA,19CB,19CC,19CD,19CE,19CF,19DB,19DC,19DD,1A1C,1A1D,1A5F,1A7D,1A7E,1A8A,1A8B,1A8C,1A8D,1A8E,1A8F,1A9A,1A9B,1A9C,1A9D,1A9E,1A9F,1AAE,1AAF,1ACF,1AD*,1AE*,1AF*,1B4D,1B4E,1B4F,1B7F,1BF4,1BF5,1BF6,1BF7,1BF8,1BF9,1BFA,1BFB,1C38,1C39,1C3A,1C4A,1C4B,1C4C,1C89,1C8A,1C8B,1C8C,1C8D,1C8E,1C8F,1CBB,1CBC,1CC^,1CFB,1CFC,1CFD,1CFE,1CFF,1F16,1F17,1F1E,1F1F,1F46,1F47,1F4E,1F4F,1F58,1F5A,1F5C,1F5E,1F7E,1F7F,1FB5,1FC5,1FD4,1FD5,1FDC,1FF0,1FF1,1FF5,1FFF,2065,2072,2073,208F,209D,209E,209F,20C1,20C2,20C3,20C4,20C5,20C6,20C7,20C^,20F1,20F2,20F3,20F4,20F5,20F6,20F7,20F^,218C,218D,218E,218F,2427,242^,243*,244B,244C,244D,244E,244F,245*,2B74,2B75,2B96,2CF4,2CF5,2CF6,2CF7,2CF8,2D26,2D28,2D29,2D2A,2D2B,2D2C,2D2E,2D2F,2D68,2D69,2D6A,2D6B,2D6C,2D6D,2D6E,2D71,2D72,2D73,2D74,2D75,2D76,2D77,2D78,2D79,2D7A,2D7B,2D7C,2D7D,2D7E,2D97,2D9^,2DA7,2DAF,2DB7,2DBF,2DC7,2DCF,2DD7,2DDF,2E5E,2E5F,2E6*,2E7*,2E9A,2EF4,2EF5,2EF6,2EF7,2EF^,2FD6,2FD7,2FD^,2FE*,2FFC,2FFD,2FFE,2FFF,3040,3097,3098,3100,3101,3102,3103,3104,3130,318F,31E4,31E5,31E6,31E7,31E^,321F," + +//>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Cn}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), +// "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") +// As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) +//"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037_,037A,037B,037C,037D,037E,037F,0384,0385,0386,0387,0388,0389,038A,038C,038E,038F,039*,03A0,03A1,03A3,03A4,03A5,03A6,03A7,03A^,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,0531,0532,0533,0534,0535,0536,0537,053^,054*,0550,0551,0552,0553,0554,0555,0556,0559,055A,055B,055C,055D,055E,055F,056*,057*,058_,0588,0589,058A,058D,058E,058F,0591,0592,0593,0594,0595,0596,0597,059^,05A*,05B*,05C_,05D*,05E_,05E8,05E9,05EA,05EF,05F0,05F1,05F2,05F3,05F4,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070_,0708,0709,070A,070B,070C,070D,070F,071*,072*,073*,074_,0748,0749,074A,074D,074E,074F,075*,076*,077*,078*,079*,07A*,07B0,07B1,07C*,07D*,07E*,07F_,07F8,07F9,07FA,07FD,07FE,07FF,080*,081*,082_,0828,0829,082A,082B,082C,082D,083_,0838,0839,083A,083B,083C,083D,083E,084*,085_,0858,0859,085A,085B,085E,086_,0868,0869,086A,087*,088_,0888,0889,088A,088B,088C,088D,088E,0890,0891,089^,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,0980,0981,0982,0983,0985,0986,0987,0988,0989,098A,098B,098C,098F,0990,0993,0994,0995,0996,0997,099^,09A_,09A8,09AA,09AB,09AC,09AD,09AE,09AF,09B0,09B2,09B6,09B7,09B8,09B9,09BC,09BD,09BE,09BF,09C0,09C1,09C2,09C3,09C4,09C7,09C8,09CB,09CC,09CD,09CE,09D7,09DC,09DD,09DF,09E0,09E1,09E2,09E3,09E6,09E7,09E^,09F_,09F8,09F9,09FA,09FB,09FC,09FD,09FE,0A01,0A02,0A03,0A05,0A06,0A07,0A08,0A09,0A0A,0A0F,0A10,0A13,0A14,0A15,0A16,0A17,0A1^,0A2_,0A28,0A2A,0A2B,0A2C,0A2D,0A2E,0A2F,0A30,0A32,0A33,0A35,0A36,0A38,0A39,0A3C,0A3E,0A3F,0A40,0A41,0A42,0A47,0A48,0A4B,0A4C,0A4D,0A51,0A59,0A5A,0A5B,0A5C,0A5E,0A66,0A67,0A6^,0A70,0A71,0A72,0A73,0A74,0A75,0A76,0A81,0A82,0A83,0A85,0A86,0A87,0A88,0A89,0A8A,0A8B,0A8C,0A8D,0A8F,0A90,0A91,0A93,0A94,0A95,0A96,0A97,0A9^,0AA_,0AA8,0AAA,0AAB,0AAC,0AAD,0AAE,0AAF,0AB0,0AB2,0AB3,0AB5,0AB6,0AB7,0AB8,0AB9,0ABC,0ABD,0ABE,0ABF,0AC0,0AC1,0AC2,0AC3,0AC4,0AC5,0AC7,0AC8,0AC9,0ACB,0ACC,0ACD,0AD0,0AE0,0AE1,0AE2,0AE3,0AE6,0AE7,0AE^,0AF0,0AF1,0AF9,0AFA,0AFB,0AFC,0AFD,0AFE,0AFF,0B01,0B02,0B03,0B05,0B06,0B07,0B08,0B09,0B0A,0B0B,0B0C,0B0F,0B10,0B13,0B14,0B15,0B16,0B17,0B1^,0B2_,0B28,0B2A,0B2B,0B2C,0B2D,0B2E,0B2F,0B30,0B32,0B33,0B35,0B36,0B37,0B38,0B39,0B3C,0B3D,0B3E,0B3F,0B40,0B41,0B42,0B43,0B44,0B47,0B48,0B4B,0B4C,0B4D,0B55,0B56,0B57,0B5C,0B5D,0B5F,0B60,0B61,0B62,0B63,0B66,0B67,0B6^,0B7_,0B82,0B83,0B85,0B86,0B87,0B88,0B89,0B8A,0B8E,0B8F,0B90,0B92,0B93,0B94,0B95,0B99,0B9A,0B9C,0B9E,0B9F,0BA3,0BA4,0BA8,0BA9,0BAA,0BAE,0BAF,0BB_,0BB8,0BB9,0BBE,0BBF,0BC0,0BC1,0BC2,0BC6,0BC7,0BC8,0BCA,0BCB,0BCC,0BCD,0BD0,0BD7,0BE6,0BE7,0BE^,0BF_,0BF8,0BF9,0BFA,0C0_,0C08,0C09,0C0A,0C0B,0C0C,0C0E,0C0F,0C10,0C12,0C13,0C14,0C15,0C16,0C17,0C1^,0C2_,0C28,0C2A,0C2B,0C2C,0C2D,0C2E,0C2F,0C3_,0C38,0C39,0C3C,0C3D,0C3E,0C3F,0C40,0C41,0C42,0C43,0C44,0C46,0C47,0C48,0C4A,0C4B,0C4C,0C4D,0C55,0C56,0C58,0C59,0C5A,0C5D,0C60,0C61,0C62,0C63,0C66,0C67,0C6^,0C77,0C7^,0C8_,0C88,0C89,0C8A,0C8B,0C8C,0C8E,0C8F,0C90,0C92,0C93,0C94,0C95,0C96,0C97,0C9^,0CA_,0CA8,0CAA,0CAB,0CAC,0CAD,0CAE,0CAF,0CB0,0CB1,0CB2,0CB3,0CB5,0CB6,0CB7,0CB8,0CB9,0CBC,0CBD,0CBE,0CBF,0CC0,0CC1,0CC2,0CC3,0CC4,0CC6,0CC7,0CC8,0CCA,0CCB,0CCC,0CCD,0CD5,0CD6,0CDD,0CDE,0CE0,0CE1,0CE2,0CE3,0CE6,0CE7,0CE^,0CF1,0CF2,0D0_,0D08,0D09,0D0A,0D0B,0D0C,0D0E,0D0F,0D10,0D12,0D13,0D14,0D15,0D16,0D17,0D1^,0D2*,0D3*,0D40,0D41,0D42,0D43,0D44,0D46,0D47,0D48,0D4A,0D4B,0D4C,0D4D,0D4E,0D4F,0D54,0D55,0D56,0D57,0D5^,0D60,0D61,0D62,0D63,0D66,0D67,0D6^,0D7*,0D81,0D82,0D83,0D85,0D86,0D87,0D8^,0D90,0D91,0D92,0D93,0D94,0D95,0D96,0D9A,0D9B,0D9C,0D9D,0D9E,0D9F,0DA*,0DB0,0DB1,0DB3,0DB4,0DB5,0DB6,0DB7,0DB8,0DB9,0DBA,0DBB,0DBD,0DC0,0DC1,0DC2,0DC3,0DC4,0DC5,0DC6,0DCA,0DCF,0DD0,0DD1,0DD2,0DD3,0DD4,0DD6,0DD^,0DE6,0DE7,0DE^,0DF2,0DF3,0DF4,0E01,0E02,0E03,0E04,0E05,0E06,0E07,0E0^,0E1*,0E2*,0E3_,0E38,0E39,0E3A,0E3F,0E4*,0E5_,0E58,0E59,0E5A,0E5B,0E81,0E82,0E84,0E86,0E87,0E88,0E89,0E8A,0E8C,0E8D,0E8E,0E8F,0E9*,0EA0,0EA1,0EA2,0EA3,0EA5,0EA7,0EA^,0EB_,0EB8,0EB9,0EBA,0EBB,0EBC,0EBD,0EC0,0EC1,0EC2,0EC3,0EC4,0EC6,0EC8,0EC9,0ECA,0ECB,0ECC,0ECD,0ED_,0ED8,0ED9,0EDC,0EDD,0EDE,0EDF,0F0*,0F1*,0F2*,0F3*,0F4_,0F49,0F4A,0F4B,0F4C,0F4D,0F4E,0F4F,0F5*,0F6_,0F68,0F69,0F6A,0F6B,0F6C,0F71,0F72,0F73,0F74,0F75,0F76,0F77,0F7^,0F8*,0F9_,0F99,0F9A,0F9B,0F9C,0F9D,0F9E,0F9F,0FA*,0FB_,0FB8,0FB9,0FBA,0FBB,0FBC,0FBE,0FBF,0FC_,0FC8,0FC9,0FCA,0FCB,0FCC,0FCE,0FCF,0FD_,0FD8,0FD9,0FDA,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C0,10C1,10C2,10C3,10C4,10C5,10C7,10CD,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124_,1248,124A,124B,124C,124D,1250,1251,1252,1253,1254,1255,1256,1258,125A,125B,125C,125D,126*,127*,128_,1288,128A,128B,128C,128D,129*,12A*,12B0,12B2,12B3,12B4,12B5,12B8,12B9,12BA,12BB,12BC,12BD,12BE,12C0,12C2,12C3,12C4,12C5,12C^,12D0,12D1,12D2,12D3,12D4,12D5,12D6,12D^,12E*,12F*,130*,1310,1312,1313,1314,1315,131^,132*,133*,134*,135_,1358,1359,135A,135D,135E,135F,136*,137_,1378,1379,137A,137B,137C,138*,139_,1398,1399,13A*,13B*,13C*,13D*,13E*,13F0,13F1,13F2,13F3,13F4,13F5,13F8,13F9,13FA,13FB,13FC,13FD,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169_,1698,1699,169A,169B,169C,16A*,16B*,16C*,16D*,16E*,16F_,16F8,170*,1710,1711,1712,1713,1714,1715,171F,172*,1730,1731,1732,1733,1734,1735,1736,174*,1750,1751,1752,1753,176_,1768,1769,176A,176B,176C,176E,176F,1770,1772,1773,178*,179*,17A*,17B*,17C*,17D_,17D8,17D9,17DA,17DB,17DC,17DD,17E_,17E8,17E9,17F_,17F8,17F9,180*,181_,1818,1819,182*,183*,184*,185*,186*,187_,1878,188*,189*,18A_,18A8,18A9,18AA,18B*,18C*,18D*,18E*,18F0,18F1,18F2,18F3,18F4,18F5,190*,191_,1918,1919,191A,191B,191C,191D,191E,192_,1928,1929,192A,192B,193_,1938,1939,193A,193B,1940,1944,1945,1946,1947,194^,195*,196_,1968,1969,196A,196B,196C,196D,1970,1971,1972,1973,1974,198*,199*,19A_,19A8,19A9,19AA,19AB,19B*,19C_,19C8,19C9,19D_,19D8,19D9,19DA,19DE,19DF,19E*,19F*,1A0*,1A1_,1A18,1A19,1A1A,1A1B,1A1E,1A1F,1A2*,1A3*,1A4*,1A5_,1A58,1A59,1A5A,1A5B,1A5C,1A5D,1A5E,1A6*,1A7_,1A78,1A79,1A7A,1A7B,1A7C,1A7F,1A8_,1A88,1A89,1A9_,1A98,1A99,1AA_,1AA8,1AA9,1AAA,1AAB,1AAC,1AAD,1AB*,1AC_,1AC8,1AC9,1ACA,1ACB,1ACC,1ACD,1ACE,1B0*,1B1*,1B2*,1B3*,1B4_,1B48,1B49,1B4A,1B4B,1B4C,1B5*,1B6*,1B7_,1B78,1B79,1B7A,1B7B,1B7C,1B7D,1B7E,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF0,1BF1,1BF2,1BF3,1BFC,1BFD,1BFE,1BFF,1C0*,1C1*,1C2*,1C3_,1C3B,1C3C,1C3D,1C3E,1C3F,1C4_,1C48,1C49,1C4D,1C4E,1C4F,1C5*,1C6*,1C7*,1C8_,1C88,1C9*,1CA*,1CB_,1CB8,1CB9,1CBA,1CBD,1CBE,1CBF,1CC_,1CD*,1CE*,1CF_,1CF8,1CF9,1CFA,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F10,1F11,1F12,1F13,1F14,1F15,1F18,1F19,1F1A,1F1B,1F1C,1F1D,1F2*,1F3*,1F40,1F41,1F42,1F43,1F44,1F45,1F48,1F49,1F4A,1F4B,1F4C,1F4D,1F5_,1F59,1F5B,1F5D,1F5F,1F6*,1F7_,1F78,1F79,1F7A,1F7B,1F7C,1F7D,1F8*,1F9*,1FA*,1FB0,1FB1,1FB2,1FB3,1FB4,1FB6,1FB7,1FB^,1FC0,1FC1,1FC2,1FC3,1FC4,1FC6,1FC7,1FC^,1FD0,1FD1,1FD2,1FD3,1FD6,1FD7,1FD8,1FD9,1FDA,1FDB,1FDD,1FDE,1FDF,1FE*,1FF2,1FF3,1FF4,1FF6,1FF7,1FF8,1FF9,1FFA,1FFB,1FFC,1FFD,1FFE,200*,201*,202*,203*,204*,205*,2060,2061,2062,2063,2064,2066,2067,206^,2070,2071,2074,2075,2076,2077,207^,208_,2088,2089,208A,208B,208C,208D,208E,209_,2098,2099,209A,209B,209C,20A*,20B*,20C0,20D*,20E*,20F0,210*,211*,212*,213*,214*,215*,216*,217*,218_,2188,2189,218A,218B,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,2420,2421,2422,2423,2424,2425,2426,244_,2448,2449,244A,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B70,2B71,2B72,2B73,2B76,2B77,2B7^,2B8*,2B90,2B91,2B92,2B93,2B94,2B95,2B97,2B9^,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF0,2CF1,2CF2,2CF3,2CF9,2CFA,2CFB,2CFC,2CFD,2CFE,2CFF,2D0*,2D1*,2D20,2D21,2D22,2D23,2D24,2D25,2D27,2D2D,2D3*,2D4*,2D5*,2D6_,2D6F,2D70,2D7F,2D8*,2D90,2D91,2D92,2D93,2D94,2D95,2D96,2DA0,2DA1,2DA2,2DA3,2DA4,2DA5,2DA6,2DA8,2DA9,2DAA,2DAB,2DAC,2DAD,2DAE,2DB0,2DB1,2DB2,2DB3,2DB4,2DB5,2DB6,2DB8,2DB9,2DBA,2DBB,2DBC,2DBD,2DBE,2DC0,2DC1,2DC2,2DC3,2DC4,2DC5,2DC6,2DC8,2DC9,2DCA,2DCB,2DCC,2DCD,2DCE,2DD0,2DD1,2DD2,2DD3,2DD4,2DD5,2DD6,2DD8,2DD9,2DDA,2DDB,2DDC,2DDD,2DDE,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5_,2E58,2E59,2E5A,2E5B,2E5C,2E5D,2E8*,2E9_,2E98,2E99,2E9B,2E9C,2E9D,2E9E,2E9F,2EA*,2EB*,2EC*,2ED*,2EE*,2EF0,2EF1,2EF2,2EF3,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD0,2FD1,2FD2,2FD3,2FD4,2FD5,2FF_,2FF8,2FF9,2FFA,2FFB,300*,301*,302*,303*,3041,3042,3043,3044,3045,3046,3047,304^,305*,306*,307*,308*,3090,3091,3092,3093,3094,3095,3096,3099,309A,309B,309C,309D,309E,309F,30A*,30B*,30C*,30D*,30E*,30F*,3105,3106,3107,310^,311*,312*,3131,3132,3133,3134,3135,3136,3137,313^,314*,315*,316*,317*,318_,3188,3189,318A,318B,318C,318D,318E,319*,31A*,31B*,31C*,31D*,31E0,31E1,31E2,31E3,31F*,320*,321_,3218,3219,321A,321B,321C,321D,321E,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," \ No newline at end of file diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_V1Compat.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_V1Compat.txt index 7f05de1c33..701f0195a7 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_V1Compat.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_V1Compat.txt @@ -24,7 +24,7 @@ Blank() >> Match("JohnDoe@microsoft.com", Match.Email) {FullMatch:"JohnDoe@microsoft.com",StartMatch:1} ->> Match("(555) 123-4567", "^[\+]?[\(]?[0-9]{3}[\)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$") +>> Match("(555) 123-4567", "^[\+]?[\(]?[0-9]{3}[\)]?[\-\s\.]?[0-9]{3}[\-\s\.]?[0-9]{4,6}$") {FullMatch:"(555) 123-4567",StartMatch:1} >> Match("Hello", "Hello", MatchOptions.IgnoreCase) diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs index aceaaa0752..2271343be2 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs @@ -38,20 +38,30 @@ function AlterRegex_JavaScript(regex, flags) var openCharacterClass = false; // are we defining a character class? var altered = ''; var spaceWaiting = false; + var mainCharacterClass = ''; + var orCharacterClass = ''; for ( ; index < regex.length; index++) { + var alteredToken = ''; + switch (regex.charAt(index) ) { case '[': openCharacterClass = true; - altered = altered.concat('['); + mainCharacterClass = ''; + orCharacterClass = ''; spaceWaiting = false; break; case ']': openCharacterClass = false; - altered = altered.concat(']'); + if (mainCharacterClass != '' && orCharacterClass != '') + altered = altered.concat('(?:[', mainCharacterClass, ']', orCharacterClass, ')'); + else if(mainCharacterClass != '') + altered = altered.concat('[', mainCharacterClass, ']'); + else + altered = altered.concat(orCharacterClass.substring(1)); // strip leading '|' deliniator spaceWaiting = false; break; @@ -65,63 +75,72 @@ function AlterRegex_JavaScript(regex, flags) switch (regex.charAt(index)) { case 'w': - altered = altered.concat((openCharacterClass ? '' : '['), wordChar, (openCharacterClass ? '' : ']')); + alteredToken = ''.concat(openCharacterClass ? '' : '[', wordChar, openCharacterClass ? '' : ']'); break; case 'W': - altered = altered.concat('[^', wordChar, ']'); + if (openCharacterClass) + orCharacterClass = orCharacterClass.concat( '|[^', wordChar, ']' ); + else + alteredToken = ''.concat('[^', wordChar, ']'); break; case 'b': - altered = altered.concat(`(?:(?<=[${wordChar}])(?![${wordChar}])|(? 0 && altered.charAt(altered.length-1) == '(') { - altered = altered.concat( '(?:)' ); + alteredToken = '(?:)'; spaceWaiting = false; } - altered = altered.concat(regex.charAt(index)); + alteredToken = alteredToken.concat(regex.charAt(index)); spaceWaiting = false; break; default: if (spaceWaiting) { - altered = altered.concat( '(?:)' ); + alteredToken = '(?:)'; spaceWaiting = false; } - altered = altered.concat(regex.charAt(index)); + alteredToken = alteredToken.concat(regex.charAt(index)); break; } + + if (openCharacterClass) + mainCharacterClass = mainCharacterClass.concat(alteredToken); + else + altered = altered.concat(alteredToken); } if (flags.includes('^')) diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index f84a356558..c03b5b1979 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -23,7 +23,7 @@ public FileExpressionEvaluationTests(ITestOutputHelper output) Console = output; } - // ab File expression tests are run multiple times for the different ways a host can use Power Fx. + // abcde File expression tests are run multiple times for the different ways a host can use Power Fx. // // 1. Features.PowerFxV1 without NumberIsFloat - the main way that most hosts will use Power Fx. // 2. Feautres.PowerFxV1 with NumberIsFloat - for hosts that wish to use floating point instead of Decimal. @@ -93,10 +93,10 @@ public void None_Float(ExpressionTestCase testCase) } #endif -#if false +#if true // Runs only tests that have asked for RegEx setup. This test run will compare the regular expression results between // .NET (used in the C# interpreter), NodeJS with JavaScript (used in Canvas), and PCRE2 (used in Excel). - // This is not run all the time. It requires Node to be installed and PCRE2 built as a shared library DLL and on the path.ababceeefeeerwee + // This is not run all the time. It requires Node to be installed and PCRE2 built as a shared library DLL and on the path. [TxtFileData("ExpressionTestCases", "InterpreterExpressionTestCases", nameof(InterpreterRunner), "PowerFxV1,disable:NumberIsFloat,DecimalSupport", "RegEx")] [InterpreterTheory] public void RegExCompare(ExpressionTestCase t) diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs index a013e83ece..0ed4719706 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs @@ -90,6 +90,7 @@ function MatchTest( subject, pattern, flags, matchAll ) const [alteredPattern, alteredFlags] = AlterRegex_JavaScript( pattern, flags ); const regex = RegExp(alteredPattern, alteredFlags.concat(matchAll ? 'g' : '')); const matches = matchAll ? [...subject.matchAll(regex)] : [subject.match(regex)]; + // console.log(alteredPattern); // useful to debug AlterRegex_JavaScript console.log('%%begin%%'); if (matches.length != 0 && matches[0] != null) { diff --git a/src/tools/Repl/Program.cs b/src/tools/Repl/Program.cs index 1a5ab902db..5fb1460cf4 100644 --- a/src/tools/Repl/Program.cs +++ b/src/tools/Repl/Program.cs @@ -42,8 +42,8 @@ public static class ConsoleRepl private const string OptionTextFirst = "TextFirst"; private static bool _textFirst = false; - private const string OptionRegExCompare = "RegExCompare"; - private static bool _regExCompare = false; + private const string OptionMatchCompare = "MatchCompare"; + private static bool _matchCompare = false; private const string OptionUDF = "UserDefinedFunctions"; private static bool _enableUDFs = true; @@ -75,7 +75,7 @@ private static RecalcEngine ReplRecalcEngine() { OptionHashCodes, OptionHashCodes }, { OptionStackTrace, OptionStackTrace }, { OptionTextFirst, OptionTextFirst }, - { OptionRegExCompare, OptionRegExCompare }, + { OptionMatchCompare, OptionMatchCompare }, { OptionUDF, OptionUDF }, }; @@ -106,7 +106,7 @@ private static RecalcEngine ReplRecalcEngine() var optionsSet = new OptionSet("Options", DisplayNameUtility.MakeUnique(options)); - if (_regExCompare) + if (_matchCompare) { // requires PCRE2 DLL (pcre2-16d.dll) on the path and Node.JS installed // can also use RegEx_PCRE2 and RegEx_NodeJS directly too @@ -141,6 +141,8 @@ public static void Main() REPL(Console.In, prompt: true, echo: false, printResult: true, lineNumber: null); } +#pragma warning disable CS0618 + // Hook repl engine with customizations. private class MyRepl : PowerFxREPL { @@ -402,9 +404,9 @@ public FormulaValue Execute(StringValue option, BooleanValue value) return value; } - if (string.Equals(option.Value, OptionRegExCompare, StringComparison.OrdinalIgnoreCase)) + if (string.Equals(option.Value, OptionMatchCompare, StringComparison.OrdinalIgnoreCase)) { - _regExCompare = value.Value; + _matchCompare = value.Value; _reset = true; return value; } From 6b4499b433f0dfde3f3f36abd7f3f22dc1da533c Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Thu, 24 Oct 2024 16:20:53 -0700 Subject: [PATCH 51/61] Updates --- .../ExpressionTestCases/Match_Limited.txt | 2 +- .../ExpressionTestCases/Match_Unicode.txt | 1 + .../FileExpressionEvaluationTests.cs | 2 +- .../Helpers/LibraryRegEx_Compare.cs | 24 ++- .../Helpers/LibraryRegEx_NodeJS.cs | 173 ++++++++++-------- .../Helpers/LibraryRegEx_PCRE2.cs | 14 +- 6 files changed, 132 insertions(+), 84 deletions(-) diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt index 34ad933b15..5c2c7eba14 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt @@ -537,7 +537,7 @@ Errors: Error 35-46: Invalid regular expression: Negative escape character not p {FullMatch:"123",StartMatch:4} >> Match( "foo123test456", "[^\P{L}]+") // would be problematic if we wanted to implement MatchOptions.LocaleAware in the future -Errors: Error 24-34: Invalid regular expression: Negative escape character not permitted within negated character class, found "\P{L}...".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 24-35: Invalid regular expression: Negative escape character not permitted within negated character class, found "\P{L}...".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "$test" & Char(8) & "test", "[\w]test" ) // \w is OK Blank() diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Unicode.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Unicode.txt index 34ec85f3c8..edd4377704 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Unicode.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Unicode.txt @@ -60,6 +60,7 @@ "0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003A,003B,003C,003D,003E,003F,004*,005*,006*,007*,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066A,066B,066C,066D,066E,066F,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06FA,06FB,06FC,06FD,06FE,06FF,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07CA,07CB,07CC,07CD,07CE,07CF,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,0960,0961,0962,0963,0964,0965,097*,098*,099*,09A*,09B*,09C*,09D*,09E0,09E1,09E2,09E3,09E4,09E5,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A60,0A61,0A62,0A63,0A64,0A65,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE0,0AE1,0AE2,0AE3,0AE4,0AE5,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B60,0B61,0B62,0B63,0B64,0B65,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE0,0BE1,0BE2,0BE3,0BE4,0BE5,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C60,0C61,0C62,0C63,0C64,0C65,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE0,0CE1,0CE2,0CE3,0CE4,0CE5,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D60,0D61,0D62,0D63,0D64,0D65,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE0,0DE1,0DE2,0DE3,0DE4,0DE5,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5A,0E5B,0E5C,0E5D,0E5E,0E5F,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0EDA,0EDB,0EDC,0EDD,0EDE,0EDF,0EE*,0EF*,0F0*,0F1*,0F2A,0F2B,0F2C,0F2D,0F2E,0F2F,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104A,104B,104C,104D,104E,104F,105*,106*,107*,108*,109A,109B,109C,109D,109E,109F,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17EA,17EB,17EC,17ED,17EE,17EF,17F*,180*,181A,181B,181C,181D,181E,181F,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,1940,1941,1942,1943,1944,1945,195*,196*,197*,198*,199*,19A*,19B*,19C*,19DA,19DB,19DC,19DD,19DE,19DF,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8A,1A8B,1A8C,1A8D,1A8E,1A8F,1A9A,1A9B,1A9C,1A9D,1A9E,1A9F,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5A,1B5B,1B5C,1B5D,1B5E,1B5F,1B6*,1B7*,1B8*,1B9*,1BA*,1BBA,1BBB,1BBC,1BBD,1BBE,1BBF,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4A,1C4B,1C4C,1C4D,1C4E,1C4F,1C5A,1C5B,1C5C,1C5D,1C5E,1C5F,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," // s +// PCRE2 uses an older version of Unicode where \u180e is in the space category. This is corrected for in LibraryRegEx_PCRE2 for testing comparisons. >> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\s" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index c03b5b1979..3729a9a21b 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -96,7 +96,7 @@ public void None_Float(ExpressionTestCase testCase) #if true // Runs only tests that have asked for RegEx setup. This test run will compare the regular expression results between // .NET (used in the C# interpreter), NodeJS with JavaScript (used in Canvas), and PCRE2 (used in Excel). - // This is not run all the time. It requires Node to be installed and PCRE2 built as a shared library DLL and on the path. + // This is not run all the time. It requires Node to be installed and PCRE2 built as a shared library DLL and on the path.eb [TxtFileData("ExpressionTestCases", "InterpreterExpressionTestCases", nameof(InterpreterRunner), "PowerFxV1,disable:NumberIsFloat,DecimalSupport", "RegEx")] [InterpreterTheory] public void RegExCompare(ExpressionTestCase t) diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_Compare.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_Compare.cs index c28229f595..a8a078378e 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_Compare.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_Compare.cs @@ -64,6 +64,26 @@ internal abstract class Compare_CommonImplementation : Library.RegexCommonImplem protected Library.RegexCommonImplementation node_alt; protected Library.RegexCommonImplementation pcre2_alt; + private string CharCodes(string text) + { + StringBuilder sb = new StringBuilder(); + + foreach (char c in text) + { + sb.Append(Convert.ToInt32(c).ToString("X4")); + sb.Append(" "); + } + + if (sb.Length > 0) + { + return sb.ToString().Substring(0, sb.Length - 1); + } + else + { + return string.Empty; + } + } + private FormulaValue InvokeRegexFunctionOne(string input, string regex, string options, Library.RegexCommonImplementation dotnet, Library.RegexCommonImplementation node, Library.RegexCommonImplementation pcre2, string kind) { var nodeMatch = node.InvokeRegexFunction(input, regex, options); @@ -77,12 +97,12 @@ private FormulaValue InvokeRegexFunctionOne(string input, string regex, string o if (nodeExpr != dotnetExpr) { - throw new Exception($"{kind}: node != net on input='{input}', re='{regex}', options='{options}',\n net='{dotnetExpr}',\n node='{nodeExpr}',\n pcre2='{pcre2Expr}'"); + throw new Exception($"{kind}: node != net on re='{regex}' options='{options}'\n input='{input}' ({CharCodes(input)})\n net='{dotnetExpr}'\n node='{nodeExpr}'\n pcre2='{pcre2Expr}'\n"); } if (pcre2Expr != dotnetExpr) { - throw new Exception($"{kind}: pcre2 != net on input='{input}', re='{regex}', options='{options}',\n net='{dotnetExpr}',\n node='{nodeExpr}',\n pcre2='{pcre2Expr}'"); + throw new Exception($"{kind}: pcre2 != net on re='{regex}' options='{options}'\n input='{input}' ({CharCodes(input)})\n net='{dotnetExpr}'\n node='{nodeExpr}'\n pcre2='{pcre2Expr}'\n"); } return dotnetMatch; diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs index 0ed4719706..55cbd5f242 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs @@ -12,6 +12,7 @@ using System.Text; using System.Text.Json; using System.Text.RegularExpressions; +using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Differencing; using Microsoft.PowerFx.Core.Functions; @@ -26,23 +27,32 @@ namespace Microsoft.PowerFx.Functions public class RegEx_NodeJS { private static Process node; + private static readonly Mutex NodeMutex = new Mutex(); // protect concurrent access to the node process - private static readonly StringBuilder OutputSB = new StringBuilder(); - private static readonly StringBuilder ErrorSB = new StringBuilder(); + private static StringBuilder outputSB; + private static StringBuilder errorSB; private static TaskCompletionSource readTask = null; + private static string output; + private static string error; private static void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine) { - OutputSB.Append(outLine.Data); + outputSB.Append(outLine.Data); if (outLine.Data.Contains("%%end%%")) { + output = outputSB.ToString(); + error = errorSB.ToString(); readTask.TrySetResult(true); } } private static void ErrorHandler(object sendingProcess, DataReceivedEventArgs outLine) { - ErrorSB.Append(outLine.Data); + errorSB.Append(outLine.Data); + + output = outputSB.ToString(); + error = errorSB.ToString(); + readTask.TrySetResult(true); } @@ -59,7 +69,9 @@ internal abstract class NodeJS_RegexCommonImplementation : Library.RegexCommonIm { internal static FormulaValue Match(string subject, string pattern, string flags, bool matchAll = false) { + NodeMutex.WaitOne(); Task task = Task.Run(async () => await MatchAsync(subject, pattern, flags, matchAll)); + NodeMutex.ReleaseMutex(); return task.Result; } @@ -67,10 +79,16 @@ internal static async Task MatchAsync(string subject, string patte { var js = new StringBuilder(); - js.Append($"MatchTest('{subject.Replace("\\", "\\\\").Replace("\r", "\\r").Replace("\n", "\\n").Replace("'", "\\'")}',"); - js.Append($"'{pattern.Replace("\\", "\\\\").Replace("\r", "\\r").Replace("\n", "\\n").Replace("'", "\\'")}',"); - js.Append($"'{flags}',"); - js.Append($"{(matchAll ? "true" : "false")});"); + outputSB = new StringBuilder(); + errorSB = new StringBuilder(); + readTask = new TaskCompletionSource(); + + try + { + js.Append($"MatchTest('{subject.Replace("\\", "\\\\").Replace("\r", "\\r").Replace("\n", "\\n").Replace("'", "\\'")}',"); + js.Append($"'{pattern.Replace("\\", "\\\\").Replace("\r", "\\r").Replace("\n", "\\n").Replace("'", "\\'")}',"); + js.Append($"'{flags}',"); + js.Append($"{(matchAll ? "true" : "false")});"); #if false // for debugging unicode passing of strings to Node, output ignored by deserializer but visible in the debugger @@ -82,9 +100,9 @@ internal static async Task MatchAsync(string subject, string patte "); #endif - if (node == null) - { - string js2 = @" + if (node == null) + { + string js2 = @" function MatchTest( subject, pattern, flags, matchAll ) { const [alteredPattern, alteredFlags] = AlterRegex_JavaScript( pattern, flags ); @@ -109,104 +127,103 @@ function MatchTest( subject, pattern, flags, matchAll ) } "; - node = new Process(); - node.StartInfo.FileName = "node.exe"; - node.StartInfo.Arguments = "-i"; - node.StartInfo.RedirectStandardInput = true; - node.StartInfo.RedirectStandardOutput = true; - node.StartInfo.RedirectStandardError = true; - node.StartInfo.CreateNoWindow = true; - node.StartInfo.UseShellExecute = false; - node.StartInfo.StandardOutputEncoding = System.Text.Encoding.UTF8; - - // Not supported by .NET framework 4.6.2, we need to use the manual GetBytes method below - // node.StartInfo.StandardInputEncoding = System.Text.Encoding.UTF8; - - node.OutputDataReceived += OutputHandler; - node.ErrorDataReceived += ErrorHandler; + node = new Process(); + node.StartInfo.FileName = "node.exe"; + node.StartInfo.Arguments = "-i"; + node.StartInfo.RedirectStandardInput = true; + node.StartInfo.RedirectStandardOutput = true; + node.StartInfo.RedirectStandardError = true; + node.StartInfo.CreateNoWindow = true; + node.StartInfo.UseShellExecute = false; + node.StartInfo.StandardOutputEncoding = System.Text.Encoding.UTF8; - node.Start(); + // Not supported by .NET framework 4.6.2, we need to use the manual GetBytes method below + // node.StartInfo.StandardInputEncoding = System.Text.Encoding.UTF8; - node.BeginOutputReadLine(); - node.BeginErrorReadLine(); + node.OutputDataReceived += OutputHandler; + node.ErrorDataReceived += ErrorHandler; - await node.StandardInput.WriteLineAsync(RegEx_JavaScript.AlterRegex_JavaScript); - await node.StandardInput.WriteLineAsync(js2); - } + node.Start(); - OutputSB.Clear(); - ErrorSB.Clear(); - readTask = new TaskCompletionSource(); + node.BeginOutputReadLine(); + node.BeginErrorReadLine(); - var jsString = js.ToString(); - var bytes = Encoding.UTF8.GetBytes(jsString); - await node.StandardInput.BaseStream.WriteAsync(bytes, 0, bytes.Length); - await node.StandardInput.WriteLineAsync(); + await node.StandardInput.WriteLineAsync(RegEx_JavaScript.AlterRegex_JavaScript); + await node.StandardInput.WriteLineAsync(js2); + } - await node.StandardInput.FlushAsync(); + var jsString = js.ToString(); + var bytes = Encoding.UTF8.GetBytes(jsString); + await node.StandardInput.BaseStream.WriteAsync(bytes, 0, bytes.Length); + await node.StandardInput.WriteLineAsync(); - await readTask.Task; + await node.StandardInput.FlushAsync(); - string output = OutputSB.ToString(); - string error = ErrorSB.ToString(); + await readTask.Task; - if (error.Length > 0) - { - throw new InvalidOperationException(error); - } + if (error.Length > 0) + { + throw new InvalidOperationException(error); + } - int begin = output.IndexOf("%%begin%%"); - int end = output.IndexOf("%%end%%"); + int begin = output.IndexOf("%%begin%%"); + int end = output.IndexOf("%%end%%"); - var type = new KnownRecordType(GetRecordTypeFromRegularExpression(pattern, flags.Contains('N') ? RegexOptions.None : RegexOptions.ExplicitCapture)); + var type = new KnownRecordType(GetRecordTypeFromRegularExpression(pattern, (flags.Contains('N') ? RegexOptions.None : RegexOptions.ExplicitCapture) | (flags.Contains('x') ? RegexOptions.IgnorePatternWhitespace : RegexOptions.None))); - if (end == begin + 9) - { - return matchAll ? FormulaValue.NewTable(type) : new BlankValue(IRContext.NotInSource(type)); - } + if (end == begin + 9) + { + return matchAll ? FormulaValue.NewTable(type) : new BlankValue(IRContext.NotInSource(type)); + } - string json = output.Substring(begin + 9, end - begin - 9); - var result = JsonSerializer.Deserialize(json); + string json = output.Substring(begin + 9, end - begin - 9); + var result = JsonSerializer.Deserialize(json); - List allMatches = new (); + List allMatches = new (); - foreach (JSMatch match in result) - { - Dictionary fields = new Dictionary() + foreach (JSMatch match in result) + { + Dictionary fields = new Dictionary() { { STARTMATCH, new NamedValue(STARTMATCH, NumberValue.New(Convert.ToDouble(match.Index) + 1)) }, { FULLMATCH, new NamedValue(FULLMATCH, match.Numbered[0] == null ? BlankValue.NewBlank(FormulaType.String) : StringValue.New(match.Numbered[0])) }, }; - if (match.Named != null) - { - foreach (var name in type.FieldNames) + if (match.Named != null) { - if (name != STARTMATCH && name != FULLMATCH && name != SUBMATCHES) + foreach (var name in type.FieldNames) { - fields.Add(name, new NamedValue(name, match.Named.ContainsKey(name) ? StringValue.New(match.Named[name]) : BlankValue.NewBlank(FormulaType.String))); + if (name != STARTMATCH && name != FULLMATCH && name != SUBMATCHES) + { + fields.Add(name, new NamedValue(name, match.Named.ContainsKey(name) ? StringValue.New(match.Named[name]) : BlankValue.NewBlank(FormulaType.String))); + } } } - } - if (flags.Contains('N')) - { - List subMatches = new List(); - - for (int i = 1; i < match.Numbered.Count(); i++) + if (flags.Contains('N')) { - var n = match.Numbered[i]; - subMatches.Add(FormulaValue.NewRecordFromFields(new NamedValue(TableValue.ValueName, n == null ? BlankValue.NewBlank(FormulaType.String) : StringValue.New(n)))); + List subMatches = new List(); + + for (int i = 1; i < match.Numbered.Count(); i++) + { + var n = match.Numbered[i]; + subMatches.Add(FormulaValue.NewRecordFromFields(new NamedValue(TableValue.ValueName, n == null ? BlankValue.NewBlank(FormulaType.String) : StringValue.New(n)))); + } + + var recordType = RecordType.Empty().Add(TableValue.ValueName, FormulaType.String); + fields.Add(SUBMATCHES, new NamedValue(SUBMATCHES, TableValue.NewTable(recordType, subMatches))); } - var recordType = RecordType.Empty().Add(TableValue.ValueName, FormulaType.String); - fields.Add(SUBMATCHES, new NamedValue(SUBMATCHES, TableValue.NewTable(recordType, subMatches))); + allMatches.Add(RecordValue.NewRecordFromFields(fields.Values)); } - allMatches.Add(RecordValue.NewRecordFromFields(fields.Values)); + return matchAll ? FormulaValue.NewTable(allMatches.First().Type, allMatches) : allMatches.First(); + } + catch (Exception e) + { + // rethrow here just so we can debug the exception in the task + throw e; } - - return matchAll ? FormulaValue.NewTable(allMatches.First().Type, allMatches) : allMatches.First(); } } diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs index cf229cda6f..1de1fc2c22 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs @@ -13,6 +13,7 @@ using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; +using System.Threading; using Microsoft.PowerFx.Core.Functions; using Microsoft.PowerFx.Core.IR; using Microsoft.PowerFx.Core.Texl.Builtins; @@ -78,6 +79,8 @@ internal enum PCRE2_OPTIONS : uint NO_AUTO_CAPTURE = 0x00002000, } + private static readonly Mutex PCRE2Mutex = new Mutex(); // protect concurrent access to the node process + internal static FormulaValue Match(string subject, string pattern, string flags, bool matchAll = false) { int errorNumber = 0; @@ -139,6 +142,8 @@ internal static FormulaValue Match(string subject, string pattern, string flags, pattern = pattern + "$"; } + PCRE2Mutex.WaitOne(); + var patternPCRE2 = Regex.Replace(pattern, @"\\u(?\w\w\w\w)", @"\x{${hex}}"); var code = NativeMethods.pcre2_compile_16(patternPCRE2, -1, (uint)pcreOptions, ref errorNumber, ref errorOffset, context); var md = NativeMethods.pcre2_match_data_create_from_pattern_16(code, generalContext); @@ -146,6 +151,9 @@ internal static FormulaValue Match(string subject, string pattern, string flags, var startMatch = 0; List allMatches = new (); + // PCRE2 uses an older definition of Unicode where 180e is a space character, moving it to something else (used defined cahracter) here for category comparisons tests + subject = subject.Replace('\u180e', '\uf8ff'); + while (startMatch >= 0 && NativeMethods.pcre2_match_16(code, subject, -1, startMatch, 0, md, matchContext) > 0) { Dictionary fields = new (); @@ -156,7 +164,7 @@ internal static FormulaValue Match(string subject, string pattern, string flags, IntPtr op = NativeMethods.pcre2_get_ovector_pointer_16(md); var start0 = Marshal.ReadInt32(op, 0); var end0 = Marshal.ReadInt32(op, Marshal.SizeOf(typeof(long))); - fields.Add(FULLMATCH, new NamedValue(FULLMATCH, StringValue.New(subject.Substring(start0, end0 - start0)))); + fields.Add(FULLMATCH, new NamedValue(FULLMATCH, StringValue.New(subject.Replace('\uf8ff', '\u180e').Substring(start0, end0 - start0)))); startMatch = matchAll ? end0 : -1; // for next iteration List subMatches = new List(); @@ -167,7 +175,7 @@ internal static FormulaValue Match(string subject, string pattern, string flags, var end = Marshal.ReadInt32(op, ((i * 2) + 1) * Marshal.SizeOf(typeof(long))); if (start >= 0 && end >= 0) { - subMatches.Add(StringValue.New(subject.Substring(start, end - start))); + subMatches.Add(StringValue.New(subject.Replace('\uf8ff', '\u180e').Substring(start, end - start))); } else { @@ -201,6 +209,8 @@ internal static FormulaValue Match(string subject, string pattern, string flags, NativeMethods.pcre2_match_data_free_16(md); NativeMethods.pcre2_code_free_16(code); + PCRE2Mutex.ReleaseMutex(); + if (allMatches.Count == 0) { return matchAll ? FormulaValue.NewTable(new KnownRecordType(GetRecordTypeFromRegularExpression(pattern, options))) From fa7edbe692614b5d668857a837f18497e0f80709 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Fri, 25 Oct 2024 03:05:54 -0700 Subject: [PATCH 52/61] updats --- .../Helpers/RegEx_JavaScript.cs | 2 +- .../FileExpressionEvaluationTests.cs | 2 +- .../Helpers/LibraryRegEx_Compare.cs | 116 ++++++++++++------ .../Helpers/LibraryRegEx_NodeJS.cs | 8 +- .../Helpers/LibraryRegEx_PCRE2.cs | 20 +-- .../PowerFxEvaluationTests.cs | 5 +- 6 files changed, 101 insertions(+), 52 deletions(-) diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs index 2271343be2..3e452f72a9 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/Helpers/RegEx_JavaScript.cs @@ -68,7 +68,7 @@ function AlterRegex_JavaScript(regex, flags) case '\\': if (++index < regex.length) { - const wordChar = '\\p{Ll}\\p{Lu}\\p{Lt}\\p{Lo}\\p{Lm}\\p{Nd}\\p{Pc}'; + const wordChar = '\\p{Ll}\\p{Lu}\\p{Lt}\\p{Lo}\\p{Lm}\\p{Mn}\\p{Nd}\\p{Pc}'; const spaceChar = '\\f\\n\\r\\t\\v\\x85\\p{Z}'; const digitChar = '\\p{Nd}'; diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index 3729a9a21b..c03b5b1979 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -96,7 +96,7 @@ public void None_Float(ExpressionTestCase testCase) #if true // Runs only tests that have asked for RegEx setup. This test run will compare the regular expression results between // .NET (used in the C# interpreter), NodeJS with JavaScript (used in Canvas), and PCRE2 (used in Excel). - // This is not run all the time. It requires Node to be installed and PCRE2 built as a shared library DLL and on the path.eb + // This is not run all the time. It requires Node to be installed and PCRE2 built as a shared library DLL and on the path. [TxtFileData("ExpressionTestCases", "InterpreterExpressionTestCases", nameof(InterpreterRunner), "PowerFxV1,disable:NumberIsFloat,DecimalSupport", "RegEx")] [InterpreterTheory] public void RegExCompare(ExpressionTestCase t) diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_Compare.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_Compare.cs index a8a078378e..06aec596d5 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_Compare.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_Compare.cs @@ -18,11 +18,11 @@ namespace Microsoft.PowerFx.Functions { public class RegEx_Compare { - public static void EnableRegExFunctions(PowerFxConfig config, TimeSpan regExTimeout = default, int regexCacheSize = -1) + public static void EnableRegExFunctions(PowerFxConfig config, TimeSpan regExTimeout = default, int regexCacheSize = -1, bool includeNode = true, bool includePCRE2 = true) { RegexTypeCache regexTypeCache = new (regexCacheSize); - foreach (KeyValuePair func in RegexFunctions(regExTimeout, regexTypeCache)) + foreach (KeyValuePair func in RegexFunctions(regExTimeout, regexTypeCache, includeNode, includePCRE2)) { if (config.SymbolTable.Functions.AnyWithName(func.Key.Name)) { @@ -34,7 +34,7 @@ public static void EnableRegExFunctions(PowerFxConfig config, TimeSpan regExTime } } - internal static Dictionary RegexFunctions(TimeSpan regexTimeout, RegexTypeCache regexCache) + internal static Dictionary RegexFunctions(TimeSpan regexTimeout, RegexTypeCache regexCache, bool includeNode, bool includePCRE2) { if (regexTimeout == TimeSpan.Zero) { @@ -48,9 +48,9 @@ internal static Dictionary RegexFunctions(Time return new Dictionary() { - { new IsMatchFunction(), new Compare_IsMatchImplementation(regexTimeout) }, - { new MatchFunction(regexCache), new Compare_MatchImplementation(regexTimeout) }, - { new MatchAllFunction(regexCache), new Compare_MatchAllImplementation(regexTimeout) } + { new IsMatchFunction(), new Compare_IsMatchImplementation(regexTimeout, includeNode, includePCRE2) }, + { new MatchFunction(regexCache), new Compare_MatchImplementation(regexTimeout, includeNode, includePCRE2) }, + { new MatchAllFunction(regexCache), new Compare_MatchAllImplementation(regexTimeout, includeNode, includePCRE2) } }; } @@ -85,24 +85,47 @@ private string CharCodes(string text) } private FormulaValue InvokeRegexFunctionOne(string input, string regex, string options, Library.RegexCommonImplementation dotnet, Library.RegexCommonImplementation node, Library.RegexCommonImplementation pcre2, string kind) - { - var nodeMatch = node.InvokeRegexFunction(input, regex, options); - var nodeExpr = nodeMatch.ToExpression(); - - var pcre2Match = pcre2.InvokeRegexFunction(input, regex, options); - var pcre2Expr = pcre2Match.ToExpression(); - + { var dotnetMatch = dotnet.InvokeRegexFunction(input, regex, options); - var dotnetExpr = dotnetMatch.ToExpression(); - - if (nodeExpr != dotnetExpr) - { - throw new Exception($"{kind}: node != net on re='{regex}' options='{options}'\n input='{input}' ({CharCodes(input)})\n net='{dotnetExpr}'\n node='{nodeExpr}'\n pcre2='{pcre2Expr}'\n"); + var dotnetExpr = dotnetMatch.ToExpression(); + + string nodeExpr = null; + string pcre2Expr = null; + + if (node != null) + { + var nodeMatch = node.InvokeRegexFunction(input, regex, options); + nodeExpr = nodeMatch.ToExpression(); + } + + if (pcre2 != null) + { + var pcre2Match = pcre2.InvokeRegexFunction(input, regex, options); + pcre2Expr = pcre2Match.ToExpression(); + } + + string prefix = null; + + if (nodeExpr != null && nodeExpr != dotnetExpr) + { + prefix = $"{kind}: node != net"; } - if (pcre2Expr != dotnetExpr) + if (pcre2Expr != null && pcre2Expr != dotnetExpr) { - throw new Exception($"{kind}: pcre2 != net on re='{regex}' options='{options}'\n input='{input}' ({CharCodes(input)})\n net='{dotnetExpr}'\n node='{nodeExpr}'\n pcre2='{pcre2Expr}'\n"); + prefix = $"{kind}: node != net"; + } + + if (prefix != null) + { + var report = + $" re='{regex}' options='{options}'\n" + + $" input='{input}' ({CharCodes(input)})\n" + + $" net={dotnetExpr}\n" + + (nodeExpr != null ? $" node={nodeExpr}\n" : string.Empty) + + (pcre2Expr != null ? $" pcre2={pcre2Expr}\n" : string.Empty); + + throw new Exception($"{prefix}\n{report}"); } return dotnetMatch; @@ -125,15 +148,22 @@ internal class Compare_IsMatchImplementation : Compare_CommonImplementation { protected override string DefaultRegexOptions => DefaultIsMatchOptions; - internal Compare_IsMatchImplementation(TimeSpan regexTimeout) + internal Compare_IsMatchImplementation(TimeSpan regexTimeout, bool includeNode, bool includePCRE2) { - node = new NodeJS_IsMatchImplementation(regexTimeout); - pcre2 = new PCRE2_IsMatchImplementation(regexTimeout); dotnet = new Library.IsMatchImplementation(regexTimeout); - - node_alt = new NodeJS_MatchImplementation(regexTimeout); - pcre2_alt = new PCRE2_MatchImplementation(regexTimeout); - dotnet_alt = new Library.MatchImplementation(regexTimeout); + dotnet_alt = new Library.MatchImplementation(regexTimeout); + + if (includeNode) + { + node = new NodeJS_IsMatchImplementation(regexTimeout); + node_alt = new NodeJS_MatchImplementation(regexTimeout); + } + + if (includePCRE2) + { + pcre2 = new PCRE2_IsMatchImplementation(regexTimeout); + pcre2_alt = new PCRE2_MatchImplementation(regexTimeout); + } } } @@ -141,10 +171,18 @@ internal class Compare_MatchImplementation : Compare_CommonImplementation { protected override string DefaultRegexOptions => DefaultMatchOptions; - internal Compare_MatchImplementation(TimeSpan regexTimeout) - { - node = new NodeJS_MatchImplementation(regexTimeout); - pcre2 = new PCRE2_MatchImplementation(regexTimeout); + internal Compare_MatchImplementation(TimeSpan regexTimeout, bool includeNode, bool includePCRE2) + { + if (includeNode) + { + node = new NodeJS_MatchImplementation(regexTimeout); + } + + if (includePCRE2) + { + pcre2 = new PCRE2_MatchImplementation(regexTimeout); + } + dotnet = new Library.MatchImplementation(regexTimeout); } } @@ -153,10 +191,18 @@ internal class Compare_MatchAllImplementation : Compare_CommonImplementation { protected override string DefaultRegexOptions => DefaultMatchAllOptions; - internal Compare_MatchAllImplementation(TimeSpan regexTimeout) - { - node = new NodeJS_MatchAllImplementation(regexTimeout); - pcre2 = new PCRE2_MatchAllImplementation(regexTimeout); + internal Compare_MatchAllImplementation(TimeSpan regexTimeout, bool includeNode, bool includePCRE2) + { + if (includeNode) + { + node = new NodeJS_MatchAllImplementation(regexTimeout); + } + + if (includePCRE2) + { + pcre2 = new PCRE2_MatchAllImplementation(regexTimeout); + } + dotnet = new Library.MatchAllImplementation(regexTimeout); } } diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs index 55cbd5f242..616d80d656 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs @@ -167,8 +167,10 @@ function MatchTest( subject, pattern, flags, matchAll ) } int begin = output.IndexOf("%%begin%%"); - int end = output.IndexOf("%%end%%"); - + int end = output.IndexOf("%%end%%"); + + // In x mode, comment line endings are [\r\n], but .NET only supports \n. For our purposes here, we can just replace the \r. + pattern = pattern.Replace('\r', '\n'); var type = new KnownRecordType(GetRecordTypeFromRegularExpression(pattern, (flags.Contains('N') ? RegexOptions.None : RegexOptions.ExplicitCapture) | (flags.Contains('x') ? RegexOptions.IgnorePatternWhitespace : RegexOptions.None))); if (end == begin + 9) @@ -193,7 +195,7 @@ function MatchTest( subject, pattern, flags, matchAll ) { foreach (var name in type.FieldNames) { - if (name != STARTMATCH && name != FULLMATCH && name != SUBMATCHES) + if (name != STARTMATCH && name != FULLMATCH && !(name == SUBMATCHES && type.GetFieldType(SUBMATCHES) != FormulaType.String)) { fields.Add(name, new NamedValue(name, match.Named.ContainsKey(name) ? StringValue.New(match.Named[name]) : BlankValue.NewBlank(FormulaType.String))); } diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs index 1de1fc2c22..ce819316e6 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_PCRE2.cs @@ -27,43 +27,43 @@ internal abstract class PCRE2_RegexCommonImplementation : Library.RegexCommonImp { internal static class NativeMethods { - [DllImport("pcre2-16d.dll", CharSet = CharSet.Unicode)] + [DllImport("pcre2-16.dll", CharSet = CharSet.Unicode)] [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] internal static extern IntPtr pcre2_compile_16(string pattern, int patternLength, uint patternOptions, ref int errorNumber, ref int errorOffset, IntPtr context); - [DllImport("pcre2-16d.dll", CharSet = CharSet.Unicode)] + [DllImport("pcre2-16.dll", CharSet = CharSet.Unicode)] [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] internal static extern int pcre2_match_16(IntPtr code, string subject, int subjectLength, int subjectOffset, uint subjectOptions, IntPtr matchData, IntPtr matchContext); - [DllImport("pcre2-16d.dll")] + [DllImport("pcre2-16.dll")] [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] internal static extern IntPtr pcre2_match_data_create_16(int ovecSize, IntPtr generalContext); - [DllImport("pcre2-16d.dll")] + [DllImport("pcre2-16.dll")] [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] internal static extern IntPtr pcre2_match_data_create_from_pattern_16(IntPtr code, IntPtr generalContext); - [DllImport("pcre2-16d.dll")] + [DllImport("pcre2-16.dll")] [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] internal static extern int pcre2_get_startchar_16(IntPtr matchData); - [DllImport("pcre2-16d.dll")] + [DllImport("pcre2-16.dll")] [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] internal static extern int pcre2_get_ovector_count_16(IntPtr matchData); - [DllImport("pcre2-16d.dll")] + [DllImport("pcre2-16.dll")] [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] internal static extern IntPtr pcre2_get_ovector_pointer_16(IntPtr matchData); - [DllImport("pcre2-16d.dll", CharSet = CharSet.Unicode)] + [DllImport("pcre2-16.dll", CharSet = CharSet.Unicode)] [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] internal static extern int pcre2_substring_number_from_name_16(IntPtr code, string name); - [DllImport("pcre2-16d.dll", CharSet = CharSet.Unicode)] + [DllImport("pcre2-16.dll", CharSet = CharSet.Unicode)] [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] internal static extern void pcre2_match_data_free_16(IntPtr data); - [DllImport("pcre2-16d.dll", CharSet = CharSet.Unicode)] + [DllImport("pcre2-16.dll", CharSet = CharSet.Unicode)] [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] internal static extern void pcre2_code_free_16(IntPtr code); } diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/PowerFxEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/PowerFxEvaluationTests.cs index 645c71005b..086d624c61 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/PowerFxEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/PowerFxEvaluationTests.cs @@ -71,8 +71,9 @@ private static object EnableJsonFunctions(PowerFxConfig config, SymbolTable symb private static object RegExSetup(PowerFxConfig config, SymbolTable symbolTable) { if (RegExCompareEnabled) - { - Functions.RegEx_Compare.EnableRegExFunctions(config, new TimeSpan(0, 0, 5)); + { + // PCRE2 has scalability probleems running all the tests, not included here but is enabled with the REPL + Functions.RegEx_Compare.EnableRegExFunctions(config, new TimeSpan(0, 0, 5), includePCRE2: false); } else { From 13ea69a2af16ca0985a7b00520067fe898454552 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Fri, 25 Oct 2024 03:21:46 -0700 Subject: [PATCH 53/61] Updates --- src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index 1bf8a97481..63ee610c43 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -298,7 +298,7 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter } else if (token.Groups["goodUnicodeCategory"].Success) { - if (openCharacterClass && openCharacterClassNegative) + if (token.Value.Substring(1, 1) == "P" && openCharacterClass && openCharacterClassNegative) { errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadEscapeInsideNegativeCharacterClass, token.Index >= regexPattern.Length - 5 ? regexPattern.Substring(token.Index) : regexPattern.Substring(token.Index, 5) + "..."); return false; @@ -309,7 +309,7 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadUnicodeCategory, token.Value); return false; } - } + } else if (token.Groups["openCharClass"].Success) { if (openCharacterClass) From 4a254e404e598dfaf5f493b16d9b985ee9b5eb22 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Fri, 25 Oct 2024 09:17:53 -0700 Subject: [PATCH 54/61] Updates --- .../Texl/Builtins/Match.cs | 16 +- .../ExpressionTestCases/Match_Unicode.txt | 512 ------------------ .../FileExpressionEvaluationTests.cs | 2 +- 3 files changed, 9 insertions(+), 521 deletions(-) delete mode 100644 src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Unicode.txt diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index 63ee610c43..ad5a52051b 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -138,7 +138,7 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp (returnType == DType.Boolean || TryCreateReturnType(regExNode, regularExpression, alteredOptions, errors, ref returnType)); } - private static readonly string[] UnicodeCategories = + private static readonly IReadOnlyCollection UnicodeCategories = new HashSet() { "L", "Lu", "Ll", "Lt", "Lm", "Lo", "M", "Mn", "Mc", "Me", @@ -148,7 +148,7 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp "Z", "Zs", "Zl", "Zp", "Cc", "Cf", - // "C", "Cs", "Co", "Cn", are left out for now until we have a good scenario for them, as they differ between implementations + // "C", "Cs", "Co", "Cn", are left out for now until we have a good scenario, as they differ between implementations }; // Limit regular expressions to common features that are supported, with consistent semantics, by both canonical .NET and XRegExp. @@ -201,9 +201,9 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter c[a-zA-Z] | # Ctrl character classes x[0-9a-fA-F]{2} | # hex character, must be exactly 2 hex digits u[0-9a-fA-F]{4})) | # Unicode characters, must be exactly 4 hex digits - \\[pP]\{(?[\w=:-]+)\} | # Unicode chaeracter classes, extra characters here for a better error message - (?\\[DWS]) | - (?\\[bB]) | # acceptable outside a character class, includes negative classes until we have character class subtraction, include \P for future MatchOptions.LocaleAware + \\(?[pP])\{(?[\w=:-]+)\} | # Unicode chaeracter classes, extra characters here for a better error message + (?\\[DWS]) | + (?\\[bB]) | # acceptable outside a character class, includes negative classes until we have character class subtraction, include \P for future MatchOptions.LocaleAware (?\\[\-]) | # needed for /v compatibility with ECMAScript (?\\.) | # all other escaped characters are invalid and reserved for future use @@ -296,15 +296,15 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter return false; } } - else if (token.Groups["goodUnicodeCategory"].Success) + else if (token.Groups["goodUEscape"].Success) { - if (token.Value.Substring(1, 1) == "P" && openCharacterClass && openCharacterClassNegative) + if (token.Groups["goodUEscape"].Value == "P" && openCharacterClass && openCharacterClassNegative) { errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadEscapeInsideNegativeCharacterClass, token.Index >= regexPattern.Length - 5 ? regexPattern.Substring(token.Index) : regexPattern.Substring(token.Index, 5) + "..."); return false; } - if (!UnicodeCategories.Contains(token.Groups["goodUnicodeCategory"].Value)) + if (!UnicodeCategories.Contains(token.Groups["UCategory"].Value)) { errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadUnicodeCategory, token.Value); return false; diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Unicode.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Unicode.txt deleted file mode 100644 index edd4377704..0000000000 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Unicode.txt +++ /dev/null @@ -1,512 +0,0 @@ -#SETUP: RegEx,PowerFxV1CompatibilityRules,SupportColumnNamesAsIdentifiers,DisableMemChecks - -// Unicode character behavior in Power Fx regular expressions. -// -// Effective Usage .NET ECMAScript PCRE2 Power Fx -// ===================================================================================================================================== -// \p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Lm}\p{Nd}\p{Pc} \w, \W, \b, \B Yes No Yes Yes -// \p{Nd} \d, \D Yes No Yes Yes -// \p{Category} \p, \P Yes Yes Yes Yes -// \p{Script} \p, \P Yes Yes Yes No (syntax varies) -// -// We chose to use canonical .NET instead of RegexOptions.ECMAScript because we wanted the unicode definitions for words. -// See https://learn.microsoft.com/dotnet/standard/base-types/regular-expression-options#ecmascript-matching-behavior for more details - -// Changes in case insensitive matching in .NET 7 causes different answers that are consistent with PCRE2 and Node -// See https://devblogs.microsoft.com/dotnet/regular-expression-improvements-in-dotnet-7/#case-insensitive-matching-and-regexoptions-ignorecase - ->> Match( UniChar(Hex2Dec("03a9")), "\u03c9", MatchOptions.IgnoreCase ).FullMatch -"Ω" - ->> Match( UniChar(Hex2Dec("03c9")), "\u03a9", MatchOptions.IgnoreCase ).FullMatch -"ω" - -#DISABLE.NET:462 ->> Match( UniChar(Hex2Dec("03a9")), "\u2126", MatchOptions.IgnoreCase ).FullMatch -"Ω" - -#DISABLE.NET:462 ->> Match( UniChar(Hex2Dec("03c9")), "\u2126", MatchOptions.IgnoreCase ).FullMatch -"ω" - -#DISABLE.NET:462 ->> Match( UniChar(Hex2Dec("2126")), "\u03c9", MatchOptions.IgnoreCase ).FullMatch -"Ω" - -#DISABLE.NET:462 ->> Match( UniChar(Hex2Dec("2126")), "\u03a9", MatchOptions.IgnoreCase ).FullMatch -"Ω" - -// w ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\w" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"003_,0038,0039,0041,0042,0043,0044,0045,0046,0047,004^,005_,0058,0059,005A,005F,0061,0062,0063,0064,0065,0066,0067,006^,007_,0078,0079,007A,00AA,00B5,00BA,00C*,00D0,00D1,00D2,00D3,00D4,00D5,00D6,00D^,00E*,00F0,00F1,00F2,00F3,00F4,00F5,00F6,00F^,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C0,02C1,02C6,02C7,02C^,02D0,02D1,02E0,02E1,02E2,02E3,02E4,02EC,02EE,030*,031*,032*,033*,034*,035*,036*,0370,0371,0372,0373,0374,0376,0377,037A,037B,037C,037D,037F,0386,0388,0389,038A,038C,038E,038F,039*,03A0,03A1,03A3,03A4,03A5,03A6,03A7,03A^,03B*,03C*,03D*,03E*,03F0,03F1,03F2,03F3,03F4,03F5,03F7,03F^,040*,041*,042*,043*,044*,045*,046*,047*,0480,0481,0483,0484,0485,0486,0487,048A,048B,048C,048D,048E,048F,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,0531,0532,0533,0534,0535,0536,0537,053^,054*,0550,0551,0552,0553,0554,0555,0556,0559,056*,057*,058_,0588,0591,0592,0593,0594,0595,0596,0597,059^,05A*,05B_,05B8,05B9,05BA,05BB,05BC,05BD,05BF,05C1,05C2,05C4,05C5,05C7,05D*,05E_,05E8,05E9,05EA,05EF,05F0,05F1,05F2,061_,0618,0619,061A,062*,063*,064*,065*,066_,0668,0669,066E,066F,067*,068*,069*,06A*,06B*,06C*,06D0,06D1,06D2,06D3,06D5,06D6,06D7,06D8,06D9,06DA,06DB,06DC,06DF,06E_,06E8,06EA,06EB,06EC,06ED,06EE,06EF,06F_,06F8,06F9,06FA,06FB,06FC,06FF,071*,072*,073*,074_,0748,0749,074A,074D,074E,074F,075*,076*,077*,078*,079*,07A*,07B0,07B1,07C*,07D*,07E*,07F0,07F1,07F2,07F3,07F4,07F5,07FA,07FD,080*,081*,082_,0828,0829,082A,082B,082C,082D,084*,085_,0858,0859,085A,085B,086_,0868,0869,086A,087*,088_,0889,088A,088B,088C,088D,088E,089^,08A*,08B*,08C*,08D*,08E0,08E1,08E3,08E4,08E5,08E6,08E7,08E^,08F*,0900,0901,0902,0904,0905,0906,0907,090^,091*,092*,093_,0938,0939,093A,093C,093D,0941,0942,0943,0944,0945,0946,0947,0948,094D,095*,0960,0961,0962,0963,0966,0967,096^,0971,0972,0973,0974,0975,0976,0977,097^,0980,0981,0985,0986,0987,0988,0989,098A,098B,098C,098F,0990,0993,0994,0995,0996,0997,099^,09A_,09A8,09AA,09AB,09AC,09AD,09AE,09AF,09B0,09B2,09B6,09B7,09B8,09B9,09BC,09BD,09C1,09C2,09C3,09C4,09CD,09CE,09DC,09DD,09DF,09E0,09E1,09E2,09E3,09E6,09E7,09E^,09F0,09F1,09FC,09FE,0A01,0A02,0A05,0A06,0A07,0A08,0A09,0A0A,0A0F,0A10,0A13,0A14,0A15,0A16,0A17,0A1^,0A2_,0A28,0A2A,0A2B,0A2C,0A2D,0A2E,0A2F,0A30,0A32,0A33,0A35,0A36,0A38,0A39,0A3C,0A41,0A42,0A47,0A48,0A4B,0A4C,0A4D,0A51,0A59,0A5A,0A5B,0A5C,0A5E,0A66,0A67,0A6^,0A70,0A71,0A72,0A73,0A74,0A75,0A81,0A82,0A85,0A86,0A87,0A88,0A89,0A8A,0A8B,0A8C,0A8D,0A8F,0A90,0A91,0A93,0A94,0A95,0A96,0A97,0A9^,0AA_,0AA8,0AAA,0AAB,0AAC,0AAD,0AAE,0AAF,0AB0,0AB2,0AB3,0AB5,0AB6,0AB7,0AB8,0AB9,0ABC,0ABD,0AC1,0AC2,0AC3,0AC4,0AC5,0AC7,0AC8,0ACD,0AD0,0AE0,0AE1,0AE2,0AE3,0AE6,0AE7,0AE^,0AF9,0AFA,0AFB,0AFC,0AFD,0AFE,0AFF,0B01,0B05,0B06,0B07,0B08,0B09,0B0A,0B0B,0B0C,0B0F,0B10,0B13,0B14,0B15,0B16,0B17,0B1^,0B2_,0B28,0B2A,0B2B,0B2C,0B2D,0B2E,0B2F,0B30,0B32,0B33,0B35,0B36,0B37,0B38,0B39,0B3C,0B3D,0B3F,0B41,0B42,0B43,0B44,0B4D,0B55,0B56,0B5C,0B5D,0B5F,0B60,0B61,0B62,0B63,0B66,0B67,0B6^,0B71,0B82,0B83,0B85,0B86,0B87,0B88,0B89,0B8A,0B8E,0B8F,0B90,0B92,0B93,0B94,0B95,0B99,0B9A,0B9C,0B9E,0B9F,0BA3,0BA4,0BA8,0BA9,0BAA,0BAE,0BAF,0BB_,0BB8,0BB9,0BC0,0BCD,0BD0,0BE6,0BE7,0BE^,0C00,0C04,0C05,0C06,0C07,0C08,0C09,0C0A,0C0B,0C0C,0C0E,0C0F,0C10,0C12,0C13,0C14,0C15,0C16,0C17,0C1^,0C2_,0C28,0C2A,0C2B,0C2C,0C2D,0C2E,0C2F,0C3_,0C38,0C39,0C3C,0C3D,0C3E,0C3F,0C40,0C46,0C47,0C48,0C4A,0C4B,0C4C,0C4D,0C55,0C56,0C58,0C59,0C5A,0C5D,0C60,0C61,0C62,0C63,0C66,0C67,0C6^,0C80,0C81,0C85,0C86,0C87,0C88,0C89,0C8A,0C8B,0C8C,0C8E,0C8F,0C90,0C92,0C93,0C94,0C95,0C96,0C97,0C9^,0CA_,0CA8,0CAA,0CAB,0CAC,0CAD,0CAE,0CAF,0CB0,0CB1,0CB2,0CB3,0CB5,0CB6,0CB7,0CB8,0CB9,0CBC,0CBD,0CBF,0CC6,0CCC,0CCD,0CDD,0CDE,0CE0,0CE1,0CE2,0CE3,0CE6,0CE7,0CE^,0CF1,0CF2,0D00,0D01,0D04,0D05,0D06,0D07,0D08,0D09,0D0A,0D0B,0D0C,0D0E,0D0F,0D10,0D12,0D13,0D14,0D15,0D16,0D17,0D1^,0D2*,0D3_,0D38,0D39,0D3A,0D3B,0D3C,0D3D,0D41,0D42,0D43,0D44,0D4D,0D4E,0D54,0D55,0D56,0D5F,0D60,0D61,0D62,0D63,0D66,0D67,0D6^,0D7A,0D7B,0D7C,0D7D,0D7E,0D7F,0D81,0D85,0D86,0D87,0D8^,0D90,0D91,0D92,0D93,0D94,0D95,0D96,0D9A,0D9B,0D9C,0D9D,0D9E,0D9F,0DA*,0DB0,0DB1,0DB3,0DB4,0DB5,0DB6,0DB7,0DB8,0DB9,0DBA,0DBB,0DBD,0DC0,0DC1,0DC2,0DC3,0DC4,0DC5,0DC6,0DCA,0DD2,0DD3,0DD4,0DD6,0DE6,0DE7,0DE^,0E01,0E02,0E03,0E04,0E05,0E06,0E07,0E0^,0E1*,0E2*,0E3_,0E38,0E39,0E3A,0E4_,0E48,0E49,0E4A,0E4B,0E4C,0E4D,0E4E,0E5_,0E58,0E59,0E81,0E82,0E84,0E86,0E87,0E88,0E89,0E8A,0E8C,0E8D,0E8E,0E8F,0E9*,0EA0,0EA1,0EA2,0EA3,0EA5,0EA7,0EA^,0EB_,0EB8,0EB9,0EBA,0EBB,0EBC,0EBD,0EC0,0EC1,0EC2,0EC3,0EC4,0EC6,0EC8,0EC9,0ECA,0ECB,0ECC,0ECD,0ED_,0ED8,0ED9,0EDC,0EDD,0EDE,0EDF,0F00,0F18,0F19,0F2_,0F28,0F29,0F35,0F37,0F39,0F4_,0F49,0F4A,0F4B,0F4C,0F4D,0F4E,0F4F,0F5*,0F6_,0F68,0F69,0F6A,0F6B,0F6C,0F71,0F72,0F73,0F74,0F75,0F76,0F77,0F78,0F79,0F7A,0F7B,0F7C,0F7D,0F7E,0F80,0F81,0F82,0F83,0F84,0F86,0F87,0F8^,0F9_,0F99,0F9A,0F9B,0F9C,0F9D,0F9E,0F9F,0FA*,0FB_,0FB8,0FB9,0FBA,0FBB,0FBC,0FC6,100*,101*,102_,1028,1029,102A,102D,102E,102F,1030,1032,1033,1034,1035,1036,1037,1039,103A,103D,103E,103F,104_,1048,1049,1050,1051,1052,1053,1054,1055,105^,1060,1061,1065,1066,106E,106F,107*,1080,1081,1082,1085,1086,108D,108E,109_,1098,1099,109D,10A*,10B*,10C0,10C1,10C2,10C3,10C4,10C5,10C7,10CD,10D*,10E*,10F_,10F8,10F9,10FA,10FC,10FD,10FE,10FF,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124_,1248,124A,124B,124C,124D,1250,1251,1252,1253,1254,1255,1256,1258,125A,125B,125C,125D,126*,127*,128_,1288,128A,128B,128C,128D,129*,12A*,12B0,12B2,12B3,12B4,12B5,12B8,12B9,12BA,12BB,12BC,12BD,12BE,12C0,12C2,12C3,12C4,12C5,12C^,12D0,12D1,12D2,12D3,12D4,12D5,12D6,12D^,12E*,12F*,130*,1310,1312,1313,1314,1315,131^,132*,133*,134*,135_,1358,1359,135A,135D,135E,135F,138*,13A*,13B*,13C*,13D*,13E*,13F0,13F1,13F2,13F3,13F4,13F5,13F8,13F9,13FA,13FB,13FC,13FD,1401,1402,1403,1404,1405,1406,1407,140^,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166_,1668,1669,166A,166B,166C,166F,167*,1681,1682,1683,1684,1685,1686,1687,168^,169_,1698,1699,169A,16A*,16B*,16C*,16D*,16E_,16E8,16E9,16EA,16F1,16F2,16F3,16F4,16F5,16F6,16F7,16F8,170*,1710,1711,1712,1713,1714,171F,172*,1730,1731,1732,1733,174*,1750,1751,1752,1753,176_,1768,1769,176A,176B,176C,176E,176F,1770,1772,1773,178*,179*,17A*,17B0,17B1,17B2,17B3,17B4,17B5,17B7,17B8,17B9,17BA,17BB,17BC,17BD,17C6,17C9,17CA,17CB,17CC,17CD,17CE,17CF,17D0,17D1,17D2,17D3,17D7,17DC,17DD,17E_,17E8,17E9,180B,180C,180D,180F,181_,1818,1819,182*,183*,184*,185*,186*,187_,1878,188*,189*,18A_,18A8,18A9,18AA,18B*,18C*,18D*,18E*,18F0,18F1,18F2,18F3,18F4,18F5,190*,191_,1918,1919,191A,191B,191C,191D,191E,1920,1921,1922,1927,1928,1932,1939,193A,193B,1946,1947,194^,195*,196_,1968,1969,196A,196B,196C,196D,1970,1971,1972,1973,1974,198*,199*,19A_,19A8,19A9,19AA,19AB,19B*,19C_,19C8,19C9,19D_,19D8,19D9,1A0*,1A1_,1A18,1A1B,1A2*,1A3*,1A4*,1A50,1A51,1A52,1A53,1A54,1A56,1A58,1A59,1A5A,1A5B,1A5C,1A5D,1A5E,1A60,1A62,1A65,1A66,1A67,1A68,1A69,1A6A,1A6B,1A6C,1A73,1A74,1A75,1A76,1A77,1A78,1A79,1A7A,1A7B,1A7C,1A7F,1A8_,1A88,1A89,1A9_,1A98,1A99,1AA7,1AB_,1AB8,1AB9,1ABA,1ABB,1ABC,1ABD,1ABF,1AC_,1AC8,1AC9,1ACA,1ACB,1ACC,1ACD,1ACE,1B00,1B01,1B02,1B03,1B05,1B06,1B07,1B0^,1B1*,1B2*,1B30,1B31,1B32,1B33,1B34,1B36,1B37,1B38,1B39,1B3A,1B3C,1B42,1B45,1B46,1B47,1B48,1B49,1B4A,1B4B,1B4C,1B5_,1B58,1B59,1B6B,1B6C,1B6D,1B6E,1B6F,1B70,1B71,1B72,1B73,1B80,1B81,1B83,1B84,1B85,1B86,1B87,1B8^,1B9*,1BA0,1BA2,1BA3,1BA4,1BA5,1BA8,1BA9,1BAB,1BAC,1BAD,1BAE,1BAF,1BB*,1BC*,1BD*,1BE0,1BE1,1BE2,1BE3,1BE4,1BE5,1BE6,1BE8,1BE9,1BED,1BEF,1BF0,1BF1,1C0*,1C1*,1C20,1C21,1C22,1C23,1C2C,1C2D,1C2E,1C2F,1C30,1C31,1C32,1C33,1C36,1C37,1C4_,1C48,1C49,1C4D,1C4E,1C4F,1C5*,1C6*,1C7_,1C78,1C79,1C7A,1C7B,1C7C,1C7D,1C8_,1C88,1C9*,1CA*,1CB_,1CB8,1CB9,1CBA,1CBD,1CBE,1CBF,1CD0,1CD1,1CD2,1CD4,1CD5,1CD6,1CD7,1CD^,1CE0,1CE2,1CE3,1CE4,1CE5,1CE6,1CE7,1CE^,1CF0,1CF1,1CF2,1CF3,1CF4,1CF5,1CF6,1CF8,1CF9,1CFA,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F10,1F11,1F12,1F13,1F14,1F15,1F18,1F19,1F1A,1F1B,1F1C,1F1D,1F2*,1F3*,1F40,1F41,1F42,1F43,1F44,1F45,1F48,1F49,1F4A,1F4B,1F4C,1F4D,1F5_,1F59,1F5B,1F5D,1F5F,1F6*,1F7_,1F78,1F79,1F7A,1F7B,1F7C,1F7D,1F8*,1F9*,1FA*,1FB0,1FB1,1FB2,1FB3,1FB4,1FB6,1FB7,1FB8,1FB9,1FBA,1FBB,1FBC,1FBE,1FC2,1FC3,1FC4,1FC6,1FC7,1FC8,1FC9,1FCA,1FCB,1FCC,1FD0,1FD1,1FD2,1FD3,1FD6,1FD7,1FD8,1FD9,1FDA,1FDB,1FE_,1FE8,1FE9,1FEA,1FEB,1FEC,1FF2,1FF3,1FF4,1FF6,1FF7,1FF8,1FF9,1FFA,1FFB,1FFC,203F,2040,2054,2071,207F,209_,2098,2099,209A,209B,209C,20D_,20D8,20D9,20DA,20DB,20DC,20E1,20E5,20E6,20E7,20E^,20F0,2102,2107,210A,210B,210C,210D,210E,210F,2110,2111,2112,2113,2115,2119,211A,211B,211C,211D,2124,2126,2128,212A,212B,212C,212D,212F,213_,2138,2139,213C,213D,213E,213F,2145,2146,2147,2148,2149,214E,2183,2184,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE0,2CE1,2CE2,2CE3,2CE4,2CEB,2CEC,2CED,2CEE,2CEF,2CF0,2CF1,2CF2,2CF3,2D0*,2D1*,2D20,2D21,2D22,2D23,2D24,2D25,2D27,2D2D,2D3*,2D4*,2D5*,2D6_,2D6F,2D7F,2D8*,2D90,2D91,2D92,2D93,2D94,2D95,2D96,2DA0,2DA1,2DA2,2DA3,2DA4,2DA5,2DA6,2DA8,2DA9,2DAA,2DAB,2DAC,2DAD,2DAE,2DB0,2DB1,2DB2,2DB3,2DB4,2DB5,2DB6,2DB8,2DB9,2DBA,2DBB,2DBC,2DBD,2DBE,2DC0,2DC1,2DC2,2DC3,2DC4,2DC5,2DC6,2DC8,2DC9,2DCA,2DCB,2DCC,2DCD,2DCE,2DD0,2DD1,2DD2,2DD3,2DD4,2DD5,2DD6,2DD8,2DD9,2DDA,2DDB,2DDC,2DDD,2DDE,2DE*,2DF*,2E2F,3005,3006,302A,302B,302C,302D,3031,3032,3033,3034,3035,303B,303C,3041,3042,3043,3044,3045,3046,3047,304^,305*,306*,307*,308*,3090,3091,3092,3093,3094,3095,3096,3099,309A,309D,309E,309F,30A1,30A2,30A3,30A4,30A5,30A6,30A7,30A^,30B*,30C*,30D*,30E*,30F_,30F8,30F9,30FA,30FC,30FD,30FE,30FF,3105,3106,3107,310^,311*,312*,3131,3132,3133,3134,3135,3136,3137,313^,314*,315*,316*,317*,318_,3188,3189,318A,318B,318C,318D,318E,31A*,31B*,31F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\W" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003A,003B,003C,003D,003E,003F,0040,005B,005C,005D,005E,0060,007B,007C,007D,007E,007F,008*,009*,00A_,00A8,00A9,00AB,00AC,00AD,00AE,00AF,00B0,00B1,00B2,00B3,00B4,00B6,00B7,00B8,00B9,00BB,00BC,00BD,00BE,00BF,00D7,00F7,02C2,02C3,02C4,02C5,02D2,02D3,02D4,02D5,02D6,02D7,02D^,02E5,02E6,02E7,02E8,02E9,02EA,02EB,02ED,02EF,02F*,0375,0378,0379,037E,0380,0381,0382,0383,0384,0385,0387,038B,038D,03A2,03F6,0482,0488,0489,0530,0557,0558,055A,055B,055C,055D,055E,055F,0589,058A,058B,058C,058D,058E,058F,0590,05BE,05C0,05C3,05C6,05C^,05EB,05EC,05ED,05EE,05F3,05F4,05F5,05F6,05F7,05F^,060*,061B,061C,061D,061E,061F,066A,066B,066C,066D,06D4,06DD,06DE,06E9,06FD,06FE,070*,074B,074C,07B2,07B3,07B4,07B5,07B6,07B7,07B^,07F6,07F7,07F8,07F9,07FB,07FC,07FE,07FF,082E,082F,083*,085C,085D,085E,085F,086B,086C,086D,086E,086F,0888,088F,089_,08E2,0903,093B,093E,093F,0940,0949,094A,094B,094C,094E,094F,0964,0965,0970,0982,0983,0984,098D,098E,0991,0992,09A9,09B1,09B3,09B4,09B5,09BA,09BB,09BE,09BF,09C0,09C5,09C6,09C7,09C8,09C9,09CA,09CB,09CC,09CF,09D_,09D8,09D9,09DA,09DB,09DE,09E4,09E5,09F2,09F3,09F4,09F5,09F6,09F7,09F8,09F9,09FA,09FB,09FD,09FF,0A00,0A03,0A04,0A0B,0A0C,0A0D,0A0E,0A11,0A12,0A29,0A31,0A34,0A37,0A3A,0A3B,0A3D,0A3E,0A3F,0A40,0A43,0A44,0A45,0A46,0A49,0A4A,0A4E,0A4F,0A50,0A52,0A53,0A54,0A55,0A56,0A57,0A58,0A5D,0A5F,0A60,0A61,0A62,0A63,0A64,0A65,0A76,0A77,0A7^,0A80,0A83,0A84,0A8E,0A92,0AA9,0AB1,0AB4,0ABA,0ABB,0ABE,0ABF,0AC0,0AC6,0AC9,0ACA,0ACB,0ACC,0ACE,0ACF,0AD1,0AD2,0AD3,0AD4,0AD5,0AD6,0AD7,0AD^,0AE4,0AE5,0AF_,0AF8,0B00,0B02,0B03,0B04,0B0D,0B0E,0B11,0B12,0B29,0B31,0B34,0B3A,0B3B,0B3E,0B40,0B45,0B46,0B47,0B48,0B49,0B4A,0B4B,0B4C,0B4E,0B4F,0B50,0B51,0B52,0B53,0B54,0B57,0B58,0B59,0B5A,0B5B,0B5E,0B64,0B65,0B70,0B72,0B73,0B74,0B75,0B76,0B77,0B7^,0B80,0B81,0B84,0B8B,0B8C,0B8D,0B91,0B96,0B97,0B98,0B9B,0B9D,0BA0,0BA1,0BA2,0BA5,0BA6,0BA7,0BAB,0BAC,0BAD,0BBA,0BBB,0BBC,0BBD,0BBE,0BBF,0BC1,0BC2,0BC3,0BC4,0BC5,0BC6,0BC7,0BC8,0BC9,0BCA,0BCB,0BCC,0BCE,0BCF,0BD1,0BD2,0BD3,0BD4,0BD5,0BD6,0BD7,0BD^,0BE0,0BE1,0BE2,0BE3,0BE4,0BE5,0BF*,0C01,0C02,0C03,0C0D,0C11,0C29,0C3A,0C3B,0C41,0C42,0C43,0C44,0C45,0C49,0C4E,0C4F,0C50,0C51,0C52,0C53,0C54,0C57,0C5B,0C5C,0C5E,0C5F,0C64,0C65,0C7*,0C82,0C83,0C84,0C8D,0C91,0CA9,0CB4,0CBA,0CBB,0CBE,0CC0,0CC1,0CC2,0CC3,0CC4,0CC5,0CC7,0CC8,0CC9,0CCA,0CCB,0CCE,0CCF,0CD_,0CD8,0CD9,0CDA,0CDB,0CDC,0CDF,0CE4,0CE5,0CF0,0CF3,0CF4,0CF5,0CF6,0CF7,0CF^,0D02,0D03,0D0D,0D11,0D3E,0D3F,0D40,0D45,0D46,0D47,0D48,0D49,0D4A,0D4B,0D4C,0D4F,0D50,0D51,0D52,0D53,0D57,0D58,0D59,0D5A,0D5B,0D5C,0D5D,0D5E,0D64,0D65,0D7_,0D78,0D79,0D80,0D82,0D83,0D84,0D97,0D98,0D99,0DB2,0DBC,0DBE,0DBF,0DC7,0DC8,0DC9,0DCB,0DCC,0DCD,0DCE,0DCF,0DD0,0DD1,0DD5,0DD7,0DD^,0DE0,0DE1,0DE2,0DE3,0DE4,0DE5,0DF*,0E00,0E3B,0E3C,0E3D,0E3E,0E3F,0E4F,0E5A,0E5B,0E5C,0E5D,0E5E,0E5F,0E6*,0E7*,0E80,0E83,0E85,0E8B,0EA4,0EA6,0EBE,0EBF,0EC5,0EC7,0ECE,0ECF,0EDA,0EDB,0EE*,0EF*,0F01,0F02,0F03,0F04,0F05,0F06,0F07,0F0^,0F1_,0F1A,0F1B,0F1C,0F1D,0F1E,0F1F,0F2A,0F2B,0F2C,0F2D,0F2E,0F2F,0F30,0F31,0F32,0F33,0F34,0F36,0F38,0F3A,0F3B,0F3C,0F3D,0F3E,0F3F,0F48,0F6D,0F6E,0F6F,0F70,0F7F,0F85,0F98,0FBD,0FBE,0FBF,0FC0,0FC1,0FC2,0FC3,0FC4,0FC5,0FC7,0FC^,0FD*,0FE*,0FF*,102B,102C,1031,1038,103B,103C,104A,104B,104C,104D,104E,104F,1056,1057,1062,1063,1064,1067,1068,1069,106A,106B,106C,106D,1083,1084,1087,1088,1089,108A,108B,108C,108F,109A,109B,109C,109E,109F,10C6,10C8,10C9,10CA,10CB,10CC,10CE,10CF,10FB,1249,124E,124F,1257,1259,125E,125F,1289,128E,128F,12B1,12B6,12B7,12BF,12C1,12C6,12C7,12D7,1311,1316,1317,135B,135C,136*,137*,139*,13F6,13F7,13FE,13FF,1400,166D,166E,1680,169B,169C,169D,169E,169F,16EB,16EC,16ED,16EE,16EF,16F0,16F9,16FA,16FB,16FC,16FD,16FE,16FF,1715,1716,1717,1718,1719,171A,171B,171C,171D,171E,1734,1735,1736,1737,173^,1754,1755,1756,1757,175^,176D,1771,1774,1775,1776,1777,177^,17B6,17BE,17BF,17C0,17C1,17C2,17C3,17C4,17C5,17C7,17C8,17D4,17D5,17D6,17D8,17D9,17DA,17DB,17DE,17DF,17EA,17EB,17EC,17ED,17EE,17EF,17F*,180_,1808,1809,180A,180E,181A,181B,181C,181D,181E,181F,1879,187A,187B,187C,187D,187E,187F,18AB,18AC,18AD,18AE,18AF,18F6,18F7,18F^,191F,1923,1924,1925,1926,1929,192A,192B,192C,192D,192E,192F,1930,1931,1933,1934,1935,1936,1937,1938,193C,193D,193E,193F,1940,1941,1942,1943,1944,1945,196E,196F,1975,1976,1977,197^,19AC,19AD,19AE,19AF,19CA,19CB,19CC,19CD,19CE,19CF,19DA,19DB,19DC,19DD,19DE,19DF,19E*,19F*,1A19,1A1A,1A1C,1A1D,1A1E,1A1F,1A55,1A57,1A5F,1A61,1A63,1A64,1A6D,1A6E,1A6F,1A70,1A71,1A72,1A7D,1A7E,1A8A,1A8B,1A8C,1A8D,1A8E,1A8F,1A9A,1A9B,1A9C,1A9D,1A9E,1A9F,1AA0,1AA1,1AA2,1AA3,1AA4,1AA5,1AA6,1AA^,1ABE,1ACF,1AD*,1AE*,1AF*,1B04,1B35,1B3B,1B3D,1B3E,1B3F,1B40,1B41,1B43,1B44,1B4D,1B4E,1B4F,1B5A,1B5B,1B5C,1B5D,1B5E,1B5F,1B6_,1B68,1B69,1B6A,1B74,1B75,1B76,1B77,1B7^,1B82,1BA1,1BA6,1BA7,1BAA,1BE7,1BEA,1BEB,1BEC,1BEE,1BF2,1BF3,1BF4,1BF5,1BF6,1BF7,1BF^,1C24,1C25,1C26,1C27,1C28,1C29,1C2A,1C2B,1C34,1C35,1C3^,1C4A,1C4B,1C4C,1C7E,1C7F,1C89,1C8A,1C8B,1C8C,1C8D,1C8E,1C8F,1CBB,1CBC,1CC*,1CD3,1CE1,1CF7,1CFB,1CFC,1CFD,1CFE,1CFF,1F16,1F17,1F1E,1F1F,1F46,1F47,1F4E,1F4F,1F58,1F5A,1F5C,1F5E,1F7E,1F7F,1FB5,1FBD,1FBF,1FC0,1FC1,1FC5,1FCD,1FCE,1FCF,1FD4,1FD5,1FDC,1FDD,1FDE,1FDF,1FED,1FEE,1FEF,1FF0,1FF1,1FF5,1FFD,1FFE,1FFF,200*,201*,202*,203_,2038,2039,203A,203B,203C,203D,203E,2041,2042,2043,2044,2045,2046,2047,204^,2050,2051,2052,2053,2055,2056,2057,205^,206*,2070,2072,2073,2074,2075,2076,2077,2078,2079,207A,207B,207C,207D,207E,208*,209D,209E,209F,20A*,20B*,20C*,20DD,20DE,20DF,20E0,20E2,20E3,20E4,20F1,20F2,20F3,20F4,20F5,20F6,20F7,20F^,2100,2101,2103,2104,2105,2106,2108,2109,2114,2116,2117,2118,211E,211F,2120,2121,2122,2123,2125,2127,2129,212E,213A,213B,2140,2141,2142,2143,2144,214A,214B,214C,214D,214F,215*,216*,217*,2180,2181,2182,2185,2186,2187,218^,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2CE5,2CE6,2CE7,2CE8,2CE9,2CEA,2CF4,2CF5,2CF6,2CF7,2CF^,2D26,2D28,2D29,2D2A,2D2B,2D2C,2D2E,2D2F,2D68,2D69,2D6A,2D6B,2D6C,2D6D,2D6E,2D7_,2D78,2D79,2D7A,2D7B,2D7C,2D7D,2D7E,2D97,2D9^,2DA7,2DAF,2DB7,2DBF,2DC7,2DCF,2DD7,2DDF,2E0*,2E1*,2E2_,2E28,2E29,2E2A,2E2B,2E2C,2E2D,2E2E,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,3000,3001,3002,3003,3004,3007,300^,301*,302_,3028,3029,302E,302F,3030,3036,3037,3038,3039,303A,303D,303E,303F,3040,3097,3098,309B,309C,30A0,30FB,3100,3101,3102,3103,3104,3130,318F,319*,31C*,31D*,31E*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*," - -// d ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\d" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"003_,0038,0039,066_,0668,0669,06F_,06F8,06F9,07C_,07C8,07C9,0966,0967,096^,09E6,09E7,09E^,0A66,0A67,0A6^,0AE6,0AE7,0AE^,0B66,0B67,0B6^,0BE6,0BE7,0BE^,0C66,0C67,0C6^,0CE6,0CE7,0CE^,0D66,0D67,0D6^,0DE6,0DE7,0DE^,0E5_,0E58,0E59,0ED_,0ED8,0ED9,0F2_,0F28,0F29,104_,1048,1049,109_,1098,1099,17E_,17E8,17E9,181_,1818,1819,1946,1947,194^,19D_,19D8,19D9,1A8_,1A88,1A89,1A9_,1A98,1A99,1B5_,1B58,1B59,1BB_,1BB8,1BB9,1C4_,1C48,1C49,1C5_,1C58,1C59," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\D" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003A,003B,003C,003D,003E,003F,004*,005*,006*,007*,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066A,066B,066C,066D,066E,066F,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06FA,06FB,06FC,06FD,06FE,06FF,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07CA,07CB,07CC,07CD,07CE,07CF,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,0960,0961,0962,0963,0964,0965,097*,098*,099*,09A*,09B*,09C*,09D*,09E0,09E1,09E2,09E3,09E4,09E5,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A60,0A61,0A62,0A63,0A64,0A65,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE0,0AE1,0AE2,0AE3,0AE4,0AE5,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B60,0B61,0B62,0B63,0B64,0B65,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE0,0BE1,0BE2,0BE3,0BE4,0BE5,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C60,0C61,0C62,0C63,0C64,0C65,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE0,0CE1,0CE2,0CE3,0CE4,0CE5,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D60,0D61,0D62,0D63,0D64,0D65,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE0,0DE1,0DE2,0DE3,0DE4,0DE5,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5A,0E5B,0E5C,0E5D,0E5E,0E5F,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0EDA,0EDB,0EDC,0EDD,0EDE,0EDF,0EE*,0EF*,0F0*,0F1*,0F2A,0F2B,0F2C,0F2D,0F2E,0F2F,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104A,104B,104C,104D,104E,104F,105*,106*,107*,108*,109A,109B,109C,109D,109E,109F,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17EA,17EB,17EC,17ED,17EE,17EF,17F*,180*,181A,181B,181C,181D,181E,181F,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,1940,1941,1942,1943,1944,1945,195*,196*,197*,198*,199*,19A*,19B*,19C*,19DA,19DB,19DC,19DD,19DE,19DF,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8A,1A8B,1A8C,1A8D,1A8E,1A8F,1A9A,1A9B,1A9C,1A9D,1A9E,1A9F,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5A,1B5B,1B5C,1B5D,1B5E,1B5F,1B6*,1B7*,1B8*,1B9*,1BA*,1BBA,1BBB,1BBC,1BBD,1BBE,1BBF,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4A,1C4B,1C4C,1C4D,1C4E,1C4F,1C5A,1C5B,1C5C,1C5D,1C5E,1C5F,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// s -// PCRE2 uses an older version of Unicode where \u180e is in the space category. This is corrected for in LibraryRegEx_PCRE2 for testing comparisons. ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\s" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0009,000A,000B,000C,000D,0020,0085,00A0,1680,200_,2008,2009,200A,2028,2029,202F,205F,3000," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\S" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,0008,000E,000F,001*,0021,0022,0023,0024,0025,0026,0027,002^,003*,004*,005*,006*,007*,0080,0081,0082,0083,0084,0086,0087,008^,009*,00A1,00A2,00A3,00A4,00A5,00A6,00A7,00A^,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,1681,1682,1683,1684,1685,1686,1687,168^,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200B,200C,200D,200E,200F,201*,202_,202A,202B,202C,202D,202E,203*,204*,205_,2058,2059,205A,205B,205C,205D,205E,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,3001,3002,3003,3004,3005,3006,3007,300^,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// L ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{L}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0041,0042,0043,0044,0045,0046,0047,004^,005_,0058,0059,005A,0061,0062,0063,0064,0065,0066,0067,006^,007_,0078,0079,007A,00AA,00B5,00BA,00C*,00D0,00D1,00D2,00D3,00D4,00D5,00D6,00D^,00E*,00F0,00F1,00F2,00F3,00F4,00F5,00F6,00F^,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C0,02C1,02C6,02C7,02C^,02D0,02D1,02E0,02E1,02E2,02E3,02E4,02EC,02EE,0370,0371,0372,0373,0374,0376,0377,037A,037B,037C,037D,037F,0386,0388,0389,038A,038C,038E,038F,039*,03A0,03A1,03A3,03A4,03A5,03A6,03A7,03A^,03B*,03C*,03D*,03E*,03F0,03F1,03F2,03F3,03F4,03F5,03F7,03F^,040*,041*,042*,043*,044*,045*,046*,047*,0480,0481,048A,048B,048C,048D,048E,048F,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,0531,0532,0533,0534,0535,0536,0537,053^,054*,0550,0551,0552,0553,0554,0555,0556,0559,056*,057*,058_,0588,05D*,05E_,05E8,05E9,05EA,05EF,05F0,05F1,05F2,062*,063*,064_,0648,0649,064A,066E,066F,0671,0672,0673,0674,0675,0676,0677,067^,068*,069*,06A*,06B*,06C*,06D0,06D1,06D2,06D3,06D5,06E5,06E6,06EE,06EF,06FA,06FB,06FC,06FF,0710,0712,0713,0714,0715,0716,0717,071^,072*,074D,074E,074F,075*,076*,077*,078*,079*,07A0,07A1,07A2,07A3,07A4,07A5,07B1,07CA,07CB,07CC,07CD,07CE,07CF,07D*,07E_,07E8,07E9,07EA,07F4,07F5,07FA,080*,0810,0811,0812,0813,0814,0815,081A,0824,0828,084*,085_,0858,086_,0868,0869,086A,087*,088_,0889,088A,088B,088C,088D,088E,08A*,08B*,08C_,08C8,08C9,0904,0905,0906,0907,090^,091*,092*,093_,0938,0939,093D,0950,095^,0960,0961,0971,0972,0973,0974,0975,0976,0977,097^,0980,0985,0986,0987,0988,0989,098A,098B,098C,098F,0990,0993,0994,0995,0996,0997,099^,09A_,09A8,09AA,09AB,09AC,09AD,09AE,09AF,09B0,09B2,09B6,09B7,09B8,09B9,09BD,09CE,09DC,09DD,09DF,09E0,09E1,09F0,09F1,09FC,0A05,0A06,0A07,0A08,0A09,0A0A,0A0F,0A10,0A13,0A14,0A15,0A16,0A17,0A1^,0A2_,0A28,0A2A,0A2B,0A2C,0A2D,0A2E,0A2F,0A30,0A32,0A33,0A35,0A36,0A38,0A39,0A59,0A5A,0A5B,0A5C,0A5E,0A72,0A73,0A74,0A85,0A86,0A87,0A88,0A89,0A8A,0A8B,0A8C,0A8D,0A8F,0A90,0A91,0A93,0A94,0A95,0A96,0A97,0A9^,0AA_,0AA8,0AAA,0AAB,0AAC,0AAD,0AAE,0AAF,0AB0,0AB2,0AB3,0AB5,0AB6,0AB7,0AB8,0AB9,0ABD,0AD0,0AE0,0AE1,0AF9,0B05,0B06,0B07,0B08,0B09,0B0A,0B0B,0B0C,0B0F,0B10,0B13,0B14,0B15,0B16,0B17,0B1^,0B2_,0B28,0B2A,0B2B,0B2C,0B2D,0B2E,0B2F,0B30,0B32,0B33,0B35,0B36,0B37,0B38,0B39,0B3D,0B5C,0B5D,0B5F,0B60,0B61,0B71,0B83,0B85,0B86,0B87,0B88,0B89,0B8A,0B8E,0B8F,0B90,0B92,0B93,0B94,0B95,0B99,0B9A,0B9C,0B9E,0B9F,0BA3,0BA4,0BA8,0BA9,0BAA,0BAE,0BAF,0BB_,0BB8,0BB9,0BD0,0C05,0C06,0C07,0C08,0C09,0C0A,0C0B,0C0C,0C0E,0C0F,0C10,0C12,0C13,0C14,0C15,0C16,0C17,0C1^,0C2_,0C28,0C2A,0C2B,0C2C,0C2D,0C2E,0C2F,0C3_,0C38,0C39,0C3D,0C58,0C59,0C5A,0C5D,0C60,0C61,0C80,0C85,0C86,0C87,0C88,0C89,0C8A,0C8B,0C8C,0C8E,0C8F,0C90,0C92,0C93,0C94,0C95,0C96,0C97,0C9^,0CA_,0CA8,0CAA,0CAB,0CAC,0CAD,0CAE,0CAF,0CB0,0CB1,0CB2,0CB3,0CB5,0CB6,0CB7,0CB8,0CB9,0CBD,0CDD,0CDE,0CE0,0CE1,0CF1,0CF2,0D04,0D05,0D06,0D07,0D08,0D09,0D0A,0D0B,0D0C,0D0E,0D0F,0D10,0D12,0D13,0D14,0D15,0D16,0D17,0D1^,0D2*,0D3_,0D38,0D39,0D3A,0D3D,0D4E,0D54,0D55,0D56,0D5F,0D60,0D61,0D7A,0D7B,0D7C,0D7D,0D7E,0D7F,0D85,0D86,0D87,0D8^,0D90,0D91,0D92,0D93,0D94,0D95,0D96,0D9A,0D9B,0D9C,0D9D,0D9E,0D9F,0DA*,0DB0,0DB1,0DB3,0DB4,0DB5,0DB6,0DB7,0DB8,0DB9,0DBA,0DBB,0DBD,0DC0,0DC1,0DC2,0DC3,0DC4,0DC5,0DC6,0E01,0E02,0E03,0E04,0E05,0E06,0E07,0E0^,0E1*,0E2*,0E30,0E32,0E33,0E40,0E41,0E42,0E43,0E44,0E45,0E46,0E81,0E82,0E84,0E86,0E87,0E88,0E89,0E8A,0E8C,0E8D,0E8E,0E8F,0E9*,0EA0,0EA1,0EA2,0EA3,0EA5,0EA7,0EA^,0EB0,0EB2,0EB3,0EBD,0EC0,0EC1,0EC2,0EC3,0EC4,0EC6,0EDC,0EDD,0EDE,0EDF,0F00,0F4_,0F49,0F4A,0F4B,0F4C,0F4D,0F4E,0F4F,0F5*,0F6_,0F68,0F69,0F6A,0F6B,0F6C,0F88,0F89,0F8A,0F8B,0F8C,100*,101*,102_,1028,1029,102A,103F,1050,1051,1052,1053,1054,1055,105A,105B,105C,105D,1061,1065,1066,106E,106F,1070,1075,1076,1077,107^,1080,1081,108E,10A*,10B*,10C0,10C1,10C2,10C3,10C4,10C5,10C7,10CD,10D*,10E*,10F_,10F8,10F9,10FA,10FC,10FD,10FE,10FF,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124_,1248,124A,124B,124C,124D,1250,1251,1252,1253,1254,1255,1256,1258,125A,125B,125C,125D,126*,127*,128_,1288,128A,128B,128C,128D,129*,12A*,12B0,12B2,12B3,12B4,12B5,12B8,12B9,12BA,12BB,12BC,12BD,12BE,12C0,12C2,12C3,12C4,12C5,12C^,12D0,12D1,12D2,12D3,12D4,12D5,12D6,12D^,12E*,12F*,130*,1310,1312,1313,1314,1315,131^,132*,133*,134*,135_,1358,1359,135A,138*,13A*,13B*,13C*,13D*,13E*,13F0,13F1,13F2,13F3,13F4,13F5,13F8,13F9,13FA,13FB,13FC,13FD,1401,1402,1403,1404,1405,1406,1407,140^,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166_,1668,1669,166A,166B,166C,166F,167*,1681,1682,1683,1684,1685,1686,1687,168^,169_,1698,1699,169A,16A*,16B*,16C*,16D*,16E_,16E8,16E9,16EA,16F1,16F2,16F3,16F4,16F5,16F6,16F7,16F8,170*,1710,1711,171F,172*,1730,1731,174*,1750,1751,176_,1768,1769,176A,176B,176C,176E,176F,1770,178*,179*,17A*,17B0,17B1,17B2,17B3,17D7,17DC,182*,183*,184*,185*,186*,187_,1878,1880,1881,1882,1883,1884,1887,188^,189*,18A_,18A8,18AA,18B*,18C*,18D*,18E*,18F0,18F1,18F2,18F3,18F4,18F5,190*,191_,1918,1919,191A,191B,191C,191D,191E,195*,196_,1968,1969,196A,196B,196C,196D,1970,1971,1972,1973,1974,198*,199*,19A_,19A8,19A9,19AA,19AB,19B*,19C_,19C8,19C9,1A0*,1A10,1A11,1A12,1A13,1A14,1A15,1A16,1A2*,1A3*,1A4*,1A50,1A51,1A52,1A53,1A54,1AA7,1B05,1B06,1B07,1B0^,1B1*,1B2*,1B30,1B31,1B32,1B33,1B45,1B46,1B47,1B48,1B49,1B4A,1B4B,1B4C,1B83,1B84,1B85,1B86,1B87,1B8^,1B9*,1BA0,1BAE,1BAF,1BBA,1BBB,1BBC,1BBD,1BBE,1BBF,1BC*,1BD*,1BE0,1BE1,1BE2,1BE3,1BE4,1BE5,1C0*,1C1*,1C20,1C21,1C22,1C23,1C4D,1C4E,1C4F,1C5A,1C5B,1C5C,1C5D,1C5E,1C5F,1C6*,1C7_,1C78,1C79,1C7A,1C7B,1C7C,1C7D,1C8_,1C88,1C9*,1CA*,1CB_,1CB8,1CB9,1CBA,1CBD,1CBE,1CBF,1CE9,1CEA,1CEB,1CEC,1CEE,1CEF,1CF0,1CF1,1CF2,1CF3,1CF5,1CF6,1CFA,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F10,1F11,1F12,1F13,1F14,1F15,1F18,1F19,1F1A,1F1B,1F1C,1F1D,1F2*,1F3*,1F40,1F41,1F42,1F43,1F44,1F45,1F48,1F49,1F4A,1F4B,1F4C,1F4D,1F5_,1F59,1F5B,1F5D,1F5F,1F6*,1F7_,1F78,1F79,1F7A,1F7B,1F7C,1F7D,1F8*,1F9*,1FA*,1FB0,1FB1,1FB2,1FB3,1FB4,1FB6,1FB7,1FB8,1FB9,1FBA,1FBB,1FBC,1FBE,1FC2,1FC3,1FC4,1FC6,1FC7,1FC8,1FC9,1FCA,1FCB,1FCC,1FD0,1FD1,1FD2,1FD3,1FD6,1FD7,1FD8,1FD9,1FDA,1FDB,1FE_,1FE8,1FE9,1FEA,1FEB,1FEC,1FF2,1FF3,1FF4,1FF6,1FF7,1FF8,1FF9,1FFA,1FFB,1FFC,2071,207F,209_,2098,2099,209A,209B,209C,2102,2107,210A,210B,210C,210D,210E,210F,2110,2111,2112,2113,2115,2119,211A,211B,211C,211D,2124,2126,2128,212A,212B,212C,212D,212F,213_,2138,2139,213C,213D,213E,213F,2145,2146,2147,2148,2149,214E,2183,2184,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE0,2CE1,2CE2,2CE3,2CE4,2CEB,2CEC,2CED,2CEE,2CF2,2CF3,2D0*,2D1*,2D20,2D21,2D22,2D23,2D24,2D25,2D27,2D2D,2D3*,2D4*,2D5*,2D6_,2D6F,2D8*,2D90,2D91,2D92,2D93,2D94,2D95,2D96,2DA0,2DA1,2DA2,2DA3,2DA4,2DA5,2DA6,2DA8,2DA9,2DAA,2DAB,2DAC,2DAD,2DAE,2DB0,2DB1,2DB2,2DB3,2DB4,2DB5,2DB6,2DB8,2DB9,2DBA,2DBB,2DBC,2DBD,2DBE,2DC0,2DC1,2DC2,2DC3,2DC4,2DC5,2DC6,2DC8,2DC9,2DCA,2DCB,2DCC,2DCD,2DCE,2DD0,2DD1,2DD2,2DD3,2DD4,2DD5,2DD6,2DD8,2DD9,2DDA,2DDB,2DDC,2DDD,2DDE,2E2F,3005,3006,3031,3032,3033,3034,3035,303B,303C,3041,3042,3043,3044,3045,3046,3047,304^,305*,306*,307*,308*,3090,3091,3092,3093,3094,3095,3096,309D,309E,309F,30A1,30A2,30A3,30A4,30A5,30A6,30A7,30A^,30B*,30C*,30D*,30E*,30F_,30F8,30F9,30FA,30FC,30FD,30FE,30FF,3105,3106,3107,310^,311*,312*,3131,3132,3133,3134,3135,3136,3137,313^,314*,315*,316*,317*,318_,3188,3189,318A,318B,318C,318D,318E,31A*,31B*,31F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{L}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,0040,005B,005C,005D,005E,005F,0060,007B,007C,007D,007E,007F,008*,009*,00A_,00A8,00A9,00AB,00AC,00AD,00AE,00AF,00B0,00B1,00B2,00B3,00B4,00B6,00B7,00B8,00B9,00BB,00BC,00BD,00BE,00BF,00D7,00F7,02C2,02C3,02C4,02C5,02D2,02D3,02D4,02D5,02D6,02D7,02D^,02E5,02E6,02E7,02E8,02E9,02EA,02EB,02ED,02EF,02F*,030*,031*,032*,033*,034*,035*,036*,0375,0378,0379,037E,0380,0381,0382,0383,0384,0385,0387,038B,038D,03A2,03F6,0482,0483,0484,0485,0486,0487,0488,0489,0530,0557,0558,055A,055B,055C,055D,055E,055F,0589,058A,058B,058C,058D,058E,058F,059*,05A*,05B*,05C*,05EB,05EC,05ED,05EE,05F3,05F4,05F5,05F6,05F7,05F^,060*,061*,064B,064C,064D,064E,064F,065*,066_,0668,0669,066A,066B,066C,066D,0670,06D4,06D6,06D7,06D^,06E0,06E1,06E2,06E3,06E4,06E7,06E8,06E9,06EA,06EB,06EC,06ED,06F_,06F8,06F9,06FD,06FE,070*,0711,073*,074_,0748,0749,074A,074B,074C,07A6,07A7,07A^,07B0,07B2,07B3,07B4,07B5,07B6,07B7,07B^,07C_,07C8,07C9,07EB,07EC,07ED,07EE,07EF,07F0,07F1,07F2,07F3,07F6,07F7,07F8,07F9,07FB,07FC,07FD,07FE,07FF,0816,0817,0818,0819,081B,081C,081D,081E,081F,0820,0821,0822,0823,0825,0826,0827,0829,082A,082B,082C,082D,082E,082F,083*,0859,085A,085B,085C,085D,085E,085F,086B,086C,086D,086E,086F,0888,088F,089*,08CA,08CB,08CC,08CD,08CE,08CF,08D*,08E*,08F*,0900,0901,0902,0903,093A,093B,093C,093E,093F,094*,0951,0952,0953,0954,0955,0956,0957,0962,0963,0964,0965,0966,0967,096^,0970,0981,0982,0983,0984,098D,098E,0991,0992,09A9,09B1,09B3,09B4,09B5,09BA,09BB,09BC,09BE,09BF,09C_,09C8,09C9,09CA,09CB,09CC,09CD,09CF,09D_,09D8,09D9,09DA,09DB,09DE,09E2,09E3,09E4,09E5,09E6,09E7,09E^,09F2,09F3,09F4,09F5,09F6,09F7,09F8,09F9,09FA,09FB,09FD,09FE,09FF,0A00,0A01,0A02,0A03,0A04,0A0B,0A0C,0A0D,0A0E,0A11,0A12,0A29,0A31,0A34,0A37,0A3A,0A3B,0A3C,0A3D,0A3E,0A3F,0A4*,0A5_,0A58,0A5D,0A5F,0A6*,0A70,0A71,0A75,0A76,0A77,0A7^,0A80,0A81,0A82,0A83,0A84,0A8E,0A92,0AA9,0AB1,0AB4,0ABA,0ABB,0ABC,0ABE,0ABF,0AC*,0AD1,0AD2,0AD3,0AD4,0AD5,0AD6,0AD7,0AD^,0AE2,0AE3,0AE4,0AE5,0AE6,0AE7,0AE^,0AF_,0AF8,0AFA,0AFB,0AFC,0AFD,0AFE,0AFF,0B00,0B01,0B02,0B03,0B04,0B0D,0B0E,0B11,0B12,0B29,0B31,0B34,0B3A,0B3B,0B3C,0B3E,0B3F,0B4*,0B5_,0B58,0B59,0B5A,0B5B,0B5E,0B62,0B63,0B64,0B65,0B66,0B67,0B6^,0B70,0B72,0B73,0B74,0B75,0B76,0B77,0B7^,0B80,0B81,0B82,0B84,0B8B,0B8C,0B8D,0B91,0B96,0B97,0B98,0B9B,0B9D,0BA0,0BA1,0BA2,0BA5,0BA6,0BA7,0BAB,0BAC,0BAD,0BBA,0BBB,0BBC,0BBD,0BBE,0BBF,0BC*,0BD1,0BD2,0BD3,0BD4,0BD5,0BD6,0BD7,0BD^,0BE*,0BF*,0C00,0C01,0C02,0C03,0C04,0C0D,0C11,0C29,0C3A,0C3B,0C3C,0C3E,0C3F,0C4*,0C5_,0C5B,0C5C,0C5E,0C5F,0C62,0C63,0C64,0C65,0C66,0C67,0C6^,0C7*,0C81,0C82,0C83,0C84,0C8D,0C91,0CA9,0CB4,0CBA,0CBB,0CBC,0CBE,0CBF,0CC*,0CD_,0CD8,0CD9,0CDA,0CDB,0CDC,0CDF,0CE2,0CE3,0CE4,0CE5,0CE6,0CE7,0CE^,0CF0,0CF3,0CF4,0CF5,0CF6,0CF7,0CF^,0D00,0D01,0D02,0D03,0D0D,0D11,0D3B,0D3C,0D3E,0D3F,0D4_,0D48,0D49,0D4A,0D4B,0D4C,0D4D,0D4F,0D50,0D51,0D52,0D53,0D57,0D58,0D59,0D5A,0D5B,0D5C,0D5D,0D5E,0D62,0D63,0D64,0D65,0D66,0D67,0D6^,0D7_,0D78,0D79,0D80,0D81,0D82,0D83,0D84,0D97,0D98,0D99,0DB2,0DBC,0DBE,0DBF,0DC7,0DC^,0DD*,0DE*,0DF*,0E00,0E31,0E34,0E35,0E36,0E37,0E3^,0E47,0E4^,0E5*,0E6*,0E7*,0E80,0E83,0E85,0E8B,0EA4,0EA6,0EB1,0EB4,0EB5,0EB6,0EB7,0EB8,0EB9,0EBA,0EBB,0EBC,0EBE,0EBF,0EC5,0EC7,0EC^,0ED_,0ED8,0ED9,0EDA,0EDB,0EE*,0EF*,0F01,0F02,0F03,0F04,0F05,0F06,0F07,0F0^,0F1*,0F2*,0F3*,0F48,0F6D,0F6E,0F6F,0F7*,0F8_,0F8D,0F8E,0F8F,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,102B,102C,102D,102E,102F,103_,1038,1039,103A,103B,103C,103D,103E,104*,1056,1057,1058,1059,105E,105F,1060,1062,1063,1064,1067,1068,1069,106A,106B,106C,106D,1071,1072,1073,1074,1082,1083,1084,1085,1086,1087,1088,1089,108A,108B,108C,108D,108F,109*,10C6,10C8,10C9,10CA,10CB,10CC,10CE,10CF,10FB,1249,124E,124F,1257,1259,125E,125F,1289,128E,128F,12B1,12B6,12B7,12BF,12C1,12C6,12C7,12D7,1311,1316,1317,135B,135C,135D,135E,135F,136*,137*,139*,13F6,13F7,13FE,13FF,1400,166D,166E,1680,169B,169C,169D,169E,169F,16EB,16EC,16ED,16EE,16EF,16F0,16F9,16FA,16FB,16FC,16FD,16FE,16FF,1712,1713,1714,1715,1716,1717,1718,1719,171A,171B,171C,171D,171E,1732,1733,1734,1735,1736,1737,173^,1752,1753,1754,1755,1756,1757,175^,176D,1771,1772,1773,1774,1775,1776,1777,177^,17B4,17B5,17B6,17B7,17B^,17C*,17D0,17D1,17D2,17D3,17D4,17D5,17D6,17D8,17D9,17DA,17DB,17DD,17DE,17DF,17E*,17F*,180*,181*,1879,187A,187B,187C,187D,187E,187F,1885,1886,18A9,18AB,18AC,18AD,18AE,18AF,18F6,18F7,18F^,191F,192*,193*,194*,196E,196F,1975,1976,1977,197^,19AC,19AD,19AE,19AF,19CA,19CB,19CC,19CD,19CE,19CF,19D*,19E*,19F*,1A17,1A1^,1A55,1A56,1A57,1A5^,1A6*,1A7*,1A8*,1A9*,1AA0,1AA1,1AA2,1AA3,1AA4,1AA5,1AA6,1AA^,1AB*,1AC*,1AD*,1AE*,1AF*,1B00,1B01,1B02,1B03,1B04,1B34,1B35,1B36,1B37,1B3^,1B40,1B41,1B42,1B43,1B44,1B4D,1B4E,1B4F,1B5*,1B6*,1B7*,1B80,1B81,1B82,1BA1,1BA2,1BA3,1BA4,1BA5,1BA6,1BA7,1BA8,1BA9,1BAA,1BAB,1BAC,1BAD,1BB_,1BB8,1BB9,1BE6,1BE7,1BE^,1BF*,1C24,1C25,1C26,1C27,1C2^,1C3*,1C4_,1C48,1C49,1C4A,1C4B,1C4C,1C5_,1C58,1C59,1C7E,1C7F,1C89,1C8A,1C8B,1C8C,1C8D,1C8E,1C8F,1CBB,1CBC,1CC*,1CD*,1CE_,1CE8,1CED,1CF4,1CF7,1CF8,1CF9,1CFB,1CFC,1CFD,1CFE,1CFF,1DC*,1DD*,1DE*,1DF*,1F16,1F17,1F1E,1F1F,1F46,1F47,1F4E,1F4F,1F58,1F5A,1F5C,1F5E,1F7E,1F7F,1FB5,1FBD,1FBF,1FC0,1FC1,1FC5,1FCD,1FCE,1FCF,1FD4,1FD5,1FDC,1FDD,1FDE,1FDF,1FED,1FEE,1FEF,1FF0,1FF1,1FF5,1FFD,1FFE,1FFF,200*,201*,202*,203*,204*,205*,206*,2070,2072,2073,2074,2075,2076,2077,2078,2079,207A,207B,207C,207D,207E,208*,209D,209E,209F,20A*,20B*,20C*,20D*,20E*,20F*,2100,2101,2103,2104,2105,2106,2108,2109,2114,2116,2117,2118,211E,211F,2120,2121,2122,2123,2125,2127,2129,212E,213A,213B,2140,2141,2142,2143,2144,214A,214B,214C,214D,214F,215*,216*,217*,2180,2181,2182,2185,2186,2187,218^,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2CE5,2CE6,2CE7,2CE8,2CE9,2CEA,2CEF,2CF0,2CF1,2CF4,2CF5,2CF6,2CF7,2CF^,2D26,2D28,2D29,2D2A,2D2B,2D2C,2D2E,2D2F,2D68,2D69,2D6A,2D6B,2D6C,2D6D,2D6E,2D7*,2D97,2D9^,2DA7,2DAF,2DB7,2DBF,2DC7,2DCF,2DD7,2DDF,2DE*,2DF*,2E0*,2E1*,2E2_,2E28,2E29,2E2A,2E2B,2E2C,2E2D,2E2E,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,3000,3001,3002,3003,3004,3007,300^,301*,302*,3030,3036,3037,3038,3039,303A,303D,303E,303F,3040,3097,3098,3099,309A,309B,309C,30A0,30FB,3100,3101,3102,3103,3104,3130,318F,319*,31C*,31D*,31E*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*," - -// Ll ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Ll}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0061,0062,0063,0064,0065,0066,0067,006^,007_,0078,0079,007A,00B5,00DF,00E*,00F0,00F1,00F2,00F3,00F4,00F5,00F6,00F^,0101,0103,0105,0107,0109,010B,010D,010F,0111,0113,0115,0117,0119,011B,011D,011F,0121,0123,0125,0127,0129,012B,012D,012F,0131,0133,0135,0137,0138,013A,013C,013E,0140,0142,0144,0146,0148,0149,014B,014D,014F,0151,0153,0155,0157,0159,015B,015D,015F,0161,0163,0165,0167,0169,016B,016D,016F,0171,0173,0175,0177,017A,017C,017E,017F,0180,0183,0185,0188,018C,018D,0192,0195,0199,019A,019B,019E,01A1,01A3,01A5,01A8,01AA,01AB,01AD,01B0,01B4,01B6,01B9,01BA,01BD,01BE,01BF,01C6,01C9,01CC,01CE,01D0,01D2,01D4,01D6,01D8,01DA,01DC,01DD,01DF,01E1,01E3,01E5,01E7,01E9,01EB,01ED,01EF,01F0,01F3,01F5,01F9,01FB,01FD,01FF,0201,0203,0205,0207,0209,020B,020D,020F,0211,0213,0215,0217,0219,021B,021D,021F,0221,0223,0225,0227,0229,022B,022D,022F,0231,0233,0234,0235,0236,0237,0238,0239,023C,023F,0240,0242,0247,0249,024B,024D,024F,025*,026*,027*,028*,0290,0291,0292,0293,0295,0296,0297,029^,02A*,0371,0373,0377,037B,037C,037D,0390,03AC,03AD,03AE,03AF,03B*,03C_,03C8,03C9,03CA,03CB,03CC,03CD,03CE,03D0,03D1,03D5,03D6,03D7,03D9,03DB,03DD,03DF,03E1,03E3,03E5,03E7,03E9,03EB,03ED,03EF,03F0,03F1,03F2,03F3,03F5,03F8,03FB,03FC,043*,044*,045*,0461,0463,0465,0467,0469,046B,046D,046F,0471,0473,0475,0477,0479,047B,047D,047F,0481,048B,048D,048F,0491,0493,0495,0497,0499,049B,049D,049F,04A1,04A3,04A5,04A7,04A9,04AB,04AD,04AF,04B1,04B3,04B5,04B7,04B9,04BB,04BD,04BF,04C2,04C4,04C6,04C8,04CA,04CC,04CE,04CF,04D1,04D3,04D5,04D7,04D9,04DB,04DD,04DF,04E1,04E3,04E5,04E7,04E9,04EB,04ED,04EF,04F1,04F3,04F5,04F7,04F9,04FB,04FD,04FF,0501,0503,0505,0507,0509,050B,050D,050F,0511,0513,0515,0517,0519,051B,051D,051F,0521,0523,0525,0527,0529,052B,052D,052F,056*,057*,058_,0588,10D*,10E*,10F_,10F8,10F9,10FA,10FD,10FE,10FF,13F8,13F9,13FA,13FB,13FC,13FD,1C8_,1C88,1D0*,1D1*,1D2_,1D28,1D29,1D2A,1D2B,1D6B,1D6C,1D6D,1D6E,1D6F,1D7_,1D79,1D7A,1D7B,1D7C,1D7D,1D7E,1D7F,1D8*,1D9_,1D98,1D99,1D9A,1E01,1E03,1E05,1E07,1E09,1E0B,1E0D,1E0F,1E11,1E13,1E15,1E17,1E19,1E1B,1E1D,1E1F,1E21,1E23,1E25,1E27,1E29,1E2B,1E2D,1E2F,1E31,1E33,1E35,1E37,1E39,1E3B,1E3D,1E3F,1E41,1E43,1E45,1E47,1E49,1E4B,1E4D,1E4F,1E51,1E53,1E55,1E57,1E59,1E5B,1E5D,1E5F,1E61,1E63,1E65,1E67,1E69,1E6B,1E6D,1E6F,1E71,1E73,1E75,1E77,1E79,1E7B,1E7D,1E7F,1E81,1E83,1E85,1E87,1E89,1E8B,1E8D,1E8F,1E91,1E93,1E95,1E96,1E97,1E98,1E99,1E9A,1E9B,1E9C,1E9D,1E9F,1EA1,1EA3,1EA5,1EA7,1EA9,1EAB,1EAD,1EAF,1EB1,1EB3,1EB5,1EB7,1EB9,1EBB,1EBD,1EBF,1EC1,1EC3,1EC5,1EC7,1EC9,1ECB,1ECD,1ECF,1ED1,1ED3,1ED5,1ED7,1ED9,1EDB,1EDD,1EDF,1EE1,1EE3,1EE5,1EE7,1EE9,1EEB,1EED,1EEF,1EF1,1EF3,1EF5,1EF7,1EF9,1EFB,1EFD,1EFF,1F0_,1F10,1F11,1F12,1F13,1F14,1F15,1F2_,1F3_,1F40,1F41,1F42,1F43,1F44,1F45,1F5_,1F6_,1F7_,1F78,1F79,1F7A,1F7B,1F7C,1F7D,1F8_,1F9_,1FA_,1FB0,1FB1,1FB2,1FB3,1FB4,1FB6,1FB7,1FBE,1FC2,1FC3,1FC4,1FC6,1FC7,1FD0,1FD1,1FD2,1FD3,1FD6,1FD7,1FE_,1FF2,1FF3,1FF4,1FF6,1FF7,210A,210E,210F,2113,212F,2134,2139,213C,213D,2146,2147,2148,2149,214E,2184,2C3*,2C4*,2C5*,2C61,2C65,2C66,2C68,2C6A,2C6C,2C71,2C73,2C74,2C76,2C77,2C78,2C79,2C7A,2C7B,2C81,2C83,2C85,2C87,2C89,2C8B,2C8D,2C8F,2C91,2C93,2C95,2C97,2C99,2C9B,2C9D,2C9F,2CA1,2CA3,2CA5,2CA7,2CA9,2CAB,2CAD,2CAF,2CB1,2CB3,2CB5,2CB7,2CB9,2CBB,2CBD,2CBF,2CC1,2CC3,2CC5,2CC7,2CC9,2CCB,2CCD,2CCF,2CD1,2CD3,2CD5,2CD7,2CD9,2CDB,2CDD,2CDF,2CE1,2CE3,2CE4,2CEC,2CEE,2CF3,2D0*,2D1*,2D20,2D21,2D22,2D23,2D24,2D25,2D27,2D2D," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Ll}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,0060,007B,007C,007D,007E,007F,008*,009*,00A*,00B0,00B1,00B2,00B3,00B4,00B6,00B7,00B^,00C*,00D_,00D8,00D9,00DA,00DB,00DC,00DD,00DE,00F7,0100,0102,0104,0106,0108,010A,010C,010E,0110,0112,0114,0116,0118,011A,011C,011E,0120,0122,0124,0126,0128,012A,012C,012E,0130,0132,0134,0136,0139,013B,013D,013F,0141,0143,0145,0147,014A,014C,014E,0150,0152,0154,0156,0158,015A,015C,015E,0160,0162,0164,0166,0168,016A,016C,016E,0170,0172,0174,0176,0178,0179,017B,017D,0181,0182,0184,0186,0187,0189,018A,018B,018E,018F,0190,0191,0193,0194,0196,0197,0198,019C,019D,019F,01A0,01A2,01A4,01A6,01A7,01A9,01AC,01AE,01AF,01B1,01B2,01B3,01B5,01B7,01B8,01BB,01BC,01C0,01C1,01C2,01C3,01C4,01C5,01C7,01C8,01CA,01CB,01CD,01CF,01D1,01D3,01D5,01D7,01D9,01DB,01DE,01E0,01E2,01E4,01E6,01E8,01EA,01EC,01EE,01F1,01F2,01F4,01F6,01F7,01F8,01FA,01FC,01FE,0200,0202,0204,0206,0208,020A,020C,020E,0210,0212,0214,0216,0218,021A,021C,021E,0220,0222,0224,0226,0228,022A,022C,022E,0230,0232,023A,023B,023D,023E,0241,0243,0244,0245,0246,0248,024A,024C,024E,0294,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,0370,0372,0374,0375,0376,0378,0379,037A,037E,037F,038*,0391,0392,0393,0394,0395,0396,0397,039^,03A_,03A8,03A9,03AA,03AB,03CF,03D2,03D3,03D4,03D8,03DA,03DC,03DE,03E0,03E2,03E4,03E6,03E8,03EA,03EC,03EE,03F4,03F6,03F7,03F9,03FA,03FD,03FE,03FF,040*,041*,042*,0460,0462,0464,0466,0468,046A,046C,046E,0470,0472,0474,0476,0478,047A,047C,047E,0480,0482,0483,0484,0485,0486,0487,0488,0489,048A,048C,048E,0490,0492,0494,0496,0498,049A,049C,049E,04A0,04A2,04A4,04A6,04A8,04AA,04AC,04AE,04B0,04B2,04B4,04B6,04B8,04BA,04BC,04BE,04C0,04C1,04C3,04C5,04C7,04C9,04CB,04CD,04D0,04D2,04D4,04D6,04D8,04DA,04DC,04DE,04E0,04E2,04E4,04E6,04E8,04EA,04EC,04EE,04F0,04F2,04F4,04F6,04F8,04FA,04FC,04FE,0500,0502,0504,0506,0508,050A,050C,050E,0510,0512,0514,0516,0518,051A,051C,051E,0520,0522,0524,0526,0528,052A,052C,052E,053*,054*,055*,0589,058A,058B,058C,058D,058E,058F,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10FB,10FC,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F_,13FE,13FF,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C89,1C8A,1C8B,1C8C,1C8D,1C8E,1C8F,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D2C,1D2D,1D2E,1D2F,1D3*,1D4*,1D5*,1D6_,1D68,1D69,1D6A,1D78,1D9B,1D9C,1D9D,1D9E,1D9F,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E00,1E02,1E04,1E06,1E08,1E0A,1E0C,1E0E,1E10,1E12,1E14,1E16,1E18,1E1A,1E1C,1E1E,1E20,1E22,1E24,1E26,1E28,1E2A,1E2C,1E2E,1E30,1E32,1E34,1E36,1E38,1E3A,1E3C,1E3E,1E40,1E42,1E44,1E46,1E48,1E4A,1E4C,1E4E,1E50,1E52,1E54,1E56,1E58,1E5A,1E5C,1E5E,1E60,1E62,1E64,1E66,1E68,1E6A,1E6C,1E6E,1E70,1E72,1E74,1E76,1E78,1E7A,1E7C,1E7E,1E80,1E82,1E84,1E86,1E88,1E8A,1E8C,1E8E,1E90,1E92,1E94,1E9E,1EA0,1EA2,1EA4,1EA6,1EA8,1EAA,1EAC,1EAE,1EB0,1EB2,1EB4,1EB6,1EB8,1EBA,1EBC,1EBE,1EC0,1EC2,1EC4,1EC6,1EC8,1ECA,1ECC,1ECE,1ED0,1ED2,1ED4,1ED6,1ED8,1EDA,1EDC,1EDE,1EE0,1EE2,1EE4,1EE6,1EE8,1EEA,1EEC,1EEE,1EF0,1EF2,1EF4,1EF6,1EF8,1EFA,1EFC,1EFE,1F0^,1F16,1F17,1F1^,1F2^,1F3^,1F46,1F47,1F4^,1F5^,1F6^,1F7E,1F7F,1F8^,1F9^,1FA^,1FB5,1FB8,1FB9,1FBA,1FBB,1FBC,1FBD,1FBF,1FC0,1FC1,1FC5,1FC^,1FD4,1FD5,1FD^,1FE^,1FF0,1FF1,1FF5,1FF^,200*,201*,202*,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210_,2108,2109,210B,210C,210D,2110,2111,2112,2114,2115,2116,2117,211^,212_,2128,2129,212A,212B,212C,212D,212E,2130,2131,2132,2133,2135,2136,2137,2138,213A,213B,213E,213F,2140,2141,2142,2143,2144,2145,214A,214B,214C,214D,214F,215*,216*,217*,2180,2181,2182,2183,2185,2186,2187,218^,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C60,2C62,2C63,2C64,2C67,2C69,2C6B,2C6D,2C6E,2C6F,2C70,2C72,2C75,2C7C,2C7D,2C7E,2C7F,2C80,2C82,2C84,2C86,2C88,2C8A,2C8C,2C8E,2C90,2C92,2C94,2C96,2C98,2C9A,2C9C,2C9E,2CA0,2CA2,2CA4,2CA6,2CA8,2CAA,2CAC,2CAE,2CB0,2CB2,2CB4,2CB6,2CB8,2CBA,2CBC,2CBE,2CC0,2CC2,2CC4,2CC6,2CC8,2CCA,2CCC,2CCE,2CD0,2CD2,2CD4,2CD6,2CD8,2CDA,2CDC,2CDE,2CE0,2CE2,2CE5,2CE6,2CE7,2CE8,2CE9,2CEA,2CEB,2CED,2CEF,2CF0,2CF1,2CF2,2CF4,2CF5,2CF6,2CF7,2CF^,2D26,2D28,2D29,2D2A,2D2B,2D2C,2D2E,2D2F,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// Lu ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Lu}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0041,0042,0043,0044,0045,0046,0047,004^,005_,0058,0059,005A,00C*,00D0,00D1,00D2,00D3,00D4,00D5,00D6,00D8,00D9,00DA,00DB,00DC,00DD,00DE,0100,0102,0104,0106,0108,010A,010C,010E,0110,0112,0114,0116,0118,011A,011C,011E,0120,0122,0124,0126,0128,012A,012C,012E,0130,0132,0134,0136,0139,013B,013D,013F,0141,0143,0145,0147,014A,014C,014E,0150,0152,0154,0156,0158,015A,015C,015E,0160,0162,0164,0166,0168,016A,016C,016E,0170,0172,0174,0176,0178,0179,017B,017D,0181,0182,0184,0186,0187,0189,018A,018B,018E,018F,0190,0191,0193,0194,0196,0197,0198,019C,019D,019F,01A0,01A2,01A4,01A6,01A7,01A9,01AC,01AE,01AF,01B1,01B2,01B3,01B5,01B7,01B8,01BC,01C4,01C7,01CA,01CD,01CF,01D1,01D3,01D5,01D7,01D9,01DB,01DE,01E0,01E2,01E4,01E6,01E8,01EA,01EC,01EE,01F1,01F4,01F6,01F7,01F8,01FA,01FC,01FE,0200,0202,0204,0206,0208,020A,020C,020E,0210,0212,0214,0216,0218,021A,021C,021E,0220,0222,0224,0226,0228,022A,022C,022E,0230,0232,023A,023B,023D,023E,0241,0243,0244,0245,0246,0248,024A,024C,024E,0370,0372,0376,037F,0386,0388,0389,038A,038C,038E,038F,0391,0392,0393,0394,0395,0396,0397,039^,03A0,03A1,03A3,03A4,03A5,03A6,03A7,03A8,03A9,03AA,03AB,03CF,03D2,03D3,03D4,03D8,03DA,03DC,03DE,03E0,03E2,03E4,03E6,03E8,03EA,03EC,03EE,03F4,03F7,03F9,03FA,03FD,03FE,03FF,040*,041*,042*,0460,0462,0464,0466,0468,046A,046C,046E,0470,0472,0474,0476,0478,047A,047C,047E,0480,048A,048C,048E,0490,0492,0494,0496,0498,049A,049C,049E,04A0,04A2,04A4,04A6,04A8,04AA,04AC,04AE,04B0,04B2,04B4,04B6,04B8,04BA,04BC,04BE,04C0,04C1,04C3,04C5,04C7,04C9,04CB,04CD,04D0,04D2,04D4,04D6,04D8,04DA,04DC,04DE,04E0,04E2,04E4,04E6,04E8,04EA,04EC,04EE,04F0,04F2,04F4,04F6,04F8,04FA,04FC,04FE,0500,0502,0504,0506,0508,050A,050C,050E,0510,0512,0514,0516,0518,051A,051C,051E,0520,0522,0524,0526,0528,052A,052C,052E,0531,0532,0533,0534,0535,0536,0537,053^,054*,0550,0551,0552,0553,0554,0555,0556,10A*,10B*,10C0,10C1,10C2,10C3,10C4,10C5,10C7,10CD,13A*,13B*,13C*,13D*,13E*,13F0,13F1,13F2,13F3,13F4,13F5,1C9*,1CA*,1CB_,1CB8,1CB9,1CBA,1CBD,1CBE,1CBF,1E00,1E02,1E04,1E06,1E08,1E0A,1E0C,1E0E,1E10,1E12,1E14,1E16,1E18,1E1A,1E1C,1E1E,1E20,1E22,1E24,1E26,1E28,1E2A,1E2C,1E2E,1E30,1E32,1E34,1E36,1E38,1E3A,1E3C,1E3E,1E40,1E42,1E44,1E46,1E48,1E4A,1E4C,1E4E,1E50,1E52,1E54,1E56,1E58,1E5A,1E5C,1E5E,1E60,1E62,1E64,1E66,1E68,1E6A,1E6C,1E6E,1E70,1E72,1E74,1E76,1E78,1E7A,1E7C,1E7E,1E80,1E82,1E84,1E86,1E88,1E8A,1E8C,1E8E,1E90,1E92,1E94,1E9E,1EA0,1EA2,1EA4,1EA6,1EA8,1EAA,1EAC,1EAE,1EB0,1EB2,1EB4,1EB6,1EB8,1EBA,1EBC,1EBE,1EC0,1EC2,1EC4,1EC6,1EC8,1ECA,1ECC,1ECE,1ED0,1ED2,1ED4,1ED6,1ED8,1EDA,1EDC,1EDE,1EE0,1EE2,1EE4,1EE6,1EE8,1EEA,1EEC,1EEE,1EF0,1EF2,1EF4,1EF6,1EF8,1EFA,1EFC,1EFE,1F0^,1F18,1F19,1F1A,1F1B,1F1C,1F1D,1F2^,1F3^,1F48,1F49,1F4A,1F4B,1F4C,1F4D,1F59,1F5B,1F5D,1F5F,1F6^,1FB8,1FB9,1FBA,1FBB,1FC8,1FC9,1FCA,1FCB,1FD8,1FD9,1FDA,1FDB,1FE8,1FE9,1FEA,1FEB,1FEC,1FF8,1FF9,1FFA,1FFB,2102,2107,210B,210C,210D,2110,2111,2112,2115,2119,211A,211B,211C,211D,2124,2126,2128,212A,212B,212C,212D,2130,2131,2132,2133,213E,213F,2145,2183,2C0*,2C1*,2C2*,2C60,2C62,2C63,2C64,2C67,2C69,2C6B,2C6D,2C6E,2C6F,2C70,2C72,2C75,2C7E,2C7F,2C80,2C82,2C84,2C86,2C88,2C8A,2C8C,2C8E,2C90,2C92,2C94,2C96,2C98,2C9A,2C9C,2C9E,2CA0,2CA2,2CA4,2CA6,2CA8,2CAA,2CAC,2CAE,2CB0,2CB2,2CB4,2CB6,2CB8,2CBA,2CBC,2CBE,2CC0,2CC2,2CC4,2CC6,2CC8,2CCA,2CCC,2CCE,2CD0,2CD2,2CD4,2CD6,2CD8,2CDA,2CDC,2CDE,2CE0,2CE2,2CEB,2CED,2CF2," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Lu}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,0040,005B,005C,005D,005E,005F,006*,007*,008*,009*,00A*,00B*,00D7,00DF,00E*,00F*,0101,0103,0105,0107,0109,010B,010D,010F,0111,0113,0115,0117,0119,011B,011D,011F,0121,0123,0125,0127,0129,012B,012D,012F,0131,0133,0135,0137,0138,013A,013C,013E,0140,0142,0144,0146,0148,0149,014B,014D,014F,0151,0153,0155,0157,0159,015B,015D,015F,0161,0163,0165,0167,0169,016B,016D,016F,0171,0173,0175,0177,017A,017C,017E,017F,0180,0183,0185,0188,018C,018D,0192,0195,0199,019A,019B,019E,01A1,01A3,01A5,01A8,01AA,01AB,01AD,01B0,01B4,01B6,01B9,01BA,01BB,01BD,01BE,01BF,01C0,01C1,01C2,01C3,01C5,01C6,01C8,01C9,01CB,01CC,01CE,01D0,01D2,01D4,01D6,01D8,01DA,01DC,01DD,01DF,01E1,01E3,01E5,01E7,01E9,01EB,01ED,01EF,01F0,01F2,01F3,01F5,01F9,01FB,01FD,01FF,0201,0203,0205,0207,0209,020B,020D,020F,0211,0213,0215,0217,0219,021B,021D,021F,0221,0223,0225,0227,0229,022B,022D,022F,0231,0233,0234,0235,0236,0237,0238,0239,023C,023F,0240,0242,0247,0249,024B,024D,024F,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,0371,0373,0374,0375,0377,0378,0379,037A,037B,037C,037D,037E,0380,0381,0382,0383,0384,0385,0387,038B,038D,0390,03A2,03AC,03AD,03AE,03AF,03B*,03C_,03C8,03C9,03CA,03CB,03CC,03CD,03CE,03D0,03D1,03D5,03D6,03D7,03D9,03DB,03DD,03DF,03E1,03E3,03E5,03E7,03E9,03EB,03ED,03EF,03F0,03F1,03F2,03F3,03F5,03F6,03F8,03FB,03FC,043*,044*,045*,0461,0463,0465,0467,0469,046B,046D,046F,0471,0473,0475,0477,0479,047B,047D,047F,0481,0482,0483,0484,0485,0486,0487,0488,0489,048B,048D,048F,0491,0493,0495,0497,0499,049B,049D,049F,04A1,04A3,04A5,04A7,04A9,04AB,04AD,04AF,04B1,04B3,04B5,04B7,04B9,04BB,04BD,04BF,04C2,04C4,04C6,04C8,04CA,04CC,04CE,04CF,04D1,04D3,04D5,04D7,04D9,04DB,04DD,04DF,04E1,04E3,04E5,04E7,04E9,04EB,04ED,04EF,04F1,04F3,04F5,04F7,04F9,04FB,04FD,04FF,0501,0503,0505,0507,0509,050B,050D,050F,0511,0513,0515,0517,0519,051B,051D,051F,0521,0523,0525,0527,0529,052B,052D,052F,0530,0557,055^,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10C6,10C8,10C9,10CA,10CB,10CC,10CE,10CF,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13F6,13F7,13F^,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1CBB,1CBC,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E01,1E03,1E05,1E07,1E09,1E0B,1E0D,1E0F,1E11,1E13,1E15,1E17,1E19,1E1B,1E1D,1E1F,1E21,1E23,1E25,1E27,1E29,1E2B,1E2D,1E2F,1E31,1E33,1E35,1E37,1E39,1E3B,1E3D,1E3F,1E41,1E43,1E45,1E47,1E49,1E4B,1E4D,1E4F,1E51,1E53,1E55,1E57,1E59,1E5B,1E5D,1E5F,1E61,1E63,1E65,1E67,1E69,1E6B,1E6D,1E6F,1E71,1E73,1E75,1E77,1E79,1E7B,1E7D,1E7F,1E81,1E83,1E85,1E87,1E89,1E8B,1E8D,1E8F,1E91,1E93,1E95,1E96,1E97,1E98,1E99,1E9A,1E9B,1E9C,1E9D,1E9F,1EA1,1EA3,1EA5,1EA7,1EA9,1EAB,1EAD,1EAF,1EB1,1EB3,1EB5,1EB7,1EB9,1EBB,1EBD,1EBF,1EC1,1EC3,1EC5,1EC7,1EC9,1ECB,1ECD,1ECF,1ED1,1ED3,1ED5,1ED7,1ED9,1EDB,1EDD,1EDF,1EE1,1EE3,1EE5,1EE7,1EE9,1EEB,1EED,1EEF,1EF1,1EF3,1EF5,1EF7,1EF9,1EFB,1EFD,1EFF,1F0_,1F1_,1F1E,1F1F,1F2_,1F3_,1F4_,1F4E,1F4F,1F5_,1F58,1F5A,1F5C,1F5E,1F6_,1F7*,1F8*,1F9*,1FA*,1FB_,1FBC,1FBD,1FBE,1FBF,1FC_,1FCC,1FCD,1FCE,1FCF,1FD_,1FDC,1FDD,1FDE,1FDF,1FE_,1FED,1FEE,1FEF,1FF_,1FFC,1FFD,1FFE,1FFF,200*,201*,202*,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,2100,2101,2103,2104,2105,2106,2108,2109,210A,210E,210F,2113,2114,2116,2117,2118,211E,211F,2120,2121,2122,2123,2125,2127,2129,212E,212F,2134,2135,2136,2137,2138,2139,213A,213B,213C,213D,2140,2141,2142,2143,2144,2146,2147,214^,215*,216*,217*,2180,2181,2182,2184,2185,2186,2187,218^,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C3*,2C4*,2C5*,2C61,2C65,2C66,2C68,2C6A,2C6C,2C71,2C73,2C74,2C76,2C77,2C78,2C79,2C7A,2C7B,2C7C,2C7D,2C81,2C83,2C85,2C87,2C89,2C8B,2C8D,2C8F,2C91,2C93,2C95,2C97,2C99,2C9B,2C9D,2C9F,2CA1,2CA3,2CA5,2CA7,2CA9,2CAB,2CAD,2CAF,2CB1,2CB3,2CB5,2CB7,2CB9,2CBB,2CBD,2CBF,2CC1,2CC3,2CC5,2CC7,2CC9,2CCB,2CCD,2CCF,2CD1,2CD3,2CD5,2CD7,2CD9,2CDB,2CDD,2CDF,2CE1,2CE3,2CE4,2CE5,2CE6,2CE7,2CE8,2CE9,2CEA,2CEC,2CEE,2CEF,2CF0,2CF1,2CF3,2CF4,2CF5,2CF6,2CF7,2CF^,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// Lt ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Lt}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"01C5,01C8,01CB,01F2,1F8^,1F9^,1FA^,1FBC,1FCC,1FFC," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Lt}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C0,01C1,01C2,01C3,01C4,01C6,01C7,01C9,01CA,01CC,01CD,01CE,01CF,01D*,01E*,01F0,01F1,01F3,01F4,01F5,01F6,01F7,01F^,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8_,1F9_,1FA_,1FB_,1FB8,1FB9,1FBA,1FBB,1FBD,1FBE,1FBF,1FC_,1FC8,1FC9,1FCA,1FCB,1FCD,1FCE,1FCF,1FD*,1FE*,1FF_,1FF8,1FF9,1FFA,1FFB,1FFD,1FFE,1FFF,200*,201*,202*,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// Lm ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Lm}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"02B*,02C0,02C1,02C6,02C7,02C^,02D0,02D1,02E0,02E1,02E2,02E3,02E4,02EC,02EE,0374,037A,0559,0640,06E5,06E6,07F4,07F5,07FA,081A,0824,0828,08C9,0971,0E46,0EC6,10FC,17D7,1843,1AA7,1C78,1C79,1C7A,1C7B,1C7C,1C7D,1D2C,1D2D,1D2E,1D2F,1D3*,1D4*,1D5*,1D6_,1D68,1D69,1D6A,1D78,1D9B,1D9C,1D9D,1D9E,1D9F,1DA*,1DB*,2071,207F,209_,2098,2099,209A,209B,209C,2C7C,2C7D,2D6F,2E2F,3005,3031,3032,3033,3034,3035,303B,309D,309E,30FC,30FD,30FE," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Lm}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02C2,02C3,02C4,02C5,02D2,02D3,02D4,02D5,02D6,02D7,02D^,02E5,02E6,02E7,02E8,02E9,02EA,02EB,02ED,02EF,02F*,030*,031*,032*,033*,034*,035*,036*,0370,0371,0372,0373,0375,0376,0377,0378,0379,037B,037C,037D,037E,037F,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055_,0558,055A,055B,055C,055D,055E,055F,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,0641,0642,0643,0644,0645,0646,0647,064^,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E0,06E1,06E2,06E3,06E4,06E7,06E^,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F0,07F1,07F2,07F3,07F6,07F7,07F8,07F9,07FB,07FC,07FD,07FE,07FF,080*,081_,0818,0819,081B,081C,081D,081E,081F,0820,0821,0822,0823,0825,0826,0827,0829,082A,082B,082C,082D,082E,082F,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C_,08C8,08CA,08CB,08CC,08CD,08CE,08CF,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,0970,0972,0973,0974,0975,0976,0977,097^,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E40,0E41,0E42,0E43,0E44,0E45,0E47,0E4^,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC0,0EC1,0EC2,0EC3,0EC4,0EC5,0EC7,0EC^,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F_,10F8,10F9,10FA,10FB,10FD,10FE,10FF,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D0,17D1,17D2,17D3,17D4,17D5,17D6,17D^,17E*,17F*,180*,181*,182*,183*,1840,1841,1842,1844,1845,1846,1847,184^,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA0,1AA1,1AA2,1AA3,1AA4,1AA5,1AA6,1AA^,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7_,1C7E,1C7F,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2_,1D28,1D29,1D2A,1D2B,1D6B,1D6C,1D6D,1D6E,1D6F,1D7_,1D79,1D7A,1D7B,1D7C,1D7D,1D7E,1D7F,1D8*,1D9_,1D98,1D99,1D9A,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,204*,205*,206*,2070,2072,2073,2074,2075,2076,2077,2078,2079,207A,207B,207C,207D,207E,208*,209D,209E,209F,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7_,2C78,2C79,2C7A,2C7B,2C7E,2C7F,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6_,2D68,2D69,2D6A,2D6B,2D6C,2D6D,2D6E,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2_,2E28,2E29,2E2A,2E2B,2E2C,2E2D,2E2E,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,3000,3001,3002,3003,3004,3006,3007,300^,301*,302*,3030,3036,3037,3038,3039,303A,303C,303D,303E,303F,304*,305*,306*,307*,308*,309_,3098,3099,309A,309B,309C,309F,30A*,30B*,30C*,30D*,30E*,30F_,30F8,30F9,30FA,30FB,30FF,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// Lo ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Lo}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"00AA,00BA,01BB,01C0,01C1,01C2,01C3,0294,05D*,05E_,05E8,05E9,05EA,05EF,05F0,05F1,05F2,062*,063*,0641,0642,0643,0644,0645,0646,0647,0648,0649,064A,066E,066F,0671,0672,0673,0674,0675,0676,0677,067^,068*,069*,06A*,06B*,06C*,06D0,06D1,06D2,06D3,06D5,06EE,06EF,06FA,06FB,06FC,06FF,0710,0712,0713,0714,0715,0716,0717,071^,072*,074D,074E,074F,075*,076*,077*,078*,079*,07A0,07A1,07A2,07A3,07A4,07A5,07B1,07CA,07CB,07CC,07CD,07CE,07CF,07D*,07E_,07E8,07E9,07EA,080*,0810,0811,0812,0813,0814,0815,084*,085_,0858,086_,0868,0869,086A,087*,088_,0889,088A,088B,088C,088D,088E,08A*,08B*,08C_,08C8,0904,0905,0906,0907,090^,091*,092*,093_,0938,0939,093D,0950,095^,0960,0961,0972,0973,0974,0975,0976,0977,097^,0980,0985,0986,0987,0988,0989,098A,098B,098C,098F,0990,0993,0994,0995,0996,0997,099^,09A_,09A8,09AA,09AB,09AC,09AD,09AE,09AF,09B0,09B2,09B6,09B7,09B8,09B9,09BD,09CE,09DC,09DD,09DF,09E0,09E1,09F0,09F1,09FC,0A05,0A06,0A07,0A08,0A09,0A0A,0A0F,0A10,0A13,0A14,0A15,0A16,0A17,0A1^,0A2_,0A28,0A2A,0A2B,0A2C,0A2D,0A2E,0A2F,0A30,0A32,0A33,0A35,0A36,0A38,0A39,0A59,0A5A,0A5B,0A5C,0A5E,0A72,0A73,0A74,0A85,0A86,0A87,0A88,0A89,0A8A,0A8B,0A8C,0A8D,0A8F,0A90,0A91,0A93,0A94,0A95,0A96,0A97,0A9^,0AA_,0AA8,0AAA,0AAB,0AAC,0AAD,0AAE,0AAF,0AB0,0AB2,0AB3,0AB5,0AB6,0AB7,0AB8,0AB9,0ABD,0AD0,0AE0,0AE1,0AF9,0B05,0B06,0B07,0B08,0B09,0B0A,0B0B,0B0C,0B0F,0B10,0B13,0B14,0B15,0B16,0B17,0B1^,0B2_,0B28,0B2A,0B2B,0B2C,0B2D,0B2E,0B2F,0B30,0B32,0B33,0B35,0B36,0B37,0B38,0B39,0B3D,0B5C,0B5D,0B5F,0B60,0B61,0B71,0B83,0B85,0B86,0B87,0B88,0B89,0B8A,0B8E,0B8F,0B90,0B92,0B93,0B94,0B95,0B99,0B9A,0B9C,0B9E,0B9F,0BA3,0BA4,0BA8,0BA9,0BAA,0BAE,0BAF,0BB_,0BB8,0BB9,0BD0,0C05,0C06,0C07,0C08,0C09,0C0A,0C0B,0C0C,0C0E,0C0F,0C10,0C12,0C13,0C14,0C15,0C16,0C17,0C1^,0C2_,0C28,0C2A,0C2B,0C2C,0C2D,0C2E,0C2F,0C3_,0C38,0C39,0C3D,0C58,0C59,0C5A,0C5D,0C60,0C61,0C80,0C85,0C86,0C87,0C88,0C89,0C8A,0C8B,0C8C,0C8E,0C8F,0C90,0C92,0C93,0C94,0C95,0C96,0C97,0C9^,0CA_,0CA8,0CAA,0CAB,0CAC,0CAD,0CAE,0CAF,0CB0,0CB1,0CB2,0CB3,0CB5,0CB6,0CB7,0CB8,0CB9,0CBD,0CDD,0CDE,0CE0,0CE1,0CF1,0CF2,0D04,0D05,0D06,0D07,0D08,0D09,0D0A,0D0B,0D0C,0D0E,0D0F,0D10,0D12,0D13,0D14,0D15,0D16,0D17,0D1^,0D2*,0D3_,0D38,0D39,0D3A,0D3D,0D4E,0D54,0D55,0D56,0D5F,0D60,0D61,0D7A,0D7B,0D7C,0D7D,0D7E,0D7F,0D85,0D86,0D87,0D8^,0D90,0D91,0D92,0D93,0D94,0D95,0D96,0D9A,0D9B,0D9C,0D9D,0D9E,0D9F,0DA*,0DB0,0DB1,0DB3,0DB4,0DB5,0DB6,0DB7,0DB8,0DB9,0DBA,0DBB,0DBD,0DC0,0DC1,0DC2,0DC3,0DC4,0DC5,0DC6,0E01,0E02,0E03,0E04,0E05,0E06,0E07,0E0^,0E1*,0E2*,0E30,0E32,0E33,0E40,0E41,0E42,0E43,0E44,0E45,0E81,0E82,0E84,0E86,0E87,0E88,0E89,0E8A,0E8C,0E8D,0E8E,0E8F,0E9*,0EA0,0EA1,0EA2,0EA3,0EA5,0EA7,0EA^,0EB0,0EB2,0EB3,0EBD,0EC0,0EC1,0EC2,0EC3,0EC4,0EDC,0EDD,0EDE,0EDF,0F00,0F4_,0F49,0F4A,0F4B,0F4C,0F4D,0F4E,0F4F,0F5*,0F6_,0F68,0F69,0F6A,0F6B,0F6C,0F88,0F89,0F8A,0F8B,0F8C,100*,101*,102_,1028,1029,102A,103F,1050,1051,1052,1053,1054,1055,105A,105B,105C,105D,1061,1065,1066,106E,106F,1070,1075,1076,1077,107^,1080,1081,108E,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124_,1248,124A,124B,124C,124D,1250,1251,1252,1253,1254,1255,1256,1258,125A,125B,125C,125D,126*,127*,128_,1288,128A,128B,128C,128D,129*,12A*,12B0,12B2,12B3,12B4,12B5,12B8,12B9,12BA,12BB,12BC,12BD,12BE,12C0,12C2,12C3,12C4,12C5,12C^,12D0,12D1,12D2,12D3,12D4,12D5,12D6,12D^,12E*,12F*,130*,1310,1312,1313,1314,1315,131^,132*,133*,134*,135_,1358,1359,135A,138*,1401,1402,1403,1404,1405,1406,1407,140^,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166_,1668,1669,166A,166B,166C,166F,167*,1681,1682,1683,1684,1685,1686,1687,168^,169_,1698,1699,169A,16A*,16B*,16C*,16D*,16E_,16E8,16E9,16EA,16F1,16F2,16F3,16F4,16F5,16F6,16F7,16F8,170*,1710,1711,171F,172*,1730,1731,174*,1750,1751,176_,1768,1769,176A,176B,176C,176E,176F,1770,178*,179*,17A*,17B0,17B1,17B2,17B3,17DC,182*,183*,1840,1841,1842,1844,1845,1846,1847,184^,185*,186*,187_,1878,1880,1881,1882,1883,1884,1887,188^,189*,18A_,18A8,18AA,18B*,18C*,18D*,18E*,18F0,18F1,18F2,18F3,18F4,18F5,190*,191_,1918,1919,191A,191B,191C,191D,191E,195*,196_,1968,1969,196A,196B,196C,196D,1970,1971,1972,1973,1974,198*,199*,19A_,19A8,19A9,19AA,19AB,19B*,19C_,19C8,19C9,1A0*,1A10,1A11,1A12,1A13,1A14,1A15,1A16,1A2*,1A3*,1A4*,1A50,1A51,1A52,1A53,1A54,1B05,1B06,1B07,1B0^,1B1*,1B2*,1B30,1B31,1B32,1B33,1B45,1B46,1B47,1B48,1B49,1B4A,1B4B,1B4C,1B83,1B84,1B85,1B86,1B87,1B8^,1B9*,1BA0,1BAE,1BAF,1BBA,1BBB,1BBC,1BBD,1BBE,1BBF,1BC*,1BD*,1BE0,1BE1,1BE2,1BE3,1BE4,1BE5,1C0*,1C1*,1C20,1C21,1C22,1C23,1C4D,1C4E,1C4F,1C5A,1C5B,1C5C,1C5D,1C5E,1C5F,1C6*,1C7_,1CE9,1CEA,1CEB,1CEC,1CEE,1CEF,1CF0,1CF1,1CF2,1CF3,1CF5,1CF6,1CFA,2135,2136,2137,2138,2D3*,2D4*,2D5*,2D6_,2D8*,2D90,2D91,2D92,2D93,2D94,2D95,2D96,2DA0,2DA1,2DA2,2DA3,2DA4,2DA5,2DA6,2DA8,2DA9,2DAA,2DAB,2DAC,2DAD,2DAE,2DB0,2DB1,2DB2,2DB3,2DB4,2DB5,2DB6,2DB8,2DB9,2DBA,2DBB,2DBC,2DBD,2DBE,2DC0,2DC1,2DC2,2DC3,2DC4,2DC5,2DC6,2DC8,2DC9,2DCA,2DCB,2DCC,2DCD,2DCE,2DD0,2DD1,2DD2,2DD3,2DD4,2DD5,2DD6,2DD8,2DD9,2DDA,2DDB,2DDC,2DDD,2DDE,3006,303C,3041,3042,3043,3044,3045,3046,3047,304^,305*,306*,307*,308*,3090,3091,3092,3093,3094,3095,3096,309F,30A1,30A2,30A3,30A4,30A5,30A6,30A7,30A^,30B*,30C*,30D*,30E*,30F_,30F8,30F9,30FA,30FF,3105,3106,3107,310^,311*,312*,3131,3132,3133,3134,3135,3136,3137,313^,314*,315*,316*,317*,318_,3188,3189,318A,318B,318C,318D,318E,31A*,31B*,31F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Lo}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A_,00A8,00A9,00AB,00AC,00AD,00AE,00AF,00B_,00B8,00B9,00BB,00BC,00BD,00BE,00BF,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B_,01B8,01B9,01BA,01BC,01BD,01BE,01BF,01C4,01C5,01C6,01C7,01C^,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,0290,0291,0292,0293,0295,0296,0297,029^,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05EB,05EC,05ED,05EE,05F3,05F4,05F5,05F6,05F7,05F^,060*,061*,0640,064B,064C,064D,064E,064F,065*,066_,0668,0669,066A,066B,066C,066D,0670,06D4,06D6,06D7,06D^,06E_,06E8,06E9,06EA,06EB,06EC,06ED,06F_,06F8,06F9,06FD,06FE,070*,0711,073*,074_,0748,0749,074A,074B,074C,07A6,07A7,07A^,07B0,07B2,07B3,07B4,07B5,07B6,07B7,07B^,07C_,07C8,07C9,07EB,07EC,07ED,07EE,07EF,07F*,0816,0817,081^,082*,083*,0859,085A,085B,085C,085D,085E,085F,086B,086C,086D,086E,086F,0888,088F,089*,08C9,08CA,08CB,08CC,08CD,08CE,08CF,08D*,08E*,08F*,0900,0901,0902,0903,093A,093B,093C,093E,093F,094*,0951,0952,0953,0954,0955,0956,0957,0962,0963,0964,0965,0966,0967,096^,0970,0971,0981,0982,0983,0984,098D,098E,0991,0992,09A9,09B1,09B3,09B4,09B5,09BA,09BB,09BC,09BE,09BF,09C_,09C8,09C9,09CA,09CB,09CC,09CD,09CF,09D_,09D8,09D9,09DA,09DB,09DE,09E2,09E3,09E4,09E5,09E6,09E7,09E^,09F2,09F3,09F4,09F5,09F6,09F7,09F8,09F9,09FA,09FB,09FD,09FE,09FF,0A00,0A01,0A02,0A03,0A04,0A0B,0A0C,0A0D,0A0E,0A11,0A12,0A29,0A31,0A34,0A37,0A3A,0A3B,0A3C,0A3D,0A3E,0A3F,0A4*,0A5_,0A58,0A5D,0A5F,0A6*,0A70,0A71,0A75,0A76,0A77,0A7^,0A80,0A81,0A82,0A83,0A84,0A8E,0A92,0AA9,0AB1,0AB4,0ABA,0ABB,0ABC,0ABE,0ABF,0AC*,0AD1,0AD2,0AD3,0AD4,0AD5,0AD6,0AD7,0AD^,0AE2,0AE3,0AE4,0AE5,0AE6,0AE7,0AE^,0AF_,0AF8,0AFA,0AFB,0AFC,0AFD,0AFE,0AFF,0B00,0B01,0B02,0B03,0B04,0B0D,0B0E,0B11,0B12,0B29,0B31,0B34,0B3A,0B3B,0B3C,0B3E,0B3F,0B4*,0B5_,0B58,0B59,0B5A,0B5B,0B5E,0B62,0B63,0B64,0B65,0B66,0B67,0B6^,0B70,0B72,0B73,0B74,0B75,0B76,0B77,0B7^,0B80,0B81,0B82,0B84,0B8B,0B8C,0B8D,0B91,0B96,0B97,0B98,0B9B,0B9D,0BA0,0BA1,0BA2,0BA5,0BA6,0BA7,0BAB,0BAC,0BAD,0BBA,0BBB,0BBC,0BBD,0BBE,0BBF,0BC*,0BD1,0BD2,0BD3,0BD4,0BD5,0BD6,0BD7,0BD^,0BE*,0BF*,0C00,0C01,0C02,0C03,0C04,0C0D,0C11,0C29,0C3A,0C3B,0C3C,0C3E,0C3F,0C4*,0C5_,0C5B,0C5C,0C5E,0C5F,0C62,0C63,0C64,0C65,0C66,0C67,0C6^,0C7*,0C81,0C82,0C83,0C84,0C8D,0C91,0CA9,0CB4,0CBA,0CBB,0CBC,0CBE,0CBF,0CC*,0CD_,0CD8,0CD9,0CDA,0CDB,0CDC,0CDF,0CE2,0CE3,0CE4,0CE5,0CE6,0CE7,0CE^,0CF0,0CF3,0CF4,0CF5,0CF6,0CF7,0CF^,0D00,0D01,0D02,0D03,0D0D,0D11,0D3B,0D3C,0D3E,0D3F,0D4_,0D48,0D49,0D4A,0D4B,0D4C,0D4D,0D4F,0D50,0D51,0D52,0D53,0D57,0D58,0D59,0D5A,0D5B,0D5C,0D5D,0D5E,0D62,0D63,0D64,0D65,0D66,0D67,0D6^,0D7_,0D78,0D79,0D80,0D81,0D82,0D83,0D84,0D97,0D98,0D99,0DB2,0DBC,0DBE,0DBF,0DC7,0DC^,0DD*,0DE*,0DF*,0E00,0E31,0E34,0E35,0E36,0E37,0E3^,0E46,0E47,0E4^,0E5*,0E6*,0E7*,0E80,0E83,0E85,0E8B,0EA4,0EA6,0EB1,0EB4,0EB5,0EB6,0EB7,0EB8,0EB9,0EBA,0EBB,0EBC,0EBE,0EBF,0EC5,0EC6,0EC7,0EC^,0ED_,0ED8,0ED9,0EDA,0EDB,0EE*,0EF*,0F01,0F02,0F03,0F04,0F05,0F06,0F07,0F0^,0F1*,0F2*,0F3*,0F48,0F6D,0F6E,0F6F,0F7*,0F8_,0F8D,0F8E,0F8F,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,102B,102C,102D,102E,102F,103_,1038,1039,103A,103B,103C,103D,103E,104*,1056,1057,1058,1059,105E,105F,1060,1062,1063,1064,1067,1068,1069,106A,106B,106C,106D,1071,1072,1073,1074,1082,1083,1084,1085,1086,1087,1088,1089,108A,108B,108C,108D,108F,109*,10A*,10B*,10C*,10D*,10E*,10F*,1249,124E,124F,1257,1259,125E,125F,1289,128E,128F,12B1,12B6,12B7,12BF,12C1,12C6,12C7,12D7,1311,1316,1317,135B,135C,135D,135E,135F,136*,137*,139*,13A*,13B*,13C*,13D*,13E*,13F*,1400,166D,166E,1680,169B,169C,169D,169E,169F,16EB,16EC,16ED,16EE,16EF,16F0,16F9,16FA,16FB,16FC,16FD,16FE,16FF,1712,1713,1714,1715,1716,1717,1718,1719,171A,171B,171C,171D,171E,1732,1733,1734,1735,1736,1737,173^,1752,1753,1754,1755,1756,1757,175^,176D,1771,1772,1773,1774,1775,1776,1777,177^,17B4,17B5,17B6,17B7,17B^,17C*,17D_,17D8,17D9,17DA,17DB,17DD,17DE,17DF,17E*,17F*,180*,181*,1843,1879,187A,187B,187C,187D,187E,187F,1885,1886,18A9,18AB,18AC,18AD,18AE,18AF,18F6,18F7,18F^,191F,192*,193*,194*,196E,196F,1975,1976,1977,197^,19AC,19AD,19AE,19AF,19CA,19CB,19CC,19CD,19CE,19CF,19D*,19E*,19F*,1A17,1A1^,1A55,1A56,1A57,1A5^,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B00,1B01,1B02,1B03,1B04,1B34,1B35,1B36,1B37,1B3^,1B40,1B41,1B42,1B43,1B44,1B4D,1B4E,1B4F,1B5*,1B6*,1B7*,1B80,1B81,1B82,1BA1,1BA2,1BA3,1BA4,1BA5,1BA6,1BA7,1BA8,1BA9,1BAA,1BAB,1BAC,1BAD,1BB_,1BB8,1BB9,1BE6,1BE7,1BE^,1BF*,1C24,1C25,1C26,1C27,1C2^,1C3*,1C4_,1C48,1C49,1C4A,1C4B,1C4C,1C5_,1C58,1C59,1C7^,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE_,1CE8,1CED,1CF4,1CF7,1CF8,1CF9,1CFB,1CFC,1CFD,1CFE,1CFF,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,2130,2131,2132,2133,2134,2139,213A,213B,213C,213D,213E,213F,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D6^,2D7*,2D97,2D9^,2DA7,2DAF,2DB7,2DBF,2DC7,2DCF,2DD7,2DDF,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,3000,3001,3002,3003,3004,3005,3007,300^,301*,302*,303_,3038,3039,303A,303B,303D,303E,303F,3040,3097,3098,3099,309A,309B,309C,309D,309E,30A0,30FB,30FC,30FD,30FE,3100,3101,3102,3103,3104,3130,318F,319*,31C*,31D*,31E*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*," - -// M -// \u0cf3 reports as false in .NET 4.7 & .NET 7, but true in .NET 8, PCRE2, and JavaScript ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{M}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"030*,031*,032*,033*,034*,035*,036*,0483,0484,0485,0486,0487,0488,0489,0591,0592,0593,0594,0595,0596,0597,059^,05A*,05B_,05B8,05B9,05BA,05BB,05BC,05BD,05BF,05C1,05C2,05C4,05C5,05C7,061_,0618,0619,061A,064B,064C,064D,064E,064F,065*,0670,06D6,06D7,06D8,06D9,06DA,06DB,06DC,06DF,06E0,06E1,06E2,06E3,06E4,06E7,06E8,06EA,06EB,06EC,06ED,0711,073*,074_,0748,0749,074A,07A6,07A7,07A^,07B0,07EB,07EC,07ED,07EE,07EF,07F0,07F1,07F2,07F3,07FD,0816,0817,0818,0819,081B,081C,081D,081E,081F,0820,0821,0822,0823,0825,0826,0827,0829,082A,082B,082C,082D,0859,085A,085B,089^,08CA,08CB,08CC,08CD,08CE,08CF,08D*,08E0,08E1,08E3,08E4,08E5,08E6,08E7,08E^,08F*,0900,0901,0902,0903,093A,093B,093C,093E,093F,094*,0951,0952,0953,0954,0955,0956,0957,0962,0963,0981,0982,0983,09BC,09BE,09BF,09C0,09C1,09C2,09C3,09C4,09C7,09C8,09CB,09CC,09CD,09D7,09E2,09E3,09FE,0A01,0A02,0A03,0A3C,0A3E,0A3F,0A40,0A41,0A42,0A47,0A48,0A4B,0A4C,0A4D,0A51,0A70,0A71,0A75,0A81,0A82,0A83,0ABC,0ABE,0ABF,0AC0,0AC1,0AC2,0AC3,0AC4,0AC5,0AC7,0AC8,0AC9,0ACB,0ACC,0ACD,0AE2,0AE3,0AFA,0AFB,0AFC,0AFD,0AFE,0AFF,0B01,0B02,0B03,0B3C,0B3E,0B3F,0B40,0B41,0B42,0B43,0B44,0B47,0B48,0B4B,0B4C,0B4D,0B55,0B56,0B57,0B62,0B63,0B82,0BBE,0BBF,0BC0,0BC1,0BC2,0BC6,0BC7,0BC8,0BCA,0BCB,0BCC,0BCD,0BD7,0C00,0C01,0C02,0C03,0C04,0C3C,0C3E,0C3F,0C40,0C41,0C42,0C43,0C44,0C46,0C47,0C48,0C4A,0C4B,0C4C,0C4D,0C55,0C56,0C62,0C63,0C81,0C82,0C83,0CBC,0CBE,0CBF,0CC0,0CC1,0CC2,0CC3,0CC4,0CC6,0CC7,0CC8,0CCA,0CCB,0CCC,0CCD,0CD5,0CD6,0CE2,0CE3,0D00,0D01,0D02,0D03,0D3B,0D3C,0D3E,0D3F,0D40,0D41,0D42,0D43,0D44,0D46,0D47,0D48,0D4A,0D4B,0D4C,0D4D,0D57,0D62,0D63,0D81,0D82,0D83,0DCA,0DCF,0DD0,0DD1,0DD2,0DD3,0DD4,0DD6,0DD^,0DF2,0DF3,0E31,0E34,0E35,0E36,0E37,0E38,0E39,0E3A,0E47,0E48,0E49,0E4A,0E4B,0E4C,0E4D,0E4E,0EB1,0EB4,0EB5,0EB6,0EB7,0EB8,0EB9,0EBA,0EBB,0EBC,0EC8,0EC9,0ECA,0ECB,0ECC,0ECD,0F18,0F19,0F35,0F37,0F39,0F3E,0F3F,0F71,0F72,0F73,0F74,0F75,0F76,0F77,0F7^,0F80,0F81,0F82,0F83,0F84,0F86,0F87,0F8D,0F8E,0F8F,0F9_,0F99,0F9A,0F9B,0F9C,0F9D,0F9E,0F9F,0FA*,0FB_,0FB8,0FB9,0FBA,0FBB,0FBC,0FC6,102B,102C,102D,102E,102F,103_,1038,1039,103A,103B,103C,103D,103E,1056,1057,1058,1059,105E,105F,1060,1062,1063,1064,1067,1068,1069,106A,106B,106C,106D,1071,1072,1073,1074,1082,1083,1084,1085,1086,1087,1088,1089,108A,108B,108C,108D,108F,109A,109B,109C,109D,135D,135E,135F,1712,1713,1714,1715,1732,1733,1734,1752,1753,1772,1773,17B4,17B5,17B6,17B7,17B^,17C*,17D0,17D1,17D2,17D3,17DD,180B,180C,180D,180F,1885,1886,18A9,192_,1928,1929,192A,192B,193_,1938,1939,193A,193B,1A17,1A18,1A19,1A1A,1A1B,1A55,1A56,1A57,1A58,1A59,1A5A,1A5B,1A5C,1A5D,1A5E,1A6*,1A7_,1A78,1A79,1A7A,1A7B,1A7C,1A7F,1AB*,1AC_,1AC8,1AC9,1ACA,1ACB,1ACC,1ACD,1ACE,1B00,1B01,1B02,1B03,1B04,1B34,1B35,1B36,1B37,1B3^,1B40,1B41,1B42,1B43,1B44,1B6B,1B6C,1B6D,1B6E,1B6F,1B70,1B71,1B72,1B73,1B80,1B81,1B82,1BA1,1BA2,1BA3,1BA4,1BA5,1BA6,1BA7,1BA8,1BA9,1BAA,1BAB,1BAC,1BAD,1BE6,1BE7,1BE^,1BF0,1BF1,1BF2,1BF3,1C24,1C25,1C26,1C27,1C2^,1C3_,1CD0,1CD1,1CD2,1CD4,1CD5,1CD6,1CD7,1CD^,1CE_,1CE8,1CED,1CF4,1CF7,1CF8,1CF9,1DC*,1DD*,1DE*,1DF*,20D*,20E*,20F0,2CEF,2CF0,2CF1,2D7F,2DE*,2DF*,302A,302B,302C,302D,302E,302F,3099,309A," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{M}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,0480,0481,0482,048A,048B,048C,048D,048E,048F,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,0590,05BE,05C0,05C3,05C6,05C^,05D*,05E*,05F*,060*,061B,061C,061D,061E,061F,062*,063*,064_,0648,0649,064A,066*,0671,0672,0673,0674,0675,0676,0677,067^,068*,069*,06A*,06B*,06C*,06D0,06D1,06D2,06D3,06D4,06D5,06DD,06DE,06E5,06E6,06E9,06EE,06EF,06F*,070*,0710,0712,0713,0714,0715,0716,0717,071^,072*,074B,074C,074D,074E,074F,075*,076*,077*,078*,079*,07A0,07A1,07A2,07A3,07A4,07A5,07B1,07B2,07B3,07B4,07B5,07B6,07B7,07B^,07C*,07D*,07E_,07E8,07E9,07EA,07F4,07F5,07F6,07F7,07F8,07F9,07FA,07FB,07FC,07FE,07FF,080*,0810,0811,0812,0813,0814,0815,081A,0824,0828,082E,082F,083*,084*,085_,0858,085C,085D,085E,085F,086*,087*,088*,089_,08A*,08B*,08C_,08C8,08C9,08E2,0904,0905,0906,0907,090^,091*,092*,093_,0938,0939,093D,0950,095^,0960,0961,0964,0965,0966,0967,096^,097*,0980,0984,0985,0986,0987,098^,099*,09A*,09B_,09B8,09B9,09BA,09BB,09BD,09C5,09C6,09C9,09CA,09CE,09CF,09D0,09D1,09D2,09D3,09D4,09D5,09D6,09D^,09E0,09E1,09E4,09E5,09E6,09E7,09E^,09F_,09F8,09F9,09FA,09FB,09FC,09FD,09FF,0A00,0A04,0A05,0A06,0A07,0A0^,0A1*,0A2*,0A3_,0A38,0A39,0A3A,0A3B,0A3D,0A43,0A44,0A45,0A46,0A49,0A4A,0A4E,0A4F,0A50,0A52,0A53,0A54,0A55,0A56,0A57,0A5^,0A6*,0A72,0A73,0A74,0A76,0A77,0A7^,0A80,0A84,0A85,0A86,0A87,0A8^,0A9*,0AA*,0AB_,0AB8,0AB9,0ABA,0ABB,0ABD,0AC6,0ACA,0ACE,0ACF,0AD*,0AE0,0AE1,0AE4,0AE5,0AE6,0AE7,0AE^,0AF_,0AF8,0AF9,0B00,0B04,0B05,0B06,0B07,0B0^,0B1*,0B2*,0B3_,0B38,0B39,0B3A,0B3B,0B3D,0B45,0B46,0B49,0B4A,0B4E,0B4F,0B50,0B51,0B52,0B53,0B54,0B5^,0B60,0B61,0B64,0B65,0B66,0B67,0B6^,0B7*,0B80,0B81,0B83,0B84,0B85,0B86,0B87,0B8^,0B9*,0BA*,0BB_,0BB8,0BB9,0BBA,0BBB,0BBC,0BBD,0BC3,0BC4,0BC5,0BC9,0BCE,0BCF,0BD0,0BD1,0BD2,0BD3,0BD4,0BD5,0BD6,0BD^,0BE*,0BF*,0C05,0C06,0C07,0C0^,0C1*,0C2*,0C3_,0C38,0C39,0C3A,0C3B,0C3D,0C45,0C49,0C4E,0C4F,0C50,0C51,0C52,0C53,0C54,0C57,0C5^,0C60,0C61,0C64,0C65,0C66,0C67,0C6^,0C7*,0C80,0C84,0C85,0C86,0C87,0C8^,0C9*,0CA*,0CB_,0CB8,0CB9,0CBA,0CBB,0CBD,0CC5,0CC9,0CCE,0CCF,0CD0,0CD1,0CD2,0CD3,0CD4,0CD7,0CD^,0CE0,0CE1,0CE4,0CE5,0CE6,0CE7,0CE^,0CF*,0D04,0D05,0D06,0D07,0D0^,0D1*,0D2*,0D3_,0D38,0D39,0D3A,0D3D,0D45,0D49,0D4E,0D4F,0D50,0D51,0D52,0D53,0D54,0D55,0D56,0D5^,0D60,0D61,0D64,0D65,0D66,0D67,0D6^,0D7*,0D80,0D84,0D85,0D86,0D87,0D8^,0D9*,0DA*,0DB*,0DC_,0DC8,0DC9,0DCB,0DCC,0DCD,0DCE,0DD5,0DD7,0DE*,0DF0,0DF1,0DF4,0DF5,0DF6,0DF7,0DF^,0E0*,0E1*,0E2*,0E30,0E32,0E33,0E3B,0E3C,0E3D,0E3E,0E3F,0E40,0E41,0E42,0E43,0E44,0E45,0E46,0E4F,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB0,0EB2,0EB3,0EBD,0EBE,0EBF,0EC_,0ECE,0ECF,0ED*,0EE*,0EF*,0F0*,0F1_,0F1A,0F1B,0F1C,0F1D,0F1E,0F1F,0F2*,0F30,0F31,0F32,0F33,0F34,0F36,0F38,0F3A,0F3B,0F3C,0F3D,0F4*,0F5*,0F6*,0F70,0F85,0F88,0F89,0F8A,0F8B,0F8C,0F98,0FBD,0FBE,0FBF,0FC0,0FC1,0FC2,0FC3,0FC4,0FC5,0FC7,0FC^,0FD*,0FE*,0FF*,100*,101*,102_,1028,1029,102A,103F,104*,1050,1051,1052,1053,1054,1055,105A,105B,105C,105D,1061,1065,1066,106E,106F,1070,1075,1076,1077,107^,1080,1081,108E,109_,1098,1099,109E,109F,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135_,1358,1359,135A,135B,135C,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,1710,1711,1716,1717,171^,172*,1730,1731,1735,1736,1737,173^,174*,1750,1751,1754,1755,1756,1757,175^,176*,1770,1771,1774,1775,1776,1777,177^,178*,179*,17A*,17B0,17B1,17B2,17B3,17D4,17D5,17D6,17D7,17D8,17D9,17DA,17DB,17DC,17DE,17DF,17E*,17F*,180_,1808,1809,180A,180E,181*,182*,183*,184*,185*,186*,187*,1880,1881,1882,1883,1884,1887,188^,189*,18A_,18A8,18AA,18AB,18AC,18AD,18AE,18AF,18B*,18C*,18D*,18E*,18F*,190*,191*,192C,192D,192E,192F,193C,193D,193E,193F,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A10,1A11,1A12,1A13,1A14,1A15,1A16,1A1C,1A1D,1A1E,1A1F,1A2*,1A3*,1A4*,1A50,1A51,1A52,1A53,1A54,1A5F,1A7D,1A7E,1A8*,1A9*,1AA*,1ACF,1AD*,1AE*,1AF*,1B05,1B06,1B07,1B0^,1B1*,1B2*,1B30,1B31,1B32,1B33,1B45,1B46,1B47,1B4^,1B5*,1B6_,1B68,1B69,1B6A,1B74,1B75,1B76,1B77,1B7^,1B83,1B84,1B85,1B86,1B87,1B8^,1B9*,1BA0,1BAE,1BAF,1BB*,1BC*,1BD*,1BE0,1BE1,1BE2,1BE3,1BE4,1BE5,1BF4,1BF5,1BF6,1BF7,1BF^,1C0*,1C1*,1C20,1C21,1C22,1C23,1C3^,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD3,1CE9,1CEA,1CEB,1CEC,1CEE,1CEF,1CF0,1CF1,1CF2,1CF3,1CF5,1CF6,1CFA,1CFB,1CFC,1CFD,1CFE,1CFF,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20F1,20F2,20F3,20F4,20F5,20F6,20F7,20F^,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE_,2CE8,2CE9,2CEA,2CEB,2CEC,2CED,2CEE,2CF2,2CF3,2CF4,2CF5,2CF6,2CF7,2CF^,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7_,2D78,2D79,2D7A,2D7B,2D7C,2D7D,2D7E,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302_,3028,3029,303*,304*,305*,306*,307*,308*,309_,3098,309B,309C,309D,309E,309F,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// Mn ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Mn}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"030*,031*,032*,033*,034*,035*,036*,0483,0484,0485,0486,0487,0591,0592,0593,0594,0595,0596,0597,059^,05A*,05B_,05B8,05B9,05BA,05BB,05BC,05BD,05BF,05C1,05C2,05C4,05C5,05C7,061_,0618,0619,061A,064B,064C,064D,064E,064F,065*,0670,06D6,06D7,06D8,06D9,06DA,06DB,06DC,06DF,06E0,06E1,06E2,06E3,06E4,06E7,06E8,06EA,06EB,06EC,06ED,0711,073*,074_,0748,0749,074A,07A6,07A7,07A^,07B0,07EB,07EC,07ED,07EE,07EF,07F0,07F1,07F2,07F3,07FD,0816,0817,0818,0819,081B,081C,081D,081E,081F,0820,0821,0822,0823,0825,0826,0827,0829,082A,082B,082C,082D,0859,085A,085B,089^,08CA,08CB,08CC,08CD,08CE,08CF,08D*,08E0,08E1,08E3,08E4,08E5,08E6,08E7,08E^,08F*,0900,0901,0902,093A,093C,0941,0942,0943,0944,0945,0946,0947,0948,094D,0951,0952,0953,0954,0955,0956,0957,0962,0963,0981,09BC,09C1,09C2,09C3,09C4,09CD,09E2,09E3,09FE,0A01,0A02,0A3C,0A41,0A42,0A47,0A48,0A4B,0A4C,0A4D,0A51,0A70,0A71,0A75,0A81,0A82,0ABC,0AC1,0AC2,0AC3,0AC4,0AC5,0AC7,0AC8,0ACD,0AE2,0AE3,0AFA,0AFB,0AFC,0AFD,0AFE,0AFF,0B01,0B3C,0B3F,0B41,0B42,0B43,0B44,0B4D,0B55,0B56,0B62,0B63,0B82,0BC0,0BCD,0C00,0C04,0C3C,0C3E,0C3F,0C40,0C46,0C47,0C48,0C4A,0C4B,0C4C,0C4D,0C55,0C56,0C62,0C63,0C81,0CBC,0CBF,0CC6,0CCC,0CCD,0CE2,0CE3,0D00,0D01,0D3B,0D3C,0D41,0D42,0D43,0D44,0D4D,0D62,0D63,0D81,0DCA,0DD2,0DD3,0DD4,0DD6,0E31,0E34,0E35,0E36,0E37,0E38,0E39,0E3A,0E47,0E48,0E49,0E4A,0E4B,0E4C,0E4D,0E4E,0EB1,0EB4,0EB5,0EB6,0EB7,0EB8,0EB9,0EBA,0EBB,0EBC,0EC8,0EC9,0ECA,0ECB,0ECC,0ECD,0F18,0F19,0F35,0F37,0F39,0F71,0F72,0F73,0F74,0F75,0F76,0F77,0F78,0F79,0F7A,0F7B,0F7C,0F7D,0F7E,0F80,0F81,0F82,0F83,0F84,0F86,0F87,0F8D,0F8E,0F8F,0F9_,0F99,0F9A,0F9B,0F9C,0F9D,0F9E,0F9F,0FA*,0FB_,0FB8,0FB9,0FBA,0FBB,0FBC,0FC6,102D,102E,102F,1030,1032,1033,1034,1035,1036,1037,1039,103A,103D,103E,1058,1059,105E,105F,1060,1071,1072,1073,1074,1082,1085,1086,108D,109D,135D,135E,135F,1712,1713,1714,1732,1733,1752,1753,1772,1773,17B4,17B5,17B7,17B8,17B9,17BA,17BB,17BC,17BD,17C6,17C9,17CA,17CB,17CC,17CD,17CE,17CF,17D0,17D1,17D2,17D3,17DD,180B,180C,180D,180F,1885,1886,18A9,1920,1921,1922,1927,1928,1932,1939,193A,193B,1A17,1A18,1A1B,1A56,1A58,1A59,1A5A,1A5B,1A5C,1A5D,1A5E,1A60,1A62,1A65,1A66,1A67,1A68,1A69,1A6A,1A6B,1A6C,1A73,1A74,1A75,1A76,1A77,1A78,1A79,1A7A,1A7B,1A7C,1A7F,1AB_,1AB8,1AB9,1ABA,1ABB,1ABC,1ABD,1ABF,1AC_,1AC8,1AC9,1ACA,1ACB,1ACC,1ACD,1ACE,1B00,1B01,1B02,1B03,1B34,1B36,1B37,1B38,1B39,1B3A,1B3C,1B42,1B6B,1B6C,1B6D,1B6E,1B6F,1B70,1B71,1B72,1B73,1B80,1B81,1BA2,1BA3,1BA4,1BA5,1BA8,1BA9,1BAB,1BAC,1BAD,1BE6,1BE8,1BE9,1BED,1BEF,1BF0,1BF1,1C2C,1C2D,1C2E,1C2F,1C30,1C31,1C32,1C33,1C36,1C37,1CD0,1CD1,1CD2,1CD4,1CD5,1CD6,1CD7,1CD^,1CE0,1CE2,1CE3,1CE4,1CE5,1CE6,1CE7,1CE8,1CED,1CF4,1CF8,1CF9,1DC*,1DD*,1DE*,1DF*,20D_,20D8,20D9,20DA,20DB,20DC,20E1,20E5,20E6,20E7,20E^,20F0,2CEF,2CF0,2CF1,2D7F,2DE*,2DF*,302A,302B,302C,302D,3099,309A," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Mn}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,0480,0481,0482,048^,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,0590,05BE,05C0,05C3,05C6,05C^,05D*,05E*,05F*,060*,061B,061C,061D,061E,061F,062*,063*,064_,0648,0649,064A,066*,0671,0672,0673,0674,0675,0676,0677,067^,068*,069*,06A*,06B*,06C*,06D0,06D1,06D2,06D3,06D4,06D5,06DD,06DE,06E5,06E6,06E9,06EE,06EF,06F*,070*,0710,0712,0713,0714,0715,0716,0717,071^,072*,074B,074C,074D,074E,074F,075*,076*,077*,078*,079*,07A0,07A1,07A2,07A3,07A4,07A5,07B1,07B2,07B3,07B4,07B5,07B6,07B7,07B^,07C*,07D*,07E_,07E8,07E9,07EA,07F4,07F5,07F6,07F7,07F8,07F9,07FA,07FB,07FC,07FE,07FF,080*,0810,0811,0812,0813,0814,0815,081A,0824,0828,082E,082F,083*,084*,085_,0858,085C,085D,085E,085F,086*,087*,088*,089_,08A*,08B*,08C_,08C8,08C9,08E2,0903,0904,0905,0906,0907,090^,091*,092*,093_,0938,0939,093B,093D,093E,093F,0940,0949,094A,094B,094C,094E,094F,0950,095^,0960,0961,0964,0965,0966,0967,096^,097*,0980,0982,0983,0984,0985,0986,0987,098^,099*,09A*,09B_,09B8,09B9,09BA,09BB,09BD,09BE,09BF,09C0,09C5,09C6,09C7,09C8,09C9,09CA,09CB,09CC,09CE,09CF,09D*,09E0,09E1,09E4,09E5,09E6,09E7,09E^,09F_,09F8,09F9,09FA,09FB,09FC,09FD,09FF,0A00,0A03,0A04,0A05,0A06,0A07,0A0^,0A1*,0A2*,0A3_,0A38,0A39,0A3A,0A3B,0A3D,0A3E,0A3F,0A40,0A43,0A44,0A45,0A46,0A49,0A4A,0A4E,0A4F,0A50,0A52,0A53,0A54,0A55,0A56,0A57,0A5^,0A6*,0A72,0A73,0A74,0A76,0A77,0A7^,0A80,0A83,0A84,0A85,0A86,0A87,0A8^,0A9*,0AA*,0AB_,0AB8,0AB9,0ABA,0ABB,0ABD,0ABE,0ABF,0AC0,0AC6,0AC9,0ACA,0ACB,0ACC,0ACE,0ACF,0AD*,0AE0,0AE1,0AE4,0AE5,0AE6,0AE7,0AE^,0AF_,0AF8,0AF9,0B00,0B02,0B03,0B04,0B05,0B06,0B07,0B0^,0B1*,0B2*,0B3_,0B38,0B39,0B3A,0B3B,0B3D,0B3E,0B40,0B45,0B46,0B47,0B48,0B49,0B4A,0B4B,0B4C,0B4E,0B4F,0B50,0B51,0B52,0B53,0B54,0B57,0B5^,0B60,0B61,0B64,0B65,0B66,0B67,0B6^,0B7*,0B80,0B81,0B83,0B84,0B85,0B86,0B87,0B8^,0B9*,0BA*,0BB*,0BC1,0BC2,0BC3,0BC4,0BC5,0BC6,0BC7,0BC8,0BC9,0BCA,0BCB,0BCC,0BCE,0BCF,0BD*,0BE*,0BF*,0C01,0C02,0C03,0C05,0C06,0C07,0C0^,0C1*,0C2*,0C3_,0C38,0C39,0C3A,0C3B,0C3D,0C41,0C42,0C43,0C44,0C45,0C49,0C4E,0C4F,0C50,0C51,0C52,0C53,0C54,0C57,0C5^,0C60,0C61,0C64,0C65,0C66,0C67,0C6^,0C7*,0C80,0C82,0C83,0C84,0C85,0C86,0C87,0C8^,0C9*,0CA*,0CB_,0CB8,0CB9,0CBA,0CBB,0CBD,0CBE,0CC0,0CC1,0CC2,0CC3,0CC4,0CC5,0CC7,0CC8,0CC9,0CCA,0CCB,0CCE,0CCF,0CD*,0CE0,0CE1,0CE4,0CE5,0CE6,0CE7,0CE^,0CF*,0D02,0D03,0D04,0D05,0D06,0D07,0D0^,0D1*,0D2*,0D3_,0D38,0D39,0D3A,0D3D,0D3E,0D3F,0D40,0D45,0D46,0D47,0D48,0D49,0D4A,0D4B,0D4C,0D4E,0D4F,0D5*,0D60,0D61,0D64,0D65,0D66,0D67,0D6^,0D7*,0D80,0D82,0D83,0D84,0D85,0D86,0D87,0D8^,0D9*,0DA*,0DB*,0DC_,0DC8,0DC9,0DCB,0DCC,0DCD,0DCE,0DCF,0DD0,0DD1,0DD5,0DD7,0DD^,0DE*,0DF*,0E0*,0E1*,0E2*,0E30,0E32,0E33,0E3B,0E3C,0E3D,0E3E,0E3F,0E40,0E41,0E42,0E43,0E44,0E45,0E46,0E4F,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB0,0EB2,0EB3,0EBD,0EBE,0EBF,0EC_,0ECE,0ECF,0ED*,0EE*,0EF*,0F0*,0F1_,0F1A,0F1B,0F1C,0F1D,0F1E,0F1F,0F2*,0F30,0F31,0F32,0F33,0F34,0F36,0F38,0F3A,0F3B,0F3C,0F3D,0F3E,0F3F,0F4*,0F5*,0F6*,0F70,0F7F,0F85,0F88,0F89,0F8A,0F8B,0F8C,0F98,0FBD,0FBE,0FBF,0FC0,0FC1,0FC2,0FC3,0FC4,0FC5,0FC7,0FC^,0FD*,0FE*,0FF*,100*,101*,102_,1028,1029,102A,102B,102C,1031,1038,103B,103C,103F,104*,105_,105A,105B,105C,105D,1061,1062,1063,1064,1065,1066,1067,106^,1070,1075,1076,1077,107^,1080,1081,1083,1084,1087,1088,1089,108A,108B,108C,108E,108F,109_,1098,1099,109A,109B,109C,109E,109F,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135_,1358,1359,135A,135B,135C,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,1710,1711,1715,1716,1717,171^,172*,1730,1731,1734,1735,1736,1737,173^,174*,1750,1751,1754,1755,1756,1757,175^,176*,1770,1771,1774,1775,1776,1777,177^,178*,179*,17A*,17B0,17B1,17B2,17B3,17B6,17BE,17BF,17C0,17C1,17C2,17C3,17C4,17C5,17C7,17C8,17D4,17D5,17D6,17D7,17D8,17D9,17DA,17DB,17DC,17DE,17DF,17E*,17F*,180_,1808,1809,180A,180E,181*,182*,183*,184*,185*,186*,187*,1880,1881,1882,1883,1884,1887,188^,189*,18A_,18A8,18AA,18AB,18AC,18AD,18AE,18AF,18B*,18C*,18D*,18E*,18F*,190*,191*,1923,1924,1925,1926,1929,192A,192B,192C,192D,192E,192F,1930,1931,1933,1934,1935,1936,1937,1938,193C,193D,193E,193F,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A10,1A11,1A12,1A13,1A14,1A15,1A16,1A19,1A1A,1A1C,1A1D,1A1E,1A1F,1A2*,1A3*,1A4*,1A50,1A51,1A52,1A53,1A54,1A55,1A57,1A5F,1A61,1A63,1A64,1A6D,1A6E,1A6F,1A70,1A71,1A72,1A7D,1A7E,1A8*,1A9*,1AA*,1ABE,1ACF,1AD*,1AE*,1AF*,1B04,1B05,1B06,1B07,1B0^,1B1*,1B2*,1B30,1B31,1B32,1B33,1B35,1B3B,1B3D,1B3E,1B3F,1B40,1B41,1B43,1B44,1B45,1B46,1B47,1B4^,1B5*,1B6_,1B68,1B69,1B6A,1B74,1B75,1B76,1B77,1B7^,1B82,1B83,1B84,1B85,1B86,1B87,1B8^,1B9*,1BA0,1BA1,1BA6,1BA7,1BAA,1BAE,1BAF,1BB*,1BC*,1BD*,1BE0,1BE1,1BE2,1BE3,1BE4,1BE5,1BE7,1BEA,1BEB,1BEC,1BEE,1BF2,1BF3,1BF4,1BF5,1BF6,1BF7,1BF^,1C0*,1C1*,1C2_,1C28,1C29,1C2A,1C2B,1C34,1C35,1C3^,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD3,1CE1,1CE9,1CEA,1CEB,1CEC,1CEE,1CEF,1CF0,1CF1,1CF2,1CF3,1CF5,1CF6,1CF7,1CFA,1CFB,1CFC,1CFD,1CFE,1CFF,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20DD,20DE,20DF,20E0,20E2,20E3,20E4,20F1,20F2,20F3,20F4,20F5,20F6,20F7,20F^,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE_,2CE8,2CE9,2CEA,2CEB,2CEC,2CED,2CEE,2CF2,2CF3,2CF4,2CF5,2CF6,2CF7,2CF^,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7_,2D78,2D79,2D7A,2D7B,2D7C,2D7D,2D7E,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302_,3028,3029,302E,302F,303*,304*,305*,306*,307*,308*,309_,3098,309B,309C,309D,309E,309F,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// Mc -// \u0cf3 reports as false in .NET 4.7 & .NET 7, but true in .NET 8, PCRE2, and JavaScript ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Mc}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0903,093B,093E,093F,0940,0949,094A,094B,094C,094E,094F,0982,0983,09BE,09BF,09C0,09C7,09C8,09CB,09CC,09D7,0A03,0A3E,0A3F,0A40,0A83,0ABE,0ABF,0AC0,0AC9,0ACB,0ACC,0B02,0B03,0B3E,0B40,0B47,0B48,0B4B,0B4C,0B57,0BBE,0BBF,0BC1,0BC2,0BC6,0BC7,0BC8,0BCA,0BCB,0BCC,0BD7,0C01,0C02,0C03,0C41,0C42,0C43,0C44,0C82,0C83,0CBE,0CC0,0CC1,0CC2,0CC3,0CC4,0CC7,0CC8,0CCA,0CCB,0CD5,0CD6,0D02,0D03,0D3E,0D3F,0D40,0D46,0D47,0D48,0D4A,0D4B,0D4C,0D57,0D82,0D83,0DCF,0DD0,0DD1,0DD^,0DF2,0DF3,0F3E,0F3F,0F7F,102B,102C,1031,1038,103B,103C,1056,1057,1062,1063,1064,1067,1068,1069,106A,106B,106C,106D,1083,1084,1087,1088,1089,108A,108B,108C,108F,109A,109B,109C,1715,1734,17B6,17BE,17BF,17C0,17C1,17C2,17C3,17C4,17C5,17C7,17C8,1923,1924,1925,1926,1929,192A,192B,1930,1931,1933,1934,1935,1936,1937,1938,1A19,1A1A,1A55,1A57,1A61,1A63,1A64,1A6D,1A6E,1A6F,1A70,1A71,1A72,1B04,1B35,1B3B,1B3D,1B3E,1B3F,1B40,1B41,1B43,1B44,1B82,1BA1,1BA6,1BA7,1BAA,1BE7,1BEA,1BEB,1BEC,1BEE,1BF2,1BF3,1C24,1C25,1C26,1C27,1C28,1C29,1C2A,1C2B,1C34,1C35,1CE1,1CF7,302E,302F," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Mc}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,0900,0901,0902,0904,0905,0906,0907,090^,091*,092*,093_,0938,0939,093A,093C,093D,0941,0942,0943,0944,0945,0946,0947,0948,094D,095*,096*,097*,0980,0981,0984,0985,0986,0987,098^,099*,09A*,09B_,09B8,09B9,09BA,09BB,09BC,09BD,09C1,09C2,09C3,09C4,09C5,09C6,09C9,09CA,09CD,09CE,09CF,09D0,09D1,09D2,09D3,09D4,09D5,09D6,09D^,09E*,09F*,0A00,0A01,0A02,0A04,0A05,0A06,0A07,0A0^,0A1*,0A2*,0A3_,0A38,0A39,0A3A,0A3B,0A3C,0A3D,0A41,0A42,0A43,0A44,0A45,0A46,0A47,0A4^,0A5*,0A6*,0A7*,0A80,0A81,0A82,0A84,0A85,0A86,0A87,0A8^,0A9*,0AA*,0AB_,0AB8,0AB9,0ABA,0ABB,0ABC,0ABD,0AC1,0AC2,0AC3,0AC4,0AC5,0AC6,0AC7,0AC8,0ACA,0ACD,0ACE,0ACF,0AD*,0AE*,0AF*,0B00,0B01,0B04,0B05,0B06,0B07,0B0^,0B1*,0B2*,0B3_,0B38,0B39,0B3A,0B3B,0B3C,0B3D,0B3F,0B41,0B42,0B43,0B44,0B45,0B46,0B49,0B4A,0B4D,0B4E,0B4F,0B50,0B51,0B52,0B53,0B54,0B55,0B56,0B5^,0B6*,0B7*,0B8*,0B9*,0BA*,0BB_,0BB8,0BB9,0BBA,0BBB,0BBC,0BBD,0BC0,0BC3,0BC4,0BC5,0BC9,0BCD,0BCE,0BCF,0BD0,0BD1,0BD2,0BD3,0BD4,0BD5,0BD6,0BD^,0BE*,0BF*,0C00,0C04,0C05,0C06,0C07,0C0^,0C1*,0C2*,0C3*,0C40,0C45,0C46,0C47,0C4^,0C5*,0C6*,0C7*,0C80,0C81,0C84,0C85,0C86,0C87,0C8^,0C9*,0CA*,0CB_,0CB8,0CB9,0CBA,0CBB,0CBC,0CBD,0CBF,0CC5,0CC6,0CC9,0CCC,0CCD,0CCE,0CCF,0CD0,0CD1,0CD2,0CD3,0CD4,0CD7,0CD^,0CE*,0CF*,0D00,0D01,0D04,0D05,0D06,0D07,0D0^,0D1*,0D2*,0D3_,0D38,0D39,0D3A,0D3B,0D3C,0D3D,0D41,0D42,0D43,0D44,0D45,0D49,0D4D,0D4E,0D4F,0D50,0D51,0D52,0D53,0D54,0D55,0D56,0D5^,0D6*,0D7*,0D80,0D81,0D84,0D85,0D86,0D87,0D8^,0D9*,0DA*,0DB*,0DC_,0DC8,0DC9,0DCA,0DCB,0DCC,0DCD,0DCE,0DD2,0DD3,0DD4,0DD5,0DD6,0DD7,0DE*,0DF0,0DF1,0DF4,0DF5,0DF6,0DF7,0DF^,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3_,0F38,0F39,0F3A,0F3B,0F3C,0F3D,0F4*,0F5*,0F6*,0F7_,0F78,0F79,0F7A,0F7B,0F7C,0F7D,0F7E,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102_,1028,1029,102A,102D,102E,102F,1030,1032,1033,1034,1035,1036,1037,1039,103A,103D,103E,103F,104*,1050,1051,1052,1053,1054,1055,105^,1060,1061,1065,1066,106E,106F,107*,1080,1081,1082,1085,1086,108D,108E,109_,1098,1099,109D,109E,109F,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,1710,1711,1712,1713,1714,1716,1717,171^,172*,1730,1731,1732,1733,1735,1736,1737,173^,174*,175*,176*,177*,178*,179*,17A*,17B0,17B1,17B2,17B3,17B4,17B5,17B7,17B8,17B9,17BA,17BB,17BC,17BD,17C6,17C9,17CA,17CB,17CC,17CD,17CE,17CF,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,1920,1921,1922,1927,1928,192C,192D,192E,192F,1932,1939,193A,193B,193C,193D,193E,193F,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1_,1A18,1A1B,1A1C,1A1D,1A1E,1A1F,1A2*,1A3*,1A4*,1A50,1A51,1A52,1A53,1A54,1A56,1A5^,1A60,1A62,1A65,1A66,1A67,1A68,1A69,1A6A,1A6B,1A6C,1A73,1A74,1A75,1A76,1A77,1A7^,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B00,1B01,1B02,1B03,1B05,1B06,1B07,1B0^,1B1*,1B2*,1B30,1B31,1B32,1B33,1B34,1B36,1B37,1B38,1B39,1B3A,1B3C,1B42,1B45,1B46,1B47,1B4^,1B5*,1B6*,1B7*,1B80,1B81,1B83,1B84,1B85,1B86,1B87,1B8^,1B9*,1BA0,1BA2,1BA3,1BA4,1BA5,1BA8,1BA9,1BAB,1BAC,1BAD,1BAE,1BAF,1BB*,1BC*,1BD*,1BE0,1BE1,1BE2,1BE3,1BE4,1BE5,1BE6,1BE8,1BE9,1BED,1BEF,1BF0,1BF1,1BF4,1BF5,1BF6,1BF7,1BF^,1C0*,1C1*,1C20,1C21,1C22,1C23,1C2C,1C2D,1C2E,1C2F,1C30,1C31,1C32,1C33,1C36,1C37,1C3^,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE0,1CE2,1CE3,1CE4,1CE5,1CE6,1CE7,1CE^,1CF0,1CF1,1CF2,1CF3,1CF4,1CF5,1CF6,1CF^,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302_,3028,3029,302A,302B,302C,302D,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// Me ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Me}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0488,0489,1ABE,20DD,20DE,20DF,20E0,20E2,20E3,20E4," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Me}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048_,048A,048B,048C,048D,048E,048F,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB_,1AB8,1AB9,1ABA,1ABB,1ABC,1ABD,1ABF,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D_,20D8,20D9,20DA,20DB,20DC,20E1,20E5,20E6,20E7,20E^,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// N ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{N}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"003_,0038,0039,00B2,00B3,00B9,00BC,00BD,00BE,066_,0668,0669,06F_,06F8,06F9,07C_,07C8,07C9,0966,0967,096^,09E6,09E7,09E^,09F4,09F5,09F6,09F7,09F8,09F9,0A66,0A67,0A6^,0AE6,0AE7,0AE^,0B66,0B67,0B6^,0B72,0B73,0B74,0B75,0B76,0B77,0BE6,0BE7,0BE^,0BF0,0BF1,0BF2,0C66,0C67,0C6^,0C78,0C79,0C7A,0C7B,0C7C,0C7D,0C7E,0CE6,0CE7,0CE^,0D58,0D59,0D5A,0D5B,0D5C,0D5D,0D5E,0D66,0D67,0D6^,0D7_,0D78,0DE6,0DE7,0DE^,0E5_,0E58,0E59,0ED_,0ED8,0ED9,0F2*,0F30,0F31,0F32,0F33,104_,1048,1049,109_,1098,1099,1369,136A,136B,136C,136D,136E,136F,137_,1378,1379,137A,137B,137C,16EE,16EF,16F0,17E_,17E8,17E9,17F_,17F8,17F9,181_,1818,1819,1946,1947,194^,19D_,19D8,19D9,19DA,1A8_,1A88,1A89,1A9_,1A98,1A99,1B5_,1B58,1B59,1BB_,1BB8,1BB9,1C4_,1C48,1C49,1C5_,1C58,1C59,2070,2074,2075,2076,2077,2078,2079,208_,2088,2089,215*,216*,217*,2180,2181,2182,2185,2186,2187,2188,2189,246*,247*,248*,249_,2498,2499,249A,249B,24EA,24EB,24EC,24ED,24EE,24EF,24F*,2776,2777,277^,278*,2790,2791,2792,2793,2CFD,3007,3021,3022,3023,3024,3025,3026,3027,3028,3029,3038,3039,303A,3192,3193,3194,3195,322_,3228,3229,324^,3251,3252,3253,3254,3255,3256,3257,325^,328_,3288,3289,32B1,32B2,32B3,32B4,32B5,32B6,32B7,32B^," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{N}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003A,003B,003C,003D,003E,003F,004*,005*,006*,007*,008*,009*,00A*,00B0,00B1,00B4,00B5,00B6,00B7,00B8,00BA,00BB,00BF,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066A,066B,066C,066D,066E,066F,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06FA,06FB,06FC,06FD,06FE,06FF,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07CA,07CB,07CC,07CD,07CE,07CF,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,0960,0961,0962,0963,0964,0965,097*,098*,099*,09A*,09B*,09C*,09D*,09E0,09E1,09E2,09E3,09E4,09E5,09F0,09F1,09F2,09F3,09FA,09FB,09FC,09FD,09FE,09FF,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A60,0A61,0A62,0A63,0A64,0A65,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE0,0AE1,0AE2,0AE3,0AE4,0AE5,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B60,0B61,0B62,0B63,0B64,0B65,0B70,0B71,0B7^,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE0,0BE1,0BE2,0BE3,0BE4,0BE5,0BF3,0BF4,0BF5,0BF6,0BF7,0BF^,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C60,0C61,0C62,0C63,0C64,0C65,0C7_,0C7F,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE0,0CE1,0CE2,0CE3,0CE4,0CE5,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5_,0D5F,0D60,0D61,0D62,0D63,0D64,0D65,0D79,0D7A,0D7B,0D7C,0D7D,0D7E,0D7F,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE0,0DE1,0DE2,0DE3,0DE4,0DE5,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5A,0E5B,0E5C,0E5D,0E5E,0E5F,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0EDA,0EDB,0EDC,0EDD,0EDE,0EDF,0EE*,0EF*,0F0*,0F1*,0F34,0F35,0F36,0F37,0F3^,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104A,104B,104C,104D,104E,104F,105*,106*,107*,108*,109A,109B,109C,109D,109E,109F,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136_,1368,137D,137E,137F,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E_,16E8,16E9,16EA,16EB,16EC,16ED,16F1,16F2,16F3,16F4,16F5,16F6,16F7,16F^,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17EA,17EB,17EC,17ED,17EE,17EF,17FA,17FB,17FC,17FD,17FE,17FF,180*,181A,181B,181C,181D,181E,181F,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,1940,1941,1942,1943,1944,1945,195*,196*,197*,198*,199*,19A*,19B*,19C*,19DB,19DC,19DD,19DE,19DF,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8A,1A8B,1A8C,1A8D,1A8E,1A8F,1A9A,1A9B,1A9C,1A9D,1A9E,1A9F,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5A,1B5B,1B5C,1B5D,1B5E,1B5F,1B6*,1B7*,1B8*,1B9*,1BA*,1BBA,1BBB,1BBC,1BBD,1BBE,1BBF,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4A,1C4B,1C4C,1C4D,1C4E,1C4F,1C5A,1C5B,1C5C,1C5D,1C5E,1C5F,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,204*,205*,206*,2071,2072,2073,207A,207B,207C,207D,207E,207F,208A,208B,208C,208D,208E,208F,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,2183,2184,218A,218B,218C,218D,218E,218F,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,249C,249D,249E,249F,24A*,24B*,24C*,24D*,24E_,24E8,24E9,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,2770,2771,2772,2773,2774,2775,2794,2795,2796,2797,279^,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF_,2CF8,2CF9,2CFA,2CFB,2CFC,2CFE,2CFF,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,3000,3001,3002,3003,3004,3005,3006,300^,301*,3020,302A,302B,302C,302D,302E,302F,303_,303B,303C,303D,303E,303F,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,3190,3191,3196,3197,319^,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322A,322B,322C,322D,322E,322F,323*,324_,3250,326*,327*,328A,328B,328C,328D,328E,328F,329*,32A*,32B0,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// Nd ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Nd}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"003_,0038,0039,066_,0668,0669,06F_,06F8,06F9,07C_,07C8,07C9,0966,0967,096^,09E6,09E7,09E^,0A66,0A67,0A6^,0AE6,0AE7,0AE^,0B66,0B67,0B6^,0BE6,0BE7,0BE^,0C66,0C67,0C6^,0CE6,0CE7,0CE^,0D66,0D67,0D6^,0DE6,0DE7,0DE^,0E5_,0E58,0E59,0ED_,0ED8,0ED9,0F2_,0F28,0F29,104_,1048,1049,109_,1098,1099,17E_,17E8,17E9,181_,1818,1819,1946,1947,194^,19D_,19D8,19D9,1A8_,1A88,1A89,1A9_,1A98,1A99,1B5_,1B58,1B59,1BB_,1BB8,1BB9,1C4_,1C48,1C49,1C5_,1C58,1C59," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Nd}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003A,003B,003C,003D,003E,003F,004*,005*,006*,007*,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066A,066B,066C,066D,066E,066F,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06FA,06FB,06FC,06FD,06FE,06FF,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07CA,07CB,07CC,07CD,07CE,07CF,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,0960,0961,0962,0963,0964,0965,097*,098*,099*,09A*,09B*,09C*,09D*,09E0,09E1,09E2,09E3,09E4,09E5,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A60,0A61,0A62,0A63,0A64,0A65,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE0,0AE1,0AE2,0AE3,0AE4,0AE5,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B60,0B61,0B62,0B63,0B64,0B65,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE0,0BE1,0BE2,0BE3,0BE4,0BE5,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C60,0C61,0C62,0C63,0C64,0C65,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE0,0CE1,0CE2,0CE3,0CE4,0CE5,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D60,0D61,0D62,0D63,0D64,0D65,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE0,0DE1,0DE2,0DE3,0DE4,0DE5,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5A,0E5B,0E5C,0E5D,0E5E,0E5F,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0EDA,0EDB,0EDC,0EDD,0EDE,0EDF,0EE*,0EF*,0F0*,0F1*,0F2A,0F2B,0F2C,0F2D,0F2E,0F2F,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104A,104B,104C,104D,104E,104F,105*,106*,107*,108*,109A,109B,109C,109D,109E,109F,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17EA,17EB,17EC,17ED,17EE,17EF,17F*,180*,181A,181B,181C,181D,181E,181F,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,1940,1941,1942,1943,1944,1945,195*,196*,197*,198*,199*,19A*,19B*,19C*,19DA,19DB,19DC,19DD,19DE,19DF,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8A,1A8B,1A8C,1A8D,1A8E,1A8F,1A9A,1A9B,1A9C,1A9D,1A9E,1A9F,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5A,1B5B,1B5C,1B5D,1B5E,1B5F,1B6*,1B7*,1B8*,1B9*,1BA*,1BBA,1BBB,1BBC,1BBD,1BBE,1BBF,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4A,1C4B,1C4C,1C4D,1C4E,1C4F,1C5A,1C5B,1C5C,1C5D,1C5E,1C5F,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// Nl ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Nl}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"16EE,16EF,16F0,216*,217*,2180,2181,2182,2185,2186,2187,2188,3007,3021,3022,3023,3024,3025,3026,3027,3028,3029,3038,3039,303A," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Nl}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E_,16E8,16E9,16EA,16EB,16EC,16ED,16F1,16F2,16F3,16F4,16F5,16F6,16F7,16F^,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,2183,2184,2189,218A,218B,218C,218D,218E,218F,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,3000,3001,3002,3003,3004,3005,3006,300^,301*,3020,302A,302B,302C,302D,302E,302F,303_,303B,303C,303D,303E,303F,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// No ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{No}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"00B2,00B3,00B9,00BC,00BD,00BE,09F4,09F5,09F6,09F7,09F8,09F9,0B72,0B73,0B74,0B75,0B76,0B77,0BF0,0BF1,0BF2,0C78,0C79,0C7A,0C7B,0C7C,0C7D,0C7E,0D58,0D59,0D5A,0D5B,0D5C,0D5D,0D5E,0D7_,0D78,0F2A,0F2B,0F2C,0F2D,0F2E,0F2F,0F30,0F31,0F32,0F33,1369,136A,136B,136C,136D,136E,136F,137_,1378,1379,137A,137B,137C,17F_,17F8,17F9,19DA,2070,2074,2075,2076,2077,2078,2079,208_,2088,2089,215*,2189,246*,247*,248*,249_,2498,2499,249A,249B,24EA,24EB,24EC,24ED,24EE,24EF,24F*,2776,2777,277^,278*,2790,2791,2792,2793,2CFD,3192,3193,3194,3195,322_,3228,3229,324^,3251,3252,3253,3254,3255,3256,3257,325^,328_,3288,3289,32B1,32B2,32B3,32B4,32B5,32B6,32B7,32B^," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{No}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A*,00B0,00B1,00B4,00B5,00B6,00B7,00B8,00BA,00BB,00BF,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F0,09F1,09F2,09F3,09FA,09FB,09FC,09FD,09FE,09FF,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B70,0B71,0B7^,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF3,0BF4,0BF5,0BF6,0BF7,0BF^,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7_,0C7F,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5_,0D5F,0D6*,0D79,0D7A,0D7B,0D7C,0D7D,0D7E,0D7F,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2_,0F28,0F29,0F34,0F35,0F36,0F37,0F3^,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136_,1368,137D,137E,137F,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17FA,17FB,17FC,17FD,17FE,17FF,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D_,19D8,19D9,19DB,19DC,19DD,19DE,19DF,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,204*,205*,206*,2071,2072,2073,207A,207B,207C,207D,207E,207F,208A,208B,208C,208D,208E,208F,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,216*,217*,218_,2188,218A,218B,218C,218D,218E,218F,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,249C,249D,249E,249F,24A*,24B*,24C*,24D*,24E_,24E8,24E9,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,2770,2771,2772,2773,2774,2775,2794,2795,2796,2797,279^,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF_,2CF8,2CF9,2CFA,2CFB,2CFC,2CFE,2CFF,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,3190,3191,3196,3197,319^,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322A,322B,322C,322D,322E,322F,323*,324_,3250,326*,327*,328A,328B,328C,328D,328E,328F,329*,32A*,32B0,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// P ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{P}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0021,0022,0023,0025,0026,0027,0028,0029,002A,002C,002D,002E,002F,003A,003B,003F,0040,005B,005C,005D,005F,007B,007D,00A1,00A7,00AB,00B6,00B7,00BB,00BF,037E,0387,055A,055B,055C,055D,055E,055F,0589,058A,05BE,05C0,05C3,05C6,05F3,05F4,0609,060A,060C,060D,061B,061D,061E,061F,066A,066B,066C,066D,06D4,070_,0708,0709,070A,070B,070C,070D,07F7,07F8,07F9,083_,0838,0839,083A,083B,083C,083D,083E,085E,0964,0965,0970,09FD,0A76,0AF0,0C77,0C84,0DF4,0E4F,0E5A,0E5B,0F04,0F05,0F06,0F07,0F0^,0F10,0F11,0F12,0F14,0F3A,0F3B,0F3C,0F3D,0F85,0FD0,0FD1,0FD2,0FD3,0FD4,0FD9,0FDA,104A,104B,104C,104D,104E,104F,10FB,136_,1368,1400,166E,169B,169C,16EB,16EC,16ED,1735,1736,17D4,17D5,17D6,17D8,17D9,17DA,180_,1808,1809,180A,1944,1945,1A1E,1A1F,1AA0,1AA1,1AA2,1AA3,1AA4,1AA5,1AA6,1AA8,1AA9,1AAA,1AAB,1AAC,1AAD,1B5A,1B5B,1B5C,1B5D,1B5E,1B5F,1B60,1B7D,1B7E,1BFC,1BFD,1BFE,1BFF,1C3B,1C3C,1C3D,1C3E,1C3F,1C7E,1C7F,1CC_,1CD3,201*,202_,203*,2040,2041,2042,2043,2045,2046,2047,204^,2050,2051,2053,2054,2055,2056,2057,2058,2059,205A,205B,205C,205D,205E,207D,207E,208D,208E,2308,2309,230A,230B,2329,232A,276^,2770,2771,2772,2773,2774,2775,27C5,27C6,27E6,27E7,27E^,2983,2984,2985,2986,2987,298^,299_,2998,29D8,29D9,29DA,29DB,29FC,29FD,2CF9,2CFA,2CFB,2CFC,2CFE,2CFF,2D70,2E0*,2E1*,2E2_,2E28,2E29,2E2A,2E2B,2E2C,2E2D,2E2E,2E3*,2E4*,2E52,2E53,2E54,2E55,2E56,2E57,2E58,2E59,2E5A,2E5B,2E5C,2E5D,3001,3002,3003,300^,3010,3011,3014,3015,3016,3017,301^,3030,303D,30A0,30FB," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{P}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,0020,0024,002B,003_,0038,0039,003C,003D,003E,0041,0042,0043,0044,0045,0046,0047,004^,005_,0058,0059,005A,005E,006*,007_,0078,0079,007A,007C,007E,007F,008*,009*,00A0,00A2,00A3,00A4,00A5,00A6,00A8,00A9,00AA,00AC,00AD,00AE,00AF,00B0,00B1,00B2,00B3,00B4,00B5,00B8,00B9,00BA,00BC,00BD,00BE,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037_,0378,0379,037A,037B,037C,037D,037F,0380,0381,0382,0383,0384,0385,0386,038^,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055_,0558,0559,056*,057*,058_,0588,058B,058C,058D,058E,058F,059*,05A*,05B_,05B8,05B9,05BA,05BB,05BC,05BD,05BF,05C1,05C2,05C4,05C5,05C7,05C^,05D*,05E*,05F0,05F1,05F2,05F5,05F6,05F7,05F^,060_,0608,060B,060E,060F,061_,0618,0619,061A,061C,062*,063*,064*,065*,066_,0668,0669,066E,066F,067*,068*,069*,06A*,06B*,06C*,06D0,06D1,06D2,06D3,06D5,06D6,06D7,06D^,06E*,06F*,070E,070F,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F0,07F1,07F2,07F3,07F4,07F5,07F6,07FA,07FB,07FC,07FD,07FE,07FF,080*,081*,082*,083F,084*,085_,0858,0859,085A,085B,085C,085D,085F,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,0960,0961,0962,0963,0966,0967,096^,0971,0972,0973,0974,0975,0976,0977,097^,098*,099*,09A*,09B*,09C*,09D*,09E*,09F_,09F8,09F9,09FA,09FB,09FC,09FE,09FF,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A70,0A71,0A72,0A73,0A74,0A75,0A77,0A7^,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF1,0AF2,0AF3,0AF4,0AF5,0AF6,0AF7,0AF^,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C70,0C71,0C72,0C73,0C74,0C75,0C76,0C7^,0C80,0C81,0C82,0C83,0C85,0C86,0C87,0C8^,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF0,0DF1,0DF2,0DF3,0DF5,0DF6,0DF7,0DF^,0E0*,0E1*,0E2*,0E3*,0E4_,0E48,0E49,0E4A,0E4B,0E4C,0E4D,0E4E,0E5_,0E58,0E59,0E5C,0E5D,0E5E,0E5F,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F00,0F01,0F02,0F03,0F13,0F15,0F16,0F17,0F1^,0F2*,0F3_,0F38,0F39,0F3E,0F3F,0F4*,0F5*,0F6*,0F7*,0F80,0F81,0F82,0F83,0F84,0F86,0F87,0F8^,0F9*,0FA*,0FB*,0FC*,0FD5,0FD6,0FD7,0FD8,0FDB,0FDC,0FDD,0FDE,0FDF,0FE*,0FF*,100*,101*,102*,103*,104_,1048,1049,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F_,10F8,10F9,10FA,10FC,10FD,10FE,10FF,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,1369,136A,136B,136C,136D,136E,136F,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,1401,1402,1403,1404,1405,1406,1407,140^,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166_,1668,1669,166A,166B,166C,166D,166F,167*,168*,169_,1698,1699,169A,169D,169E,169F,16A*,16B*,16C*,16D*,16E_,16E8,16E9,16EA,16EE,16EF,16F*,170*,171*,172*,1730,1731,1732,1733,1734,1737,173^,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D0,17D1,17D2,17D3,17D7,17DB,17DC,17DD,17DE,17DF,17E*,17F*,180B,180C,180D,180E,180F,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,1940,1941,1942,1943,1946,1947,194^,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1_,1A18,1A19,1A1A,1A1B,1A1C,1A1D,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA7,1AAE,1AAF,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5_,1B58,1B59,1B61,1B62,1B63,1B64,1B65,1B66,1B67,1B6^,1B7_,1B78,1B79,1B7A,1B7B,1B7C,1B7F,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF_,1BF8,1BF9,1BFA,1BFB,1C0*,1C1*,1C2*,1C3_,1C38,1C39,1C3A,1C4*,1C5*,1C6*,1C7_,1C78,1C79,1C7A,1C7B,1C7C,1C7D,1C8*,1C9*,1CA*,1CB*,1CC^,1CD0,1CD1,1CD2,1CD4,1CD5,1CD6,1CD7,1CD^,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,202^,2044,2052,205F,206*,207_,2078,2079,207A,207B,207C,207F,208_,2088,2089,208A,208B,208C,208F,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230_,230C,230D,230E,230F,231*,232_,2328,232B,232C,232D,232E,232F,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276_,2776,2777,277^,278*,279*,27A*,27B*,27C0,27C1,27C2,27C3,27C4,27C7,27C^,27D*,27E0,27E1,27E2,27E3,27E4,27E5,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,2980,2981,2982,2999,299A,299B,299C,299D,299E,299F,29A*,29B*,29C*,29D_,29DC,29DD,29DE,29DF,29E*,29F_,29F8,29F9,29FA,29FB,29FE,29FF,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF_,2CF8,2CFD,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D71,2D72,2D73,2D74,2D75,2D76,2D77,2D7^,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E2F,2E50,2E51,2E5E,2E5F,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,3000,3004,3005,3006,3007,3012,3013,302*,3031,3032,3033,3034,3035,3036,3037,3038,3039,303A,303B,303C,303E,303F,304*,305*,306*,307*,308*,309*,30A1,30A2,30A3,30A4,30A5,30A6,30A7,30A^,30B*,30C*,30D*,30E*,30F_,30F8,30F9,30FA,30FC,30FD,30FE,30FF,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// Pc ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Pc}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"005F,203F,2040,2054," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Pc}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005_,0058,0059,005A,005B,005C,005D,005E,006*,007*,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203_,2038,2039,203A,203B,203C,203D,203E,2041,2042,2043,2044,2045,2046,2047,204^,2050,2051,2052,2053,2055,2056,2057,205^,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// Pd ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Pd}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"002D,058A,05BE,1400,1806,2010,2011,2012,2013,2014,2015,2E17,2E1A,2E3A,2E3B,2E40,2E5D,301C,3030,30A0," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Pd}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,002_,0028,0029,002A,002B,002C,002E,002F,003*,004*,005*,006*,007*,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058_,0588,0589,058B,058C,058D,058E,058F,059*,05A*,05B_,05B8,05B9,05BA,05BB,05BC,05BD,05BF,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,1401,1402,1403,1404,1405,1406,1407,140^,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,1800,1801,1802,1803,1804,1805,1807,180^,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,2016,2017,201^,202*,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E10,2E11,2E12,2E13,2E14,2E15,2E16,2E18,2E19,2E1B,2E1C,2E1D,2E1E,2E1F,2E2*,2E3_,2E38,2E39,2E3C,2E3D,2E3E,2E3F,2E41,2E42,2E43,2E44,2E45,2E46,2E47,2E4^,2E5_,2E58,2E59,2E5A,2E5B,2E5C,2E5E,2E5F,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301_,3018,3019,301A,301B,301D,301E,301F,302*,3031,3032,3033,3034,3035,3036,3037,303^,304*,305*,306*,307*,308*,309*,30A1,30A2,30A3,30A4,30A5,30A6,30A7,30A^,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// Ps ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Ps}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0028,005B,007B,0F3A,0F3C,169B,201A,201E,2045,207D,208D,2308,230A,2329,2768,276A,276C,276E,2770,2772,2774,27C5,27E6,27E8,27EA,27EC,27EE,2983,2985,2987,2989,298B,298D,298F,2991,2993,2995,2997,29D8,29DA,29FC,2E22,2E24,2E26,2E28,2E42,2E55,2E57,2E59,2E5B,3008,300A,300C,300E,3010,3014,3016,3018,301A,301D," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Ps}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,002_,0029,002A,002B,002C,002D,002E,002F,003*,004*,005_,0058,0059,005A,005C,005D,005E,005F,006*,007_,0078,0079,007A,007C,007D,007E,007F,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3_,0F38,0F39,0F3B,0F3D,0F3E,0F3F,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169_,1698,1699,169A,169C,169D,169E,169F,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201_,2018,2019,201B,201C,201D,201F,202*,203*,2040,2041,2042,2043,2044,2046,2047,204^,205*,206*,207_,2078,2079,207A,207B,207C,207E,207F,208_,2088,2089,208A,208B,208C,208E,208F,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230_,2309,230B,230C,230D,230E,230F,231*,232_,2328,232A,232B,232C,232D,232E,232F,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276_,2769,276B,276D,276F,2771,2773,2775,2776,2777,277^,278*,279*,27A*,27B*,27C0,27C1,27C2,27C3,27C4,27C6,27C7,27C^,27D*,27E0,27E1,27E2,27E3,27E4,27E5,27E7,27E9,27EB,27ED,27EF,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,2980,2981,2982,2984,2986,2988,298A,298C,298E,2990,2992,2994,2996,299^,29A*,29B*,29C*,29D_,29D9,29DB,29DC,29DD,29DE,29DF,29E*,29F_,29F8,29F9,29FA,29FB,29FD,29FE,29FF,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E20,2E21,2E23,2E25,2E27,2E29,2E2A,2E2B,2E2C,2E2D,2E2E,2E2F,2E3*,2E40,2E41,2E43,2E44,2E45,2E46,2E47,2E4^,2E50,2E51,2E52,2E53,2E54,2E56,2E58,2E5A,2E5C,2E5D,2E5E,2E5F,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300_,3009,300B,300D,300F,3011,3012,3013,3015,3017,3019,301B,301C,301E,301F,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// Pe ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Pe}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0029,005D,007D,0F3B,0F3D,169C,2046,207E,208E,2309,230B,232A,2769,276B,276D,276F,2771,2773,2775,27C6,27E7,27E9,27EB,27ED,27EF,2984,2986,2988,298A,298C,298E,2990,2992,2994,2996,2998,29D9,29DB,29FD,2E23,2E25,2E27,2E29,2E56,2E58,2E5A,2E5C,3009,300B,300D,300F,3011,3015,3017,3019,301B,301E,301F," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Pe}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,002_,0028,002A,002B,002C,002D,002E,002F,003*,004*,005_,0058,0059,005A,005B,005C,005E,005F,006*,007_,0078,0079,007A,007B,007C,007E,007F,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3_,0F38,0F39,0F3A,0F3C,0F3E,0F3F,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169_,1698,1699,169A,169B,169D,169E,169F,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,2040,2041,2042,2043,2044,2045,2047,204^,205*,206*,207_,2078,2079,207A,207B,207C,207D,207F,208_,2088,2089,208A,208B,208C,208D,208F,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230_,2308,230A,230C,230D,230E,230F,231*,232_,2328,2329,232B,232C,232D,232E,232F,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276_,2768,276A,276C,276E,2770,2772,2774,2776,2777,277^,278*,279*,27A*,27B*,27C0,27C1,27C2,27C3,27C4,27C5,27C7,27C^,27D*,27E0,27E1,27E2,27E3,27E4,27E5,27E6,27E8,27EA,27EC,27EE,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,2980,2981,2982,2983,2985,2987,2989,298B,298D,298F,2991,2993,2995,2997,2999,299A,299B,299C,299D,299E,299F,29A*,29B*,29C*,29D_,29D8,29DA,29DC,29DD,29DE,29DF,29E*,29F_,29F8,29F9,29FA,29FB,29FC,29FE,29FF,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E20,2E21,2E22,2E24,2E26,2E28,2E2A,2E2B,2E2C,2E2D,2E2E,2E2F,2E3*,2E4*,2E50,2E51,2E52,2E53,2E54,2E55,2E57,2E59,2E5B,2E5D,2E5E,2E5F,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300_,3008,300A,300C,300E,3010,3012,3013,3014,3016,3018,301A,301C,301D,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// Pi ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Pi}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"00AB,2018,201B,201C,201F,2039,2E02,2E04,2E09,2E0C,2E1C,2E20," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Pi}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A_,00A8,00A9,00AA,00AC,00AD,00AE,00AF,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201_,2019,201A,201D,201E,202*,203_,2038,203A,203B,203C,203D,203E,203F,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E00,2E01,2E03,2E05,2E06,2E07,2E08,2E0A,2E0B,2E0D,2E0E,2E0F,2E1_,2E18,2E19,2E1A,2E1B,2E1D,2E1E,2E1F,2E21,2E22,2E23,2E24,2E25,2E26,2E27,2E2^,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// Pf ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Pf}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"00BB,2019,201D,203A,2E03,2E05,2E0A,2E0D,2E1D,2E21," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Pf}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A*,00B_,00B8,00B9,00BA,00BC,00BD,00BE,00BF,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201_,2018,201A,201B,201C,201E,201F,202*,203_,2038,2039,203B,203C,203D,203E,203F,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E00,2E01,2E02,2E04,2E06,2E07,2E08,2E09,2E0B,2E0C,2E0E,2E0F,2E1_,2E18,2E19,2E1A,2E1B,2E1C,2E1E,2E1F,2E20,2E22,2E23,2E24,2E25,2E26,2E27,2E2^,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// Po ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Po}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0021,0022,0023,0025,0026,0027,002A,002C,002E,002F,003A,003B,003F,0040,005C,00A1,00A7,00B6,00B7,00BF,037E,0387,055A,055B,055C,055D,055E,055F,0589,05C0,05C3,05C6,05F3,05F4,0609,060A,060C,060D,061B,061D,061E,061F,066A,066B,066C,066D,06D4,070_,0708,0709,070A,070B,070C,070D,07F7,07F8,07F9,083_,0838,0839,083A,083B,083C,083D,083E,085E,0964,0965,0970,09FD,0A76,0AF0,0C77,0C84,0DF4,0E4F,0E5A,0E5B,0F04,0F05,0F06,0F07,0F0^,0F10,0F11,0F12,0F14,0F85,0FD0,0FD1,0FD2,0FD3,0FD4,0FD9,0FDA,104A,104B,104C,104D,104E,104F,10FB,136_,1368,166E,16EB,16EC,16ED,1735,1736,17D4,17D5,17D6,17D8,17D9,17DA,1800,1801,1802,1803,1804,1805,1807,1808,1809,180A,1944,1945,1A1E,1A1F,1AA0,1AA1,1AA2,1AA3,1AA4,1AA5,1AA6,1AA8,1AA9,1AAA,1AAB,1AAC,1AAD,1B5A,1B5B,1B5C,1B5D,1B5E,1B5F,1B60,1B7D,1B7E,1BFC,1BFD,1BFE,1BFF,1C3B,1C3C,1C3D,1C3E,1C3F,1C7E,1C7F,1CC_,1CD3,2016,2017,202_,203_,2038,203B,203C,203D,203E,2041,2042,2043,2047,204^,2050,2051,2053,2055,2056,2057,2058,2059,205A,205B,205C,205D,205E,2CF9,2CFA,2CFB,2CFC,2CFE,2CFF,2D70,2E00,2E01,2E06,2E07,2E08,2E0B,2E0E,2E0F,2E10,2E11,2E12,2E13,2E14,2E15,2E16,2E18,2E19,2E1B,2E1E,2E1F,2E2A,2E2B,2E2C,2E2D,2E2E,2E3_,2E38,2E39,2E3C,2E3D,2E3E,2E3F,2E41,2E43,2E44,2E45,2E46,2E47,2E4^,2E52,2E53,2E54,3001,3002,3003,303D,30FB," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Po}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,0020,0024,0028,0029,002B,002D,003_,0038,0039,003C,003D,003E,0041,0042,0043,0044,0045,0046,0047,004^,005_,0058,0059,005A,005B,005D,005E,005F,006*,007*,008*,009*,00A0,00A2,00A3,00A4,00A5,00A6,00A^,00B0,00B1,00B2,00B3,00B4,00B5,00B8,00B9,00BA,00BB,00BC,00BD,00BE,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037_,0378,0379,037A,037B,037C,037D,037F,0380,0381,0382,0383,0384,0385,0386,038^,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055_,0558,0559,056*,057*,058_,0588,058A,058B,058C,058D,058E,058F,059*,05A*,05B*,05C1,05C2,05C4,05C5,05C7,05C^,05D*,05E*,05F0,05F1,05F2,05F5,05F6,05F7,05F^,060_,0608,060B,060E,060F,061_,0618,0619,061A,061C,062*,063*,064*,065*,066_,0668,0669,066E,066F,067*,068*,069*,06A*,06B*,06C*,06D0,06D1,06D2,06D3,06D5,06D6,06D7,06D^,06E*,06F*,070E,070F,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F0,07F1,07F2,07F3,07F4,07F5,07F6,07FA,07FB,07FC,07FD,07FE,07FF,080*,081*,082*,083F,084*,085_,0858,0859,085A,085B,085C,085D,085F,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,0960,0961,0962,0963,0966,0967,096^,0971,0972,0973,0974,0975,0976,0977,097^,098*,099*,09A*,09B*,09C*,09D*,09E*,09F_,09F8,09F9,09FA,09FB,09FC,09FE,09FF,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A70,0A71,0A72,0A73,0A74,0A75,0A77,0A7^,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF1,0AF2,0AF3,0AF4,0AF5,0AF6,0AF7,0AF^,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C70,0C71,0C72,0C73,0C74,0C75,0C76,0C7^,0C80,0C81,0C82,0C83,0C85,0C86,0C87,0C8^,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF0,0DF1,0DF2,0DF3,0DF5,0DF6,0DF7,0DF^,0E0*,0E1*,0E2*,0E3*,0E4_,0E48,0E49,0E4A,0E4B,0E4C,0E4D,0E4E,0E5_,0E58,0E59,0E5C,0E5D,0E5E,0E5F,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F00,0F01,0F02,0F03,0F13,0F15,0F16,0F17,0F1^,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F80,0F81,0F82,0F83,0F84,0F86,0F87,0F8^,0F9*,0FA*,0FB*,0FC*,0FD5,0FD6,0FD7,0FD8,0FDB,0FDC,0FDD,0FDE,0FDF,0FE*,0FF*,100*,101*,102*,103*,104_,1048,1049,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F_,10F8,10F9,10FA,10FC,10FD,10FE,10FF,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,1369,136A,136B,136C,136D,136E,136F,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166_,1668,1669,166A,166B,166C,166D,166F,167*,168*,169*,16A*,16B*,16C*,16D*,16E_,16E8,16E9,16EA,16EE,16EF,16F*,170*,171*,172*,1730,1731,1732,1733,1734,1737,173^,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D0,17D1,17D2,17D3,17D7,17DB,17DC,17DD,17DE,17DF,17E*,17F*,1806,180B,180C,180D,180E,180F,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,1940,1941,1942,1943,1946,1947,194^,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1_,1A18,1A19,1A1A,1A1B,1A1C,1A1D,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA7,1AAE,1AAF,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5_,1B58,1B59,1B61,1B62,1B63,1B64,1B65,1B66,1B67,1B6^,1B7_,1B78,1B79,1B7A,1B7B,1B7C,1B7F,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF_,1BF8,1BF9,1BFA,1BFB,1C0*,1C1*,1C2*,1C3_,1C38,1C39,1C3A,1C4*,1C5*,1C6*,1C7_,1C78,1C79,1C7A,1C7B,1C7C,1C7D,1C8*,1C9*,1CA*,1CB*,1CC^,1CD0,1CD1,1CD2,1CD4,1CD5,1CD6,1CD7,1CD^,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,2010,2011,2012,2013,2014,2015,201^,202^,2039,203A,203F,2040,2044,2045,2046,2052,2054,205F,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF_,2CF8,2CFD,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D71,2D72,2D73,2D74,2D75,2D76,2D77,2D7^,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E02,2E03,2E04,2E05,2E09,2E0A,2E0C,2E0D,2E17,2E1A,2E1C,2E1D,2E2_,2E28,2E29,2E2F,2E3A,2E3B,2E40,2E42,2E50,2E51,2E55,2E56,2E57,2E5^,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,3000,3004,3005,3006,3007,300^,301*,302*,303_,3038,3039,303A,303B,303C,303E,303F,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F_,30F8,30F9,30FA,30FC,30FD,30FE,30FF,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// S ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{S}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0024,002B,003C,003D,003E,005E,0060,007C,007E,00A2,00A3,00A4,00A5,00A6,00A8,00A9,00AC,00AE,00AF,00B0,00B1,00B4,00B8,00D7,00F7,02C2,02C3,02C4,02C5,02D2,02D3,02D4,02D5,02D6,02D7,02D^,02E5,02E6,02E7,02E8,02E9,02EA,02EB,02ED,02EF,02F*,0375,0384,0385,03F6,0482,058D,058E,058F,0606,0607,0608,060B,060E,060F,06DE,06E9,06FD,06FE,07F6,07FE,07FF,0888,09F2,09F3,09FA,09FB,0AF1,0B70,0BF3,0BF4,0BF5,0BF6,0BF7,0BF8,0BF9,0BFA,0C7F,0D4F,0D79,0E3F,0F01,0F02,0F03,0F13,0F15,0F16,0F17,0F1A,0F1B,0F1C,0F1D,0F1E,0F1F,0F34,0F36,0F38,0FBE,0FBF,0FC0,0FC1,0FC2,0FC3,0FC4,0FC5,0FC7,0FC8,0FC9,0FCA,0FCB,0FCC,0FCE,0FCF,0FD5,0FD6,0FD7,0FD8,109E,109F,139_,1398,1399,166D,17DB,1940,19DE,19DF,19E*,19F*,1B61,1B62,1B63,1B64,1B65,1B66,1B67,1B68,1B69,1B6A,1B74,1B75,1B76,1B77,1B78,1B79,1B7A,1B7B,1B7C,1FBD,1FBF,1FC0,1FC1,1FCD,1FCE,1FCF,1FDD,1FDE,1FDF,1FED,1FEE,1FEF,1FFD,1FFE,2044,2052,207A,207B,207C,208A,208B,208C,20A*,20B*,20C0,2100,2101,2103,2104,2105,2106,2108,2109,2114,2116,2117,2118,211E,211F,2120,2121,2122,2123,2125,2127,2129,212E,213A,213B,2140,2141,2142,2143,2144,214A,214B,214C,214D,214F,218A,218B,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230_,230C,230D,230E,230F,231*,232_,2328,232B,232C,232D,232E,232F,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,2420,2421,2422,2423,2424,2425,2426,244_,2448,2449,244A,249C,249D,249E,249F,24A*,24B*,24C*,24D*,24E_,24E8,24E9,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276_,2794,2795,2796,2797,279^,27A*,27B*,27C0,27C1,27C2,27C3,27C4,27C7,27C^,27D*,27E0,27E1,27E2,27E3,27E4,27E5,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,2980,2981,2982,2999,299A,299B,299C,299D,299E,299F,29A*,29B*,29C*,29D_,29DC,29DD,29DE,29DF,29E*,29F_,29F8,29F9,29FA,29FB,29FE,29FF,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B70,2B71,2B72,2B73,2B76,2B77,2B7^,2B8*,2B90,2B91,2B92,2B93,2B94,2B95,2B97,2B9^,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2CE5,2CE6,2CE7,2CE8,2CE9,2CEA,2E50,2E51,2E8*,2E9_,2E98,2E99,2E9B,2E9C,2E9D,2E9E,2E9F,2EA*,2EB*,2EC*,2ED*,2EE*,2EF0,2EF1,2EF2,2EF3,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD0,2FD1,2FD2,2FD3,2FD4,2FD5,2FF_,2FF8,2FF9,2FFA,2FFB,3004,3012,3013,3020,3036,3037,303E,303F,309B,309C,3190,3191,3196,3197,319^,31C*,31D*,31E0,31E1,31E2,31E3,320*,321_,3218,3219,321A,321B,321C,321D,321E,322A,322B,322C,322D,322E,322F,323*,324_,3250,326*,327*,328A,328B,328C,328D,328E,328F,329*,32A*,32B0,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{S}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,0020,0021,0022,0023,0025,0026,0027,0028,0029,002A,002C,002D,002E,002F,003_,0038,0039,003A,003B,003F,004*,005_,0058,0059,005A,005B,005C,005D,005F,0061,0062,0063,0064,0065,0066,0067,006^,007_,0078,0079,007A,007B,007D,007F,008*,009*,00A0,00A1,00A7,00AA,00AB,00AD,00B2,00B3,00B5,00B6,00B7,00B9,00BA,00BB,00BC,00BD,00BE,00BF,00C*,00D0,00D1,00D2,00D3,00D4,00D5,00D6,00D^,00E*,00F0,00F1,00F2,00F3,00F4,00F5,00F6,00F^,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C0,02C1,02C6,02C7,02C^,02D0,02D1,02E0,02E1,02E2,02E3,02E4,02EC,02EE,030*,031*,032*,033*,034*,035*,036*,0370,0371,0372,0373,0374,0376,0377,037^,0380,0381,0382,0383,0386,0387,038^,039*,03A*,03B*,03C*,03D*,03E*,03F0,03F1,03F2,03F3,03F4,03F5,03F7,03F^,040*,041*,042*,043*,044*,045*,046*,047*,0480,0481,0483,0484,0485,0486,0487,048^,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058_,0588,0589,058A,058B,058C,059*,05A*,05B*,05C*,05D*,05E*,05F*,0600,0601,0602,0603,0604,0605,0609,060A,060C,060D,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D_,06D8,06D9,06DA,06DB,06DC,06DD,06DF,06E_,06E8,06EA,06EB,06EC,06ED,06EE,06EF,06F_,06F8,06F9,06FA,06FB,06FC,06FF,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F0,07F1,07F2,07F3,07F4,07F5,07F7,07F8,07F9,07FA,07FB,07FC,07FD,080*,081*,082*,083*,084*,085*,086*,087*,088_,0889,088A,088B,088C,088D,088E,088F,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F0,09F1,09F4,09F5,09F6,09F7,09F8,09F9,09FC,09FD,09FE,09FF,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF0,0AF2,0AF3,0AF4,0AF5,0AF6,0AF7,0AF^,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B71,0B72,0B73,0B74,0B75,0B76,0B77,0B7^,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF0,0BF1,0BF2,0BFB,0BFC,0BFD,0BFE,0BFF,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7_,0C78,0C79,0C7A,0C7B,0C7C,0C7D,0C7E,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4_,0D48,0D49,0D4A,0D4B,0D4C,0D4D,0D4E,0D5*,0D6*,0D7_,0D78,0D7A,0D7B,0D7C,0D7D,0D7E,0D7F,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3_,0E38,0E39,0E3A,0E3B,0E3C,0E3D,0E3E,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F00,0F04,0F05,0F06,0F07,0F0^,0F10,0F11,0F12,0F14,0F18,0F19,0F2*,0F30,0F31,0F32,0F33,0F35,0F37,0F39,0F3A,0F3B,0F3C,0F3D,0F3E,0F3F,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB_,0FB8,0FB9,0FBA,0FBB,0FBC,0FBD,0FC6,0FCD,0FD0,0FD1,0FD2,0FD3,0FD4,0FD9,0FDA,0FDB,0FDC,0FDD,0FDE,0FDF,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109_,1098,1099,109A,109B,109C,109D,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139A,139B,139C,139D,139E,139F,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166_,1668,1669,166A,166B,166C,166E,166F,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D_,17D8,17D9,17DA,17DC,17DD,17DE,17DF,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,1941,1942,1943,1944,1945,1946,1947,194^,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D_,19D8,19D9,19DA,19DB,19DC,19DD,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B60,1B6B,1B6C,1B6D,1B6E,1B6F,1B70,1B71,1B72,1B73,1B7D,1B7E,1B7F,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB_,1FB8,1FB9,1FBA,1FBB,1FBC,1FBE,1FC2,1FC3,1FC4,1FC5,1FC6,1FC7,1FC8,1FC9,1FCA,1FCB,1FCC,1FD_,1FD8,1FD9,1FDA,1FDB,1FDC,1FE_,1FE8,1FE9,1FEA,1FEB,1FEC,1FF_,1FF8,1FF9,1FFA,1FFB,1FFC,1FFF,200*,201*,202*,203*,2040,2041,2042,2043,2045,2046,2047,204^,2050,2051,2053,2054,2055,2056,2057,205^,206*,207_,2078,2079,207D,207E,207F,208_,2088,2089,208D,208E,208F,209*,20C1,20C2,20C3,20C4,20C5,20C6,20C7,20C^,20D*,20E*,20F*,2102,2107,210A,210B,210C,210D,210E,210F,2110,2111,2112,2113,2115,2119,211A,211B,211C,211D,2124,2126,2128,212A,212B,212C,212D,212F,213_,2138,2139,213C,213D,213E,213F,2145,2146,2147,2148,2149,214E,215*,216*,217*,218_,2188,2189,218C,218D,218E,218F,2308,2309,230A,230B,2329,232A,2427,242^,243*,244B,244C,244D,244E,244F,245*,246*,247*,248*,249_,2498,2499,249A,249B,24EA,24EB,24EC,24ED,24EE,24EF,24F*,276^,277*,278*,2790,2791,2792,2793,27C5,27C6,27E6,27E7,27E^,2983,2984,2985,2986,2987,298^,299_,2998,29D8,29D9,29DA,29DB,29FC,29FD,2B74,2B75,2B96,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE0,2CE1,2CE2,2CE3,2CE4,2CEB,2CEC,2CED,2CEE,2CEF,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E52,2E53,2E54,2E55,2E56,2E57,2E5^,2E6*,2E7*,2E9A,2EF4,2EF5,2EF6,2EF7,2EF^,2FD6,2FD7,2FD^,2FE*,2FFC,2FFD,2FFE,2FFF,3000,3001,3002,3003,3005,3006,3007,300^,3010,3011,3014,3015,3016,3017,301^,3021,3022,3023,3024,3025,3026,3027,302^,3030,3031,3032,3033,3034,3035,3038,3039,303A,303B,303C,303D,304*,305*,306*,307*,308*,309_,3098,3099,309A,309D,309E,309F,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,3192,3193,3194,3195,31A*,31B*,31E4,31E5,31E6,31E7,31E^,31F*,321F,322_,3228,3229,324^,3251,3252,3253,3254,3255,3256,3257,325^,328_,3288,3289,32B1,32B2,32B3,32B4,32B5,32B6,32B7,32B^,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// Sm ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Sm}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"002B,003C,003D,003E,007C,007E,00AC,00B1,00D7,00F7,03F6,0606,0607,0608,2044,2052,207A,207B,207C,208A,208B,208C,2118,2140,2141,2142,2143,2144,214B,2190,2191,2192,2193,2194,219A,219B,21A0,21A3,21A6,21AE,21CE,21CF,21D2,21D4,21F4,21F5,21F6,21F7,21F^,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,2320,2321,237C,239B,239C,239D,239E,239F,23A*,23B0,23B1,23B2,23B3,23DC,23DD,23DE,23DF,23E0,23E1,25B7,25C1,25F^,266F,27C0,27C1,27C2,27C3,27C4,27C7,27C^,27D*,27E0,27E1,27E2,27E3,27E4,27E5,27F*,290*,291*,292*,293*,294*,295*,296*,297*,2980,2981,2982,2999,299A,299B,299C,299D,299E,299F,29A*,29B*,29C*,29D_,29DC,29DD,29DE,29DF,29E*,29F_,29F8,29F9,29FA,29FB,29FE,29FF,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B3*,2B40,2B41,2B42,2B43,2B44,2B47,2B48,2B49,2B4A,2B4B,2B4C," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Sm}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,002_,0028,0029,002A,002C,002D,002E,002F,003_,0038,0039,003A,003B,003F,004*,005*,006*,007_,0078,0079,007A,007B,007D,007F,008*,009*,00A_,00A8,00A9,00AA,00AB,00AD,00AE,00AF,00B0,00B2,00B3,00B4,00B5,00B6,00B7,00B^,00C*,00D0,00D1,00D2,00D3,00D4,00D5,00D6,00D^,00E*,00F0,00F1,00F2,00F3,00F4,00F5,00F6,00F^,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F0,03F1,03F2,03F3,03F4,03F5,03F7,03F^,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,0600,0601,0602,0603,0604,0605,0609,060A,060B,060C,060D,060E,060F,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,2040,2041,2042,2043,2045,2046,2047,204^,2050,2051,2053,2054,2055,2056,2057,205^,206*,207_,2078,2079,207D,207E,207F,208_,2088,2089,208D,208E,208F,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211_,2119,211A,211B,211C,211D,211E,211F,212*,213*,2145,2146,2147,2148,2149,214A,214C,214D,214E,214F,215*,216*,217*,218*,2195,2196,2197,2198,2199,219C,219D,219E,219F,21A1,21A2,21A4,21A5,21A7,21A8,21A9,21AA,21AB,21AC,21AD,21AF,21B*,21C_,21C8,21C9,21CA,21CB,21CC,21CD,21D0,21D1,21D3,21D5,21D6,21D7,21D^,21E*,21F0,21F1,21F2,21F3,230*,231*,2322,2323,2324,2325,2326,2327,232^,233*,234*,235*,236*,237_,2378,2379,237A,237B,237D,237E,237F,238*,239_,2398,2399,239A,23B4,23B5,23B6,23B7,23B^,23C*,23D_,23D8,23D9,23DA,23DB,23E2,23E3,23E4,23E5,23E6,23E7,23E^,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B0,25B1,25B2,25B3,25B4,25B5,25B6,25B^,25C0,25C2,25C3,25C4,25C5,25C6,25C7,25C^,25D*,25E*,25F_,260*,261*,262*,263*,264*,265*,266_,2668,2669,266A,266B,266C,266D,266E,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C5,27C6,27E6,27E7,27E^,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,2983,2984,2985,2986,2987,298^,299_,2998,29D8,29D9,29DA,29DB,29FC,29FD,2B0*,2B1*,2B2*,2B45,2B46,2B4D,2B4E,2B4F,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// Sc ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Sc}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0024,00A2,00A3,00A4,00A5,058F,060B,07FE,07FF,09F2,09F3,09FB,0AF1,0BF9,0E3F,17DB,20A*,20B*,20C0," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Sc}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,0020,0021,0022,0023,0025,0026,0027,002^,003*,004*,005*,006*,007*,008*,009*,00A0,00A1,00A6,00A7,00A^,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058_,0588,0589,058A,058B,058C,058D,058E,059*,05A*,05B*,05C*,05D*,05E*,05F*,060_,0608,0609,060A,060C,060D,060E,060F,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F_,07F8,07F9,07FA,07FB,07FC,07FD,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F0,09F1,09F4,09F5,09F6,09F7,09F8,09F9,09FA,09FC,09FD,09FE,09FF,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF0,0AF2,0AF3,0AF4,0AF5,0AF6,0AF7,0AF^,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF_,0BF8,0BFA,0BFB,0BFC,0BFD,0BFE,0BFF,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3_,0E38,0E39,0E3A,0E3B,0E3C,0E3D,0E3E,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D_,17D8,17D9,17DA,17DC,17DD,17DE,17DF,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,204*,205*,206*,207*,208*,209*,20C1,20C2,20C3,20C4,20C5,20C6,20C7,20C^,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// Sk ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Sk}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"005E,0060,00A8,00AF,00B4,00B8,02C2,02C3,02C4,02C5,02D2,02D3,02D4,02D5,02D6,02D7,02D^,02E5,02E6,02E7,02E8,02E9,02EA,02EB,02ED,02EF,02F*,0375,0384,0385,0888,1FBD,1FBF,1FC0,1FC1,1FCD,1FCE,1FCF,1FDD,1FDE,1FDF,1FED,1FEE,1FEF,1FFD,1FFE,309B,309C," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Sk}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005_,0058,0059,005A,005B,005C,005D,005F,0061,0062,0063,0064,0065,0066,0067,006^,007*,008*,009*,00A_,00A9,00AA,00AB,00AC,00AD,00AE,00B0,00B1,00B2,00B3,00B5,00B6,00B7,00B9,00BA,00BB,00BC,00BD,00BE,00BF,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C0,02C1,02C6,02C7,02C^,02D0,02D1,02E0,02E1,02E2,02E3,02E4,02EC,02EE,030*,031*,032*,033*,034*,035*,036*,0370,0371,0372,0373,0374,0376,0377,037^,0380,0381,0382,0383,0386,0387,038^,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088_,0889,088A,088B,088C,088D,088E,088F,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB_,1FB8,1FB9,1FBA,1FBB,1FBC,1FBE,1FC2,1FC3,1FC4,1FC5,1FC6,1FC7,1FC8,1FC9,1FCA,1FCB,1FCC,1FD_,1FD8,1FD9,1FDA,1FDB,1FDC,1FE_,1FE8,1FE9,1FEA,1FEB,1FEC,1FF_,1FF8,1FF9,1FFA,1FFB,1FFC,1FFF,200*,201*,202*,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309_,3098,3099,309A,309D,309E,309F,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// So ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{So}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"00A6,00A9,00AE,00B0,0482,058D,058E,060E,060F,06DE,06E9,06FD,06FE,07F6,09FA,0B70,0BF3,0BF4,0BF5,0BF6,0BF7,0BF8,0BFA,0C7F,0D4F,0D79,0F01,0F02,0F03,0F13,0F15,0F16,0F17,0F1A,0F1B,0F1C,0F1D,0F1E,0F1F,0F34,0F36,0F38,0FBE,0FBF,0FC0,0FC1,0FC2,0FC3,0FC4,0FC5,0FC7,0FC8,0FC9,0FCA,0FCB,0FCC,0FCE,0FCF,0FD5,0FD6,0FD7,0FD8,109E,109F,139_,1398,1399,166D,1940,19DE,19DF,19E*,19F*,1B61,1B62,1B63,1B64,1B65,1B66,1B67,1B68,1B69,1B6A,1B74,1B75,1B76,1B77,1B78,1B79,1B7A,1B7B,1B7C,2100,2101,2103,2104,2105,2106,2108,2109,2114,2116,2117,211E,211F,2120,2121,2122,2123,2125,2127,2129,212E,213A,213B,214A,214C,214D,214F,218A,218B,2195,2196,2197,2198,2199,219C,219D,219E,219F,21A1,21A2,21A4,21A5,21A7,21A8,21A9,21AA,21AB,21AC,21AD,21AF,21B*,21C_,21C8,21C9,21CA,21CB,21CC,21CD,21D0,21D1,21D3,21D5,21D6,21D7,21D^,21E*,21F0,21F1,21F2,21F3,230_,230C,230D,230E,230F,231*,2322,2323,2324,2325,2326,2327,2328,232B,232C,232D,232E,232F,233*,234*,235*,236*,237_,2378,2379,237A,237B,237D,237E,237F,238*,239_,2398,2399,239A,23B4,23B5,23B6,23B7,23B^,23C*,23D_,23D8,23D9,23DA,23DB,23E2,23E3,23E4,23E5,23E6,23E7,23E^,23F*,240*,241*,2420,2421,2422,2423,2424,2425,2426,244_,2448,2449,244A,249C,249D,249E,249F,24A*,24B*,24C*,24D*,24E_,24E8,24E9,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B0,25B1,25B2,25B3,25B4,25B5,25B6,25B^,25C0,25C2,25C3,25C4,25C5,25C6,25C7,25C^,25D*,25E*,25F_,260*,261*,262*,263*,264*,265*,266_,2668,2669,266A,266B,266C,266D,266E,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276_,2794,2795,2796,2797,279^,27A*,27B*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,2B0*,2B1*,2B2*,2B45,2B46,2B4D,2B4E,2B4F,2B5*,2B6*,2B70,2B71,2B72,2B73,2B76,2B77,2B7^,2B8*,2B90,2B91,2B92,2B93,2B94,2B95,2B97,2B9^,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2CE5,2CE6,2CE7,2CE8,2CE9,2CEA,2E50,2E51,2E8*,2E9_,2E98,2E99,2E9B,2E9C,2E9D,2E9E,2E9F,2EA*,2EB*,2EC*,2ED*,2EE*,2EF0,2EF1,2EF2,2EF3,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD0,2FD1,2FD2,2FD3,2FD4,2FD5,2FF_,2FF8,2FF9,2FFA,2FFB,3004,3012,3013,3020,3036,3037,303E,303F,3190,3191,3196,3197,319^,31C*,31D*,31E0,31E1,31E2,31E3,320*,321_,3218,3219,321A,321B,321C,321D,321E,322A,322B,322C,322D,322E,322F,323*,324_,3250,326*,327*,328A,328B,328C,328D,328E,328F,329*,32A*,32B0,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{So}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A0,00A1,00A2,00A3,00A4,00A5,00A7,00A8,00AA,00AB,00AC,00AD,00AF,00B1,00B2,00B3,00B4,00B5,00B6,00B7,00B^,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,0480,0481,0483,0484,0485,0486,0487,048^,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058_,0588,0589,058A,058B,058C,058F,059*,05A*,05B*,05C*,05D*,05E*,05F*,060_,0608,0609,060A,060B,060C,060D,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D_,06D8,06D9,06DA,06DB,06DC,06DD,06DF,06E_,06E8,06EA,06EB,06EC,06ED,06EE,06EF,06F_,06F8,06F9,06FA,06FB,06FC,06FF,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F0,07F1,07F2,07F3,07F4,07F5,07F7,07F^,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F_,09F8,09F9,09FB,09FC,09FD,09FE,09FF,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B71,0B72,0B73,0B74,0B75,0B76,0B77,0B7^,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF0,0BF1,0BF2,0BF9,0BFB,0BFC,0BFD,0BFE,0BFF,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7_,0C78,0C79,0C7A,0C7B,0C7C,0C7D,0C7E,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4_,0D48,0D49,0D4A,0D4B,0D4C,0D4D,0D4E,0D5*,0D6*,0D7_,0D78,0D7A,0D7B,0D7C,0D7D,0D7E,0D7F,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F00,0F04,0F05,0F06,0F07,0F0^,0F10,0F11,0F12,0F14,0F18,0F19,0F2*,0F30,0F31,0F32,0F33,0F35,0F37,0F39,0F3A,0F3B,0F3C,0F3D,0F3E,0F3F,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB_,0FB8,0FB9,0FBA,0FBB,0FBC,0FBD,0FC6,0FCD,0FD0,0FD1,0FD2,0FD3,0FD4,0FD9,0FDA,0FDB,0FDC,0FDD,0FDE,0FDF,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109_,1098,1099,109A,109B,109C,109D,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139A,139B,139C,139D,139E,139F,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166_,1668,1669,166A,166B,166C,166E,166F,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,1941,1942,1943,1944,1945,1946,1947,194^,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D_,19D8,19D9,19DA,19DB,19DC,19DD,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B60,1B6B,1B6C,1B6D,1B6E,1B6F,1B70,1B71,1B72,1B73,1B7D,1B7E,1B7F,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,2102,2107,210A,210B,210C,210D,210E,210F,2110,2111,2112,2113,2115,2118,2119,211A,211B,211C,211D,2124,2126,2128,212A,212B,212C,212D,212F,213_,2138,2139,213C,213D,213E,213F,214_,2148,2149,214B,214E,215*,216*,217*,218_,2188,2189,218C,218D,218E,218F,2190,2191,2192,2193,2194,219A,219B,21A0,21A3,21A6,21AE,21CE,21CF,21D2,21D4,21F4,21F5,21F6,21F7,21F^,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,2308,2309,230A,230B,2320,2321,2329,232A,237C,239B,239C,239D,239E,239F,23A*,23B0,23B1,23B2,23B3,23DC,23DD,23DE,23DF,23E0,23E1,2427,242^,243*,244B,244C,244D,244E,244F,245*,246*,247*,248*,249_,2498,2499,249A,249B,24EA,24EB,24EC,24ED,24EE,24EF,24F*,25B7,25C1,25F^,266F,276^,277*,278*,2790,2791,2792,2793,27C*,27D*,27E*,27F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B3*,2B40,2B41,2B42,2B43,2B44,2B47,2B48,2B49,2B4A,2B4B,2B4C,2B74,2B75,2B96,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE0,2CE1,2CE2,2CE3,2CE4,2CEB,2CEC,2CED,2CEE,2CEF,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E52,2E53,2E54,2E55,2E56,2E57,2E5^,2E6*,2E7*,2E9A,2EF4,2EF5,2EF6,2EF7,2EF^,2FD6,2FD7,2FD^,2FE*,2FFC,2FFD,2FFE,2FFF,3000,3001,3002,3003,3005,3006,3007,300^,3010,3011,3014,3015,3016,3017,301^,3021,3022,3023,3024,3025,3026,3027,302^,3030,3031,3032,3033,3034,3035,3038,3039,303A,303B,303C,303D,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,3192,3193,3194,3195,31A*,31B*,31E4,31E5,31E6,31E7,31E^,31F*,321F,322_,3228,3229,324^,3251,3252,3253,3254,3255,3256,3257,325^,328_,3288,3289,32B1,32B2,32B3,32B4,32B5,32B6,32B7,32B^,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// Z ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Z}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0020,00A0,1680,200_,2008,2009,200A,2028,2029,202F,205F,3000," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Z}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,0021,0022,0023,0024,0025,0026,0027,002^,003*,004*,005*,006*,007*,008*,009*,00A1,00A2,00A3,00A4,00A5,00A6,00A7,00A^,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,1681,1682,1683,1684,1685,1686,1687,168^,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200B,200C,200D,200E,200F,201*,202_,202A,202B,202C,202D,202E,203*,204*,205_,2058,2059,205A,205B,205C,205D,205E,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,3001,3002,3003,3004,3005,3006,3007,300^,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// Zs ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Zs}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0020,00A0,1680,200_,2008,2009,200A,202F,205F,3000," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Zs}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,0021,0022,0023,0024,0025,0026,0027,002^,003*,004*,005*,006*,007*,008*,009*,00A1,00A2,00A3,00A4,00A5,00A6,00A7,00A^,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,1681,1682,1683,1684,1685,1686,1687,168^,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200B,200C,200D,200E,200F,201*,202_,2028,2029,202A,202B,202C,202D,202E,203*,204*,205_,2058,2059,205A,205B,205C,205D,205E,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,3001,3002,3003,3004,3005,3006,3007,300^,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// Zl ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Zl}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"2028," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Zl}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202_,2029,202A,202B,202C,202D,202E,202F,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// Zp ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Zp}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"2029," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Zp}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202_,2028,202A,202B,202C,202D,202E,202F,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// Cc ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Cc}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,007F,008*,009*," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Cc}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"002*,003*,004*,005*,006*,007_,0078,0079,007A,007B,007C,007D,007E,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070*,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,089*,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180*,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200*,201*,202*,203*,204*,205*,206*,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// Cf ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Cf}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"00AD,0600,0601,0602,0603,0604,0605,061C,06DD,070F,0890,0891,08E2,180E,200B,200C,200D,200E,200F,202A,202B,202C,202D,202E,2060,2061,2062,2063,2064,2066,2067,206^," - ->> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Cf}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), - "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") - As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A_,00A8,00A9,00AA,00AB,00AC,00AE,00AF,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037*,038*,039*,03A*,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,053*,054*,055*,056*,057*,058*,059*,05A*,05B*,05C*,05D*,05E*,05F*,0606,0607,060^,061_,0618,0619,061A,061B,061D,061E,061F,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D_,06D8,06D9,06DA,06DB,06DC,06DE,06DF,06E*,06F*,070_,0708,0709,070A,070B,070C,070D,070E,071*,072*,073*,074*,075*,076*,077*,078*,079*,07A*,07B*,07C*,07D*,07E*,07F*,080*,081*,082*,083*,084*,085*,086*,087*,088*,0892,0893,0894,0895,0896,0897,089^,08A*,08B*,08C*,08D*,08E0,08E1,08E3,08E4,08E5,08E6,08E7,08E^,08F*,090*,091*,092*,093*,094*,095*,096*,097*,098*,099*,09A*,09B*,09C*,09D*,09E*,09F*,0A0*,0A1*,0A2*,0A3*,0A4*,0A5*,0A6*,0A7*,0A8*,0A9*,0AA*,0AB*,0AC*,0AD*,0AE*,0AF*,0B0*,0B1*,0B2*,0B3*,0B4*,0B5*,0B6*,0B7*,0B8*,0B9*,0BA*,0BB*,0BC*,0BD*,0BE*,0BF*,0C0*,0C1*,0C2*,0C3*,0C4*,0C5*,0C6*,0C7*,0C8*,0C9*,0CA*,0CB*,0CC*,0CD*,0CE*,0CF*,0D0*,0D1*,0D2*,0D3*,0D4*,0D5*,0D6*,0D7*,0D8*,0D9*,0DA*,0DB*,0DC*,0DD*,0DE*,0DF*,0E0*,0E1*,0E2*,0E3*,0E4*,0E5*,0E6*,0E7*,0E8*,0E9*,0EA*,0EB*,0EC*,0ED*,0EE*,0EF*,0F0*,0F1*,0F2*,0F3*,0F4*,0F5*,0F6*,0F7*,0F8*,0F9*,0FA*,0FB*,0FC*,0FD*,0FE*,0FF*,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C*,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124*,125*,126*,127*,128*,129*,12A*,12B*,12C*,12D*,12E*,12F*,130*,131*,132*,133*,134*,135*,136*,137*,138*,139*,13A*,13B*,13C*,13D*,13E*,13F*,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169*,16A*,16B*,16C*,16D*,16E*,16F*,170*,171*,172*,173*,174*,175*,176*,177*,178*,179*,17A*,17B*,17C*,17D*,17E*,17F*,180_,1808,1809,180A,180B,180C,180D,180F,181*,182*,183*,184*,185*,186*,187*,188*,189*,18A*,18B*,18C*,18D*,18E*,18F*,190*,191*,192*,193*,194*,195*,196*,197*,198*,199*,19A*,19B*,19C*,19D*,19E*,19F*,1A0*,1A1*,1A2*,1A3*,1A4*,1A5*,1A6*,1A7*,1A8*,1A9*,1AA*,1AB*,1AC*,1AD*,1AE*,1AF*,1B0*,1B1*,1B2*,1B3*,1B4*,1B5*,1B6*,1B7*,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF*,1C0*,1C1*,1C2*,1C3*,1C4*,1C5*,1C6*,1C7*,1C8*,1C9*,1CA*,1CB*,1CC*,1CD*,1CE*,1CF*,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F1*,1F2*,1F3*,1F4*,1F5*,1F6*,1F7*,1F8*,1F9*,1FA*,1FB*,1FC*,1FD*,1FE*,1FF*,200_,2008,2009,200A,201*,202_,2028,2029,202F,203*,204*,205*,2065,207*,208*,209*,20A*,20B*,20C*,20D*,20E*,20F*,210*,211*,212*,213*,214*,215*,216*,217*,218*,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,242*,243*,244*,245*,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B7*,2B8*,2B9*,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF*,2D0*,2D1*,2D2*,2D3*,2D4*,2D5*,2D6*,2D7*,2D8*,2D9*,2DA*,2DB*,2DC*,2DD*,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5*,2E6*,2E7*,2E8*,2E9*,2EA*,2EB*,2EC*,2ED*,2EE*,2EF*,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD*,2FE*,2FF*,300*,301*,302*,303*,304*,305*,306*,307*,308*,309*,30A*,30B*,30C*,30D*,30E*,30F*,310*,311*,312*,313*,314*,315*,316*,317*,318*,319*,31A*,31B*,31C*,31D*,31E*,31F*,320*,321*,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// ====================================================================================================================================== -// C, Cs, Co, Cn are disabled for now, implementation variability and not sure how they would be used, wait for feedback - -// C -//>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{C}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), -// "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") -// As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -//"0001,0002,0003,0004,0005,0006,0007,000^,001*,007F,008*,009*,00AD,0378,0379,0380,0381,0382,0383,038B,038D,03A2,0530,0557,0558,058B,058C,0590,05C^,05EB,05EC,05ED,05EE,05F5,05F6,05F7,05F^,0600,0601,0602,0603,0604,0605,061C,06DD,070E,070F,074B,074C,07B2,07B3,07B4,07B5,07B6,07B7,07B^,07FB,07FC,082E,082F,083F,085C,085D,085F,086B,086C,086D,086E,086F,088F,089_,08E2,0984,098D,098E,0991,0992,09A9,09B1,09B3,09B4,09B5,09BA,09BB,09C5,09C6,09C9,09CA,09CF,09D0,09D1,09D2,09D3,09D4,09D5,09D6,09D8,09D9,09DA,09DB,09DE,09E4,09E5,09FF,0A00,0A04,0A0B,0A0C,0A0D,0A0E,0A11,0A12,0A29,0A31,0A34,0A37,0A3A,0A3B,0A3D,0A43,0A44,0A45,0A46,0A49,0A4A,0A4E,0A4F,0A50,0A52,0A53,0A54,0A55,0A56,0A57,0A58,0A5D,0A5F,0A60,0A61,0A62,0A63,0A64,0A65,0A77,0A7^,0A80,0A84,0A8E,0A92,0AA9,0AB1,0AB4,0ABA,0ABB,0AC6,0ACA,0ACE,0ACF,0AD1,0AD2,0AD3,0AD4,0AD5,0AD6,0AD7,0AD^,0AE4,0AE5,0AF2,0AF3,0AF4,0AF5,0AF6,0AF7,0AF8,0B00,0B04,0B0D,0B0E,0B11,0B12,0B29,0B31,0B34,0B3A,0B3B,0B45,0B46,0B49,0B4A,0B4E,0B4F,0B50,0B51,0B52,0B53,0B54,0B58,0B59,0B5A,0B5B,0B5E,0B64,0B65,0B7^,0B80,0B81,0B84,0B8B,0B8C,0B8D,0B91,0B96,0B97,0B98,0B9B,0B9D,0BA0,0BA1,0BA2,0BA5,0BA6,0BA7,0BAB,0BAC,0BAD,0BBA,0BBB,0BBC,0BBD,0BC3,0BC4,0BC5,0BC9,0BCE,0BCF,0BD1,0BD2,0BD3,0BD4,0BD5,0BD6,0BD^,0BE0,0BE1,0BE2,0BE3,0BE4,0BE5,0BFB,0BFC,0BFD,0BFE,0BFF,0C0D,0C11,0C29,0C3A,0C3B,0C45,0C49,0C4E,0C4F,0C50,0C51,0C52,0C53,0C54,0C57,0C5B,0C5C,0C5E,0C5F,0C64,0C65,0C70,0C71,0C72,0C73,0C74,0C75,0C76,0C8D,0C91,0CA9,0CB4,0CBA,0CBB,0CC5,0CC9,0CCE,0CCF,0CD0,0CD1,0CD2,0CD3,0CD4,0CD7,0CD8,0CD9,0CDA,0CDB,0CDC,0CDF,0CE4,0CE5,0CF0,0CF3,0CF4,0CF5,0CF6,0CF7,0CF^,0D0D,0D11,0D45,0D49,0D50,0D51,0D52,0D53,0D64,0D65,0D80,0D84,0D97,0D98,0D99,0DB2,0DBC,0DBE,0DBF,0DC7,0DC8,0DC9,0DCB,0DCC,0DCD,0DCE,0DD5,0DD7,0DE0,0DE1,0DE2,0DE3,0DE4,0DE5,0DF0,0DF1,0DF5,0DF6,0DF7,0DF^,0E00,0E3B,0E3C,0E3D,0E3E,0E5C,0E5D,0E5E,0E5F,0E6*,0E7*,0E80,0E83,0E85,0E8B,0EA4,0EA6,0EBE,0EBF,0EC5,0EC7,0ECE,0ECF,0EDA,0EDB,0EE*,0EF*,0F48,0F6D,0F6E,0F6F,0F70,0F98,0FBD,0FCD,0FDB,0FDC,0FDD,0FDE,0FDF,0FE*,0FF*,10C6,10C8,10C9,10CA,10CB,10CC,10CE,10CF,1249,124E,124F,1257,1259,125E,125F,1289,128E,128F,12B1,12B6,12B7,12BF,12C1,12C6,12C7,12D7,1311,1316,1317,135B,135C,137D,137E,137F,139A,139B,139C,139D,139E,139F,13F6,13F7,13FE,13FF,169D,169E,169F,16F9,16FA,16FB,16FC,16FD,16FE,16FF,1716,1717,1718,1719,171A,171B,171C,171D,171E,1737,173^,1754,1755,1756,1757,175^,176D,1771,1774,1775,1776,1777,177^,17DE,17DF,17EA,17EB,17EC,17ED,17EE,17EF,17FA,17FB,17FC,17FD,17FE,17FF,180E,181A,181B,181C,181D,181E,181F,1879,187A,187B,187C,187D,187E,187F,18AB,18AC,18AD,18AE,18AF,18F6,18F7,18F^,191F,192C,192D,192E,192F,193C,193D,193E,193F,1941,1942,1943,196E,196F,1975,1976,1977,197^,19AC,19AD,19AE,19AF,19CA,19CB,19CC,19CD,19CE,19CF,19DB,19DC,19DD,1A1C,1A1D,1A5F,1A7D,1A7E,1A8A,1A8B,1A8C,1A8D,1A8E,1A8F,1A9A,1A9B,1A9C,1A9D,1A9E,1A9F,1AAE,1AAF,1ACF,1AD*,1AE*,1AF*,1B4D,1B4E,1B4F,1B7F,1BF4,1BF5,1BF6,1BF7,1BF8,1BF9,1BFA,1BFB,1C38,1C39,1C3A,1C4A,1C4B,1C4C,1C89,1C8A,1C8B,1C8C,1C8D,1C8E,1C8F,1CBB,1CBC,1CC^,1CFB,1CFC,1CFD,1CFE,1CFF,1F16,1F17,1F1E,1F1F,1F46,1F47,1F4E,1F4F,1F58,1F5A,1F5C,1F5E,1F7E,1F7F,1FB5,1FC5,1FD4,1FD5,1FDC,1FF0,1FF1,1FF5,1FFF,200B,200C,200D,200E,200F,202A,202B,202C,202D,202E,206*,2072,2073,208F,209D,209E,209F,20C1,20C2,20C3,20C4,20C5,20C6,20C7,20C^,20F1,20F2,20F3,20F4,20F5,20F6,20F7,20F^,218C,218D,218E,218F,2427,242^,243*,244B,244C,244D,244E,244F,245*,2B74,2B75,2B96,2CF4,2CF5,2CF6,2CF7,2CF8,2D26,2D28,2D29,2D2A,2D2B,2D2C,2D2E,2D2F,2D68,2D69,2D6A,2D6B,2D6C,2D6D,2D6E,2D71,2D72,2D73,2D74,2D75,2D76,2D77,2D78,2D79,2D7A,2D7B,2D7C,2D7D,2D7E,2D97,2D9^,2DA7,2DAF,2DB7,2DBF,2DC7,2DCF,2DD7,2DDF,2E5E,2E5F,2E6*,2E7*,2E9A,2EF4,2EF5,2EF6,2EF7,2EF^,2FD6,2FD7,2FD^,2FE*,2FFC,2FFD,2FFE,2FFF,3040,3097,3098,3100,3101,3102,3103,3104,3130,318F,31E4,31E5,31E6,31E7,31E^,321F," - -//>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{C}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), -// "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") -// As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -//"002*,003*,004*,005*,006*,007_,0078,0079,007A,007B,007C,007D,007E,00A_,00A8,00A9,00AA,00AB,00AC,00AE,00AF,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037_,037A,037B,037C,037D,037E,037F,0384,0385,0386,0387,0388,0389,038A,038C,038E,038F,039*,03A0,03A1,03A3,03A4,03A5,03A6,03A7,03A^,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,0531,0532,0533,0534,0535,0536,0537,053^,054*,0550,0551,0552,0553,0554,0555,0556,0559,055A,055B,055C,055D,055E,055F,056*,057*,058_,0588,0589,058A,058D,058E,058F,0591,0592,0593,0594,0595,0596,0597,059^,05A*,05B*,05C_,05D*,05E_,05E8,05E9,05EA,05EF,05F0,05F1,05F2,05F3,05F4,0606,0607,060^,061_,0618,0619,061A,061B,061D,061E,061F,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D_,06D8,06D9,06DA,06DB,06DC,06DE,06DF,06E*,06F*,070_,0708,0709,070A,070B,070C,070D,071*,072*,073*,074_,0748,0749,074A,074D,074E,074F,075*,076*,077*,078*,079*,07A*,07B0,07B1,07C*,07D*,07E*,07F_,07F8,07F9,07FA,07FD,07FE,07FF,080*,081*,082_,0828,0829,082A,082B,082C,082D,083_,0838,0839,083A,083B,083C,083D,083E,084*,085_,0858,0859,085A,085B,085E,086_,0868,0869,086A,087*,088_,0888,0889,088A,088B,088C,088D,088E,089^,08A*,08B*,08C*,08D*,08E0,08E1,08E3,08E4,08E5,08E6,08E7,08E^,08F*,090*,091*,092*,093*,094*,095*,096*,097*,0980,0981,0982,0983,0985,0986,0987,0988,0989,098A,098B,098C,098F,0990,0993,0994,0995,0996,0997,099^,09A_,09A8,09AA,09AB,09AC,09AD,09AE,09AF,09B0,09B2,09B6,09B7,09B8,09B9,09BC,09BD,09BE,09BF,09C0,09C1,09C2,09C3,09C4,09C7,09C8,09CB,09CC,09CD,09CE,09D7,09DC,09DD,09DF,09E0,09E1,09E2,09E3,09E6,09E7,09E^,09F_,09F8,09F9,09FA,09FB,09FC,09FD,09FE,0A01,0A02,0A03,0A05,0A06,0A07,0A08,0A09,0A0A,0A0F,0A10,0A13,0A14,0A15,0A16,0A17,0A1^,0A2_,0A28,0A2A,0A2B,0A2C,0A2D,0A2E,0A2F,0A30,0A32,0A33,0A35,0A36,0A38,0A39,0A3C,0A3E,0A3F,0A40,0A41,0A42,0A47,0A48,0A4B,0A4C,0A4D,0A51,0A59,0A5A,0A5B,0A5C,0A5E,0A66,0A67,0A6^,0A70,0A71,0A72,0A73,0A74,0A75,0A76,0A81,0A82,0A83,0A85,0A86,0A87,0A88,0A89,0A8A,0A8B,0A8C,0A8D,0A8F,0A90,0A91,0A93,0A94,0A95,0A96,0A97,0A9^,0AA_,0AA8,0AAA,0AAB,0AAC,0AAD,0AAE,0AAF,0AB0,0AB2,0AB3,0AB5,0AB6,0AB7,0AB8,0AB9,0ABC,0ABD,0ABE,0ABF,0AC0,0AC1,0AC2,0AC3,0AC4,0AC5,0AC7,0AC8,0AC9,0ACB,0ACC,0ACD,0AD0,0AE0,0AE1,0AE2,0AE3,0AE6,0AE7,0AE^,0AF0,0AF1,0AF9,0AFA,0AFB,0AFC,0AFD,0AFE,0AFF,0B01,0B02,0B03,0B05,0B06,0B07,0B08,0B09,0B0A,0B0B,0B0C,0B0F,0B10,0B13,0B14,0B15,0B16,0B17,0B1^,0B2_,0B28,0B2A,0B2B,0B2C,0B2D,0B2E,0B2F,0B30,0B32,0B33,0B35,0B36,0B37,0B38,0B39,0B3C,0B3D,0B3E,0B3F,0B40,0B41,0B42,0B43,0B44,0B47,0B48,0B4B,0B4C,0B4D,0B55,0B56,0B57,0B5C,0B5D,0B5F,0B60,0B61,0B62,0B63,0B66,0B67,0B6^,0B7_,0B82,0B83,0B85,0B86,0B87,0B88,0B89,0B8A,0B8E,0B8F,0B90,0B92,0B93,0B94,0B95,0B99,0B9A,0B9C,0B9E,0B9F,0BA3,0BA4,0BA8,0BA9,0BAA,0BAE,0BAF,0BB_,0BB8,0BB9,0BBE,0BBF,0BC0,0BC1,0BC2,0BC6,0BC7,0BC8,0BCA,0BCB,0BCC,0BCD,0BD0,0BD7,0BE6,0BE7,0BE^,0BF_,0BF8,0BF9,0BFA,0C0_,0C08,0C09,0C0A,0C0B,0C0C,0C0E,0C0F,0C10,0C12,0C13,0C14,0C15,0C16,0C17,0C1^,0C2_,0C28,0C2A,0C2B,0C2C,0C2D,0C2E,0C2F,0C3_,0C38,0C39,0C3C,0C3D,0C3E,0C3F,0C40,0C41,0C42,0C43,0C44,0C46,0C47,0C48,0C4A,0C4B,0C4C,0C4D,0C55,0C56,0C58,0C59,0C5A,0C5D,0C60,0C61,0C62,0C63,0C66,0C67,0C6^,0C77,0C7^,0C8_,0C88,0C89,0C8A,0C8B,0C8C,0C8E,0C8F,0C90,0C92,0C93,0C94,0C95,0C96,0C97,0C9^,0CA_,0CA8,0CAA,0CAB,0CAC,0CAD,0CAE,0CAF,0CB0,0CB1,0CB2,0CB3,0CB5,0CB6,0CB7,0CB8,0CB9,0CBC,0CBD,0CBE,0CBF,0CC0,0CC1,0CC2,0CC3,0CC4,0CC6,0CC7,0CC8,0CCA,0CCB,0CCC,0CCD,0CD5,0CD6,0CDD,0CDE,0CE0,0CE1,0CE2,0CE3,0CE6,0CE7,0CE^,0CF1,0CF2,0D0_,0D08,0D09,0D0A,0D0B,0D0C,0D0E,0D0F,0D10,0D12,0D13,0D14,0D15,0D16,0D17,0D1^,0D2*,0D3*,0D40,0D41,0D42,0D43,0D44,0D46,0D47,0D48,0D4A,0D4B,0D4C,0D4D,0D4E,0D4F,0D54,0D55,0D56,0D57,0D5^,0D60,0D61,0D62,0D63,0D66,0D67,0D6^,0D7*,0D81,0D82,0D83,0D85,0D86,0D87,0D8^,0D90,0D91,0D92,0D93,0D94,0D95,0D96,0D9A,0D9B,0D9C,0D9D,0D9E,0D9F,0DA*,0DB0,0DB1,0DB3,0DB4,0DB5,0DB6,0DB7,0DB8,0DB9,0DBA,0DBB,0DBD,0DC0,0DC1,0DC2,0DC3,0DC4,0DC5,0DC6,0DCA,0DCF,0DD0,0DD1,0DD2,0DD3,0DD4,0DD6,0DD^,0DE6,0DE7,0DE^,0DF2,0DF3,0DF4,0E01,0E02,0E03,0E04,0E05,0E06,0E07,0E0^,0E1*,0E2*,0E3_,0E38,0E39,0E3A,0E3F,0E4*,0E5_,0E58,0E59,0E5A,0E5B,0E81,0E82,0E84,0E86,0E87,0E88,0E89,0E8A,0E8C,0E8D,0E8E,0E8F,0E9*,0EA0,0EA1,0EA2,0EA3,0EA5,0EA7,0EA^,0EB_,0EB8,0EB9,0EBA,0EBB,0EBC,0EBD,0EC0,0EC1,0EC2,0EC3,0EC4,0EC6,0EC8,0EC9,0ECA,0ECB,0ECC,0ECD,0ED_,0ED8,0ED9,0EDC,0EDD,0EDE,0EDF,0F0*,0F1*,0F2*,0F3*,0F4_,0F49,0F4A,0F4B,0F4C,0F4D,0F4E,0F4F,0F5*,0F6_,0F68,0F69,0F6A,0F6B,0F6C,0F71,0F72,0F73,0F74,0F75,0F76,0F77,0F7^,0F8*,0F9_,0F99,0F9A,0F9B,0F9C,0F9D,0F9E,0F9F,0FA*,0FB_,0FB8,0FB9,0FBA,0FBB,0FBC,0FBE,0FBF,0FC_,0FC8,0FC9,0FCA,0FCB,0FCC,0FCE,0FCF,0FD_,0FD8,0FD9,0FDA,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C0,10C1,10C2,10C3,10C4,10C5,10C7,10CD,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124_,1248,124A,124B,124C,124D,1250,1251,1252,1253,1254,1255,1256,1258,125A,125B,125C,125D,126*,127*,128_,1288,128A,128B,128C,128D,129*,12A*,12B0,12B2,12B3,12B4,12B5,12B8,12B9,12BA,12BB,12BC,12BD,12BE,12C0,12C2,12C3,12C4,12C5,12C^,12D0,12D1,12D2,12D3,12D4,12D5,12D6,12D^,12E*,12F*,130*,1310,1312,1313,1314,1315,131^,132*,133*,134*,135_,1358,1359,135A,135D,135E,135F,136*,137_,1378,1379,137A,137B,137C,138*,139_,1398,1399,13A*,13B*,13C*,13D*,13E*,13F0,13F1,13F2,13F3,13F4,13F5,13F8,13F9,13FA,13FB,13FC,13FD,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169_,1698,1699,169A,169B,169C,16A*,16B*,16C*,16D*,16E*,16F_,16F8,170*,1710,1711,1712,1713,1714,1715,171F,172*,1730,1731,1732,1733,1734,1735,1736,174*,1750,1751,1752,1753,176_,1768,1769,176A,176B,176C,176E,176F,1770,1772,1773,178*,179*,17A*,17B*,17C*,17D_,17D8,17D9,17DA,17DB,17DC,17DD,17E_,17E8,17E9,17F_,17F8,17F9,180_,1808,1809,180A,180B,180C,180D,180F,181_,1818,1819,182*,183*,184*,185*,186*,187_,1878,188*,189*,18A_,18A8,18A9,18AA,18B*,18C*,18D*,18E*,18F0,18F1,18F2,18F3,18F4,18F5,190*,191_,1918,1919,191A,191B,191C,191D,191E,192_,1928,1929,192A,192B,193_,1938,1939,193A,193B,1940,1944,1945,1946,1947,194^,195*,196_,1968,1969,196A,196B,196C,196D,1970,1971,1972,1973,1974,198*,199*,19A_,19A8,19A9,19AA,19AB,19B*,19C_,19C8,19C9,19D_,19D8,19D9,19DA,19DE,19DF,19E*,19F*,1A0*,1A1_,1A18,1A19,1A1A,1A1B,1A1E,1A1F,1A2*,1A3*,1A4*,1A5_,1A58,1A59,1A5A,1A5B,1A5C,1A5D,1A5E,1A6*,1A7_,1A78,1A79,1A7A,1A7B,1A7C,1A7F,1A8_,1A88,1A89,1A9_,1A98,1A99,1AA_,1AA8,1AA9,1AAA,1AAB,1AAC,1AAD,1AB*,1AC_,1AC8,1AC9,1ACA,1ACB,1ACC,1ACD,1ACE,1B0*,1B1*,1B2*,1B3*,1B4_,1B48,1B49,1B4A,1B4B,1B4C,1B5*,1B6*,1B7_,1B78,1B79,1B7A,1B7B,1B7C,1B7D,1B7E,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF0,1BF1,1BF2,1BF3,1BFC,1BFD,1BFE,1BFF,1C0*,1C1*,1C2*,1C3_,1C3B,1C3C,1C3D,1C3E,1C3F,1C4_,1C48,1C49,1C4D,1C4E,1C4F,1C5*,1C6*,1C7*,1C8_,1C88,1C9*,1CA*,1CB_,1CB8,1CB9,1CBA,1CBD,1CBE,1CBF,1CC_,1CD*,1CE*,1CF_,1CF8,1CF9,1CFA,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F10,1F11,1F12,1F13,1F14,1F15,1F18,1F19,1F1A,1F1B,1F1C,1F1D,1F2*,1F3*,1F40,1F41,1F42,1F43,1F44,1F45,1F48,1F49,1F4A,1F4B,1F4C,1F4D,1F5_,1F59,1F5B,1F5D,1F5F,1F6*,1F7_,1F78,1F79,1F7A,1F7B,1F7C,1F7D,1F8*,1F9*,1FA*,1FB0,1FB1,1FB2,1FB3,1FB4,1FB6,1FB7,1FB^,1FC0,1FC1,1FC2,1FC3,1FC4,1FC6,1FC7,1FC^,1FD0,1FD1,1FD2,1FD3,1FD6,1FD7,1FD8,1FD9,1FDA,1FDB,1FDD,1FDE,1FDF,1FE*,1FF2,1FF3,1FF4,1FF6,1FF7,1FF8,1FF9,1FFA,1FFB,1FFC,1FFD,1FFE,200_,2008,2009,200A,201*,202_,2028,2029,202F,203*,204*,205*,2070,2071,2074,2075,2076,2077,207^,208_,2088,2089,208A,208B,208C,208D,208E,209_,2098,2099,209A,209B,209C,20A*,20B*,20C0,20D*,20E*,20F0,210*,211*,212*,213*,214*,215*,216*,217*,218_,2188,2189,218A,218B,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,2420,2421,2422,2423,2424,2425,2426,244_,2448,2449,244A,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B70,2B71,2B72,2B73,2B76,2B77,2B7^,2B8*,2B90,2B91,2B92,2B93,2B94,2B95,2B97,2B9^,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF0,2CF1,2CF2,2CF3,2CF9,2CFA,2CFB,2CFC,2CFD,2CFE,2CFF,2D0*,2D1*,2D20,2D21,2D22,2D23,2D24,2D25,2D27,2D2D,2D3*,2D4*,2D5*,2D6_,2D6F,2D70,2D7F,2D8*,2D90,2D91,2D92,2D93,2D94,2D95,2D96,2DA0,2DA1,2DA2,2DA3,2DA4,2DA5,2DA6,2DA8,2DA9,2DAA,2DAB,2DAC,2DAD,2DAE,2DB0,2DB1,2DB2,2DB3,2DB4,2DB5,2DB6,2DB8,2DB9,2DBA,2DBB,2DBC,2DBD,2DBE,2DC0,2DC1,2DC2,2DC3,2DC4,2DC5,2DC6,2DC8,2DC9,2DCA,2DCB,2DCC,2DCD,2DCE,2DD0,2DD1,2DD2,2DD3,2DD4,2DD5,2DD6,2DD8,2DD9,2DDA,2DDB,2DDC,2DDD,2DDE,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5_,2E58,2E59,2E5A,2E5B,2E5C,2E5D,2E8*,2E9_,2E98,2E99,2E9B,2E9C,2E9D,2E9E,2E9F,2EA*,2EB*,2EC*,2ED*,2EE*,2EF0,2EF1,2EF2,2EF3,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD0,2FD1,2FD2,2FD3,2FD4,2FD5,2FF_,2FF8,2FF9,2FFA,2FFB,300*,301*,302*,303*,3041,3042,3043,3044,3045,3046,3047,304^,305*,306*,307*,308*,3090,3091,3092,3093,3094,3095,3096,3099,309A,309B,309C,309D,309E,309F,30A*,30B*,30C*,30D*,30E*,30F*,3105,3106,3107,310^,311*,312*,3131,3132,3133,3134,3135,3136,3137,313^,314*,315*,316*,317*,318_,3188,3189,318A,318B,318C,318D,318E,319*,31A*,31B*,31C*,31D*,31E0,31E1,31E2,31E3,31F*,320*,321_,3218,3219,321A,321B,321C,321D,321E,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000,""002*,003*,004*,005*,006*,007_,0078,0079,007A,007B,007C,007D,007E,00A_,00A8,00A9,00AA,00AB,00AC,00AE,00AF,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037_,037A,037B,037C,037D,037E,037F,0384,0385,0386,0387,0388,0389,038A,038C,038E,038F,039*,03A0,03A1,03A3,03A4,03A5,03A6,03A7,03A^,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,0531,0532,0533,0534,0535,0536,0537,053^,054*,0550,0551,0552,0553,0554,0555,0556,0559,055A,055B,055C,055D,055E,055F,056*,057*,058_,0588,0589,058A,058D,058E,058F,0591,0592,0593,0594,0595,0596,0597,059^,05A*,05B*,05C_,05D*,05E_,05E8,05E9,05EA,05EF,05F0,05F1,05F2,05F3,05F4,0606,0607,060^,061_,0618,0619,061A,061B,061D,061E,061F,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D_,06D8,06D9,06DA,06DB,06DC,06DE,06DF,06E*,06F*,070_,0708,0709,070A,070B,070C,070D,071*,072*,073*,074_,0748,0749,074A,074D,074E,074F,075*,076*,077*,078*,079*,07A*,07B0,07B1,07C*,07D*,07E*,07F_,07F8,07F9,07FA,07FD,07FE,07FF,080*,081*,082_,0828,0829,082A,082B,082C,082D,083_,0838,0839,083A,083B,083C,083D,083E,084*,085_,0858,0859,085A,085B,085E,086_,0868,0869,086A,087*,088_,0888,0889,088A,088B,088C,088D,088E,089^,08A*,08B*,08C*,08D*,08E0,08E1,08E3,08E4,08E5,08E6,08E7,08E^,08F*,090*,091*,092*,093*,094*,095*,096*,097*,0980,0981,0982,0983,0985,0986,0987,0988,0989,098A,098B,098C,098F,0990,0993,0994,0995,0996,0997,099^,09A_,09A8,09AA,09AB,09AC,09AD,09AE,09AF,09B0,09B2,09B6,09B7,09B8,09B9,09BC,09BD,09BE,09BF,09C0,09C1,09C2,09C3,09C4,09C7,09C8,09CB,09CC,09CD,09CE,09D7,09DC,09DD,09DF,09E0,09E1,09E2,09E3,09E6,09E7,09E^,09F_,09F8,09F9,09FA,09FB,09FC,09FD,09FE,0A01,0A02,0A03,0A05,0A06,0A07,0A08,0A09,0A0A,0A0F,0A10,0A13,0A14,0A15,0A16,0A17,0A1^,0A2_,0A28,0A2A,0A2B,0A2C,0A2D,0A2E,0A2F,0A30,0A32,0A33,0A35,0A36,0A38,0A39,0A3C,0A3E,0A3F,0A40,0A41,0A42,0A47,0A48,0A4B,0A4C,0A4D,0A51,0A59,0A5A,0A5B,0A5C,0A5E,0A66,0A67,0A6^,0A70,0A71,0A72,0A73,0A74,0A75,0A76,0A81,0A82,0A83,0A85,0A86,0A87,0A88,0A89,0A8A,0A8B,0A8C,0A8D,0A8F,0A90,0A91,0A93,0A94,0A95,0A96,0A97,0A9^,0AA_,0AA8,0AAA,0AAB,0AAC,0AAD,0AAE,0AAF,0AB0,0AB2,0AB3,0AB5,0AB6,0AB7,0AB8,0AB9,0ABC,0ABD,0ABE,0ABF,0AC0,0AC1,0AC2,0AC3,0AC4,0AC5,0AC7,0AC8,0AC9,0ACB,0ACC,0ACD,0AD0,0AE0,0AE1,0AE2,0AE3,0AE6,0AE7,0AE^,0AF0,0AF1,0AF9,0AFA,0AFB,0AFC,0AFD,0AFE,0AFF,0B01,0B02,0B03,0B05,0B06,0B07,0B08,0B09,0B0A,0B0B,0B0C,0B0F,0B10,0B13,0B14,0B15,0B16,0B17,0B1^,0B2_,0B28,0B2A,0B2B,0B2C,0B2D,0B2E,0B2F,0B30,0B32,0B33,0B35,0B36,0B37,0B38,0B39,0B3C,0B3D,0B3E,0B3F,0B40,0B41,0B42,0B43,0B44,0B47,0B48,0B4B,0B4C,0B4D,0B55,0B56,0B57,0B5C,0B5D,0B5F,0B60,0B61,0B62,0B63,0B66,0B67,0B6^,0B7_,0B82,0B83,0B85,0B86,0B87,0B88,0B89,0B8A,0B8E,0B8F,0B90,0B92,0B93,0B94,0B95,0B99,0B9A,0B9C,0B9E,0B9F,0BA3,0BA4,0BA8,0BA9,0BAA,0BAE,0BAF,0BB_,0BB8,0BB9,0BBE,0BBF,0BC0,0BC1,0BC2,0BC6,0BC7,0BC8,0BCA,0BCB,0BCC,0BCD,0BD0,0BD7,0BE6,0BE7,0BE^,0BF_,0BF8,0BF9,0BFA,0C0_,0C08,0C09,0C0A,0C0B,0C0C,0C0E,0C0F,0C10,0C12,0C13,0C14,0C15,0C16,0C17,0C1^,0C2_,0C28,0C2A,0C2B,0C2C,0C2D,0C2E,0C2F,0C3_,0C38,0C39,0C3C,0C3D,0C3E,0C3F,0C40,0C41,0C42,0C43,0C44,0C46,0C47,0C48,0C4A,0C4B,0C4C,0C4D,0C55,0C56,0C58,0C59,0C5A,0C5D,0C60,0C61,0C62,0C63,0C66,0C67,0C6^,0C77,0C7^,0C8_,0C88,0C89,0C8A,0C8B,0C8C,0C8E,0C8F,0C90,0C92,0C93,0C94,0C95,0C96,0C97,0C9^,0CA_,0CA8,0CAA,0CAB,0CAC,0CAD,0CAE,0CAF,0CB0,0CB1,0CB2,0CB3,0CB5,0CB6,0CB7,0CB8,0CB9,0CBC,0CBD,0CBE,0CBF,0CC0,0CC1,0CC2,0CC3,0CC4,0CC6,0CC7,0CC8,0CCA,0CCB,0CCC,0CCD,0CD5,0CD6,0CDD,0CDE,0CE0,0CE1,0CE2,0CE3,0CE6,0CE7,0CE^,0CF1,0CF2,0D0_,0D08,0D09,0D0A,0D0B,0D0C,0D0E,0D0F,0D10,0D12,0D13,0D14,0D15,0D16,0D17,0D1^,0D2*,0D3*,0D40,0D41,0D42,0D43,0D44,0D46,0D47,0D48,0D4A,0D4B,0D4C,0D4D,0D4E,0D4F,0D54,0D55,0D56,0D57,0D5^,0D60,0D61,0D62,0D63,0D66,0D67,0D6^,0D7*,0D81,0D82,0D83,0D85,0D86,0D87,0D8^,0D90,0D91,0D92,0D93,0D94,0D95,0D96,0D9A,0D9B,0D9C,0D9D,0D9E,0D9F,0DA*,0DB0,0DB1,0DB3,0DB4,0DB5,0DB6,0DB7,0DB8,0DB9,0DBA,0DBB,0DBD,0DC0,0DC1,0DC2,0DC3,0DC4,0DC5,0DC6,0DCA,0DCF,0DD0,0DD1,0DD2,0DD3,0DD4,0DD6,0DD^,0DE6,0DE7,0DE^,0DF2,0DF3,0DF4,0E01,0E02,0E03,0E04,0E05,0E06,0E07,0E0^,0E1*,0E2*,0E3_,0E38,0E39,0E3A,0E3F,0E4*,0E5_,0E58,0E59,0E5A,0E5B,0E81,0E82,0E84,0E86,0E87,0E88,0E89,0E8A,0E8C,0E8D,0E8E,0E8F,0E9*,0EA0,0EA1,0EA2,0EA3,0EA5,0EA7,0EA^,0EB_,0EB8,0EB9,0EBA,0EBB,0EBC,0EBD,0EC0,0EC1,0EC2,0EC3,0EC4,0EC6,0EC8,0EC9,0ECA,0ECB,0ECC,0ECD,0ED_,0ED8,0ED9,0EDC,0EDD,0EDE,0EDF,0F0*,0F1*,0F2*,0F3*,0F4_,0F49,0F4A,0F4B,0F4C,0F4D,0F4E,0F4F,0F5*,0F6_,0F68,0F69,0F6A,0F6B,0F6C,0F71,0F72,0F73,0F74,0F75,0F76,0F77,0F7^,0F8*,0F9_,0F99,0F9A,0F9B,0F9C,0F9D,0F9E,0F9F,0FA*,0FB_,0FB8,0FB9,0FBA,0FBB,0FBC,0FBE,0FBF,0FC_,0FC8,0FC9,0FCA,0FCB,0FCC,0FCE,0FCF,0FD_,0FD8,0FD9,0FDA,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C0,10C1,10C2,10C3,10C4,10C5,10C7,10CD,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124_,1248,124A,124B,124C,124D,1250,1251,1252,1253,1254,1255,1256,1258,125A,125B,125C,125D,126*,127*,128_,1288,128A,128B,128C,128D,129*,12A*,12B0,12B2,12B3,12B4,12B5,12B8,12B9,12BA,12BB,12BC,12BD,12BE,12C0,12C2,12C3,12C4,12C5,12C^,12D0,12D1,12D2,12D3,12D4,12D5,12D6,12D^,12E*,12F*,130*,1310,1312,1313,1314,1315,131^,132*,133*,134*,135_,1358,1359,135A,135D,135E,135F,136*,137_,1378,1379,137A,137B,137C,138*,139_,1398,1399,13A*,13B*,13C*,13D*,13E*,13F0,13F1,13F2,13F3,13F4,13F5,13F8,13F9,13FA,13FB,13FC,13FD,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169_,1698,1699,169A,169B,169C,16A*,16B*,16C*,16D*,16E*,16F_,16F8,170*,1710,1711,1712,1713,1714,1715,171F,172*,1730,1731,1732,1733,1734,1735,1736,174*,1750,1751,1752,1753,176_,1768,1769,176A,176B,176C,176E,176F,1770,1772,1773,178*,179*,17A*,17B*,17C*,17D_,17D8,17D9,17DA,17DB,17DC,17DD,17E_,17E8,17E9,17F_,17F8,17F9,180_,1808,1809,180A,180B,180C,180D,180F,181_,1818,1819,182*,183*,184*,185*,186*,187_,1878,188*,189*,18A_,18A8,18A9,18AA,18B*,18C*,18D*,18E*,18F0,18F1,18F2,18F3,18F4,18F5,190*,191_,1918,1919,191A,191B,191C,191D,191E,192_,1928,1929,192A,192B,193_,1938,1939,193A,193B,1940,1944,1945,1946,1947,194^,195*,196_,1968,1969,196A,196B,196C,196D,1970,1971,1972,1973,1974,198*,199*,19A_,19A8,19A9,19AA,19AB,19B*,19C_,19C8,19C9,19D_,19D8,19D9,19DA,19DE,19DF,19E*,19F*,1A0*,1A1_,1A18,1A19,1A1A,1A1B,1A1E,1A1F,1A2*,1A3*,1A4*,1A5_,1A58,1A59,1A5A,1A5B,1A5C,1A5D,1A5E,1A6*,1A7_,1A78,1A79,1A7A,1A7B,1A7C,1A7F,1A8_,1A88,1A89,1A9_,1A98,1A99,1AA_,1AA8,1AA9,1AAA,1AAB,1AAC,1AAD,1AB*,1AC_,1AC8,1AC9,1ACA,1ACB,1ACC,1ACD,1ACE,1B0*,1B1*,1B2*,1B3*,1B4_,1B48,1B49,1B4A,1B4B,1B4C,1B5*,1B6*,1B7_,1B78,1B79,1B7A,1B7B,1B7C,1B7D,1B7E,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF0,1BF1,1BF2,1BF3,1BFC,1BFD,1BFE,1BFF,1C0*,1C1*,1C2*,1C3_,1C3B,1C3C,1C3D,1C3E,1C3F,1C4_,1C48,1C49,1C4D,1C4E,1C4F,1C5*,1C6*,1C7*,1C8_,1C88,1C9*,1CA*,1CB_,1CB8,1CB9,1CBA,1CBD,1CBE,1CBF,1CC_,1CD*,1CE*,1CF_,1CF8,1CF9,1CFA,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F10,1F11,1F12,1F13,1F14,1F15,1F18,1F19,1F1A,1F1B,1F1C,1F1D,1F2*,1F3*,1F40,1F41,1F42,1F43,1F44,1F45,1F48,1F49,1F4A,1F4B,1F4C,1F4D,1F5_,1F59,1F5B,1F5D,1F5F,1F6*,1F7_,1F78,1F79,1F7A,1F7B,1F7C,1F7D,1F8*,1F9*,1FA*,1FB0,1FB1,1FB2,1FB3,1FB4,1FB6,1FB7,1FB^,1FC0,1FC1,1FC2,1FC3,1FC4,1FC6,1FC7,1FC^,1FD0,1FD1,1FD2,1FD3,1FD6,1FD7,1FD8,1FD9,1FDA,1FDB,1FDD,1FDE,1FDF,1FE*,1FF2,1FF3,1FF4,1FF6,1FF7,1FF8,1FF9,1FFA,1FFB,1FFC,1FFD,1FFE,200_,2008,2009,200A,201*,202_,2028,2029,202F,203*,204*,205*,2070,2071,2074,2075,2076,2077,207^,208_,2088,2089,208A,208B,208C,208D,208E,209_,2098,2099,209A,209B,209C,20A*,20B*,20C0,20D*,20E*,20F0,210*,211*,212*,213*,214*,215*,216*,217*,218_,2188,2189,218A,218B,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,2420,2421,2422,2423,2424,2425,2426,244_,2448,2449,244A,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B70,2B71,2B72,2B73,2B76,2B77,2B7^,2B8*,2B90,2B91,2B92,2B93,2B94,2B95,2B97,2B9^,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF0,2CF1,2CF2,2CF3,2CF9,2CFA,2CFB,2CFC,2CFD,2CFE,2CFF,2D0*,2D1*,2D20,2D21,2D22,2D23,2D24,2D25,2D27,2D2D,2D3*,2D4*,2D5*,2D6_,2D6F,2D70,2D7F,2D8*,2D90,2D91,2D92,2D93,2D94,2D95,2D96,2DA0,2DA1,2DA2,2DA3,2DA4,2DA5,2DA6,2DA8,2DA9,2DAA,2DAB,2DAC,2DAD,2DAE,2DB0,2DB1,2DB2,2DB3,2DB4,2DB5,2DB6,2DB8,2DB9,2DBA,2DBB,2DBC,2DBD,2DBE,2DC0,2DC1,2DC2,2DC3,2DC4,2DC5,2DC6,2DC8,2DC9,2DCA,2DCB,2DCC,2DCD,2DCE,2DD0,2DD1,2DD2,2DD3,2DD4,2DD5,2DD6,2DD8,2DD9,2DDA,2DDB,2DDC,2DDD,2DDE,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5_,2E58,2E59,2E5A,2E5B,2E5C,2E5D,2E8*,2E9_,2E98,2E99,2E9B,2E9C,2E9D,2E9E,2E9F,2EA*,2EB*,2EC*,2ED*,2EE*,2EF0,2EF1,2EF2,2EF3,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD0,2FD1,2FD2,2FD3,2FD4,2FD5,2FF_,2FF8,2FF9,2FFA,2FFB,300*,301*,302*,303*,3041,3042,3043,3044,3045,3046,3047,304^,305*,306*,307*,308*,3090,3091,3092,3093,3094,3095,3096,3099,309A,309B,309C,309D,309E,309F,30A*,30B*,30C*,30D*,30E*,30F*,3105,3106,3107,310^,311*,312*,3131,3132,3133,3134,3135,3136,3137,313^,314*,315*,316*,317*,318_,3188,3189,318A,318B,318C,318D,318E,319*,31A*,31B*,31C*,31D*,31E0,31E1,31E2,31E3,31F*,320*,321_,3218,3219,321A,321B,321C,321D,321E,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," - -// Cs - reserved for surrogates, \uD800-\uDFFF, which are illegal by themselves -//>> Concat(MatchAll( Concat(ForAll(Sequence(Hex2Dec("7ff"),Hex2Dec("D000")),If( IsMatch(UniChar(Value), "\p{Cs}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), -// "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") -// As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -//"" - -//>> Concat(MatchAll( Concat(ForAll(Sequence(Hex2Dec("7ff"),Hex2Dec("E000")),If( IsMatch(UniChar(Value), "\p{Cs}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), -// "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") -// As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -//"" - -//>> UniChar(Hex2Dec("D800")) -// - -//>> UniChar(Hex2Dec("D8FF")) -// - -//>> Concat(MatchAll( Concat(ForAll(Sequence(Hex2Dec("7ff"),Hex2Dec("D000")),If( IsMatch(UniChar(Value), "\P{Cs}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), -// "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") -// As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -//"D00*,D01*,D02*,D03*,D04*,D05*,D06*,D07*,D08*,D09*,D0A*,D0B*,D0C*,D0D*,D0E*,D0F*,D10*,D11*,D12*,D13*,D14*,D15*,D16*,D17*,D18*,D19*,D1A*,D1B*,D1C*,D1D*,D1E*,D1F*,D20*,D21*,D22*,D23*,D24*,D25*,D26*,D27*,D28*,D29*,D2A*,D2B*,D2C*,D2D*,D2E*,D2F*,D30*,D31*,D32*,D33*,D34*,D35*,D36*,D37*,D38*,D39*,D3A*,D3B*,D3C*,D3D*,D3E*,D3F*,D40*,D41*,D42*,D43*,D44*,D45*,D46*,D47*,D48*,D49*,D4A*,D4B*,D4C*,D4D*,D4E*,D4F*,D50*,D51*,D52*,D53*,D54*,D55*,D56*,D57*,D58*,D59*,D5A*,D5B*,D5C*,D5D*,D5E*,D5F*,D60*,D61*,D62*,D63*,D64*,D65*,D66*,D67*,D68*,D69*,D6A*,D6B*,D6C*,D6D*,D6E*,D6F*,D70*,D71*,D72*,D73*,D74*,D75*,D76*,D77*,D78*,D79*,D7A*,D7B*,D7C*,D7D*,D7E*,D7F_,D7F8,D7F9,D7FA,D7FB,D7FC,D7FD,D7FE," - -//>> Concat(MatchAll( Concat(ForAll(Sequence(Hex2Dec("7ff"),Hex2Dec("E000")),If( IsMatch(UniChar(Value), "\P{Cs}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), -// "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") -// As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -//"E00*,E01*,E02*,E03*,E04*,E05*,E06*,E07*,E08*,E09*,E0A*,E0B*,E0C*,E0D*,E0E*,E0F*,E10*,E11*,E12*,E13*,E14*,E15*,E16*,E17*,E18*,E19*,E1A*,E1B*,E1C*,E1D*,E1E*,E1F*,E20*,E21*,E22*,E23*,E24*,E25*,E26*,E27*,E28*,E29*,E2A*,E2B*,E2C*,E2D*,E2E*,E2F*,E30*,E31*,E32*,E33*,E34*,E35*,E36*,E37*,E38*,E39*,E3A*,E3B*,E3C*,E3D*,E3E*,E3F*,E40*,E41*,E42*,E43*,E44*,E45*,E46*,E47*,E48*,E49*,E4A*,E4B*,E4C*,E4D*,E4E*,E4F*,E50*,E51*,E52*,E53*,E54*,E55*,E56*,E57*,E58*,E59*,E5A*,E5B*,E5C*,E5D*,E5E*,E5F*,E60*,E61*,E62*,E63*,E64*,E65*,E66*,E67*,E68*,E69*,E6A*,E6B*,E6C*,E6D*,E6E*,E6F*,E70*,E71*,E72*,E73*,E74*,E75*,E76*,E77*,E78*,E79*,E7A*,E7B*,E7C*,E7D*,E7E*,E7F_,E7F8,E7F9,E7FA,E7FB,E7FC,E7FD,E7FE," - -// Co - reserved for private use, \uE000-\uF8FF, \uF0000-\uFFFFD, and \u100000-\u10FFFD -//>> Concat(MatchAll( Concat(ForAll(Sequence(Hex2Dec("1FFF"),Hex2Dec("E000")),If( IsMatch(UniChar(Value), "\p{Co}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), -// "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") -// As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -//"E00*,E01*,E02*,E03*,E04*,E05*,E06*,E07*,E08*,E09*,E0A*,E0B*,E0C*,E0D*,E0E*,E0F*,E10*,E11*,E12*,E13*,E14*,E15*,E16*,E17*,E18*,E19*,E1A*,E1B*,E1C*,E1D*,E1E*,E1F*,E20*,E21*,E22*,E23*,E24*,E25*,E26*,E27*,E28*,E29*,E2A*,E2B*,E2C*,E2D*,E2E*,E2F*,E30*,E31*,E32*,E33*,E34*,E35*,E36*,E37*,E38*,E39*,E3A*,E3B*,E3C*,E3D*,E3E*,E3F*,E40*,E41*,E42*,E43*,E44*,E45*,E46*,E47*,E48*,E49*,E4A*,E4B*,E4C*,E4D*,E4E*,E4F*,E50*,E51*,E52*,E53*,E54*,E55*,E56*,E57*,E58*,E59*,E5A*,E5B*,E5C*,E5D*,E5E*,E5F*,E60*,E61*,E62*,E63*,E64*,E65*,E66*,E67*,E68*,E69*,E6A*,E6B*,E6C*,E6D*,E6E*,E6F*,E70*,E71*,E72*,E73*,E74*,E75*,E76*,E77*,E78*,E79*,E7A*,E7B*,E7C*,E7D*,E7E*,E7F*,E80*,E81*,E82*,E83*,E84*,E85*,E86*,E87*,E88*,E89*,E8A*,E8B*,E8C*,E8D*,E8E*,E8F*,E90*,E91*,E92*,E93*,E94*,E95*,E96*,E97*,E98*,E99*,E9A*,E9B*,E9C*,E9D*,E9E*,E9F*,EA0*,EA1*,EA2*,EA3*,EA4*,EA5*,EA6*,EA7*,EA8*,EA9*,EAA*,EAB*,EAC*,EAD*,EAE*,EAF*,EB0*,EB1*,EB2*,EB3*,EB4*,EB5*,EB6*,EB7*,EB8*,EB9*,EBA*,EBB*,EBC*,EBD*,EBE*,EBF*,EC0*,EC1*,EC2*,EC3*,EC4*,EC5*,EC6*,EC7*,EC8*,EC9*,ECA*,ECB*,ECC*,ECD*,ECE*,ECF*,ED0*,ED1*,ED2*,ED3*,ED4*,ED5*,ED6*,ED7*,ED8*,ED9*,EDA*,EDB*,EDC*,EDD*,EDE*,EDF*,EE0*,EE1*,EE2*,EE3*,EE4*,EE5*,EE6*,EE7*,EE8*,EE9*,EEA*,EEB*,EEC*,EED*,EEE*,EEF*,EF0*,EF1*,EF2*,EF3*,EF4*,EF5*,EF6*,EF7*,EF8*,EF9*,EFA*,EFB*,EFC*,EFD*,EFE*,EFF*,F00*,F01*,F02*,F03*,F04*,F05*,F06*,F07*,F08*,F09*,F0A*,F0B*,F0C*,F0D*,F0E*,F0F*,F10*,F11*,F12*,F13*,F14*,F15*,F16*,F17*,F18*,F19*,F1A*,F1B*,F1C*,F1D*,F1E*,F1F*,F20*,F21*,F22*,F23*,F24*,F25*,F26*,F27*,F28*,F29*,F2A*,F2B*,F2C*,F2D*,F2E*,F2F*,F30*,F31*,F32*,F33*,F34*,F35*,F36*,F37*,F38*,F39*,F3A*,F3B*,F3C*,F3D*,F3E*,F3F*,F40*,F41*,F42*,F43*,F44*,F45*,F46*,F47*,F48*,F49*,F4A*,F4B*,F4C*,F4D*,F4E*,F4F*,F50*,F51*,F52*,F53*,F54*,F55*,F56*,F57*,F58*,F59*,F5A*,F5B*,F5C*,F5D*,F5E*,F5F*,F60*,F61*,F62*,F63*,F64*,F65*,F66*,F67*,F68*,F69*,F6A*,F6B*,F6C*,F6D*,F6E*,F6F*,F70*,F71*,F72*,F73*,F74*,F75*,F76*,F77*,F78*,F79*,F7A*,F7B*,F7C*,F7D*,F7E*,F7F*,F80*,F81*,F82*,F83*,F84*,F85*,F86*,F87*,F88*,F89*,F8A*,F8B*,F8C*,F8D*,F8E*,F8F*," - -//>> Concat(MatchAll( Concat(ForAll(Sequence(Hex2Dec(""),Hex2Dec("E000")),If( IsMatch(UniChar(Value), "\p{Co}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), -// "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") -// As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -//"E00*,E01*,E02*,E03*,E04*,E05*,E06*,E07*,E08*,E09*,E0A*,E0B*,E0C*,E0D*,E0E*,E0F*,E10*,E11*,E12*,E13*,E14*,E15*,E16*,E17*,E18*,E19*,E1A*,E1B*,E1C*,E1D*,E1E*,E1F*,E20*,E21*,E22*,E23*,E24*,E25*,E26*,E27*,E28*,E29*,E2A*,E2B*,E2C*,E2D*,E2E*,E2F*,E30*,E31*,E32*,E33*,E34*,E35*,E36*,E37*,E38*,E39*,E3A*,E3B*,E3C*,E3D*,E3E*,E3F*,E40*,E41*,E42*,E43*,E44*,E45*,E46*,E47*,E48*,E49*,E4A*,E4B*,E4C*,E4D*,E4E*,E4F*,E50*,E51*,E52*,E53*,E54*,E55*,E56*,E57*,E58*,E59*,E5A*,E5B*,E5C*,E5D*,E5E*,E5F*,E60*,E61*,E62*,E63*,E64*,E65*,E66*,E67*,E68*,E69*,E6A*,E6B*,E6C*,E6D*,E6E*,E6F*,E70*,E71*,E72*,E73*,E74*,E75*,E76*,E77*,E78*,E79*,E7A*,E7B*,E7C*,E7D*,E7E*,E7F*,E80*,E81*,E82*,E83*,E84*,E85*,E86*,E87*,E88*,E89*,E8A*,E8B*,E8C*,E8D*,E8E*,E8F*,E90*,E91*,E92*,E93*,E94*,E95*,E96*,E97*,E98*,E99*,E9A*,E9B*,E9C*,E9D*,E9E*,E9F*,EA0*,EA1*,EA2*,EA3*,EA4*,EA5*,EA6*,EA7*,EA8*,EA9*,EAA*,EAB*,EAC*,EAD*,EAE*,EAF*,EB0*,EB1*,EB2*,EB3*,EB4*,EB5*,EB6*,EB7*,EB8*,EB9*,EBA*,EBB*,EBC*,EBD*,EBE*,EBF*,EC0*,EC1*,EC2*,EC3*,EC4*,EC5*,EC6*,EC7*,EC8*,EC9*,ECA*,ECB*,ECC*,ECD*,ECE*,ECF*,ED0*,ED1*,ED2*,ED3*,ED4*,ED5*,ED6*,ED7*,ED8*,ED9*,EDA*,EDB*,EDC*,EDD*,EDE*,EDF*,EE0*,EE1*,EE2*,EE3*,EE4*,EE5*,EE6*,EE7*,EE8*,EE9*,EEA*,EEB*,EEC*,EED*,EEE*,EEF*,EF0*,EF1*,EF2*,EF3*,EF4*,EF5*,EF6*,EF7*,EF8*,EF9*,EFA*,EFB*,EFC*,EFD*,EFE*,EFF*,F00*,F01*,F02*,F03*,F04*,F05*,F06*,F07*,F08*,F09*,F0A*,F0B*,F0C*,F0D*,F0E*,F0F*,F10*,F11*,F12*,F13*,F14*,F15*,F16*,F17*,F18*,F19*,F1A*,F1B*,F1C*,F1D*,F1E*,F1F*,F20*,F21*,F22*,F23*,F24*,F25*,F26*,F27*,F28*,F29*,F2A*,F2B*,F2C*,F2D*,F2E*,F2F*,F30*,F31*,F32*,F33*,F34*,F35*,F36*,F37*,F38*,F39*,F3A*,F3B*,F3C*,F3D*,F3E*,F3F*,F40*,F41*,F42*,F43*,F44*,F45*,F46*,F47*,F48*,F49*,F4A*,F4B*,F4C*,F4D*,F4E*,F4F*,F50*,F51*,F52*,F53*,F54*,F55*,F56*,F57*,F58*,F59*,F5A*,F5B*,F5C*,F5D*,F5E*,F5F*,F60*,F61*,F62*,F63*,F64*,F65*,F66*,F67*,F68*,F69*,F6A*,F6B*,F6C*,F6D*,F6E*,F6F*,F70*,F71*,F72*,F73*,F74*,F75*,F76*,F77*,F78*,F79*,F7A*,F7B*,F7C*,F7D*,F7E*,F7F*,F80*,F81*,F82*,F83*,F84*,F85*,F86*,F87*,F88*,F89*,F8A*,F8B*,F8C*,F8D*,F8E*,F8F*," - -// above F0000, .NET 7 & 8 report false, PCRE2 and JavaScript report true -//>> Concat(MatchAll( Concat(ForAll(Sequence(Hex2Dec("2000"),Hex2Dec("EFF00")),If( IsMatch(UniChar(Value), "\p{Co}" ), Dec2Hex(Value,5) & ",", "" ) ),Value ), -// "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") -// As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -//"" - -// above 100000, .NET 7 & 8 report false, PCRE2 and JavaScript report true -//>> Concat(MatchAll( Concat(ForAll(Sequence(Hex2Dec("2000"),Hex2Dec("FFF00")),If( IsMatch(UniChar(Value), "\p{Co}" ), Dec2Hex(Value,5) & ",", "" ) ),Value ), -// "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") -// As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -//"" - -// Cn - not assigned -//>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\p{Cn}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), -// "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") -// As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -//"0378,0379,0380,0381,0382,0383,038B,038D,03A2,0530,0557,0558,058B,058C,0590,05C^,05EB,05EC,05ED,05EE,05F5,05F6,05F7,05F^,070E,074B,074C,07B2,07B3,07B4,07B5,07B6,07B7,07B^,07FB,07FC,082E,082F,083F,085C,085D,085F,086B,086C,086D,086E,086F,088F,0892,0893,0894,0895,0896,0897,0984,098D,098E,0991,0992,09A9,09B1,09B3,09B4,09B5,09BA,09BB,09C5,09C6,09C9,09CA,09CF,09D0,09D1,09D2,09D3,09D4,09D5,09D6,09D8,09D9,09DA,09DB,09DE,09E4,09E5,09FF,0A00,0A04,0A0B,0A0C,0A0D,0A0E,0A11,0A12,0A29,0A31,0A34,0A37,0A3A,0A3B,0A3D,0A43,0A44,0A45,0A46,0A49,0A4A,0A4E,0A4F,0A50,0A52,0A53,0A54,0A55,0A56,0A57,0A58,0A5D,0A5F,0A60,0A61,0A62,0A63,0A64,0A65,0A77,0A7^,0A80,0A84,0A8E,0A92,0AA9,0AB1,0AB4,0ABA,0ABB,0AC6,0ACA,0ACE,0ACF,0AD1,0AD2,0AD3,0AD4,0AD5,0AD6,0AD7,0AD^,0AE4,0AE5,0AF2,0AF3,0AF4,0AF5,0AF6,0AF7,0AF8,0B00,0B04,0B0D,0B0E,0B11,0B12,0B29,0B31,0B34,0B3A,0B3B,0B45,0B46,0B49,0B4A,0B4E,0B4F,0B50,0B51,0B52,0B53,0B54,0B58,0B59,0B5A,0B5B,0B5E,0B64,0B65,0B7^,0B80,0B81,0B84,0B8B,0B8C,0B8D,0B91,0B96,0B97,0B98,0B9B,0B9D,0BA0,0BA1,0BA2,0BA5,0BA6,0BA7,0BAB,0BAC,0BAD,0BBA,0BBB,0BBC,0BBD,0BC3,0BC4,0BC5,0BC9,0BCE,0BCF,0BD1,0BD2,0BD3,0BD4,0BD5,0BD6,0BD^,0BE0,0BE1,0BE2,0BE3,0BE4,0BE5,0BFB,0BFC,0BFD,0BFE,0BFF,0C0D,0C11,0C29,0C3A,0C3B,0C45,0C49,0C4E,0C4F,0C50,0C51,0C52,0C53,0C54,0C57,0C5B,0C5C,0C5E,0C5F,0C64,0C65,0C70,0C71,0C72,0C73,0C74,0C75,0C76,0C8D,0C91,0CA9,0CB4,0CBA,0CBB,0CC5,0CC9,0CCE,0CCF,0CD0,0CD1,0CD2,0CD3,0CD4,0CD7,0CD8,0CD9,0CDA,0CDB,0CDC,0CDF,0CE4,0CE5,0CF0,0CF3,0CF4,0CF5,0CF6,0CF7,0CF^,0D0D,0D11,0D45,0D49,0D50,0D51,0D52,0D53,0D64,0D65,0D80,0D84,0D97,0D98,0D99,0DB2,0DBC,0DBE,0DBF,0DC7,0DC8,0DC9,0DCB,0DCC,0DCD,0DCE,0DD5,0DD7,0DE0,0DE1,0DE2,0DE3,0DE4,0DE5,0DF0,0DF1,0DF5,0DF6,0DF7,0DF^,0E00,0E3B,0E3C,0E3D,0E3E,0E5C,0E5D,0E5E,0E5F,0E6*,0E7*,0E80,0E83,0E85,0E8B,0EA4,0EA6,0EBE,0EBF,0EC5,0EC7,0ECE,0ECF,0EDA,0EDB,0EE*,0EF*,0F48,0F6D,0F6E,0F6F,0F70,0F98,0FBD,0FCD,0FDB,0FDC,0FDD,0FDE,0FDF,0FE*,0FF*,10C6,10C8,10C9,10CA,10CB,10CC,10CE,10CF,1249,124E,124F,1257,1259,125E,125F,1289,128E,128F,12B1,12B6,12B7,12BF,12C1,12C6,12C7,12D7,1311,1316,1317,135B,135C,137D,137E,137F,139A,139B,139C,139D,139E,139F,13F6,13F7,13FE,13FF,169D,169E,169F,16F9,16FA,16FB,16FC,16FD,16FE,16FF,1716,1717,1718,1719,171A,171B,171C,171D,171E,1737,173^,1754,1755,1756,1757,175^,176D,1771,1774,1775,1776,1777,177^,17DE,17DF,17EA,17EB,17EC,17ED,17EE,17EF,17FA,17FB,17FC,17FD,17FE,17FF,181A,181B,181C,181D,181E,181F,1879,187A,187B,187C,187D,187E,187F,18AB,18AC,18AD,18AE,18AF,18F6,18F7,18F^,191F,192C,192D,192E,192F,193C,193D,193E,193F,1941,1942,1943,196E,196F,1975,1976,1977,197^,19AC,19AD,19AE,19AF,19CA,19CB,19CC,19CD,19CE,19CF,19DB,19DC,19DD,1A1C,1A1D,1A5F,1A7D,1A7E,1A8A,1A8B,1A8C,1A8D,1A8E,1A8F,1A9A,1A9B,1A9C,1A9D,1A9E,1A9F,1AAE,1AAF,1ACF,1AD*,1AE*,1AF*,1B4D,1B4E,1B4F,1B7F,1BF4,1BF5,1BF6,1BF7,1BF8,1BF9,1BFA,1BFB,1C38,1C39,1C3A,1C4A,1C4B,1C4C,1C89,1C8A,1C8B,1C8C,1C8D,1C8E,1C8F,1CBB,1CBC,1CC^,1CFB,1CFC,1CFD,1CFE,1CFF,1F16,1F17,1F1E,1F1F,1F46,1F47,1F4E,1F4F,1F58,1F5A,1F5C,1F5E,1F7E,1F7F,1FB5,1FC5,1FD4,1FD5,1FDC,1FF0,1FF1,1FF5,1FFF,2065,2072,2073,208F,209D,209E,209F,20C1,20C2,20C3,20C4,20C5,20C6,20C7,20C^,20F1,20F2,20F3,20F4,20F5,20F6,20F7,20F^,218C,218D,218E,218F,2427,242^,243*,244B,244C,244D,244E,244F,245*,2B74,2B75,2B96,2CF4,2CF5,2CF6,2CF7,2CF8,2D26,2D28,2D29,2D2A,2D2B,2D2C,2D2E,2D2F,2D68,2D69,2D6A,2D6B,2D6C,2D6D,2D6E,2D71,2D72,2D73,2D74,2D75,2D76,2D77,2D78,2D79,2D7A,2D7B,2D7C,2D7D,2D7E,2D97,2D9^,2DA7,2DAF,2DB7,2DBF,2DC7,2DCF,2DD7,2DDF,2E5E,2E5F,2E6*,2E7*,2E9A,2EF4,2EF5,2EF6,2EF7,2EF^,2FD6,2FD7,2FD^,2FE*,2FFC,2FFD,2FFE,2FFF,3040,3097,3098,3100,3101,3102,3103,3104,3130,318F,31E4,31E5,31E6,31E7,31E^,321F," - -//>> Concat(MatchAll( Concat(ForAll(Sequence(16384),If( IsMatch(UniChar(Value), "\P{Cn}" ), Dec2Hex(Value,4) & ",", "" ) ),Value ), -// "((?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7,\k8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|(?...)0,\k1,\k2,\k3,\k4,\k5,\k6,\k7|(?...)8,\k9,\kA,\kB,\kC,\kD,\kE,\kF|.)") -// As m,If(Not IsBlank(m.x), m.x & "*", Not IsBlank(m.l), m.l & "_", Not IsBlank(m.h), m.h & "^", m.FullMatch)) -//"0001,0002,0003,0004,0005,0006,0007,000^,001*,002*,003*,004*,005*,006*,007*,008*,009*,00A*,00B*,00C*,00D*,00E*,00F*,010*,011*,012*,013*,014*,015*,016*,017*,018*,019*,01A*,01B*,01C*,01D*,01E*,01F*,020*,021*,022*,023*,024*,025*,026*,027*,028*,029*,02A*,02B*,02C*,02D*,02E*,02F*,030*,031*,032*,033*,034*,035*,036*,037_,037A,037B,037C,037D,037E,037F,0384,0385,0386,0387,0388,0389,038A,038C,038E,038F,039*,03A0,03A1,03A3,03A4,03A5,03A6,03A7,03A^,03B*,03C*,03D*,03E*,03F*,040*,041*,042*,043*,044*,045*,046*,047*,048*,049*,04A*,04B*,04C*,04D*,04E*,04F*,050*,051*,052*,0531,0532,0533,0534,0535,0536,0537,053^,054*,0550,0551,0552,0553,0554,0555,0556,0559,055A,055B,055C,055D,055E,055F,056*,057*,058_,0588,0589,058A,058D,058E,058F,0591,0592,0593,0594,0595,0596,0597,059^,05A*,05B*,05C_,05D*,05E_,05E8,05E9,05EA,05EF,05F0,05F1,05F2,05F3,05F4,060*,061*,062*,063*,064*,065*,066*,067*,068*,069*,06A*,06B*,06C*,06D*,06E*,06F*,070_,0708,0709,070A,070B,070C,070D,070F,071*,072*,073*,074_,0748,0749,074A,074D,074E,074F,075*,076*,077*,078*,079*,07A*,07B0,07B1,07C*,07D*,07E*,07F_,07F8,07F9,07FA,07FD,07FE,07FF,080*,081*,082_,0828,0829,082A,082B,082C,082D,083_,0838,0839,083A,083B,083C,083D,083E,084*,085_,0858,0859,085A,085B,085E,086_,0868,0869,086A,087*,088_,0888,0889,088A,088B,088C,088D,088E,0890,0891,089^,08A*,08B*,08C*,08D*,08E*,08F*,090*,091*,092*,093*,094*,095*,096*,097*,0980,0981,0982,0983,0985,0986,0987,0988,0989,098A,098B,098C,098F,0990,0993,0994,0995,0996,0997,099^,09A_,09A8,09AA,09AB,09AC,09AD,09AE,09AF,09B0,09B2,09B6,09B7,09B8,09B9,09BC,09BD,09BE,09BF,09C0,09C1,09C2,09C3,09C4,09C7,09C8,09CB,09CC,09CD,09CE,09D7,09DC,09DD,09DF,09E0,09E1,09E2,09E3,09E6,09E7,09E^,09F_,09F8,09F9,09FA,09FB,09FC,09FD,09FE,0A01,0A02,0A03,0A05,0A06,0A07,0A08,0A09,0A0A,0A0F,0A10,0A13,0A14,0A15,0A16,0A17,0A1^,0A2_,0A28,0A2A,0A2B,0A2C,0A2D,0A2E,0A2F,0A30,0A32,0A33,0A35,0A36,0A38,0A39,0A3C,0A3E,0A3F,0A40,0A41,0A42,0A47,0A48,0A4B,0A4C,0A4D,0A51,0A59,0A5A,0A5B,0A5C,0A5E,0A66,0A67,0A6^,0A70,0A71,0A72,0A73,0A74,0A75,0A76,0A81,0A82,0A83,0A85,0A86,0A87,0A88,0A89,0A8A,0A8B,0A8C,0A8D,0A8F,0A90,0A91,0A93,0A94,0A95,0A96,0A97,0A9^,0AA_,0AA8,0AAA,0AAB,0AAC,0AAD,0AAE,0AAF,0AB0,0AB2,0AB3,0AB5,0AB6,0AB7,0AB8,0AB9,0ABC,0ABD,0ABE,0ABF,0AC0,0AC1,0AC2,0AC3,0AC4,0AC5,0AC7,0AC8,0AC9,0ACB,0ACC,0ACD,0AD0,0AE0,0AE1,0AE2,0AE3,0AE6,0AE7,0AE^,0AF0,0AF1,0AF9,0AFA,0AFB,0AFC,0AFD,0AFE,0AFF,0B01,0B02,0B03,0B05,0B06,0B07,0B08,0B09,0B0A,0B0B,0B0C,0B0F,0B10,0B13,0B14,0B15,0B16,0B17,0B1^,0B2_,0B28,0B2A,0B2B,0B2C,0B2D,0B2E,0B2F,0B30,0B32,0B33,0B35,0B36,0B37,0B38,0B39,0B3C,0B3D,0B3E,0B3F,0B40,0B41,0B42,0B43,0B44,0B47,0B48,0B4B,0B4C,0B4D,0B55,0B56,0B57,0B5C,0B5D,0B5F,0B60,0B61,0B62,0B63,0B66,0B67,0B6^,0B7_,0B82,0B83,0B85,0B86,0B87,0B88,0B89,0B8A,0B8E,0B8F,0B90,0B92,0B93,0B94,0B95,0B99,0B9A,0B9C,0B9E,0B9F,0BA3,0BA4,0BA8,0BA9,0BAA,0BAE,0BAF,0BB_,0BB8,0BB9,0BBE,0BBF,0BC0,0BC1,0BC2,0BC6,0BC7,0BC8,0BCA,0BCB,0BCC,0BCD,0BD0,0BD7,0BE6,0BE7,0BE^,0BF_,0BF8,0BF9,0BFA,0C0_,0C08,0C09,0C0A,0C0B,0C0C,0C0E,0C0F,0C10,0C12,0C13,0C14,0C15,0C16,0C17,0C1^,0C2_,0C28,0C2A,0C2B,0C2C,0C2D,0C2E,0C2F,0C3_,0C38,0C39,0C3C,0C3D,0C3E,0C3F,0C40,0C41,0C42,0C43,0C44,0C46,0C47,0C48,0C4A,0C4B,0C4C,0C4D,0C55,0C56,0C58,0C59,0C5A,0C5D,0C60,0C61,0C62,0C63,0C66,0C67,0C6^,0C77,0C7^,0C8_,0C88,0C89,0C8A,0C8B,0C8C,0C8E,0C8F,0C90,0C92,0C93,0C94,0C95,0C96,0C97,0C9^,0CA_,0CA8,0CAA,0CAB,0CAC,0CAD,0CAE,0CAF,0CB0,0CB1,0CB2,0CB3,0CB5,0CB6,0CB7,0CB8,0CB9,0CBC,0CBD,0CBE,0CBF,0CC0,0CC1,0CC2,0CC3,0CC4,0CC6,0CC7,0CC8,0CCA,0CCB,0CCC,0CCD,0CD5,0CD6,0CDD,0CDE,0CE0,0CE1,0CE2,0CE3,0CE6,0CE7,0CE^,0CF1,0CF2,0D0_,0D08,0D09,0D0A,0D0B,0D0C,0D0E,0D0F,0D10,0D12,0D13,0D14,0D15,0D16,0D17,0D1^,0D2*,0D3*,0D40,0D41,0D42,0D43,0D44,0D46,0D47,0D48,0D4A,0D4B,0D4C,0D4D,0D4E,0D4F,0D54,0D55,0D56,0D57,0D5^,0D60,0D61,0D62,0D63,0D66,0D67,0D6^,0D7*,0D81,0D82,0D83,0D85,0D86,0D87,0D8^,0D90,0D91,0D92,0D93,0D94,0D95,0D96,0D9A,0D9B,0D9C,0D9D,0D9E,0D9F,0DA*,0DB0,0DB1,0DB3,0DB4,0DB5,0DB6,0DB7,0DB8,0DB9,0DBA,0DBB,0DBD,0DC0,0DC1,0DC2,0DC3,0DC4,0DC5,0DC6,0DCA,0DCF,0DD0,0DD1,0DD2,0DD3,0DD4,0DD6,0DD^,0DE6,0DE7,0DE^,0DF2,0DF3,0DF4,0E01,0E02,0E03,0E04,0E05,0E06,0E07,0E0^,0E1*,0E2*,0E3_,0E38,0E39,0E3A,0E3F,0E4*,0E5_,0E58,0E59,0E5A,0E5B,0E81,0E82,0E84,0E86,0E87,0E88,0E89,0E8A,0E8C,0E8D,0E8E,0E8F,0E9*,0EA0,0EA1,0EA2,0EA3,0EA5,0EA7,0EA^,0EB_,0EB8,0EB9,0EBA,0EBB,0EBC,0EBD,0EC0,0EC1,0EC2,0EC3,0EC4,0EC6,0EC8,0EC9,0ECA,0ECB,0ECC,0ECD,0ED_,0ED8,0ED9,0EDC,0EDD,0EDE,0EDF,0F0*,0F1*,0F2*,0F3*,0F4_,0F49,0F4A,0F4B,0F4C,0F4D,0F4E,0F4F,0F5*,0F6_,0F68,0F69,0F6A,0F6B,0F6C,0F71,0F72,0F73,0F74,0F75,0F76,0F77,0F7^,0F8*,0F9_,0F99,0F9A,0F9B,0F9C,0F9D,0F9E,0F9F,0FA*,0FB_,0FB8,0FB9,0FBA,0FBB,0FBC,0FBE,0FBF,0FC_,0FC8,0FC9,0FCA,0FCB,0FCC,0FCE,0FCF,0FD_,0FD8,0FD9,0FDA,100*,101*,102*,103*,104*,105*,106*,107*,108*,109*,10A*,10B*,10C0,10C1,10C2,10C3,10C4,10C5,10C7,10CD,10D*,10E*,10F*,110*,111*,112*,113*,114*,115*,116*,117*,118*,119*,11A*,11B*,11C*,11D*,11E*,11F*,120*,121*,122*,123*,124_,1248,124A,124B,124C,124D,1250,1251,1252,1253,1254,1255,1256,1258,125A,125B,125C,125D,126*,127*,128_,1288,128A,128B,128C,128D,129*,12A*,12B0,12B2,12B3,12B4,12B5,12B8,12B9,12BA,12BB,12BC,12BD,12BE,12C0,12C2,12C3,12C4,12C5,12C^,12D0,12D1,12D2,12D3,12D4,12D5,12D6,12D^,12E*,12F*,130*,1310,1312,1313,1314,1315,131^,132*,133*,134*,135_,1358,1359,135A,135D,135E,135F,136*,137_,1378,1379,137A,137B,137C,138*,139_,1398,1399,13A*,13B*,13C*,13D*,13E*,13F0,13F1,13F2,13F3,13F4,13F5,13F8,13F9,13FA,13FB,13FC,13FD,140*,141*,142*,143*,144*,145*,146*,147*,148*,149*,14A*,14B*,14C*,14D*,14E*,14F*,150*,151*,152*,153*,154*,155*,156*,157*,158*,159*,15A*,15B*,15C*,15D*,15E*,15F*,160*,161*,162*,163*,164*,165*,166*,167*,168*,169_,1698,1699,169A,169B,169C,16A*,16B*,16C*,16D*,16E*,16F_,16F8,170*,1710,1711,1712,1713,1714,1715,171F,172*,1730,1731,1732,1733,1734,1735,1736,174*,1750,1751,1752,1753,176_,1768,1769,176A,176B,176C,176E,176F,1770,1772,1773,178*,179*,17A*,17B*,17C*,17D_,17D8,17D9,17DA,17DB,17DC,17DD,17E_,17E8,17E9,17F_,17F8,17F9,180*,181_,1818,1819,182*,183*,184*,185*,186*,187_,1878,188*,189*,18A_,18A8,18A9,18AA,18B*,18C*,18D*,18E*,18F0,18F1,18F2,18F3,18F4,18F5,190*,191_,1918,1919,191A,191B,191C,191D,191E,192_,1928,1929,192A,192B,193_,1938,1939,193A,193B,1940,1944,1945,1946,1947,194^,195*,196_,1968,1969,196A,196B,196C,196D,1970,1971,1972,1973,1974,198*,199*,19A_,19A8,19A9,19AA,19AB,19B*,19C_,19C8,19C9,19D_,19D8,19D9,19DA,19DE,19DF,19E*,19F*,1A0*,1A1_,1A18,1A19,1A1A,1A1B,1A1E,1A1F,1A2*,1A3*,1A4*,1A5_,1A58,1A59,1A5A,1A5B,1A5C,1A5D,1A5E,1A6*,1A7_,1A78,1A79,1A7A,1A7B,1A7C,1A7F,1A8_,1A88,1A89,1A9_,1A98,1A99,1AA_,1AA8,1AA9,1AAA,1AAB,1AAC,1AAD,1AB*,1AC_,1AC8,1AC9,1ACA,1ACB,1ACC,1ACD,1ACE,1B0*,1B1*,1B2*,1B3*,1B4_,1B48,1B49,1B4A,1B4B,1B4C,1B5*,1B6*,1B7_,1B78,1B79,1B7A,1B7B,1B7C,1B7D,1B7E,1B8*,1B9*,1BA*,1BB*,1BC*,1BD*,1BE*,1BF0,1BF1,1BF2,1BF3,1BFC,1BFD,1BFE,1BFF,1C0*,1C1*,1C2*,1C3_,1C3B,1C3C,1C3D,1C3E,1C3F,1C4_,1C48,1C49,1C4D,1C4E,1C4F,1C5*,1C6*,1C7*,1C8_,1C88,1C9*,1CA*,1CB_,1CB8,1CB9,1CBA,1CBD,1CBE,1CBF,1CC_,1CD*,1CE*,1CF_,1CF8,1CF9,1CFA,1D0*,1D1*,1D2*,1D3*,1D4*,1D5*,1D6*,1D7*,1D8*,1D9*,1DA*,1DB*,1DC*,1DD*,1DE*,1DF*,1E0*,1E1*,1E2*,1E3*,1E4*,1E5*,1E6*,1E7*,1E8*,1E9*,1EA*,1EB*,1EC*,1ED*,1EE*,1EF*,1F0*,1F10,1F11,1F12,1F13,1F14,1F15,1F18,1F19,1F1A,1F1B,1F1C,1F1D,1F2*,1F3*,1F40,1F41,1F42,1F43,1F44,1F45,1F48,1F49,1F4A,1F4B,1F4C,1F4D,1F5_,1F59,1F5B,1F5D,1F5F,1F6*,1F7_,1F78,1F79,1F7A,1F7B,1F7C,1F7D,1F8*,1F9*,1FA*,1FB0,1FB1,1FB2,1FB3,1FB4,1FB6,1FB7,1FB^,1FC0,1FC1,1FC2,1FC3,1FC4,1FC6,1FC7,1FC^,1FD0,1FD1,1FD2,1FD3,1FD6,1FD7,1FD8,1FD9,1FDA,1FDB,1FDD,1FDE,1FDF,1FE*,1FF2,1FF3,1FF4,1FF6,1FF7,1FF8,1FF9,1FFA,1FFB,1FFC,1FFD,1FFE,200*,201*,202*,203*,204*,205*,2060,2061,2062,2063,2064,2066,2067,206^,2070,2071,2074,2075,2076,2077,207^,208_,2088,2089,208A,208B,208C,208D,208E,209_,2098,2099,209A,209B,209C,20A*,20B*,20C0,20D*,20E*,20F0,210*,211*,212*,213*,214*,215*,216*,217*,218_,2188,2189,218A,218B,219*,21A*,21B*,21C*,21D*,21E*,21F*,220*,221*,222*,223*,224*,225*,226*,227*,228*,229*,22A*,22B*,22C*,22D*,22E*,22F*,230*,231*,232*,233*,234*,235*,236*,237*,238*,239*,23A*,23B*,23C*,23D*,23E*,23F*,240*,241*,2420,2421,2422,2423,2424,2425,2426,244_,2448,2449,244A,246*,247*,248*,249*,24A*,24B*,24C*,24D*,24E*,24F*,250*,251*,252*,253*,254*,255*,256*,257*,258*,259*,25A*,25B*,25C*,25D*,25E*,25F*,260*,261*,262*,263*,264*,265*,266*,267*,268*,269*,26A*,26B*,26C*,26D*,26E*,26F*,270*,271*,272*,273*,274*,275*,276*,277*,278*,279*,27A*,27B*,27C*,27D*,27E*,27F*,280*,281*,282*,283*,284*,285*,286*,287*,288*,289*,28A*,28B*,28C*,28D*,28E*,28F*,290*,291*,292*,293*,294*,295*,296*,297*,298*,299*,29A*,29B*,29C*,29D*,29E*,29F*,2A0*,2A1*,2A2*,2A3*,2A4*,2A5*,2A6*,2A7*,2A8*,2A9*,2AA*,2AB*,2AC*,2AD*,2AE*,2AF*,2B0*,2B1*,2B2*,2B3*,2B4*,2B5*,2B6*,2B70,2B71,2B72,2B73,2B76,2B77,2B7^,2B8*,2B90,2B91,2B92,2B93,2B94,2B95,2B97,2B9^,2BA*,2BB*,2BC*,2BD*,2BE*,2BF*,2C0*,2C1*,2C2*,2C3*,2C4*,2C5*,2C6*,2C7*,2C8*,2C9*,2CA*,2CB*,2CC*,2CD*,2CE*,2CF0,2CF1,2CF2,2CF3,2CF9,2CFA,2CFB,2CFC,2CFD,2CFE,2CFF,2D0*,2D1*,2D20,2D21,2D22,2D23,2D24,2D25,2D27,2D2D,2D3*,2D4*,2D5*,2D6_,2D6F,2D70,2D7F,2D8*,2D90,2D91,2D92,2D93,2D94,2D95,2D96,2DA0,2DA1,2DA2,2DA3,2DA4,2DA5,2DA6,2DA8,2DA9,2DAA,2DAB,2DAC,2DAD,2DAE,2DB0,2DB1,2DB2,2DB3,2DB4,2DB5,2DB6,2DB8,2DB9,2DBA,2DBB,2DBC,2DBD,2DBE,2DC0,2DC1,2DC2,2DC3,2DC4,2DC5,2DC6,2DC8,2DC9,2DCA,2DCB,2DCC,2DCD,2DCE,2DD0,2DD1,2DD2,2DD3,2DD4,2DD5,2DD6,2DD8,2DD9,2DDA,2DDB,2DDC,2DDD,2DDE,2DE*,2DF*,2E0*,2E1*,2E2*,2E3*,2E4*,2E5_,2E58,2E59,2E5A,2E5B,2E5C,2E5D,2E8*,2E9_,2E98,2E99,2E9B,2E9C,2E9D,2E9E,2E9F,2EA*,2EB*,2EC*,2ED*,2EE*,2EF0,2EF1,2EF2,2EF3,2F0*,2F1*,2F2*,2F3*,2F4*,2F5*,2F6*,2F7*,2F8*,2F9*,2FA*,2FB*,2FC*,2FD0,2FD1,2FD2,2FD3,2FD4,2FD5,2FF_,2FF8,2FF9,2FFA,2FFB,300*,301*,302*,303*,3041,3042,3043,3044,3045,3046,3047,304^,305*,306*,307*,308*,3090,3091,3092,3093,3094,3095,3096,3099,309A,309B,309C,309D,309E,309F,30A*,30B*,30C*,30D*,30E*,30F*,3105,3106,3107,310^,311*,312*,3131,3132,3133,3134,3135,3136,3137,313^,314*,315*,316*,317*,318_,3188,3189,318A,318B,318C,318D,318E,319*,31A*,31B*,31C*,31D*,31E0,31E1,31E2,31E3,31F*,320*,321_,3218,3219,321A,321B,321C,321D,321E,322*,323*,324*,325*,326*,327*,328*,329*,32A*,32B*,32C*,32D*,32E*,32F*,330*,331*,332*,333*,334*,335*,336*,337*,338*,339*,33A*,33B*,33C*,33D*,33E*,33F*,340*,341*,342*,343*,344*,345*,346*,347*,348*,349*,34A*,34B*,34C*,34D*,34E*,34F*,350*,351*,352*,353*,354*,355*,356*,357*,358*,359*,35A*,35B*,35C*,35D*,35E*,35F*,360*,361*,362*,363*,364*,365*,366*,367*,368*,369*,36A*,36B*,36C*,36D*,36E*,36F*,370*,371*,372*,373*,374*,375*,376*,377*,378*,379*,37A*,37B*,37C*,37D*,37E*,37F*,380*,381*,382*,383*,384*,385*,386*,387*,388*,389*,38A*,38B*,38C*,38D*,38E*,38F*,390*,391*,392*,393*,394*,395*,396*,397*,398*,399*,39A*,39B*,39C*,39D*,39E*,39F*,3A0*,3A1*,3A2*,3A3*,3A4*,3A5*,3A6*,3A7*,3A8*,3A9*,3AA*,3AB*,3AC*,3AD*,3AE*,3AF*,3B0*,3B1*,3B2*,3B3*,3B4*,3B5*,3B6*,3B7*,3B8*,3B9*,3BA*,3BB*,3BC*,3BD*,3BE*,3BF*,3C0*,3C1*,3C2*,3C3*,3C4*,3C5*,3C6*,3C7*,3C8*,3C9*,3CA*,3CB*,3CC*,3CD*,3CE*,3CF*,3D0*,3D1*,3D2*,3D3*,3D4*,3D5*,3D6*,3D7*,3D8*,3D9*,3DA*,3DB*,3DC*,3DD*,3DE*,3DF*,3E0*,3E1*,3E2*,3E3*,3E4*,3E5*,3E6*,3E7*,3E8*,3E9*,3EA*,3EB*,3EC*,3ED*,3EE*,3EF*,3F0*,3F1*,3F2*,3F3*,3F4*,3F5*,3F6*,3F7*,3F8*,3F9*,3FA*,3FB*,3FC*,3FD*,3FE*,3FF*,4000," \ No newline at end of file diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index c03b5b1979..1044969e5a 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -93,7 +93,7 @@ public void None_Float(ExpressionTestCase testCase) } #endif -#if true +#if falsee // Runs only tests that have asked for RegEx setup. This test run will compare the regular expression results between // .NET (used in the C# interpreter), NodeJS with JavaScript (used in Canvas), and PCRE2 (used in Excel). // This is not run all the time. It requires Node to be installed and PCRE2 built as a shared library DLL and on the path. From 46f8221ff9986e3a3b9a01e36b167a2224ef6e2b Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Wed, 6 Nov 2024 11:39:15 -0800 Subject: [PATCH 55/61] Updates --- .../FileExpressionEvaluationTests.cs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index 1044969e5a..55484c12f7 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -93,7 +93,7 @@ public void None_Float(ExpressionTestCase testCase) } #endif -#if falsee +#if false // Runs only tests that have asked for RegEx setup. This test run will compare the regular expression results between // .NET (used in the C# interpreter), NodeJS with JavaScript (used in Canvas), and PCRE2 (used in Excel). // This is not run all the time. It requires Node to be installed and PCRE2 built as a shared library DLL and on the path. @@ -168,12 +168,12 @@ private static bool ShouldSkipDotNetVersion(ExpressionTestCase testCase, string return false; } -#if false +#if true // Helper to run a single .txt deefee [Fact] public void RunOne() { - var path = @"d:\repos\regex-min-7\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\match_pcre2.txt"; + var path = @"c:\temp\out.txt"; var line = 0; var runner = new InterpreterRunner(); @@ -186,8 +186,7 @@ public void RunOne() { testRunner.Tests.RemoveAll(x => x.SourceLine != line); } - - ExpressionEvaluationTests.RegExCompareEnabled = true; + var result = testRunner.RunTests(); if (result.Fail > 0) { @@ -198,6 +197,13 @@ public void RunOne() Console.WriteLine(result.Output); } } + + [Fact] + public void RunOneMatchCompare() + { + ExpressionEvaluationTests.RegExCompareEnabled = true; + RunOne(); + } #endif // Run cases in MutationScripts From c06bb988aadd00e1d3c41e4609cecc7c886957cc Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Wed, 6 Nov 2024 22:57:44 -0800 Subject: [PATCH 56/61] Updates --- .../Microsoft.PowerFx.Core/Localization/Strings.cs | 1 + .../Microsoft.PowerFx.Core/Texl/Builtins/Match.cs | 13 +++++++++++-- src/strings/PowerFxResources.en-US.resx | 4 ++++ .../Helpers/LibraryRegEx_Compare.cs | 4 ++-- .../Helpers/LibraryRegEx_NodeJS.cs | 2 +- 5 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs index 0a39152114..152fa73d8f 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs @@ -766,6 +766,7 @@ internal static class TexlStrings public static ErrorResourceKey ErrInvalidRegExOpenParenInComment = new ErrorResourceKey("ErrInvalidRegExOpenParenInComment"); public static ErrorResourceKey ErrInvalidRegExLiteralHyphenInCharacterClass = new ErrorResourceKey("ErrInvalidRegExLiteralHyphenInCharacterClass"); public static ErrorResourceKey ErrInvalidRegExBackRefInCharacterClass = new ErrorResourceKey("ErrInvalidRegExBackRefInCharacterClass"); + public static ErrorResourceKey ErrInvalidRegExUnescapedCharInCharacterClass = new ErrorResourceKey("ErrInvalidRegExUnescapedCharInCharacterClass"); public static ErrorResourceKey ErrInvalidRegExUnescapedParensInCharacterClass = new ErrorResourceKey("ErrInvalidRegExUnescapedParensInCharacterClass"); public static ErrorResourceKey ErrInvalidRegExBadUnicodeCategory = new ErrorResourceKey("ErrInvalidRegExBadUnicodeCategory"); diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index ad5a52051b..e2e0923353 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -204,7 +204,7 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter \\(?[pP])\{(?[\w=:-]+)\} | # Unicode chaeracter classes, extra characters here for a better error message (?\\[DWS]) | (?\\[bB]) | # acceptable outside a character class, includes negative classes until we have character class subtraction, include \P for future MatchOptions.LocaleAware - (?\\[\-]) | # needed for /v compatibility with ECMAScript + (?\\[\-\|]) | # needed for /v compatibility with ECMAScript (?\\.) | # all other escaped characters are invalid and reserved for future use # leading (?<, named captures @@ -233,7 +233,8 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter (?{\d+(,\d*)?}[\+|\*]) | # possessive and useless quantifiers (?[{}]) | # more constrained, blocks {,3} and Java/Rust semantics that does not treat this as a literal - (?\[\-|\-\]) | # literal not allowed within character class, needs to be escaped (ECMAScript v) + (?\[\-|\-\]) | # literal not allowed within character class, needs to be escaped (ECMAScript v) + (?\|) | # open and close regions (?\() | @@ -522,6 +523,14 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter { openPoundComment = freeSpacing; } + } + else if (token.Groups["badCharacterClass"].Success) + { + if (openCharacterClass) + { + errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExUnescapedCharInCharacterClass, token.Value); + return false; + } } else if (token.Groups["badBackRefNum"].Success) { diff --git a/src/strings/PowerFxResources.en-US.resx b/src/strings/PowerFxResources.en-US.resx index d88407f40b..5b09f8fc83 100644 --- a/src/strings/PowerFxResources.en-US.resx +++ b/src/strings/PowerFxResources.en-US.resx @@ -4647,6 +4647,10 @@ Invalid regular expression: Literal parenthesis need to be escaped with a backslash when used in a character class. Error message indicating that the regular expression has an unescaped paren within a character class. + + Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class. + Error message indicating that the regular expression has an unescaped character within a character class. + Regular expressions must be constant values. Error Message. diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_Compare.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_Compare.cs index 06aec596d5..35c622a60d 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_Compare.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_Compare.cs @@ -24,12 +24,12 @@ public static void EnableRegExFunctions(PowerFxConfig config, TimeSpan regExTime foreach (KeyValuePair func in RegexFunctions(regExTimeout, regexTypeCache, includeNode, includePCRE2)) { - if (config.SymbolTable.Functions.AnyWithName(func.Key.Name)) + if (config.ComposedConfigSymbols.Functions.AnyWithName(func.Key.Name)) { throw new InvalidOperationException("Cannot add RegEx functions more than once."); } - config.SymbolTable.AddFunction(func.Key); + config.InternalConfigSymbols.AddFunction(func.Key); config.AdditionalFunctions.Add(func.Key, func.Value); } } diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs index 616d80d656..ff64c95803 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs @@ -38,7 +38,7 @@ public class RegEx_NodeJS private static void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine) { outputSB.Append(outLine.Data); - if (outLine.Data.Contains("%%end%%")) + if (outLine.Data.Contains("%%end%%") || outLine.Data.Contains("SyntaxError")) { output = outputSB.ToString(); error = errorSB.ToString(); From 4162e1fa85c9d734d6271d842747d449a297f4ca Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Thu, 7 Nov 2024 08:45:38 -0800 Subject: [PATCH 57/61] update --- .../Helpers/LibraryRegEx_NodeJS.cs | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs index ff64c95803..41f3c41266 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/Helpers/LibraryRegEx_NodeJS.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Runtime.Serialization; @@ -29,30 +30,22 @@ public class RegEx_NodeJS private static Process node; private static readonly Mutex NodeMutex = new Mutex(); // protect concurrent access to the node process - private static StringBuilder outputSB; - private static StringBuilder errorSB; private static TaskCompletionSource readTask = null; private static string output; private static string error; private static void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine) - { - outputSB.Append(outLine.Data); - if (outLine.Data.Contains("%%end%%") || outLine.Data.Contains("SyntaxError")) + { + output = output + outLine.Data; + if (outLine.Data.Contains("%%end%%")) { - output = outputSB.ToString(); - error = errorSB.ToString(); readTask.TrySetResult(true); } } private static void ErrorHandler(object sendingProcess, DataReceivedEventArgs outLine) - { - errorSB.Append(outLine.Data); - - output = outputSB.ToString(); - error = errorSB.ToString(); - + { + error = error + outLine.Data; readTask.TrySetResult(true); } @@ -79,8 +72,8 @@ internal static async Task MatchAsync(string subject, string patte { var js = new StringBuilder(); - outputSB = new StringBuilder(); - errorSB = new StringBuilder(); + output = string.Empty; + error = string.Empty; readTask = new TaskCompletionSource(); try @@ -159,7 +152,14 @@ function MatchTest( subject, pattern, flags, matchAll ) await node.StandardInput.FlushAsync(); - await readTask.Task; + var complete = await Task.WhenAny(readTask.Task, Task.Delay(TimeSpan.FromSeconds(3))); + + if (complete != readTask.Task) + { + error = "NodeJS Timeout"; + node.Close(); + node = null; + } if (error.Length > 0) { From 03f5190d987b5f8e62285f12938caf69700e486f Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Sun, 10 Nov 2024 12:21:44 -0800 Subject: [PATCH 58/61] Updates --- .../Microsoft.PowerFx.Core/Texl/Builtins/Match.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index e2e0923353..e54e542c7f 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -234,7 +234,10 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter (?[{}]) | # more constrained, blocks {,3} and Java/Rust semantics that does not treat this as a literal (?\[\-|\-\]) | # literal not allowed within character class, needs to be escaped (ECMAScript v) - (?\|) | + (?\{|\}|\/|\||\\| # does not include \- as that is needed for ranges + \*|\+|\.|\#|\^|\$|\?| # Power Fx specific, block all special characters + &&|!!|\#\#|\$\$|%%|\*\*|\+\+|,,|\.\.|::|;;| + <<|==|>>|\?\?|@@|``|~~|\^\^\^|_\^\^|\-\-) | # ECMAScript v restrictions, including set subtraction double hyphen # open and close regions (?\() | @@ -524,7 +527,7 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter openPoundComment = freeSpacing; } } - else if (token.Groups["badCharacterClass"].Success) + else if (token.Groups["badInCharacterClass"].Success) { if (openCharacterClass) { From eae88e8688eb2227fdb3f1e97afbdb3b3334101b Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Wed, 13 Nov 2024 07:42:51 -0800 Subject: [PATCH 59/61] Updates --- .../Localization/Strings.cs | 1 + .../Texl/Builtins/Match.cs | 455 +++++++++--------- src/strings/PowerFxResources.en-US.resx | 20 +- .../ExpressionTestCases/Match_Limited.txt | 238 +++++++-- .../ExpressionTestHelpers/BaseRunner.cs | 3 +- .../FileExpressionEvaluationTests.cs | 4 +- 6 files changed, 437 insertions(+), 284 deletions(-) diff --git a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs index 152fa73d8f..29c04859c2 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs @@ -769,6 +769,7 @@ internal static class TexlStrings public static ErrorResourceKey ErrInvalidRegExUnescapedCharInCharacterClass = new ErrorResourceKey("ErrInvalidRegExUnescapedCharInCharacterClass"); public static ErrorResourceKey ErrInvalidRegExUnescapedParensInCharacterClass = new ErrorResourceKey("ErrInvalidRegExUnescapedParensInCharacterClass"); public static ErrorResourceKey ErrInvalidRegExBadUnicodeCategory = new ErrorResourceKey("ErrInvalidRegExBadUnicodeCategory"); + public static ErrorResourceKey ErrInvalidRegExEmptyCharacterClass = new ErrorResourceKey("ErrInvalidRegExEmptyCharacterClass"); public static ErrorResourceKey ErrVariableRegEx = new ErrorResourceKey("ErrVariableRegEx"); public static ErrorResourceKey ErrVariableRegExOptions = new ErrorResourceKey("ErrVariableRegExOptions"); diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index e54e542c7f..3e98da6b4e 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics; using System.Globalization; using System.Linq; using System.Text; @@ -149,7 +150,7 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp "Cc", "Cf", // "C", "Cs", "Co", "Cn", are left out for now until we have a good scenario, as they differ between implementations - }; + }; // Limit regular expressions to common features that are supported, with consistent semantics, by both canonical .NET and XRegExp. // It is better to disallow now and bring back with customer demand or as platforms add more support. @@ -184,29 +185,39 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter // Order of alternation is important. .NET regular expressions are greedy and will match the first of these that it can. // Many subexpressions here take advantage of this, matching something that is valid, before falling through to check for something that is invalid. // - // For example, consider testing "\\(\a)". This will match . + // For example, consider testing "\\(\a)". This will match . // will report an error and stop further processing. // One might think that the "\a" could have matched , but it will match first because it is first in the RE. // One might think that the "\(" could have matched , but the double backslashes will be consumed first, which is why it is important - // to gather all the matches in a linear scan from the beginning to the end. - var tokenRE = new Regex( - @" + // to gather all the matches in a linear scan from the beginning to the end. + // + // Three regular expressions are utilized: + // - escapeRE is a regular expression fragment that is shared by the other two, included at the beginning each of the others + // - generalRE is used outside of a character class + // - characterClassRE is used inside a character class + + const string escapeRE = + @" # leading backslash, escape sequences - \\k<(?\w+)> | # named backreference - (?\\0\d*) | # \0 and octal are not accepted, amiguous and not needed (use \x instead) - \\(?\d+) | # numeric backreference, must be enabled with MatchOptions.NumberedSubMatches + \\k<(?\w+)> | # named backreference + (?\\0\d*) | # \0 and octal are not accepted, ambiguous and not needed (use \x instead) + \\(?\d+) | # numeric backreference, must be enabled with MatchOptions.NumberedSubMatches (?\\ ([dfnrstw] | # standard regex character classes, missing from .NET are aAeGzZv (no XRegExp support), other common are u{} and o [\^\$\\\.\*\+\?\(\)\[\]\{\}\|\/\#\ ] | # acceptable escaped characters with Unicode aware ECMAScript with # and space for Free Spacing c[a-zA-Z] | # Ctrl character classes x[0-9a-fA-F]{2} | # hex character, must be exactly 2 hex digits u[0-9a-fA-F]{4})) | # Unicode characters, must be exactly 4 hex digits - \\(?[pP])\{(?[\w=:-]+)\} | # Unicode chaeracter classes, extra characters here for a better error message - (?\\[DWS]) | - (?\\[bB]) | # acceptable outside a character class, includes negative classes until we have character class subtraction, include \P for future MatchOptions.LocaleAware - (?\\[\-\|]) | # needed for /v compatibility with ECMAScript - (?\\.) | # all other escaped characters are invalid and reserved for future use - + \\(?[pP])\{(?[\w=:-]+)\} | # Unicode chaeracter classes, extra characters here for a better error message + (?\\[bB]) | # acceptable outside a character class, includes negative classes until we have character class subtraction, include \P for future MatchOptions.LocaleAware + (?\\[DWS]) | + (?\\[\-%!,:;<=>@`~]) | # https://262.ecma-international.org/#prod-ClassSetReservedPunctuator, others covered with goodEscape above + (?\\.) | # all other escaped characters are invalid and reserved for future use + "; + + var generalRE = new Regex( + escapeRE + + @" # leading (?<, named captures \(\?<(?[a-zA-Z][a-zA-Z\d]*)> | # named capture group, can only be letters and numbers and must start with a letter (?\(\?(=|!|<=|\(\?\() | # .NET conditional alternations are not supported # leading (, used for other special purposes - (?\([\?\+\*]) | # everything else unsupported that could start with a (, includes atomic groups, recursion, subroutines, branch reset, and future features + (?\([\?\+\*].?) | # everything else unsupported that could start with a (, includes atomic groups, recursion, subroutines, branch reset, and future features # leading ?\*\+, quantifiers (?[\?\*\+]\??) | # greedy and lazy quantifiers @@ -231,35 +242,61 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter # leading {, limited quantifiers (?{\d+(,\d*)?}\??) | # standard limited quantifiers (?{\d+(,\d*)?}[\+|\*]) | # possessive and useless quantifiers - (?[{}]) | # more constrained, blocks {,3} and Java/Rust semantics that does not treat this as a literal - - (?\[\-|\-\]) | # literal not allowed within character class, needs to be escaped (ECMAScript v) - (?\{|\}|\/|\||\\| # does not include \- as that is needed for ranges - \*|\+|\.|\#|\^|\$|\?| # Power Fx specific, block all special characters - &&|!!|\#\#|\$\$|%%|\*\*|\+\+|,,|\.\.|::|;;| - <<|==|>>|\?\?|@@|``|~~|\^\^\^|_\^\^|\-\-) | # ECMAScript v restrictions, including set subtraction double hyphen + (?[{}]) | # more constrained, blocks {,3} and Java/Rust semantics that does not treat this as a literal + + # character class + \[(?(\\\]|\\\[|[^\]\[])+)\] | # does not accept empty character class + (?\[\]) | + (?[\[\]]) | # open and close regions (?\() | - (?\)) | - (?\[) | - (?\]) | + (?\)) | (?\#) | # used in free spacing mode (to detect start of comment), ignored otherwise (?[\r\n]) # used in free spacing mode (to detect end of comment), ignored otherwise + ", RegexOptions.IgnorePatternWhitespace | RegexOptions.ExplicitCapture); + + var characterClassRE = new Regex( + escapeRE + + @" + (?^-|-$) | # literal not allowed within character class, needs to be escaped (ECMAScript v) + (? \/ | \| | \\ | # https://262.ecma-international.org/#prod-ClassSetSyntaxCharacter + \{ | \} | \( | \) | \[ | \]) | + (? << | == | >> | :: | # reserved pairs, see https://262.ecma-international.org/#prod-ClassSetReservedDoublePunctuator + @@ | `` | ~~ | %% | && | ;; | ,, | !! | # and https://www.unicode.org/reports/tr18/#Subtraction_and_Intersection + \|\| | \#\# | \$\$ | \*\* | \+\+ | \.\. | # includes set subtraction + \?\? | \^\^ | \-\-) ", RegexOptions.IgnorePatternWhitespace | RegexOptions.ExplicitCapture); int captureNumber = 0; // last numbered capture encountered var captureStack = new Stack(); // stack of all open capture groups, including null for non capturing groups, for detecting if a named group is closed var captureNames = new List(); // list of seen named groups, does not included numbered groups or non capture groups - bool openPoundComment = false; // there is an open end-of-line pound comment, only in freeFormMode - bool openInlineComment = false; // there is an open inline comment - bool openCharacterClass = false; // are we defining a character class? - bool openCharacterClassNegative = false; - int openCharacterClassStart = -1; + bool openPoundComment = false; // there is an open end-of-line pound comment, only in freeFormMode + bool openInlineComment = false; // there is an open inline comment + + foreach (Match token in generalRE.Matches(regexPattern)) + { + void RegExError(ErrorResourceKey errKey, Match errToken = null, bool context = false) + { + if (errToken == null) + { + errToken = token; + } + + if (context) + { + const int contextLength = 8; + var tokenEnd = errToken.Index + errToken.Length; + var found = tokenEnd >= contextLength ? "..." + regexPattern.Substring(tokenEnd - contextLength, contextLength) : regexPattern.Substring(0, tokenEnd); + errors.EnsureError(regExNode, errKey, found); + } + else + { + errors.EnsureError(regExNode, errKey, errToken.Value); + } + } - foreach (Match token in tokenRE.Matches(regexPattern)) - { if (token.Groups["newline"].Success) { openPoundComment = false; @@ -267,244 +304,201 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter else if (openInlineComment && (token.Groups["closeParen"].Success || token.Groups["goodEscape"].Value == "\\)")) { openInlineComment = false; - } + } else if (!openPoundComment && !openInlineComment) - { - // ordered from most common/good to least common/bad, for fewer tests - if (token.Groups["goodEscape"].Success || token.Groups["goodQuantifiers"].Success || - token.Groups["goodLimited"].Success) - { - // all is well, nothing to do - } - else if (token.Groups["goodEscapeOutside"].Success) - { - if (openCharacterClass) - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadEscapeInsideCharacterClass, token.Index >= regexPattern.Length - 5 ? regexPattern.Substring(token.Index) : regexPattern.Substring(token.Index, 5) + "..."); - return false; - } - } - else if (token.Groups["goodEscapeInsidePositive"].Success) - { - if (openCharacterClass && openCharacterClassNegative) - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadEscapeInsideNegativeCharacterClass, token.Index >= regexPattern.Length - 5 ? regexPattern.Substring(token.Index) : regexPattern.Substring(token.Index, 5) + "..."); - return false; - } - } - else if (token.Groups["goodEscapeInside"].Success) - { - if (!openCharacterClass) - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadEscapeOutsideCharacterClass, token.Index >= regexPattern.Length - 5 ? regexPattern.Substring(token.Index) : regexPattern.Substring(token.Index, 5) + "..."); - return false; - } + { + if (token.Groups["goodEscape"].Success || token.Groups["goodQuantifiers"].Success || token.Groups["goodLimited"].Success || token.Groups["goodEscapeOutsideCC"].Success || token.Groups["goodEscapeOutsideAndInsideCCIfPositive"].Success) + { + // all is well, nothing to do + } + else if (token.Groups["characterClass"].Success) + { + bool characterClassNegative = token.Groups["characterClass"].Value[0] == '^'; + string ccString = characterClassNegative ? token.Groups["characterClass"].Value.Substring(1) : token.Groups["characterClass"].Value; + + foreach (Match ccToken in characterClassRE.Matches(ccString)) + { + void CCRegExError(ErrorResourceKey errKey) + { + RegExError(errKey, errToken: ccToken); + } + + if (ccToken.Groups["goodEscape"].Success || ccToken.Groups["goodEscapeInsideCCOnly"].Success) + { + // all good, nothing to do + } + else if (ccToken.Groups["goodEscapeOutsideAndInsideCCIfPositive"].Success) + { + if (characterClassNegative) + { + CCRegExError(TexlStrings.ErrInvalidRegExBadEscapeInsideNegativeCharacterClass); + return false; + } + } + else if (ccToken.Groups["goodUEscape"].Success) + { + if (ccToken.Groups["goodUEscape"].Value == "P" && characterClassNegative) + { + CCRegExError(TexlStrings.ErrInvalidRegExBadEscapeInsideNegativeCharacterClass); + return false; + } + + if (!UnicodeCategories.Contains(ccToken.Groups["UCategory"].Value)) + { + CCRegExError(TexlStrings.ErrInvalidRegExBadUnicodeCategory); + return false; + } + } + else if (ccToken.Groups["badEscape"].Success) + { + CCRegExError(TexlStrings.ErrInvalidRegExBadEscape); + return false; + } + else if (ccToken.Groups["goodEscapeOutsideCC"].Success || ccToken.Groups["backRefName"].Success || ccToken.Groups["backRefNumber"].Success) + { + CCRegExError(TexlStrings.ErrInvalidRegExBadEscapeInsideCharacterClass); + return false; + } + else if (ccToken.Groups["badOctal"].Success) + { + CCRegExError(TexlStrings.ErrInvalidRegExBadOctal); + return false; + } + else if (ccToken.Groups["badInCharClass"].Success) + { + CCRegExError(TexlStrings.ErrInvalidRegExUnescapedCharInCharacterClass); + return false; + } + else if (ccToken.Groups["badDoubleInCharClass"].Success) + { + CCRegExError(TexlStrings.ErrInvalidRegExRepeatInCharClass); + return false; + } + else if (ccToken.Groups["badHyphen"].Success) + { + // intentionally RegExError to get the whole character class as this is on the ends + RegExError(TexlStrings.ErrInvalidRegExLiteralHyphenInCharacterClass); + return false; + } + else + { + // This should never be hit. It is here in case one of the names checked doesn't match the RE, in which case running tests would hit this. + throw new NotImplementedException("Unknown character class regular expression match: CC = " + token.Value + ", ccToken = " + ccToken.Value); + } + } } - else if (token.Groups["goodUEscape"].Success) + else if (token.Groups["goodNamedCapture"].Success) { - if (token.Groups["goodUEscape"].Value == "P" && openCharacterClass && openCharacterClassNegative) + if (numberedCpature) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadEscapeInsideNegativeCharacterClass, token.Index >= regexPattern.Length - 5 ? regexPattern.Substring(token.Index) : regexPattern.Substring(token.Index, 5) + "..."); + RegExError(TexlStrings.ErrInvalidRegExMixingNamedAndNumberedSubMatches); return false; } - if (!UnicodeCategories.Contains(token.Groups["UCategory"].Value)) + if (captureNames.Contains(token.Groups["goodNamedCapture"].Value)) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadUnicodeCategory, token.Value); + RegExError(TexlStrings.ErrInvalidRegExBadNamedCaptureAlreadyExists); return false; } - } - else if (token.Groups["openCharClass"].Success) - { - if (openCharacterClass) - { - if (token.Index > 0 && regexPattern[token.Index - 1] == '-') - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadUnsupportedCharacterClassSubtraction, token.Index - 1 >= regexPattern.Length - 5 ? regexPattern.Substring(token.Index - 1) : regexPattern.Substring(token.Index - 1, 5) + "..."); - return false; - } - else - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadCharacterClassLiteralSquareBracket); - return false; - } - } - else - { - openCharacterClassStart = token.Index; - openCharacterClass = true; - openCharacterClassNegative = token.Index + 1 < regexPattern.Length && regexPattern[token.Index + 1] == '^'; - } - } - else if (token.Groups["closeCharClass"].Success) - { - if (openCharacterClass) - { - if (token.Index == openCharacterClassStart + 1) - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadCharacterClassLiteralSquareBracket, token.Groups["badCharacterClassEmpty"].Value); - return false; - } - - // looking for any doubled punctuaion marks in the character class, as this can be used in the future for set subtraction, intserection, union, etc. - // for example, see https://www.unicode.org/reports/tr18/#Subtraction_and_Intersection - for (int i = openCharacterClassStart; i < token.Index - 1; i++) - { - if (regexPattern[i] == regexPattern[i + 1] && "-|&~+?!@#$%^=:;<>*,.`".Contains(regexPattern[i])) - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExRepeatInCharClass, regexPattern.Substring(i, 2)); - return false; - } - } - - openCharacterClass = false; - } - else - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadSquare, token.Index >= regexPattern.Length - 5 ? regexPattern.Substring(token.Index - 1) : regexPattern.Substring(token.Index - 1, 6) + "..."); - return false; - } - } - else if (token.Groups["goodNamedCapture"].Success) - { - // parens do not need to be escaped within square brackets - if (!openCharacterClass) - { - if (numberedCpature) - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExMixingNamedAndNumberedSubMatches, token.Value); - return false; - } - - if (captureNames.Contains(token.Groups["goodNamedCapture"].Value)) - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadNamedCaptureAlreadyExists, token.Value); - return false; - } - - captureStack.Push(token.Groups["goodNamedCapture"].Value); - captureNames.Add(token.Groups["goodNamedCapture"].Value); - } + + captureStack.Push(token.Groups["goodNamedCapture"].Value); + captureNames.Add(token.Groups["goodNamedCapture"].Value); } else if (token.Groups["goodNonCapture"].Success || token.Groups["goodLookaround"].Success) { - // parens do not need to be escaped within square brackets - if (!openCharacterClass) - { - captureStack.Push(null); - } + captureStack.Push(null); } else if (token.Groups["openParen"].Success) - { - if (openCharacterClass) + { + if (numberedCpature) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExUnescapedParensInCharacterClass); - return false; + captureNumber++; + captureStack.Push(captureNumber.ToString(CultureInfo.InvariantCulture)); } else - { - if (numberedCpature) - { - captureNumber++; - captureStack.Push(captureNumber.ToString(CultureInfo.InvariantCulture)); - } - else - { - captureStack.Push(null); - } + { + captureStack.Push(null); } } else if (token.Groups["closeParen"].Success) { - if (openCharacterClass) + if (captureStack.Count == 0) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExUnescapedParensInCharacterClass); + RegExError(TexlStrings.ErrInvalidRegExUnopenedCaptureGroups, context: true); return false; } else { - if (captureStack.Count == 0) - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExUnopenedCaptureGroups); - return false; - } - else - { - captureStack.Pop(); - } + captureStack.Pop(); } } - else if (token.Groups["goodBackRefName"].Success) + else if (token.Groups["backRefName"].Success) { - var backRefName = token.Groups["goodBackRefName"].Value; + var backRefName = token.Groups["backRefName"].Value; if (numberedCpature) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExMixingNamedAndNumberedSubMatches, token.Value); - return false; - } - - if (openCharacterClass) - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBackRefInCharacterClass, token.Value); + RegExError(TexlStrings.ErrInvalidRegExMixingNamedAndNumberedSubMatches); return false; } // group isn't defined, or not defined yet if (!captureNames.Contains(backRefName)) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefNotDefined, token.Value); + RegExError(TexlStrings.ErrInvalidRegExBadBackRefNotDefined); return false; } // group is not closed and thus self referencing if (captureStack.Contains(backRefName)) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefSelfReferencing, token.Value); + RegExError(TexlStrings.ErrInvalidRegExBadBackRefSelfReferencing); return false; } } - else if (token.Groups["goodBackRefNumber"].Success) + else if (token.Groups["backRefNumber"].Success) { - var backRefNumber = Convert.ToInt32(token.Groups["goodBackRefNumber"].Value, CultureInfo.InvariantCulture); + var backRefNumber = Convert.ToInt32(token.Groups["backRefNumber"].Value, CultureInfo.InvariantCulture); if (!numberedCpature) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExNumberedSubMatchesDisabled, token.Value); - return false; - } - - if (openCharacterClass) - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBackRefInCharacterClass, token.Value); + RegExError(TexlStrings.ErrInvalidRegExNumberedSubMatchesDisabled); return false; } // back ref number has not yet been defined if (backRefNumber < 1 || backRefNumber > captureNumber) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefNotDefined, token.Value); + RegExError(TexlStrings.ErrInvalidRegExBadBackRefNotDefined); return false; } // group is not closed and thus self referencing if (captureStack.Contains(token.Groups["goodBackRefNumber"].Value)) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefSelfReferencing, token.Value); + RegExError(TexlStrings.ErrInvalidRegExBadBackRefSelfReferencing); return false; } + } + else if (token.Groups["goodUEscape"].Success) + { + if (!UnicodeCategories.Contains(token.Groups["UCategory"].Value)) + { + RegExError(TexlStrings.ErrInvalidRegExBadUnicodeCategory); + return false; + } } else if (token.Groups["goodInlineOptions"].Success) { if (Regex.IsMatch(token.Groups["goodInlineOptions"].Value, @"(?.).*\k")) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExRepeatedInlineOption, token.Value); + RegExError(TexlStrings.ErrInvalidRegExRepeatedInlineOption); return false; } if (token.Groups["goodInlineOptions"].Value.Contains("n") && numberedCpature) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExInlineOptionConflictsWithNumberedSubMatches, token.Value); + RegExError(TexlStrings.ErrInvalidRegExInlineOptionConflictsWithNumberedSubMatches); return false; } @@ -515,90 +509,81 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter } else if (token.Groups["goodInlineComment"].Success) { - if (!openCharacterClass) - { - openInlineComment = true; - } + openInlineComment = true; } else if (token.Groups["poundComment"].Success) { - if (!openCharacterClass) - { - openPoundComment = freeSpacing; - } - } - else if (token.Groups["badInCharacterClass"].Success) - { - if (openCharacterClass) - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExUnescapedCharInCharacterClass, token.Value); - return false; - } - } - else if (token.Groups["badBackRefNum"].Success) - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBackRefNumber, token.Value); - return false; + openPoundComment = freeSpacing; } else if (token.Groups["badNamedCaptureName"].Success) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadNamedCaptureName, token.Groups["badNamedCaptureName"].Value); + RegExError(TexlStrings.ErrInvalidRegExBadNamedCaptureName); return false; } else if (token.Groups["badOctal"].Success) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadOctal, token.Groups["badOctal"].Value); + RegExError(TexlStrings.ErrInvalidRegExBadOctal); return false; } else if (token.Groups["badBalancing"].Success) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadBalancing, token.Groups["badBalancing"].Value); + RegExError(TexlStrings.ErrInvalidRegExBadBalancing); return false; } else if (token.Groups["badInlineOptions"].Success) { - errors.EnsureError(regExNode, token.Groups["badInlineOptions"].Index > 0 ? TexlStrings.ErrInvalidRegExInlineOptionNotAtStart : TexlStrings.ErrInvalidRegExBadInlineOptions, token.Groups["badInlineOptions"].Value); + RegExError(token.Groups["badInlineOptions"].Index > 0 ? TexlStrings.ErrInvalidRegExInlineOptionNotAtStart : TexlStrings.ErrInvalidRegExBadInlineOptions); return false; } else if (token.Groups["badSingleQuoteNamedCapture"].Success) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadSingleQuoteNamedCapture, token.Groups["badSingleQuoteNamedCapture"].Value); + RegExError(TexlStrings.ErrInvalidRegExBadSingleQuoteNamedCapture); return false; } else if (token.Groups["badConditional"].Success) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadConditional, token.Groups["badConditional"].Value); + RegExError(TexlStrings.ErrInvalidRegExBadConditional); return false; } else if (token.Groups["badEscape"].Success) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadEscape, token.Groups["badEscape"].Value); + RegExError(TexlStrings.ErrInvalidRegExBadEscape); return false; + } + else if (token.Groups["goodEscapeInsideCCOnly"].Success) + { + RegExError(TexlStrings.ErrInvalidRegExBadEscapeOutsideCharacterClass); + return false; } else if (token.Groups["badQuantifier"].Success || token.Groups["badLimited"].Success) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadQuantifier, token.Value); + RegExError(TexlStrings.ErrInvalidRegExBadQuantifier); return false; } else if (token.Groups["badCurly"].Success) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadCurly, token.Groups["badCurly"].Value); + RegExError(TexlStrings.ErrInvalidRegExBadCurly); return false; } else if (token.Groups["badParen"].Success) { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExBadParen, token.Index >= regexPattern.Length - 5 ? regexPattern.Substring(token.Index) : regexPattern.Substring(token.Index, 5) + "..."); - return false; - } - else if (token.Groups["badHyphen"].Success) - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExLiteralHyphenInCharacterClass, token.Value); + RegExError(TexlStrings.ErrInvalidRegExBadParen, context: true); return false; + } + else if (token.Groups["badSquareBrackets"].Success) + { + RegExError(TexlStrings.ErrInvalidRegExBadSquare, context: true); + return false; + } + else if (token.Groups["badEmptyCharacterClass"].Success) + { + RegExError(TexlStrings.ErrInvalidRegExEmptyCharacterClass); + return false; } else { - // This should never be hit. Here in case one of the names checked doesn't match the RE, in which case running tests would hit this. - throw new NotImplementedException("Unknown regular expression match: " + token.Value); + // This should never be hit. It is here in case one of the names checked doesn't match the RE, in which case running tests would hit this. + throw new NotImplementedException("Unknown general regular expression match: " + token.Value); } } } @@ -615,12 +600,6 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter return false; } - if (openCharacterClass) - { - errors.EnsureError(regExNode, TexlStrings.ErrInvalidRegExUnclosedCharacterClass); - return false; - } - // may be modifed by inline options; we only care about x and N in the next stage alteredOptions = (freeSpacing ? "x" : string.Empty) + (numberedCpature ? "N" : string.Empty); diff --git a/src/strings/PowerFxResources.en-US.resx b/src/strings/PowerFxResources.en-US.resx index 5b09f8fc83..b3c749eff9 100644 --- a/src/strings/PowerFxResources.en-US.resx +++ b/src/strings/PowerFxResources.en-US.resx @@ -4520,7 +4520,7 @@ Error message indicating that the regular expression has literal curly braces. - Invalid regular expression: Literal square braces must be escaped with a backslash even in character classes, for example \[ or \], found "{0}". + Invalid regular expression: Literal square braces must be escaped with a backslash even in character classes, for example \[ or \], found at the end of "{0}". Error message indicating that the regular expression has literal square braces. @@ -4604,9 +4604,13 @@ Error message indicating that the regular expression has repeated characters in a character class definition. - Invalid regular expression: Square bracket character classes cannot be empty and cannot include unescaped literal open or close square brackets, escape with "\[" or "\]". + Invalid regular expression: Square bracket character classes cannot include unescaped literal open or close square brackets, escape with "\[" or "\]", found at the end of "{0}". Error message indicating that the regular expression is trying to define the same capture group more than once. + + Invalid regular expression: Square bracket character classes cannot be empty, found "{0}". + Error message indicating that the regular expression character class is empty. + Invalid regular expression: Balancing capture groups is not supported, found "{0}". Error message indicating that the regular expression has balancing capture groups. @@ -4628,7 +4632,7 @@ Error message indicating that the regular expression is not enabled for numbered captures. - Invalid regular expression: Character class subtraction is not supported, found "{0}". + Invalid regular expression: Character class subtraction is not supported, found at the end of "{0}". Error message indicating that the regular expression is using character class subtraction and it is not supported. @@ -4636,7 +4640,7 @@ Error message indicating that the regular expression has an open paren in an inline comment. - Invalid regular expression: Literal hyphen in character class must be escaped with backslash, found "{0}". + Invalid regular expression: Literal hyphen in character class must be escaped with backslash, escape with "\-", found in "{0}". Error message indicating that the regular expression has a hyphen in a character class. @@ -4644,13 +4648,17 @@ Error message indicating that the regular expression has a backref in a character class. - Invalid regular expression: Literal parenthesis need to be escaped with a backslash when used in a character class. + Invalid regular expression: Literal parenthesis need to be escaped with a backslash when used in a character class, found at the end of "{0}". Error message indicating that the regular expression has an unescaped paren within a character class. - Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class. + Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "{0}". Error message indicating that the regular expression has an unescaped character within a character class. + + Invalid regular expression: Illegal characters in character class, found at the end of "{0}". + Error message indicating that the regular expression has an illegal character in character class. + Regular expressions must be constant values. Error Message. diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt index 5c2c7eba14..84633c21ee 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt @@ -281,19 +281,22 @@ Errors: Error 22-36: Invalid regular expression: Conditional alternation is not // character class and literal square brackets >> Match( "a", "[]" ) -Errors: Error 12-16: Invalid regular expression: Square bracket character classes cannot be empty and cannot include unescaped literal open or close square brackets, escape with "\[" or "\]".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 12-16: Invalid regular expression: Square bracket character classes cannot be empty, found "[]".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "[", "[[]" ) -Errors: Error 12-17: Invalid regular expression: Square bracket character classes cannot be empty and cannot include unescaped literal open or close square brackets, escape with "\[" or "\]".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 12-17: Invalid regular expression: Literal square braces must be escaped with a backslash even in character classes, for example \[ or \], found at the end of "[".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "]", "[]]" ) -Errors: Error 12-17: Invalid regular expression: Square bracket character classes cannot be empty and cannot include unescaped literal open or close square brackets, escape with "\[" or "\]".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 12-17: Invalid regular expression: Square bracket character classes cannot be empty, found "[]".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "abcdef]ghijk", "[\w]\w]" ) -Errors: Error 23-32: Invalid regular expression: Literal square braces must be escaped with a backslash even in character classes, for example \[ or \], found "w]".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 23-32: Invalid regular expression: Literal square braces must be escaped with a backslash even in character classes, for example \[ or \], found at the end of "[\w]\w]".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcdef]ghijk", "asdfasdfasdfsadf[\w]\w]" ) +Errors: Error 23-48: Invalid regular expression: Literal square braces must be escaped with a backslash even in character classes, for example \[ or \], found at the end of "...f[\w]\w]".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "a]", "[a]]" ) -Errors: Error 13-19: Invalid regular expression: Literal square braces must be escaped with a backslash even in character classes, for example \[ or \], found "]]".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 13-19: Invalid regular expression: Literal square braces must be escaped with a backslash even in character classes, for example \[ or \], found at the end of "[a]]".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "abcdef]ghijk", "[\w\]\w]" ) // escaped closing square bracket {FullMatch:"a",StartMatch:1} @@ -313,12 +316,12 @@ Errors: Error 13-19: Invalid regular expression: Literal square braces must be e // character class subtraction >> Match( "k", "[a-z-[b-c]]" ) -Errors: Error 12-25: Invalid regular expression: Character class subtraction is not supported, found "-[b-c...".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 12-25: Invalid regular expression: Literal square braces must be escaped with a backslash even in character classes, for example \[ or \], found at the end of "[".|Error 0-5: The function 'Match' has some invalid arguments. // repeated characters in character class, used by intersection and future character class features, also would catch POSIX cases if wasn't already blocked by nested square brackets >> Match( "hello", "[a-z&&[k-m]]" ) -Errors: Error 16-30: Invalid regular expression: Square bracket character classes cannot be empty and cannot include unescaped literal open or close square brackets, escape with "\[" or "\]".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 16-30: Invalid regular expression: Literal square braces must be escaped with a backslash even in character classes, for example \[ or \], found at the end of "[".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "hello", "[a-z&&k-m]" ) Errors: Error 16-28: Invalid regular expression: Character appears more than once in character class, found repeated "&&".|Error 0-5: The function 'Match' has some invalid arguments. @@ -327,13 +330,13 @@ Errors: Error 16-28: Invalid regular expression: Character appears more than onc {FullMatch:"h",StartMatch:1} >> Match( "HellO", "[[:lower:]]" ) -Errors: Error 16-29: Invalid regular expression: Square bracket character classes cannot be empty and cannot include unescaped literal open or close square brackets, escape with "\[" or "\]".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 16-29: Invalid regular expression: Literal square braces must be escaped with a backslash even in character classes, for example \[ or \], found at the end of "[".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "hello", "[[:s:]]" ) -Errors: Error 16-25: Invalid regular expression: Square bracket character classes cannot be empty and cannot include unescaped literal open or close square brackets, escape with "\[" or "\]".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 16-25: Invalid regular expression: Literal square braces must be escaped with a backslash even in character classes, for example \[ or \], found at the end of "[".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "hello", "[[=x=]]" ) -Errors: Error 16-25: Invalid regular expression: Square bracket character classes cannot be empty and cannot include unescaped literal open or close square brackets, escape with "\[" or "\]".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 16-25: Invalid regular expression: Literal square braces must be escaped with a backslash even in character classes, for example \[ or \], found at the end of "[".|Error 0-5: The function 'Match' has some invalid arguments. // // ESCAPES @@ -510,34 +513,34 @@ Errors: Error 15-19: Invalid regular expression: Invalid escape code, found "\_" // negated escape class and \b can't appear in a character classes, can't easily transpile without character class subtraction or intersection in ECMAScript >> Match( "$test" & Char(8) & "test", "[\b]test" ) -Errors: Error 35-45: Invalid regular expression: Escape character not permitted within character class, found "\b]te...".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 35-45: Invalid regular expression: Escape character not permitted within character class, found "\b".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "$test" & Char(8) & "test", "[\B]test" ) -Errors: Error 35-45: Invalid regular expression: Escape character not permitted within character class, found "\B]te...".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 35-45: Invalid regular expression: Escape character not permitted within character class, found "\B".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "test123bed", "[\D]+" ) {FullMatch:"test",StartMatch:1} >> Match( "test123bed", "[^\D]+" ) -Errors: Error 21-29: Invalid regular expression: Negative escape character not permitted within negated character class, found "\D]+".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 21-29: Invalid regular expression: Negative escape character not permitted within negated character class, found "\D".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "$test" & Char(8) & "test", "[\W]test" ) {FullMatch:"$test",StartMatch:1} >> Match( "$test" & Char(8) & "test", "[^\W]test" ) -Errors: Error 35-46: Invalid regular expression: Negative escape character not permitted within negated character class, found "\W]te...".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 35-46: Invalid regular expression: Negative escape character not permitted within negated character class, found "\W".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "$test" & Char(8) & "test", "[\S]test" ) {FullMatch:"$test",StartMatch:1} >> Match( "$test" & Char(8) & "test", "[^\S]test" ) -Errors: Error 35-46: Invalid regular expression: Negative escape character not permitted within negated character class, found "\S]te...".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 35-46: Invalid regular expression: Negative escape character not permitted within negated character class, found "\S".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "foo123test456", "[\P{L}]+" ) {FullMatch:"123",StartMatch:4} >> Match( "foo123test456", "[^\P{L}]+") // would be problematic if we wanted to implement MatchOptions.LocaleAware in the future -Errors: Error 24-35: Invalid regular expression: Negative escape character not permitted within negated character class, found "\P{L}...".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 24-35: Invalid regular expression: Negative escape character not permitted within negated character class, found "\P{L}".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "$test" & Char(8) & "test", "[\w]test" ) // \w is OK Blank() @@ -585,49 +588,49 @@ Errors: Error 15-22: Invalid regular expression: Invalid escape code, found "\P" // Escape characters that are blocked >> Match( "!@#%&=-`~><';:,""", "\!" ) -Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\!".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 28-32: Invalid regular expression: Escape character not permitted outside a character class, found "\!".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "!@#%&=-`~><';:,""", "\@" ) -Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\@".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 28-32: Invalid regular expression: Escape character not permitted outside a character class, found "\@".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "!@#%&=-`~><';:,""", "\%" ) -Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\%".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 28-32: Invalid regular expression: Escape character not permitted outside a character class, found "\%".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "!@#%&=-`~><';:,""", "\&" ) -Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\&".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 28-32: Invalid regular expression: Escape character not permitted outside a character class, found "\&".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "!@#%&=-`~><';:,""", "\=" ) -Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\=".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 28-32: Invalid regular expression: Escape character not permitted outside a character class, found "\=".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "!@#%&=-`~><';:,""", "\-" ) Errors: Error 28-32: Invalid regular expression: Escape character not permitted outside a character class, found "\-".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "!@#%&=-`~><';:,""", "\`" ) -Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\`".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 28-32: Invalid regular expression: Escape character not permitted outside a character class, found "\``".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "!@#%&=-`~><';:,""", "\~" ) -Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\~".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 28-32: Invalid regular expression: Escape character not permitted outside a character class, found "\~".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "!@#%&=-`~><';:,""", "\>" ) -Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\>".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 28-32: Invalid regular expression: Escape character not permitted outside a character class, found "\>".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "!@#%&=-`~><';:,""", "\<" ) -Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\<".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 28-32: Invalid regular expression: Escape character not permitted outside a character class, found "\<".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "!@#%&=-`~><';:,""", "\'" ) -Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\'".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 28-32: Invalid regular expression: Escape character not permitted outside a character class, found "\'".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "!@#%&=-`~><';:,""", "\;" ) -Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\;".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 28-32: Invalid regular expression: Escape character not permitted outside a character class, found "\;".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "!@#%&=-`~><';:,""", "\:" ) -Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\:".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 28-32: Invalid regular expression: Escape character not permitted outside a character class, found "\:".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "!@#%&=-`~><';:,""", "\," ) -Errors: Error 28-32: Invalid regular expression: Invalid escape code, found "\,".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 28-32: Invalid regular expression: Escape character not permitted outside a character class, found "\,".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "!@#%&=-`~><';:,""", "\""" ) -Errors: Error 28-33: Invalid regular expression: Invalid escape code, found "\"".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 28-32: Invalid regular expression: Escape character not permitted outside a character class, found "\""".|Error 0-5: The function 'Match' has some invalid arguments. // // OPTIONS @@ -701,7 +704,7 @@ Errors: Error 22-29: Invalid regular expression: Inline option is incompatible w Errors: Error 22-29: Invalid regular expression: Inline options are limited to a combination of the letters [imsx], cannot disable options, and cannot be used on a subexpression, found "(?A)".|Error 0-5: The function 'Match' has some invalid arguments. >> Match ("hello world", "(?^)o") // PCRE2 -Errors: Error 22-29: Invalid regular expression: Unsupported special group, found "(?^)o".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 22-29: Invalid regular expression: Unsupported special group, found "(?^".|Error 0-5: The function 'Match' has some invalid arguments. >> Match ("hello world", "(?xx)o") // PCRE2 Errors: Error 22-30: Invalid regular expression: Repeated inline option, found "(?xx)".|Error 0-5: The function 'Match' has some invalid arguments. @@ -905,6 +908,167 @@ Errors: Error 17-25: Invalid regular expression: Invalid Unicode category name, >> Match( "1aBc2+", "\P{Cn}") Errors: Error 17-25: Invalid regular expression: Invalid Unicode category name, found "\P{Cn}".|Error 0-5: The function 'Match' has some invalid arguments. +// +// CHARACTERS LIMITED IN CHARACTER CLASS +// + +>> Match( "abcd1234", "[\d]") +{FullMatch:"1",StartMatch:5} + +>> Match( "abcd1234", "[\w]") +{FullMatch:"a",StartMatch:1} + +// Single and double characters blocked + +>> Match( "abcd1234", "[{]") +Errors: Error 19-24: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "{".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234", "[}]") +Errors: Error 19-24: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "}".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234", "[/]") +Errors: Error 19-24: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "/".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234", "[|]") +Errors: Error 19-24: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "|".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234", "[\]") +Errors: Error 19-24: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "\".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234***", "[*]") +Errors: Error 22-27: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "*".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234***", "[**]") +Errors: Error 22-28: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "*".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234+++", "[+]") +Errors: Error 22-27: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "+".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234+++", "[++]") +Errors: Error 22-28: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "+".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234", "[.]") +Errors: Error 19-24: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of ".".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234", "[..]") +Errors: Error 19-25: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of ".".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234", "[#]") +Errors: Error 19-24: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "#".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234###", "[##]") +Errors: Error 22-28: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "#".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234$", "[$]") +Errors: Error 20-25: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "$".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234$$$", "[$$]") +Errors: Error 22-28: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "$".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234???", "[?]") +Errors: Error 22-27: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "?".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234???", "[??]") +Errors: Error 22-28: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "?".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234", "[a^]") +Errors: Error 19-25: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "^".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234", "[^^]") +Errors: Error 19-25: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "^".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234", "[^^^]") +Errors: Error 19-26: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "^".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234", "[-]") +Errors: Error 19-24: Invalid regular expression: Literal hyphen in character class must be escaped with backslash, escape with "\-", found in "[-]".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234", "[--]") +Errors: Error 19-25: Invalid regular expression: Literal hyphen in character class must be escaped with backslash, escape with "\-", found in "[--]".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234", "[-a]") +Errors: Error 19-25: Invalid regular expression: Literal hyphen in character class must be escaped with backslash, escape with "\-", found in "[-a]".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234", "[a-]") +Errors: Error 19-25: Invalid regular expression: Literal hyphen in character class must be escaped with backslash, escape with "\-", found in "[a-]".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234", "[a-b]") +{FullMatch:"a",StartMatch:1} + +// Single is OK but double is not + +>> Match( "abcd1234&&&", "[&]") +{FullMatch:"&",StartMatch:9} + +>> Match( "abcd1234&&&", "[&&]") +Errors: Error 22-28: Invalid regular expression: Character appears more than once in character class, found repeated "&&".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234!!!", "[!]") +{FullMatch:"!",StartMatch:9} + +>> Match( "abcd1234!!!", "[!!]") +Errors: Error 22-28: Invalid regular expression: Character appears more than once in character class, found repeated "!!".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234%%%", "[%]") +{FullMatch:"%",StartMatch:9} + +>> Match( "abcd1234%%%", "[%%]") +Errors: Error 22-28: Invalid regular expression: Character appears more than once in character class, found repeated "%%".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234,,,", "[,]") +{FullMatch:",",StartMatch:9} + +>> Match( "abcd1234,,,", "[,,]") +Errors: Error 22-28: Invalid regular expression: Character appears more than once in character class, found repeated ",,".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234:::", "[:]") +{FullMatch:":",StartMatch:9} + +>> Match( "abcd1234:::", "[::]") +Errors: Error 22-28: Invalid regular expression: Character appears more than once in character class, found repeated "::".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234;;;", "[;]") +{FullMatch:";",StartMatch:9} + +>> Match( "abcd1234;;;", "[;;]") +Errors: Error 22-28: Invalid regular expression: Character appears more than once in character class, found repeated ";;".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234<<<", "[<]") +{FullMatch:"<",StartMatch:9} + +>> Match( "abcd1234<<<", "[<<]") +Errors: Error 22-28: Invalid regular expression: Character appears more than once in character class, found repeated "<<".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234===", "[=]") +{FullMatch:"=",StartMatch:9} + +>> Match( "abcd1234===", "[==]") +Errors: Error 22-28: Invalid regular expression: Character appears more than once in character class, found repeated "==".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234>>>", "[>]") +{FullMatch:">",StartMatch:9} + +>> Match( "abcd1234>>>", "[>>]") +Errors: Error 22-28: Invalid regular expression: Character appears more than once in character class, found repeated ">>".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234@@@@", "[@]") +{FullMatch:"@",StartMatch:9} + +>> Match( "abcd1234@@@@", "[@@]") +Errors: Error 23-29: Invalid regular expression: Character appears more than once in character class, found repeated "@@".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234````", "[`]") +{FullMatch:"`",StartMatch:9} + +>> Match( "abcd1234````", "[``]") +Errors: Error 23-29: Invalid regular expression: Character appears more than once in character class, found repeated "``".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234~~~~", "[~]") +{FullMatch:"~",StartMatch:9} + +>> Match( "abcd1234~~~~", "[~~]") +Errors: Error 23-29: Invalid regular expression: Character appears more than once in character class, found repeated "~~".|Error 0-5: The function 'Match' has some invalid arguments. + // // OTHER // @@ -912,7 +1076,7 @@ Errors: Error 17-25: Invalid regular expression: Invalid Unicode category name, // Features supported by PCRE2 >> Match( "asdf", "(*MARK)") -Errors: Error 15-24: Invalid regular expression: Unsupported special group, found "(*MAR...".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 15-24: Invalid regular expression: Unsupported special group, found "(*M".|Error 0-5: The function 'Match' has some invalid arguments. // regular expression parsing @@ -923,22 +1087,22 @@ Errors: Error 22-30: Invalid regular expression: Invalid escape code, found "\a" {FullMatch:"\1",StartMatch:5} >> IsMatch( "abc", "[-a]" ) -Errors: Error 16-22: Invalid regular expression: Literal hyphen in character class must be escaped with backslash, found "[-".|Error 0-7: The function 'IsMatch' has some invalid arguments. +Errors: Error 16-22: Invalid regular expression: Literal hyphen in character class must be escaped with backslash, escape with "\-", found in "[-a]".|Error 0-7: The function 'IsMatch' has some invalid arguments. >> IsMatch( "abc", "[a-]" ) -Errors: Error 16-22: Invalid regular expression: Literal hyphen in character class must be escaped with backslash, found "-]".|Error 0-7: The function 'IsMatch' has some invalid arguments. +Errors: Error 16-22: Invalid regular expression: Literal hyphen in character class must be escaped with backslash, escape with "\-", found in "[a-]".|Error 0-7: The function 'IsMatch' has some invalid arguments. >> IsMatch( "abc", "[a-b]+c" ) true >> IsMatch( "abc", "(a)[\1]") -Errors: Error 16-25: Invalid regular expression: Use named captures with "(?" and "\k" or enable MatchOptions.NumberedSubMatches, found "\1".|Error 0-7: The function 'IsMatch' has some invalid arguments. +Errors: Error 16-25: Invalid regular expression: Escape character not permitted within character class, found "\1".|Error 0-7: The function 'IsMatch' has some invalid arguments. >> IsMatch( "abc", "(?a)[\k]") -Errors: Error 16-32: Invalid regular expression: Backref in character class, found "\k".|Error 0-7: The function 'IsMatch' has some invalid arguments. +Errors: Error 16-32: Invalid regular expression: Escape character not permitted within character class, found "\k".|Error 0-7: The function 'IsMatch' has some invalid arguments. >> IsMatch( "abc", "[(]") -Errors: Error 16-21: Invalid regular expression: Literal parenthesis need to be escaped with a backslash when used in a character class.|Error 0-7: The function 'IsMatch' has some invalid arguments. +Errors: Error 16-21: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "(".|Error 0-7: The function 'IsMatch' has some invalid arguments. >> IsMatch( "abc()", "[\(]", MatchOptions.Contains ) true diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestHelpers/BaseRunner.cs b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestHelpers/BaseRunner.cs index 17f8c60519..79937af2a7 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestHelpers/BaseRunner.cs +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestHelpers/BaseRunner.cs @@ -213,7 +213,8 @@ public abstract class BaseRunner var expectedCompilerError = expected.StartsWith("Errors: Error") || expected.StartsWith("Errors: Warning"); // $$$ Match error message. if (expectedCompilerError) { - string[] expectedStrArr = expected.Replace("Errors: ", string.Empty).Split('|'); + // regex used to support error messages that contain a | + string[] expectedStrArr = Regex.Matches(expected.Replace("Errors: ", string.Empty), "(\".*\"|[^\\|])+").Select(exp => exp.ToString()).ToArray(); string[] actualStrArr = runResult.Errors.Select(err => err.ToString()).ToArray(); bool isValid = true; diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index 55484c12f7..72af53283a 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -169,11 +169,11 @@ private static bool ShouldSkipDotNetVersion(ExpressionTestCase testCase, string } #if true - // Helper to run a single .txt deefee + // Helper to run a single .txt deefeeee [Fact] public void RunOne() { - var path = @"c:\temp\out.txt"; + var path = @"D:\repos\regex-min-9\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\Match_Limited.txt"; var line = 0; var runner = new InterpreterRunner(); From f9f9faa28a04bf8dea1b7437e53ea327d458fd7f Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Wed, 13 Nov 2024 17:45:54 -0800 Subject: [PATCH 60/61] Update --- .../Texl/Builtins/Match.cs | 101 ++++++++++++----- .../ExpressionTestCases/Match_Limited.txt | 107 +++++++++--------- .../FileExpressionEvaluationTests.cs | 2 +- 3 files changed, 128 insertions(+), 82 deletions(-) diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index 3e98da6b4e..64157b1a26 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -151,29 +151,74 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp // "C", "Cs", "Co", "Cn", are left out for now until we have a good scenario, as they differ between implementations }; - - // Limit regular expressions to common features that are supported, with consistent semantics, by both canonical .NET and XRegExp. - // It is better to disallow now and bring back with customer demand or as platforms add more support. - // - // Features that are disallowed: - // Capture groups - // Numbered capture groups, use named capture groups instead (.NET different from XRegExp). - // Self-referncing groups, such as "(a\1)" (.NET different from XRegExp). - // Single quoted "(?'name'..." and "\k'name'" (.NET only). - // Balancing capture groups (.NET only). - // Octal character codes, use \x or \u instead (.NET different from XRegExp) - // "\o" could be added in the future, but we should avoid "\0" which causes backreference confusion. - // Inline options - // Anywhere in the expression except the beginning (.NET only). - // For subexpressions (.NET only). - // Character classes - // Character class subtraction "[a-z-[m-n]]" (.NET only). - // Conditional alternation (.NET only). - // - // Features that aren't supported by canonical .NET will be blocked automatically when the regular expression is instantiated in TryCreateReturnType. - // - // We chose to use canonical .NET instead of RegexOptions.ECMAScript because we wanted the unicode definitions for words. - // See https://learn.microsoft.com/dotnet/standard/base-types/regular-expression-options#ecmascript-matching-behavior for more details + + // Power Fx regular expressions are limited to features that can be transpiled to native .NET (C# Interpreter), ECMAScript (Canvas), or PCRE2 (Excel). + // We want the same results everywhere for Power Fx, even if the underlying implementation is different. Even with these limits in place there are some minor semantic differences but we get as close as we can. + // These tests can be run through all three engines and the results compared with by setting ExpressionEvaluationTests.RegExCompareEnabled, a PCRE2 DLL and NodeJS must be installed on the system. + // + // In short, we use the insersection of canonical .NET regular expressions and ECMAScript 2024's "v" flag for escaping rules. + // Someday when "v" is more widely avaialble, we can support more of its features such as set subtraction. + // We chose to use canonical .NET instead of RegexOptions.ECMAScript because we wanted the unicode definitions for words. See https://learn.microsoft.com/dotnet/standard/base-types/regular-expression-options#ecmascript-matching-behavior + // + // In addition, Power Fx regular expressions are opinionated and try to eliminate some of the ambiguity in the common regular expression language: + // Numbered capture groups are disabled by default, and cannot be mixed with named capture groups. + // Octal character codes are not supported, use \x or \u instead. + // Literal ^, -, [, ], {, and } must be escaped when used in a character class. + // Escaping is only supported for special characters and unknown alphanumeric escape sequences are not supported. + // Unicode characters are used throughout. + // Newlines support Windows friendly \r\n as well as \r and \n. + // + // Features that are supported: + // Literal characters. Any character except the special characters [ ] \ ^ $ . | ? * + ( ) can be inserted directly. + // Escaped special characters. \ (backslash) followed by a special character to insert it directly, includes \- when in a character class. + // Operators + // Dot (.), matches everything except [\r\n] unless MatchOptions.DotAll is used. + // Anchors, ^ and $, matches the beginning and end of the string, or of a line if MatchOptions.Multiline is used. + // Quanitfiers + // Greedy quantifiers. ? matches 0 or 1 times, + matches 1 or more times, * matches 0 or more times, {3} matches exactly 3 times, {1,} matches at least 1 time, {1,3} matches between 1 and 3 times. By default, matching is "greedy" and the match will be as large as possible. + // Lazy quantifiers. Same as the greedy quantifiers followed by ?, for example *? or {1,3}?. With the lazy modifier, the match will be as small as possible. + // Alternation. a|b matches "a" or "b". + // Character classes + // Custom character class. [abc] list of characters, [a-fA-f0-9] range of characters, [^a-z] everything but these characters. Character classes cannot be nested, subtracted, or intersected, and the same character cannot appear twice in the character class (except for a hyphen). + // Word characters and breaks. \w, \W, \b, \B, using the Unicode definition of letters [\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}\p{Pc}\p{Lm}]. + // Digit characters. \d includes the digits 0-9 and \p{Nd}, \D matches everything except characters matched by \d. + // Space characters. \s includes spacing characters [ \r\n\t\f\x0B\x85\p{Z}], \S which matches everything except characters matched by \s, \r carriage return, \n newline, \t tab, \f form feed. + // Control characters. \cA, where the control characters is [A-Za-z]. + // Hexadecimal and Unicode character codes. \x20 with two hexadecimal digits, \u2028 with four hexadecimal digits. + // Unicode character class and property. \p{Ll} matches all Unicode lowercase letters, while \P{Ll} matches everything that is not a Unicode lowercase letter. + // Capture groups + // Non capture group. (?:a), group without capturing the result as a named or numbered sub-match. + // Named group and back reference. (?chars) captures a sub-match with the name name, referenced with \k. Cannot be used if MatchOptions.NumberedSubMatches is enabled. + // Numbered group and back referencs. (a|b) captures a sub-match, referenced with \1. MatchOptions.NumberedSubMatches must be enabled. + // Lookahead and lookbehind. (?=a), (?!a), (?<=b), (?[pP])\{(?[\w=:-]+)\} | # Unicode chaeracter classes, extra characters here for a better error message (?\\[bB]) | # acceptable outside a character class, includes negative classes until we have character class subtraction, include \P for future MatchOptions.LocaleAware (?\\[DWS]) | - (?\\[\-%!,:;<=>@`~]) | # https://262.ecma-international.org/#prod-ClassSetReservedPunctuator, others covered with goodEscape above + (?\\[&\-!#%,;:<=>@`~\^]) | # https://262.ecma-international.org/#prod-ClassSetReservedPunctuator, others covered with goodEscape above (?\\.) | # all other escaped characters are invalid and reserved for future use "; @@ -245,9 +290,9 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter (?[{}]) | # more constrained, blocks {,3} and Java/Rust semantics that does not treat this as a literal # character class + (?\[\]|\[^\]) | # some implementations support empty character class, with varying semantics; we do not \[(?(\\\]|\\\[|[^\]\[])+)\] | # does not accept empty character class - (?\[\]) | - (?[\[\]]) | + (?[\[\]]) | # square brackets that are not escaped and didn't define a character class # open and close regions (?\() | @@ -259,9 +304,9 @@ private bool IsSupportedRegularExpression(TexlNode regExNode, string regexPatter var characterClassRE = new Regex( escapeRE + @" - (?^-|-$) | # literal not allowed within character class, needs to be escaped (ECMAScript v) + (?^-|-$) | # begin/end literal hyphen not allowed within character class, needs to be escaped (ECMAScript v) (? \/ | \| | \\ | # https://262.ecma-international.org/#prod-ClassSetSyntaxCharacter - \{ | \} | \( | \) | \[ | \]) | + \{ | \} | \( | \) | \[ | \] | \^) | # adding ^ for Power Fx, making it clear that the carets in [^^] have different meanings (? << | == | >> | :: | # reserved pairs, see https://262.ecma-international.org/#prod-ClassSetReservedDoublePunctuator @@ | `` | ~~ | %% | && | ;; | ,, | !! | # and https://www.unicode.org/reports/tr18/#Subtraction_and_Intersection \|\| | \#\# | \$\$ | \*\* | \+\+ | \.\. | # includes set subtraction diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt index 84633c21ee..3c13955ad2 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt @@ -1,13 +1,17 @@ #SETUP: RegEx,PowerFxV1CompatibilityRules,SupportColumnNamesAsIdentifiers -// Power Fx regular expressions are limited to features that can be transpiled to native .NET (Interpreter), ECMAScript (Canvas), or PCRE2 (Excel). -// We want the same results everywhere for Power Fx, even if the underlying implementation is different. +// Power Fx regular expressions are limited to features that can be transpiled to native .NET (C# Interpreter), ECMAScript (Canvas), or PCRE2 (Excel). +// We want the same results everywhere for Power Fx, even if the underlying implementation is different. Even with these limits in place there are some minor semantic differences but we get as close as we can. // These tests can be run through all three engines and the results compared with by setting ExpressionEvaluationTests.RegExCompareEnabled, a PCRE2 DLL and NodeJS must be installed on the system. // -// In addition, Power Fx regular expressions are opinionated and try to eliminate some of the ambiguity in regular expressions: +// In short, we use the insersection of canonical .NET regular expressions and ECMAScript 2024's "v" flag for escaping rules. +// Someday when "v" is more widely avaialble, we can support more of its features such as set subtraction. +// We chose to use canonical .NET instead of RegexOptions.ECMAScript because we wanted the unicode definitions for words. See https://learn.microsoft.com/dotnet/standard/base-types/regular-expression-options#ecmascript-matching-behavior +// +// In addition, Power Fx regular expressions are opinionated and try to eliminate some of the ambiguity in the common regular expression language: // Numbered capture groups are disabled by default, and cannot be mixed with named capture groups. -// Octal character codes are not supported. -// -, [, ], {, and } must be escaped when used in a character class. +// Octal character codes are not supported, use \x or \u instead. +// Literal ^, -, [, ], {, and } must be escaped when used in a character class. // Escaping is only supported for special characters and unknown alphanumeric escape sequences are not supported. // Unicode characters are used throughout. // Newlines support Windows friendly \r\n as well as \r and \n. @@ -47,11 +51,14 @@ // Balancing capture groups // Recursion // Character classes -// \W, \D, \P, \S are not supported inside character classes -// Use of -, [, or ] without an escape inside a character class is not supported -// Character class subraction or intersection +// \W, \D, \P, \S are not supported inside character classes if the character class is negated (starts with [^...]) +// Use of ^, -, [, or ] without an escape inside a character class is not supported +// Character class set operations, such as subraction or intersection +// Empty character classes // Inline options -// Turning options on or off, or options for a subexpression +// Turning options on or off +// Changing options later in the expression +// Setting options for a subexpression // Conditionals // Octal characters // \x{...} and \u{...} notation @@ -585,7 +592,7 @@ Errors: Error 15-22: Invalid regular expression: Invalid escape code, found "\P" >> Match("^$\.*+?()[]{}|/# ", "[\^\$\\\.\*\+\?\(\)\[\]\{\}\|\/\#\ ]+" ) {FullMatch:"^$\.*+?()[]{}|/# ",StartMatch:1} -// Escape characters that are blocked +// Escape characters that are blocked a character class >> Match( "!@#%&=-`~><';:,""", "\!" ) Errors: Error 28-32: Invalid regular expression: Escape character not permitted outside a character class, found "\!".|Error 0-5: The function 'Match' has some invalid arguments. @@ -606,7 +613,7 @@ Errors: Error 28-32: Invalid regular expression: Escape character not permitted Errors: Error 28-32: Invalid regular expression: Escape character not permitted outside a character class, found "\-".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "!@#%&=-`~><';:,""", "\`" ) -Errors: Error 28-32: Invalid regular expression: Escape character not permitted outside a character class, found "\``".|Error 0-5: The function 'Match' has some invalid arguments. +Errors: Error 28-32: Invalid regular expression: Escape character not permitted outside a character class, found "\`".|Error 0-5: The function 'Match' has some invalid arguments. >> Match( "!@#%&=-`~><';:,""", "\~" ) Errors: Error 28-32: Invalid regular expression: Escape character not permitted outside a character class, found "\~".|Error 0-5: The function 'Match' has some invalid arguments. @@ -617,9 +624,6 @@ Errors: Error 28-32: Invalid regular expression: Escape character not permitted >> Match( "!@#%&=-`~><';:,""", "\<" ) Errors: Error 28-32: Invalid regular expression: Escape character not permitted outside a character class, found "\<".|Error 0-5: The function 'Match' has some invalid arguments. ->> Match( "!@#%&=-`~><';:,""", "\'" ) -Errors: Error 28-32: Invalid regular expression: Escape character not permitted outside a character class, found "\'".|Error 0-5: The function 'Match' has some invalid arguments. - >> Match( "!@#%&=-`~><';:,""", "\;" ) Errors: Error 28-32: Invalid regular expression: Escape character not permitted outside a character class, found "\;".|Error 0-5: The function 'Match' has some invalid arguments. @@ -629,9 +633,6 @@ Errors: Error 28-32: Invalid regular expression: Escape character not permitted >> Match( "!@#%&=-`~><';:,""", "\," ) Errors: Error 28-32: Invalid regular expression: Escape character not permitted outside a character class, found "\,".|Error 0-5: The function 'Match' has some invalid arguments. ->> Match( "!@#%&=-`~><';:,""", "\""" ) -Errors: Error 28-32: Invalid regular expression: Escape character not permitted outside a character class, found "\""".|Error 0-5: The function 'Match' has some invalid arguments. - // // OPTIONS // @@ -935,42 +936,6 @@ Errors: Error 19-24: Invalid regular expression: Literal character needs to be e >> Match( "abcd1234", "[\]") Errors: Error 19-24: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "\".|Error 0-5: The function 'Match' has some invalid arguments. ->> Match( "abcd1234***", "[*]") -Errors: Error 22-27: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "*".|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "abcd1234***", "[**]") -Errors: Error 22-28: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "*".|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "abcd1234+++", "[+]") -Errors: Error 22-27: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "+".|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "abcd1234+++", "[++]") -Errors: Error 22-28: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "+".|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "abcd1234", "[.]") -Errors: Error 19-24: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of ".".|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "abcd1234", "[..]") -Errors: Error 19-25: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of ".".|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "abcd1234", "[#]") -Errors: Error 19-24: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "#".|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "abcd1234###", "[##]") -Errors: Error 22-28: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "#".|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "abcd1234$", "[$]") -Errors: Error 20-25: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "$".|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "abcd1234$$$", "[$$]") -Errors: Error 22-28: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "$".|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "abcd1234???", "[?]") -Errors: Error 22-27: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "?".|Error 0-5: The function 'Match' has some invalid arguments. - ->> Match( "abcd1234???", "[??]") -Errors: Error 22-28: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "?".|Error 0-5: The function 'Match' has some invalid arguments. - >> Match( "abcd1234", "[a^]") Errors: Error 19-25: Invalid regular expression: Literal character needs to be escaped with a backslash when used in a character class, found at the end of "^".|Error 0-5: The function 'Match' has some invalid arguments. @@ -997,6 +962,42 @@ Errors: Error 19-25: Invalid regular expression: Literal hyphen in character cla // Single is OK but double is not +>> Match( "abcd1234***", "[*]") +{FullMatch:"*",StartMatch:9} + +>> Match( "abcd1234***", "[**]") +Errors: Error 22-28: Invalid regular expression: Character appears more than once in character class, found repeated "**".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234+++", "[+]") +{FullMatch:"+",StartMatch:9} + +>> Match( "abcd1234+++", "[++]") +Errors: Error 22-28: Invalid regular expression: Character appears more than once in character class, found repeated "++".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234...", "[.]") +{FullMatch:".",StartMatch:9} + +>> Match( "abcd1234...", "[..]") +Errors: Error 22-28: Invalid regular expression: Character appears more than once in character class, found repeated "..".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234###", "[#]") +{FullMatch:"#",StartMatch:9} + +>> Match( "abcd1234###", "[##]") +Errors: Error 22-28: Invalid regular expression: Character appears more than once in character class, found repeated "##".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234$", "[$]") +{FullMatch:"$",StartMatch:9} + +>> Match( "abcd1234$$$", "[$$]") +Errors: Error 22-28: Invalid regular expression: Character appears more than once in character class, found repeated "$$".|Error 0-5: The function 'Match' has some invalid arguments. + +>> Match( "abcd1234???", "[?]") +{FullMatch:"?",StartMatch:9} + +>> Match( "abcd1234???", "[??]") +Errors: Error 22-28: Invalid regular expression: Character appears more than once in character class, found repeated "??".|Error 0-5: The function 'Match' has some invalid arguments. + >> Match( "abcd1234&&&", "[&]") {FullMatch:"&",StartMatch:9} diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index 72af53283a..e03b51f11b 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -169,7 +169,7 @@ private static bool ShouldSkipDotNetVersion(ExpressionTestCase testCase, string } #if true - // Helper to run a single .txt deefeeee + // Helper to run a single .txt deefeeeee [Fact] public void RunOne() { From 147ddc5145021c4a47412370e8393dd823be7335 Mon Sep 17 00:00:00 2001 From: Greg Lindhorst Date: Fri, 15 Nov 2024 07:15:18 -0800 Subject: [PATCH 61/61] Update --- .../Microsoft.PowerFx.Core/Texl/Builtins/Match.cs | 4 ++-- .../ExpressionTestCases/Match_Limited.txt | 4 ++-- .../FileExpressionEvaluationTests.cs | 11 +++++++---- .../PowerFxEvaluationTests.cs | 10 +++++----- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs index 64157b1a26..3c77594187 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Match.cs @@ -179,11 +179,11 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp // Lazy quantifiers. Same as the greedy quantifiers followed by ?, for example *? or {1,3}?. With the lazy modifier, the match will be as small as possible. // Alternation. a|b matches "a" or "b". // Character classes - // Custom character class. [abc] list of characters, [a-fA-f0-9] range of characters, [^a-z] everything but these characters. Character classes cannot be nested, subtracted, or intersected, and the same character cannot appear twice in the character class (except for a hyphen). + // Custom character class. [abc] list of characters, [a-fA-f0-9] range of characters, [^a-z] everything but these characters. Character classes cannot be nested, subtracted, or intersected, and the same special character cannot be repeated in the character class. // Word characters and breaks. \w, \W, \b, \B, using the Unicode definition of letters [\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}\p{Pc}\p{Lm}]. // Digit characters. \d includes the digits 0-9 and \p{Nd}, \D matches everything except characters matched by \d. // Space characters. \s includes spacing characters [ \r\n\t\f\x0B\x85\p{Z}], \S which matches everything except characters matched by \s, \r carriage return, \n newline, \t tab, \f form feed. - // Control characters. \cA, where the control characters is [A-Za-z]. + // Control characters. \cA, where the control character is [A-Za-z]. // Hexadecimal and Unicode character codes. \x20 with two hexadecimal digits, \u2028 with four hexadecimal digits. // Unicode character class and property. \p{Ll} matches all Unicode lowercase letters, while \P{Ll} matches everything that is not a Unicode lowercase letter. // Capture groups diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt index 3c13955ad2..588dd72f4e 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Match_Limited.txt @@ -27,11 +27,11 @@ // Lazy quantifiers. Same as the greedy quantifiers followed by ?, for example *? or {1,3}?. With the lazy modifier, the match will be as small as possible. // Alternation. a|b matches "a" or "b". // Character classes -// Custom character class. [abc] list of characters, [a-fA-f0-9] range of characters, [^a-z] everything but these characters. Character classes cannot be nested, subtracted, or intersected, and the same character cannot appear twice in the character class (except for a hyphen). +// Custom character class. [abc] list of characters, [a-fA-f0-9] range of characters, [^a-z] everything but these characters. Character classes cannot be nested, subtracted, or intersected, and the same special character cannot be repeated in the character class. // Word characters and breaks. \w, \W, \b, \B, using the Unicode definition of letters [\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}\p{Pc}\p{Lm}]. // Digit characters. \d includes the digits 0-9 and \p{Nd}, \D matches everything except characters matched by \d. // Space characters. \s includes spacing characters [ \r\n\t\f\x0B\x85\p{Z}], \S which matches everything except characters matched by \s, \r carriage return, \n newline, \t tab, \f form feed. -// Control characters. \cA, where the control characters is [A-Za-z]. +// Control characters. \cA, where the control character is [A-Za-z]. // Hexadecimal and Unicode character codes. \x20 with two hexadecimal digits, \u2028 with four hexadecimal digits. // Unicode character class and property. \p{Ll} matches all Unicode lowercase letters, while \P{Ll} matches everything that is not a Unicode lowercase letter. // Capture groups diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs index e03b51f11b..c161aa7fdd 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/FileExpressionEvaluationTests.cs @@ -93,7 +93,7 @@ public void None_Float(ExpressionTestCase testCase) } #endif -#if false +#if true // Runs only tests that have asked for RegEx setup. This test run will compare the regular expression results between // .NET (used in the C# interpreter), NodeJS with JavaScript (used in Canvas), and PCRE2 (used in Excel). // This is not run all the time. It requires Node to be installed and PCRE2 built as a shared library DLL and on the path. @@ -101,7 +101,8 @@ public void None_Float(ExpressionTestCase testCase) [InterpreterTheory] public void RegExCompare(ExpressionTestCase t) { - ExpressionEvaluationTests.RegExCompareEnabled = true; + ExpressionEvaluationTests.RegExCompareNode = true; + ExpressionEvaluationTests.RegExComparePCRE2 = true; // PCRE2 has scalability probleems running all the tests, not included here but is enabled with the REPL and RunOne below RunExpressionTestCase(t, Features.PowerFxV1, numberIsFloat: false, Console); } #endif @@ -173,7 +174,7 @@ private static bool ShouldSkipDotNetVersion(ExpressionTestCase testCase, string [Fact] public void RunOne() { - var path = @"D:\repos\regex-min-9\src\tests\Microsoft.PowerFx.Core.Tests.Shared\ExpressionTestCases\Match_Limited.txt"; + var path = @"c:\temp\match_unicode.txt"; var line = 0; var runner = new InterpreterRunner(); @@ -198,10 +199,12 @@ public void RunOne() } } + // Helper to run a single .txt with regular expression comparison between .NET, Node, and PCRE2 [Fact] public void RunOneMatchCompare() { - ExpressionEvaluationTests.RegExCompareEnabled = true; + ExpressionEvaluationTests.RegExCompareNode = true; + ExpressionEvaluationTests.RegExComparePCRE2 = false; RunOne(); } #endif diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/PowerFxEvaluationTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/PowerFxEvaluationTests.cs index 086d624c61..a2cef65bba 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/PowerFxEvaluationTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/PowerFxEvaluationTests.cs @@ -66,14 +66,14 @@ private static object EnableJsonFunctions(PowerFxConfig config, SymbolTable symb } // This "global" turns on regex comparison. Yes, it is a hack, but it is only used for manual testing (no automated testing). - public static bool RegExCompareEnabled = false; + public static bool RegExCompareNode = false; + public static bool RegExComparePCRE2 = false; private static object RegExSetup(PowerFxConfig config, SymbolTable symbolTable) { - if (RegExCompareEnabled) - { - // PCRE2 has scalability probleems running all the tests, not included here but is enabled with the REPL - Functions.RegEx_Compare.EnableRegExFunctions(config, new TimeSpan(0, 0, 5), includePCRE2: false); + if (RegExCompareNode || RegExComparePCRE2) + { + Functions.RegEx_Compare.EnableRegExFunctions(config, new TimeSpan(0, 0, 5), includeNode: RegExCompareNode, includePCRE2: RegExComparePCRE2); } else {