【问题标题】:javascript regex of a javascript stringjavascript 字符串的 javascript 正则表达式
【发布时间】:2012-12-10 11:09:11
【问题描述】:

我需要用正则表达式匹配一个javascript字符串,这是一个用单引号括起来的字符串,并且只能包含一个反斜杠单引号。

我将匹配的示例字符串如下所示:

'abcdefg'
'abc\'defg'
'abc\'de\'fg'

【问题讨论】:

  • 字符串是否可以包含除 alpha 字符和转义单引号以外的任何内容?

标签: javascript regex


【解决方案1】:

这是匹配所有有效 JavaScript 文字字符串(由单引号 ' 包围)并拒绝所有无效字符串的正则表达式。请注意,假定为 strict 模式。

/'(?:[^'\\\n\r\u2028\u2029]|\\(?:['"\\bfnrtv]|[^\n\r\u2028\u2029'"\\bfnrtvxu0-9]|0(?![0-9])|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4})|\\(?:\n|\r\n|\r(?!\n)|[\u2028\u2029]))*'/

或更短的版本:

/'(?:[^'\\\n\r\u2028\u2029]|\\(?:[^\n\rxu0-9]|0(?![0-9])|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|\n|\r\n?))*'/

上述正则表达式基于 2011 年 6 月发布的 ECMAScript 语言规范 5.1 版中指定的StringLiteral(忽略双引号版本)的定义。

用双引号 " 包围的 JavaScript 文字字符串的正则表达式几乎相同:

/"(?:[^"\\\n\r\u2028\u2029]|\\(?:[^\n\rxu0-9]|0(?![0-9])|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|\n|\r\n?))*"/

让我们剖析一下怪物(较长的版本,因为它是从语法直接翻译而来的):

  • StringLiteral(忽略双引号版本)以 ' 开头和结尾,正如在正则表达式中所见。在引号之间是SingleStringCharacter 的可选序列。这解释了* - 0 个或更多字符。

  • SingleStringCharacter 定义为:

    单字符串字符 :: SourceCharacter 但不是 ' 或 \ 或 LineTerminator 之一 \ 转义序列 行继续

    [^'\\\n\r\u2028\u2029]对应第一条规则

    \\(?:['"\\bfnrtv]|[^\n\r\u2028\u2029'"\\bfnrtvxu0-9]|0(?![0-9])|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4})对应第二条规则

    \\(?:\n|\r\n|\r(?!\n)|[\u2028\u2029])对应第三条规则

  • 让我们看看第一条规则:SourceCharacter but not one of ' or \ or LineTerminator。第一条规则处理“正常”字符。

    SourceCharacter 是任何 Unicode 单元。

    LineTerminator 是换行符 <LF>\u000A\n),回车符 <CR>\u000D\r),行分隔符 <LS>\u2028)或段落分隔符<PS> (\u2029)。

    所以我们将只使用一个否定字符类来表示这条规则:[^'\\\n\r\u2028\u2029]

  • 对于处理转义序列的第二条规则,您可以在EscapeSequence 之前看到\,因为它出现在正则表达式中。至于EscapeSequence,这是它的语法(严格模式):

    转义序列:: 字符转义序列 0 [前瞻∉ DecimalDigit] 十六进制转义序列 Unicode转义序列

    ['"\\bfnrtv]|[^\n\r\u2028\u2029'"\\bfnrtvxu0-9]CharacterEscapeSequence 的正则表达式。其实可以简化为[^\n\r\u2028\u2029xu0-9]

    第一部分为SingleEscapeCharacter,包括'"\,以及用于控制字符的bfnrt、@ 987654364@.

    第二部分是NonEscapeCharacter,也就是SourceCharacter but not one of EscapeCharacter or LineTerminatorEscapeCharacter 定义为SingleEscapeCharacterDecimalDigitx(用于十六进制转义序列)或u(用于Unicode 转义序列)。

    0(?![0-9])EscapeSequence 第二条规则的正则表达式。这是用于指定空字符\0

    x[0-9a-fA-F]{2}HexEscapeSequence 的正则表达式

    u[0-9a-fA-F]{4}UnicodeEscapeSequence 的正则表达式

  • 第三条规则处理跨越多行的字符串。再来看看LineContinuation等相关的语法:

    LineContinuation ::
            \ LineTerminatorSequence
    
    LineTerminatorSequence :: 
            <LF> 
            <CR> [lookahead ∉ <LF> ]
            <LS>
            <PS>
            <CR> <LF>
    

    \\(?:\n|\r\n|\r(?!\n)|[\u2028\u2029])对应上面的语法。

【讨论】:

  • 嗯,看起来很奇怪,因为那些正则表达式允许 var str = '''var str = """ 但它们不应该...:/
  • 好吧,经过一番挖掘,var str = ''' 是允许的,因为你的两个正则表达式没有 ^ 和 $ 来指定开始和结束。所以,我认为这个“更好”:^"(?:[^"\\\n\r\u2028\u2029]|\\(?:[^\n\rxu0-9]|0(?![0-9])|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|\n|\r\n?))*"$|^'(?:[^'\\\n\r\u2028\u2029]|\\(?:[^\n\rxu0-9]|0(?![0-9])|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|\n|\r\n?))*'$ 它同时处理 '' 和 "" 字符串 :)
  • @Leiko: ''' 不能被上面的正则表达式匹配。您可能会得到匹配,因为 '' 被视为匹配。添加或不添加锚点取决于您的用例。
【解决方案2】:

试试这个:

/'(?:[^'\\]|\\'|\\(?!'))*'/

在您的控制台中测试它:

/'(?:[^'\\]|\\'|\\(?!'))*'/.exec("'abc\\\'de\\\'fg'")

会匹配

  • 任意数量的字符是:
    • NOT ' or \(除外)
    • \'(或)
    • \(后面不跟'

如果您希望它匹配整个字符串,请使用^ 字符串开头和$ 字符串结尾标记:

/^'(?:[^'\\]|\\'|\\(?!'))*'$/

... 将匹配 'string''string\'s are awesome' 但不匹配 'string's are awesome''string's

【讨论】:

  • 很好,解决了问题。现在只有一个*,所以它不会回溯,并且匹配一个空字符串。也改为非捕获组。干杯。
【解决方案3】:

没那么难……

另外,您需要检测一些其他可能的字符序列,例如\n\r\\,在 javascript 中没有转义的换行是无效的,您必须使用\n 序列。

/^'([^\\'\n\r]|\\'|\\n|\\r|\\\\)*'$/

执行中:

var sample = ["'abcdefg'", // Valid
              "'abc\\'defg'", // Valid
              "'abc\\'de\\'fg'", // Valid
              "'abc\\'\\r\\nde\\'fg'", // Valid
              "'abc\\'\r\nde\\'fg'", // Invalid
              "'abc'def'" // Invalid
             ];
for(var i = 0; i < sample.length; i++)
    console.log(sample[i].match( /^'([^\\'\n\r]|\\'|\\n|\\r|\\\\)*'$/ ));
  1. ^ 告诉匹配器下一个条件必须匹配字符串的开头
  2. ' 将匹配 ' 分隔符
  3. (开群
  4. [^\\'\n\r] 匹配与 \' 不同的任何字符,并且不会匹配特殊的 \n\r 字符
  5. | 如果上面的条件不匹配,则测试| 的右侧
  6. \\' 将匹配 \'
  7. \\n 将匹配 \n 文字字符串
  8. |\\r 或将匹配 \r 文字字符串
  9. |\\\\ 或将匹配 \\ 文字字符串
  10. )*关闭组并允许它重复多次并允许它不存在(例如空字符串)
  11. ' 将匹配最后的 ' 分隔符
  12. $ 告诉匹配器这必须是字符串的 and

【讨论】:

  • 但是这个字符串 'abc'def' 是匹配的,尽管它是无效的
  • 还是很容易解决的,我稍微改了一下答案,只是加了^$,现在坏阵型不匹配了
  • 这会削弱 JavaScript 中可能的字符串文字。另一个问题是性能:[^\\'] 之后的* 可以被移除以减少回溯。
  • 实际上我不同意[^\\']* 会导致性能问题,因为它会匹配每个字符直到'\ 字符,所以在字符串'12345' [^\\']* 将匹配5连续的字符(5 个滴答声),而不是失败(1 个滴答声)并处理 \\',这也将失败(1 个滴答声)并留下大约 7 个滴答声。如果* 不存在,它将匹配 1 个字符(1 个刻度)处理组(1 个刻度)匹配其他字符并执行 5 次以使组离开大约 12 个刻度
  • @JoséRobertoAraújoJúnior:当输入字符串匹配失败时会出现性能问题。 jsperf.com/regex-star-in-star
【解决方案4】:

试试这个

/^'([a-z]*(?:\')?[a-z])+'$/

参见示例here

str = 'abc\'de\'fg';

match = str.match(/^([a-z\\']+)$/g);

在 Firebug 控制台中测试。使用或不使用转义字符。

【讨论】:

  • 这不是 JavaScript 正则表达式
  • 那为什么标签上写着javascriptregex
  • 我的意思是你的答案不是与 JavaScript 兼容的 RegEx,返回 null。 JavaScript 正则表达式的符号与其他语言的正则表达式略有不同。
  • Javascript 字符串不能包含数字?为什么只有[a-z]?另外,这个正则表达式允许var str = '''
  • @Leiko 我最初询问 OP,该字符串是否可以包含除 alpha 字符和反斜杠单引号以外的任何内容,但没有收到回复,因此我采用了提供的示例。此外,var str = ''' 不是有效字符串,除非您转义中间引号。
猜你喜欢
  • 2016-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-18
  • 1970-01-01
  • 1970-01-01
  • 2013-01-21
  • 1970-01-01
相关资源
最近更新 更多