rec*_*ive 153 javascript regex
我偶然发现了一个(对我而言)令人惊讶的事实。
console.log("asdf".replace(/.*/g, "x"));Run Code Online (Sandbox Code Playgroud)
为什么要换两个?似乎任何没有换行符的非空字符串都会为这个模式产生两个替换。使用替换函数,我可以看到第一个替换是整个字符串,第二个替换是一个空字符串。
小智 111
根据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).
Run Code Online (Sandbox Code Playgroud)
这里rx是/.*/g和S是'asdf'。
见 11.c.iii.2.b:
湾 令 nextIndex 为 AdvanceStringIndex(S, thisIndex, fullUnicode)。
因此,'asdf'.replace(/.*/g, 'x')它实际上是:
[],lastIndex =0'asdf', 结果 = [ 'asdf' ], lastIndex =4'', results = [ 'asdf', '' ], lastIndex = 4, AdvanceStringIndex, 将 lastIndex 设置为5null, 结果 = [ 'asdf', '' ], 返回因此有 2 场比赛。
Com*_*eek 39
在与yawkat的离线聊天中,我们找到了一种直观的方式来了解为什么"abcd".replace(/.*/g, "x")会产生两个匹配项。请注意,我们尚未检查它是否完全等于 ECMAScript 标准强加的语义,因此仅将其作为经验法则。
(matchStr, matchIndex)按时间顺序排列的元组列表,指示输入字符串的哪些字符串部分和索引已被吃掉。matchIndex覆盖该matchStr位置的子字符串给出的索引处完成的。如果matchStr = "",则“替换”实际上是插入。形式上,匹配和替换的行为被描述为另一个答案中所见的循环。
"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 替换""。
在这里,您可以看到替换可以作为对先前字符串的真正替换,也可以作为插入新字符串。
"abcd".replace(/.*?/g, "x")带有惰性量词*?输出"xaxbxcxdx"
比赛名单是 [("", 0), ("", 1), ("", 2), ("", 3), ("", 4)]
与前面的示例相反,这里没有包括("a", 0), ("ab", 0), ("abc", 0), 甚至("abcd", 0)是由于量词的惰性严格限制它找到可能的最短匹配项。
由于所有匹配字符串都是空的,因此不会发生实际替换,而是x在位置 0、1、2、3 和 4 处插入。
"abcd".replace(/.+?/g, "x")带有惰性量词+?输出"xxxx"
[("a", 0), ("b", 1), ("c", 2), ("d", 3)]"abcd".replace(/.{2,}?/g, "x")带有惰性量词[2,}?输出"xx"
[("ab", 0), ("cd", 2)]"abcd".replace(/.{0}/g, "x")"xaxbxcxdx"通过与示例 2 中相同的逻辑输出。
如果我们总是匹配一个空字符串并控制这种匹配发生的位置,我们就可以始终如一地利用插入而不是替换的想法。例如,我们可以在每个偶数位置创建匹配空字符串的正则表达式,以在那里插入一个字符:
"abcdefgh".replace(/(?<=^(..)*)/g, "_"))具有正向后视(?<=...)输出"_ab_cd_ef_gh_"(目前仅在 Chrome 中受支持)
[("", 0), ("", 2), ("", 4), ("", 6), ("", 8)]"abcdefgh".replace(/(?=(..)*$)/g, "_"))具有正向预测(?=...)输出"_ab_cd_ef_gh_"
[("", 0), ("", 2), ("", 4), ("", 6), ("", 8)]Dav*_* SK 31
第一场比赛显然是"asdf"(Position [0,4])。由于设置了全局标志 ( g),它会继续搜索。此时(位置 4),它找到了第二个匹配项,一个空字符串(位置 [4,4])。
请记住,*匹配零个或多个元素。