【问题标题】:Is there a case where "[^xy]" is not equal to "(?!x|y)."?是否存在“[^xy]”不等于“(?!x|y).”的情况?
【发布时间】:2013-06-27 20:31:01
【问题描述】:

我正在开发自己的 JavaScript 库以支持正则表达式的新元字符和功能,我想找到[^xy] 不等于(?!x).(或更具体地(?:(?!x|y).))的情况.

以文本为例:"abc\n"

假设我想模拟一个 Perl 正则表达式:/\A.{3}\Z/s

使用单行标志,JavaScript 正则表达式应该相当于:/^[\s\S]{3}\n*$(?!\s)/\A 变为 ^. 变为 [\s\S]\Z 变为 \n*$(?!\s)

现在,/^.{3}$/ 会失败,但/^[\s\S]{3}\n*$(?!\s)/ 会捕获“abcabc”(与 Perl 正则表达式相同)

由于\Z 不仅仅包含一个元字符,模拟[^\Z] 似乎更困难。

以文本为例:"abcabc\n"

Perl 正则表达式 /.{3}[^\Za]/g 的建议 JavaScript 正则表达式将是 .{3}(?:(?!\n*$(?!\s)|a).)/g

两者都将匹配"bcab"

所以,最后,我再次提出这个问题。在这种情况下,是否存在[^xy] 不等于(?:(?!x|y).) 的情况,也许是在一个更复杂的正则表达式中,前瞻会改变这种情况?

【问题讨论】:

  • /^[\s\S]{3}\n*$(?!\s)/.exec("abcabc\n") 不适合我,也没有按照您的建议提供abcabc
  • perl 正则表达式 /\A.{3}\Z/s 也不匹配 "abcabc\n",正如您所声称的那样......
  • 正确。我改变了一些东西,忘了编辑它们。第一个场景使用文本“abc\n”,第二个场景使用文本“abcabc\n”。我已经对主帖进行了编辑。
  • [^\Z] 不是一个东西,因为\Z 不是一个字符。

标签: javascript regex


【解决方案1】:

对于输入字符串"x\na",两个正则表达式给出不同的输出,因为. 不匹配换行符。

console.log("x\na".match(/(?:(?!x|y).)/))
["a", index: 2, input: "x↵a"]
console.log("x\na".match(/[^xy]/))
["↵", index: 1, input: "x↵a"]

如果将. 更改为[\s\S],在这种情况下输出是相同的:

console.log("x\na".match(/(?:(?!x|y)[\s\S])/))
["↵", index: 1, input: "x↵a"]

我现在想不出任何其他情况。

【讨论】:

    【解决方案2】:

    是否存在[^xy]不等于(?!x|y).的情况?

    只有你已经描述的那个:JS点不匹配换行符,需要替换为[\s\S]

    \Z 变为 \n$(?!\s)

    看起来不对。在字符串结束后 (\z/$) 将永远不会有任何内容,无论是否有空格。 Afaik,\Z 是一个零宽度断言(它不消耗换行符),应该相当于

    (?=\n*$)
    //   ^ not sure whether ? or *
    

    由于\Z 不仅仅包含一个元字符,模拟[^\Z] 似乎更困难。

    “元字符”是什么意思?这是一个零宽度断言,在字符类中没有多大意义。我猜这要么是语法错误,要么会被逐字解释(未转义)为[^Z]

    【讨论】:

    • 错字:\Z 变为 \n*$(?!\s)。在 Perl 中,\Z 等价于 \n*\z。 \z 仅在字符串末尾为真。因此,如果 \z 是 $(?!\s),则 \Z 是 \n*$(?!\s)。似乎我已经开始过度思考整个“转换”的想法。关于 [^\Z] 变成 [^Z] 你是完全正确的。我想我需要从编程中休息一下,感谢您的洞察力。 :)
    • @JoeySchooley 的重点是 \n 不包括在匹配中。所以\n 也属于前瞻(我不太确定\n 之后的星号)
    • 我在上面的评论中进行了编辑,但看起来你打败了我。感谢您调查我推理的实际问题。
    • 哦,我想我现在明白了(?=\s)$ 之后的意思——这是为了确保在多行模式下正确匹配。其实我对此不太了解(从未在JS中使用过),所以我可能错了
    【解决方案3】:

    [^xy] 将匹配 \n(?!x|y).默认不会匹配\n(因为.不匹配\n

    我不相信 javascript 有“dotall”或“single-line”修饰符,但随着每个浏览器每隔几个月推出新版本,我就迷失了方向。

    【讨论】:

      【解决方案4】:

      正如其他人所说,您应该在替换中使用[\s\S] 而不是.。否则,如果您只是通过文字字符串进行转换,则需要处理更多的事情。特别是元字符和转义序列:

      [^*)] => (?!\*|\))[\s\S]
      

      但我想你还是需要特别注意解析和编写元字符。

      不过,最棘手的可能是\b,因为它是字符类中的一个字符(退格)和外部的单词边界。因此,在替换中,您必须使用八进制或十六进制转义:

      [^a\b] => (?!a|\10)[\s\S] 
          or => (?!a|\x08)[\s\S]
      

      除此之外,两者应该总是等价的。

      【讨论】:

        【解决方案5】:

        [^xy](?:(?!x|y).) 格式不同的情况是 x 是零宽度断言,而不是像这样的实际字符:

        鉴于此示例文本:ab-yz

        正则表达式:[^\by] 示例:http://www.rubular.com/r/ERKrqyeAs9

        返回:

        [0] => a
        [1] => b
        [2] => -
        [3] => z
        

        正则表达式:(?:(?!\b|y).) 示例:http://www.rubular.com/r/V5RdyQEQo5

        返回:

        [0] => b
        [1] => z
        

        其他不等价的表达式,这些主要集中在相同的语法在字符类内部或外部具有不同含义的事实:

        • [^^y] 产生 a,b,-,z 不等于 (?:(?!^|y).) 产生 b,-,z
        • [^.y] 产生 a,b,-,z 不等于 (?:(?!.|y).) 不产生任何结果

        或者你可以在 Perl 的 unicode nugget 中试试这个:http://ideone.com/2xMfkQ

        print "\ncapture\n";
        @m = ("ss" =~ m/^(?:(?!\xDF|y).)+$/ui ); 
        print for @m;
        
        print "\nclass\n";
        @m = ("ss" =~ m/^[^\xDFy]+$/ui) ; 
        print for @m;
        

        产量:

        capture
        
        class
        1
        

        【讨论】:

        • 字符类中的单词边界对您意味着什么?
        • 这对我来说没有任何意义,但是乔伊的问题是I'd like to find a case where [^xy] is not equivalent (?:(?!x|y).)).,这是一个语法正确的表达,产生了截然不同的结果。
        • 好吧[^\by] 对我来说语法不正确。在你得到的结果中,它被解释为[^by],它相当于(?!b|y).
        • 我更新了我的答案以涵盖您的问题。我认为您对角色类如何工作的理解可能令人怀疑。
        • 否定字符类中的 \b 不会被忽略,而是匹配退格字符。对于另一个表达式(?:(?!\b|y).),当正则表达式引擎遇到单词边界时,\b 匹配为是,因为接下来是单词边界,然后由于正匹配导致负前瞻失败,这迫使点没有得到测试。但是因为点确实测试了真实字符,所以分词后的字符a-y 基本上被跳过了。最重要的是,您无法测试字符类中的单词边界,从而强制得出不同的结果。
        猜你喜欢
        • 1970-01-01
        • 2019-08-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-23
        • 1970-01-01
        • 1970-01-01
        • 2019-12-23
        相关资源
        最近更新 更多