【问题标题】:Javascript regex lookbehind: Invalid regexp groupJavascript regex lookbehind:无效的正则表达式组
【发布时间】:2020-09-02 18:00:09
【问题描述】:

我有以下带有正则表达式/-+|(?<=: ?).* 的小示例。但这会导致 Node/Chrome 中的无限循环和 Firefox 中的“Invalig regex group”错误。

当我将其更改为 /-+|(?<=: ).*/gm(在后面省略 ?-量词)时,它会运行,但是 - 当然 - 我没有得到在 : 之后不包含任何值的行。

如果我将正则表达式更改为/-+|(?<=:).*/gm(将空间留在后面),我会再次陷入无限循环/错误。

谁能向我解释这种行为以及我必须使用什么正则表达式来匹配以冒号结尾的行?我很想了解...

const text = `
-------------------------------------
Prop Name: 5048603
Prop2 Name:
Bla bla bla: asjhgg | a3857
Location: Something...
-------------------------------------
Prop Name: 5048603
Prop2 Name:
Bla bla bla: asjhgg | a3857
Location: Something...
-------------------------------------
`;

const pattern = /-+|(?<=: ?).*/gm;

let res;
while((res = pattern.exec(text)) !== null)
{
    console.log(`"${res[0]}"`);
} 

编辑:

预期的输出是:

"-------------------------------------"
"5048603"
""
"asjhgg | a3857"
"Something..."
"-------------------------------------"
"5048603"
""
"asjhgg | a3857"
"Something..."
"-------------------------------------"

【问题讨论】:

  • 您发布的示例字符串希望得到什么输出?
  • @WiktorStribiżew 确实添加了预期的输出
  • 使用text.replace(/^[^:\r\n]+:[^\S\r\n]*/gm, ''),如有必要,然后使用.split("\n")
  • 通常最清楚的问题是先陈述您要达到的目标,然后在适当的情况下给出一个或多个示例,显示每个示例所需的结果,然后展示您尝试过的代码并解释为什么它不起作用,然后回顾一下你对读者的要求。

标签: javascript regex regex-lookarounds


【解决方案1】:

(?&lt;=...)lookaround 是一种积极的lookbehind,FireFox 尚不支持它(请参阅supported environments here),因此,在实施之前,您总是会遇到异常。

/-+|(?&lt;=: ?).* 模式属于可能匹配空字符串的模式,这是一种非常典型的“病态”类型的模式。 g 标志使 JS 正则表达式引擎匹配所有出现的模式,为此,它在有效匹配时推进其 lastIndex,但在匹配长度为零的情况下,它不会,并保持在同一位置再次尝试相同的正则表达式,您最终会陷入循环。请参阅here 如何正确移动lastIndex 以避免在这些情况下出现无限循环。

据我所知,您希望删除第一个 : 之前的所有行首,包括 : 和之后的任何空格。你可以使用

text.replace(/^[^:\r\n]+:[^\S\r\n]*/gm, '')

或者,如果您想实际提取那些全部为-s 或全部在: 之后的行,您可以使用

const text = `
-------------------------------------
Prop Name: 5048603
Prop2 Name:
Bla bla bla: asjhgg | a3857
Location: Something...
-------------------------------------
Prop Name: 5048603
Prop2 Name:
Bla bla bla: asjhgg | a3857
Location: Something...
-------------------------------------
`;

const pattern = /^-+$|:[^\S\r\n]*(.*)/gm;

let res;
while((res = pattern.exec(text)) !== null)
{
    if (res[1] != undefined) {
      console.log(res[1]);
    } else {
      console.log(res[0]);
    }
}

【讨论】:

    【解决方案2】:

    尝试使用这种模式:/(.*):(.*)/mg

    const regex = /(.*):(.*)/mg;
    const str = `-------------------------------------
    Prop Name: 5048603
    Prop2 Name:
    Bla bla bla: asjhgg | a3857
    Location: Something...
    -------------------------------------
    Prop Name: 5048603
    Prop2 Name:
    Bla bla bla: asjhgg | a3857
    Location: Something...
    -------------------------------------`;
    let m;
    
    while ((m = regex.exec(str)) !== null) {
        // This is necessary to avoid infinite loops with zero-width matches
        if (m.index === regex.lastIndex) {
            regex.lastIndex++;
        }
        
        // The result can be accessed through the `m`-variable.
        m.forEach((match, groupIndex) => {
            console.log(`Found match, group ${groupIndex}: ${match}`);
        });
    }

    【讨论】:

      【解决方案3】:

      预先说明:Wiktor 的答案是让它跨浏览器工作。

      对于任何对如何使用“原始”模式使其在 Chrome 中工作感兴趣的人(感谢 Wiktor 的回答,指出最后一个索引在零匹配时不会增加):

      const pattern = /-+|(?<=: ?).*/gm;
      
      let res;
      while((res = pattern.exec(text)) !== null)
      {
          if(res.index === pattern.lastIndex)
              pattern.lastIndex++;
          console.log(`"${res[0]}"`);
      }
      

      【讨论】:

        【解决方案4】:

        正则表达式前瞻是这样定义的 (?=pattern) 而不是 (pattern?)

        https://www.regular-expressions.info/lookaround.html

        【讨论】:

        猜你喜欢
        • 2022-01-25
        • 1970-01-01
        • 1970-01-01
        • 2012-02-08
        • 1970-01-01
        • 1970-01-01
        • 2023-03-06
        • 2011-05-11
        • 2021-05-01
        相关资源
        最近更新 更多