为什么“ asdf” .replace(/.*/ g,“ x”)==“ xx”?

2020/11/07 03:02 · javascript ·  · 0评论

我偶然发现了一个令人惊讶的事实。

console.log("asdf".replace(/.*/g, "x"));

为什么要两个替换?似乎任何没有换行符的非空字符串都将为该模式产生恰好两个替换。使用替换函数,我可以看到第一个替换是整个字符串,第二个替换是空字符串。

根据ECMA-262标准,String.prototype.replace调用RegExp.prototype [@@ replace],它表示:

11. Repeat, while done is false
  a. Let result be ? RegExpExec(rx, S).
  b. If result is null, set done to true.
  c. Else result is not null,
    i. Append result to the end of results.
    ii. If global is false, set done to true.
    iii. Else,
      1. Let matchStr be ? ToString(? Get(result, "0")).
      2. If matchStr is the empty String, then
        a. Let thisIndex be ? ToLength(? Get(rx, "lastIndex")).
        b. Let nextIndex be AdvanceStringIndex(S, thisIndex, fullUnicode).
        c. Perform ? Set(rx, "lastIndex", nextIndex, true).

这里rx/.*/gS'asdf'

见11.c.iii.2.b:

b。令nextIndex为AdvanceStringIndex(S,thisIndex,fullUnicode)。

因此,'asdf'.replace(/.*/g, 'x')实际上是:

  1. 结果(未定义),结果= [],lastIndex =0
  2. 结果= 'asdf',结果= [ 'asdf' ],lastIndex =4
  3. 结果= '',结果= [ 'asdf', '' ],lastIndex的= 4AdvanceStringIndex,lastIndex的设置为5
  4. 结果= null,结果= [ 'asdf', '' ],返回

因此,有2个匹配项。

在与yawkat进行的脱机聊天中,我们找到了一种直观的方式来了解为什么"abcd".replace(/.*/g, "x")精确地产生了两次匹配。请注意,我们尚未检查它是否完全等于ECMAScript标准所强加的语义,因此仅以经验为准。

经验法则

  • 将匹配项视为(matchStr, matchIndex)按时间顺序排列的元组列表,以指示输入字符串的哪些字符串部分和索引已被消耗掉。
  • 此列表是从正则表达式的输入字符串的左侧开始连续构建的。
  • 已经吃完的部分不再匹配
  • 替换是通过matchIndex覆盖该matchStr位置的子字符串所给定的索引进行的如果为matchStr = "",则“替换”实际上是插入。

形式上,匹配和替换的行为被描述为一个循环,如另一个答案所示

简单的例子

  1. "abcd".replace(/.*/g, "x")输出"xx"

    • 匹配列表为 [("abcd", 0), ("", 4)]

      值得注意的是,它并没有包括以下匹配一个能想到的,原因如下:

      • ("a", 0)("ab", 0):量词*是贪婪的
      • ("b", 1)("bc", 1)::由于之前的比赛("abcd", 0),琴弦"b""bc"已经被吃光
      • ("", 4), ("", 4) (即两次):索引位置4已被第一个明显的匹配所消耗
    • 因此,替换字符串"x"将恰好在这些位置替换找到的匹配字符串:在位置0替换字符串"abcd",在位置4替换""

      在这里,您可以看到替换可以真正替换以前的字符串,也可以像插入新字符串一样。

  2. "abcd".replace(/.*?/g, "x")带有惰性的量词*?输出"xaxbxcxdx"

    • 匹配列表为 [("", 0), ("", 1), ("", 2), ("", 3), ("", 4)]

      相较于先前的例子,在这里("a", 0)("ab", 0)("abc", 0),甚至("abcd", 0)不包括因量词的懒惰是严格限制它来寻找可能的最短匹配。

    • 由于所有匹配字符串均为空,因此不会发生实际替换,而是x在位置0、1、2、3和4处插入

  3. "abcd".replace(/.+?/g, "x")带有惰性的量词+?输出"xxxx"

    • 匹配列表为 [("a", 0), ("b", 1), ("c", 2), ("d", 3)]
  4. "abcd".replace(/.{2,}?/g, "x")带有惰性的量词[2,}?输出"xx"

    • 匹配列表为 [("ab", 0), ("cd", 2)]
  5. "abcd".replace(/.{0}/g, "x")输出"xaxbxcxdx"与示例2中相同的逻辑。

更难的例子

如果我们总是匹配一个空字符串并控制发生这种匹配的位置,那么我们可以一贯地采用插入而不是替换的想法例如,我们可以创建匹配空字符串的正则表达式,在每个偶数位置在其中插入一个字符:

  1. "abcdefgh".replace(/(?<=^(..)*)/g, "_"))(?<=...)输出"_ab_cd_ef_gh_"(到目前为止,仅Chrome支持)

    • 匹配列表为 [("", 0), ("", 2), ("", 4), ("", 6), ("", 8)]
  2. "abcdefgh".replace(/(?=(..)*$)/g, "_"))正超前(?=...)输出"_ab_cd_ef_gh_"

    • 匹配列表为 [("", 0), ("", 2), ("", 4), ("", 6), ("", 8)]

显然是第一个匹配项"asdf"(位置[0,4])。由于设置了全局标志(g),因此它将继续搜索。此时(位置4),它找到第二个匹配项,一个空字符串(位置[4,4])。

请记住,它*匹配零个或多个元素。

简单来说,第一个x是替换match asdf

秒后x为空字符串asdf搜索为空时终止。

本文地址:http://javascript.askforanswer.com/weishenme-asdf-replace-g-x-xx.html
文章标签: ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!