当前位置: 首页 > 知识库问答 >
问题:

前端 - 关于正则中的量词*匹配空字符串的问题?

冉伯寅
2025-10-31
"i=d".match(/\w*/g)
// 结果是 ['i', '', 'd', '']

对于结果中包含两个 '' 有些不解。
量词*修饰的表达式可以匹配空字符串,我看网上有的教程说,空字符串可以认为是 "位置" 。
如果从位置的角度来看,"i=d"中一共有3个字符,也就有4个位置,所以应该能匹配出4个 '',为何结果中只有2个?
结果为何不是如下所示?
['', 'i', '', '', 'd', '']

共有1个答案

柯伟志
2025-10-31

在 JavaScript 中,使用全局正则表达式标志 g 时,match() 方法会返回字符串中所有可能的匹配项,包括空字符串。对于你的例子 "i=d".match(/\w*/g),结果为 ['i', '', 'd', ''] 而不是你预期的 ['', 'i', '', '', 'd', ''],这源于正则引擎在全局匹配时的行为规则。以下我将逐步解释原因:

1. 正则表达式 /w*/g 的行为

  • \w* 匹配零个或多个单词字符(单词字符包括字母、数字或下划线)。
  • 量词 * 允许匹配空字符串(即匹配长度为 0 的位置)。
  • 由于 g 标志,引擎会从字符串的起始位置(索引 0)开始扫描整个字符串,尝试在每个可能的位置匹配模式,直到字符串结束。

2. 字符串 "i=d" 的索引和位置

  • 字符串 "i=d" 有 3 个字符,索引如下:

    • 索引 0: 'i'(单词字符)
    • 索引 1: '='(非单词字符)
    • 索引 2: 'd'(单词字符)
    • 索引 3: 字符串结束位置(一个虚拟位置)
  • 总共有 4 个位置(索引间和两端),但引擎不会在每个位置都生成一个匹配;它只在模式在当前索引匹配成功时才记录结果。

3. 匹配过程详解(按索引推进)

引擎的匹配规则:

  • 尝试在 当前索引 开始匹配 \w*
  • 如果匹配成功(包括匹配空字符串),记录结果。
  • 然后推进索引:

    • 如果匹配长度 > 0 (非空字符串),索引推进匹配的长度(例如,匹配了 "i",长度 1,索引 +1)。
    • 如果匹配长度 = 0 (空字符串),引擎强制推进索引 +1,以避免在相同位置无限循环(这很重要!)。

具体到 "i=d":

  1. 从索引 0 开始

    • 字符 'i' 是单词字符,\w* 可以匹配 "i"(长度 1)。
    • 引擎记录 "i",并推进索引:0 + 1 = 到索引 1。
    • 这里没有匹配空字符串,因为引擎优先匹配了非空字符串(量词 * 是贪婪的,会匹配尽可能多的字符)。
  2. 索引 1(字符 '=')

    • '=' 是非单词字符,\w* 只能匹配零个字符(即空字符串)。
    • 引擎记录 "" (空字符串),但匹配长度为 0,所以索引强制推进 +1,到索引 2。
  3. 索引 2(字符 'd')

    • 'd' 是单词字符,\w* 匹配 "d"(长度 1)。
    • 引擎记录 "d",并推进索引:2 + 1 = 到索引 3。
  4. 索引 3(字符串结束)

    • 这里没有字符,\w* 匹配零个字符(即空字符串)。
    • 引擎记录 "" (空字符串),索引推进 +1 到索引 4(结束)。

结果数组['i', '', 'd', ''],对应:

  • "i" at index 0(匹配非空字符串)
  • "" at index 1(空字符串匹配)
  • "d" at index 2(匹配非空字符串)
  • "" at index 3(空字符串匹配在结束位置)

4. 为什么不是预期的 ['', 'i', '', '', 'd', '']

  • 在索引 0(开头)和索引 2('d' 前)没有单独的空字符串匹配:因为引擎在索引 0 能匹配非空字符串 "i",它会优先匹配它,而不是生成一个单独的空字符串匹配。同样在索引 2,能匹配 "d"。空字符串只在无法匹配非空字符串的位置被记录。
  • 索引推进规则避免了冗余匹配:如果引擎在每个位置都匹配空字符串而不推进索引,它会卡在索引 1 无限生成空字符串(例如 ['', '', '', ...])。因此,JavaScript 的引擎强制在空匹配后推进索引 +1,确保只返回 "有意义" 的空匹配点(通常发生在非单词字符之间或字符串结尾)。
  • 位置 vs. 实际索引行为:虽然字符串有 4 个位置(索引间边界),但引擎并不独立匹配每个边界点;它只在当前索引尝试匹配,并根据匹配结果推进。因此,在索引 0 和 索引 2,由于匹配了非空字符串,就不会有额外的空字符串插入在这些位置之前。

5. 如果你想要更多位置信息,如何验证?

你可以使用 exec() 手动模拟全局匹配,查看每个匹配的索引:

let regex = /\w*/g;
let str = "i=d";
let matches = [];
let match;
while ((match = regex.exec(str)) !== null) {
  matches.push(`Matched: '${match[0]}' at index ${match.index}`);
}
console.log(matches.join('\n'));

输出:

Matched: 'i' at index 0
Matched: '' at index 1
Matched: 'd' at index 2
Matched: '' at index 3

这证实了匹配发生在索引 0、1、2、3,其中空字符串只在索引 1 和 3 出现。

总结

  • 结果为 ['i', '', 'd', ''] 是正确的:因为全局匹配只记录引擎实际命中的位置,包括空匹配点。
  • 只有两个空字符串的原因

    • 在索引 0 和索引 2,引擎匹配了非空字符串 ("i" 和 "d"),所以没有空字符串匹配在那里。
    • 在索引 1 ('=' 处) 和索引 3 (结束位置),引擎必须匹配空字符串,并推进索引。
  • 避免误解:量词 * 允许空字符串匹配,但不意味着每个位置都生成一个空匹配;引擎优先匹配非空字符串,并在空匹配后推进索引,防止死循环。
 类似资料:
  • 我有这样一个字符串: “#影响@John@Me Lorem ipsum door sit amet,奉献给精英们,让他们暂时参与劳动和生活。但是,在最低限度上,我们需要一个实验室来进行日常工作。两人或两人在一个无教区的房间里互相指责。除偶尔因疏忽而死亡外,还必须因工作原因而受到伤害 我需要以两种方式“拆分”,删除第一个单词,因为它以“#”开头(我可以做/已经做过),第二个我想不出来-我需要从字符串

  • 问题内容: 我有一个正则表达式字符串数组。其中之一必须与给定java文件中找到的任何字符串匹配。 这是我到目前为止拥有的正则表达式字符串: 但是,即使字符串内的引号被转义,该字符串也会被拒绝。我认为,无论字符串是否转义,当在字符串中找到引号时,我都会立即拒绝它。我需要它接受带转义引号的字符串文字,但它应该拒绝。 问题答案: 在Java中,您可以使用此正则表达式匹配和之间的所有转义引号: 使用的正则

  • 本文向大家介绍PHP中preg_match函数正则匹配的字符串长度问题,包括了PHP中preg_match函数正则匹配的字符串长度问题的使用技巧和注意事项,需要的朋友参考一下 项目中,用preg_match正则提取目标内容,死活有问题,代码测得死去活来。 后来怀疑PHP 的preg_match有字符串长度限制,果然,发现“pcre.backtrack_limit ”的值默认只设了100000。 解

  • 本文向大家介绍Python正则表达式匹配字符串中的数字,包括了Python正则表达式匹配字符串中的数字的使用技巧和注意事项,需要的朋友参考一下 1.使用“\d+”匹配全数字 代码: 结果: ['479', '501', '870', '209', '213', '650'] 但是上述这种方式也会引入非纯数据,例子如下: 结果: ['479', '501', '870', '209', '213',

  • 问题内容: 我在尝试将我的javascript regex经验转移到Python时遇到了麻烦。 我只是想让它工作: …但是它打印无。如果我做: 它匹配…默认情况下是否匹配字符串的开头?当匹配时,如何使用结果? 我如何进行第一场比赛?是否有比python网站提供的文档更好的文档? 问题答案: 隐式添加到您的正则表达式的开头。换句话说,它仅在字符串的开头匹配。 将在所有位置重试。 一般来说,建议您在需

  • 问题内容: 我在用Python将字符串中的数字匹配时遇到麻烦。尽管应该明确匹配,但甚至不匹配 或仅匹配。我的监督在哪里? 问题答案: 阅读文档:http : //docs.python.org/2/library/re.html#re.match 如果在零个或多个字符 开头 的 字符串 您要使用(或)

  • 我不熟悉RE2语法正则表达式,我想匹配特定字符串后面的第一个单词。 例如:

  • 我正在编写一个php类来从csv文件中提取数据。所以正则表达式需要帮助。 数据样本 正则表达式 这不应该匹配第1、2和7行,因为它在数据和字段后只有空格和制表符(空白) 这是我的regex测试程序链接https://regex101.com/r/xpG25l/1/