为什么/ [\ w-+] /是有效的正则表达式,但/ [\ w-+] / u无效?

时间:2019-01-15 18:55:06

标签: javascript regex unicode character-class

如果我在Chrome控制台中输入/[\w-+]/,它将接受它。我得到了一个正则表达式对象,可以像往常一样用来测试字符串。但是,如果我输入/[\w-+]/u,它会显示VM112:1 Uncaught SyntaxError: Invalid regular expression: /[\w-+]/: Invalid character class

在Firefox中,/[\w-+]/可以正常工作,但是如果我在控制台中键入/[\w-+]/u,则它会转到下一行,就像我键入了不完整的语句一样。如果我尝试通过运行eval('/[\w-+]/u')来强制它创建正则表达式,它将告诉我SyntaxError: invalid range in character class

为什么u标志会使正则表达式无效? MDN RegExp documentationu启用了一些Unicode功能,但是我没有看到有关它如何影响字符类范围的信息。

2 个答案:

答案 0 :(得分:3)

RegExp character set中,hyphen-minus字符(您的标准键盘破折号)表示它分隔的两个字符之间的字符代码范围。例外情况是它被转义(\-)或不分隔两个字符,因为它是该类的最后一个字符或它是第一个字符(在可选的插入符之后,反转了该类)。 / p>

三个字符范围示例:一个简单示例,一个高级示例和一个错误:

  • [a-z]非常简单,因为它按照我们期望的方式工作,尽管实际上这是因为字符代码碰巧是顺序的。另一种写法是[\x61-\x7a]
  • [!-~]一点都不简单,至少直到您查看一个字符映射表并了解到!是第一个可打印的ASCII字符,而~是最后一个( ASCII”),因此这是一种表示“所有可打印的较低ASCII字符”的方式,它等效于[\x21-\x7e]
  • [A-z]的大小写已更改。您可能不喜欢这个范围接受六个非字母字符([\x41-\x7a])的事实

ASCII Table


现在,让我们检查一下/[\w-+]/u的正则表达式Regex101有一个更有用的错误:“您不能使用简写转义序列创建范围”

由于\w本身不是字符(而是字符的集合),所以必须在字面上取一个相邻的破折号,否则必须输入错误。当您使用/u flag调用它来触发fullUnicode时,将进入更严格的模式,因此会出现错误。

我在Firefox 64.0中从"foo".match(/[\w-+]/u)得到的错误是:

  

SyntaxError:字符类转义不能在正则表达式的类范围内使用

这比您得到的错误信息多,因为它实际上告诉您问题出在转义上(尽管不是为什么这是问题)。

根据ECMAScript 2015's RegExBuiltinExec() logic

  
      
  1. 如果 fullUnicode true ,则      
        
    1. e 是从 S 派生的 Input 字符列表的索引,由 matcher 匹配。假设 eUTF S 中与 Input 的元素 e 处的字符相对应的最小索引。如果 e 大于或等于 Input 的长度,则 eUTF S中的代码单位数。
    2.   
    3. e eUTF
    4.   
  2.   

这似乎是在明确建立自己的范围解析逻辑。


解决方案是逃避连字符减号或将其放在最后(或第一个):

/[\w\-+]/u/[\w+-]/u/[-\w+]/u。我个人总是把它放在最后。

答案 1 :(得分:3)

对此有一个报告:V8 implementation: does unicode property escapes behavior in character classes range differ from other classes intentionally?


我查看了V8源代码(regexp-parser.cc),发现了这一点:

if (is_class_1 || is_class_2) {
    // Either end is an escaped character class. Treat the '-' verbatim.
    if (unicode()) {
       // ES2015 21.2.2.15.1 step 1.
       return ReportError(CStrVector(kRangeInvalid));
    }

kRangeInvalid是包含Invalid character class的常量。

21.2.2.15.1 step 1.

  

如果A不包含一个字符,或者B不包含一个字符   正好一个字符,则抛出SyntaxError异常。