2

我认为这对我的正则表达式来说是一个“不费吹灰之力”的补充,但我当然被证明是错误的......

如果字符串是符号(-、$、+、=、(、)、{、}),我当前的正则表达式返回 true:

(/^[-$+)(}{]$/).test(token);

我想在正则表达式中添加两个符号,赋值运算符 (=) 和相等运算符 (==)。我的直觉引导我做一些事情,如果存在一个带有一两个“=”的标记,则返回 true:

(/^[-$+)(}{]|(=){1,2}$/).test(token);

但如果实际令牌为(/^[-$+)(}{]|(=){1,2}$/).test("===")真,则返回。

有人可以阐明我的正则表达式缺点吗?

谢谢

4

4 回答 4

6

您遇到了一个微妙的运算符优先级问题。

/^[-$+)(}{]|(=){1,2}$/

^并且$比 绑定得更紧|,所以这相当于

/(?:^[\-$+)(}{])|(?:={1,2}$)/

而不是您可能想要的^...$包含|

/^(?:[\-$+)(}{]|={1,2})$/

或简化

/^(?:[\-$+(){}]|==?)$/

/^(?:[\-$+(){}]|==?)$/.test("===") === false;
/^(?:[\-$+(){}]|==?)$/.test("()")  === false;
/^(?:[\-$+(){}]|==?)$/.test("=")   === true;
/^(?:[\-$+(){}]|==?)$/.test("==")  === true;
/^(?:[\-$+(){}]|==?)$/.test("(")   === true;

关于捕获与非捕获括号的题外话

除非我真的想捕获内容,否则我更喜欢(?:...)这样做,因为虽然更冗长,但它对使用正则表达式的代码的微妙影响较少。(...)(?:...)

当您不打算捕获内容时使用捕获组的一些问题包括:

  1. 更改现有组的编号,因为 JS 没有命名组,
  2. 使用比我需要的效果更多的操作符会使维护者误以为我正在捕获内容是有原因的,
  3. 改变远程exec循环的行为,(这主要是 perlish 全局匹配的问题,@foo = $str =~ /(foo(bar))/g 但每隔一段时间你会看到 JS 代码做类似的事情)
  4. 改变在别处定义的(可能是可变参数的)替换函数的行为,例如
    newStr = oldStr.replace(
        regexDefinedEarlier,
        函数(var_args){
          return [].slice.call(arguments, 1, arguments.length - 2).join('');
        });
    
于 2013-04-24T16:03:24.307 回答
4

由于运算符优先级, or 分支包括 start ( ^) 和 end ( $) 零宽度匹配。要捕获 = 或 ==,您必须使用:

(/^([-$+)(}{]|={1,2})$/).test(token);
于 2013-04-24T15:59:59.467 回答
4

使用这个正则表达式:

(/^(?:[-$+)(}{]|={1,2})$/).test(token);

如果您在管道之前和之后使用锚点^(开始输入)或$(结束输入)(或用于正则表达式),则必须将 LHS 和 RHS 括|在括号中以对其进行分组,以便^$适用于括号内的整个正则表达式。

于 2013-04-24T16:00:50.067 回答
1

. . 正则表达式的问题很简单:“^”(以开头)位于“管道”的左侧,而“$”(以结尾)位于右侧。它们仅适用于正则表达式的那一部分,如下所示:

^[-$+)(}{]
OR
(=){1,2}$

. . 所以,你是说"_starts with one of these chars_ or _ends with one or two equal signs_",明白了吗?

. . 您想要的是放置一个组,以便“交替”(管道)仅适用于其内容,如下所示:

^([-$+)(}{]|={1,2})$

. . 现在你说:"the text is made of either of _this list of chars_ or _one or two equal signs_"

. Amplexos。

于 2013-04-24T16:08:03.957 回答