首页 > 解决方案 > Javascript 正则表达式:无法删除多行字符串中的前瞻组中的前导空格

问题描述

我正在尝试使用正则表达式^(?<=[\s]*namespace[\s]*---+\s+)(.|\s)+(?=\(\s*\d+\s*rows\))/gm从单列表格列表格式字符串中提取行项目。但是在匹配中添加了前导空格。lookahead 和lookbehind 组中的\s+运算符没有帮助。参考以下:

x = `namespace
-------------------
               itm1
     itm2
  itm3
               itm4
               
(4 rows)
`
console.log(x.match(/^(?<=[\s]*namespace[\s]*---+\s+)(.|\s)+(?=\(\s*\d+\s*rows\))/gm)[0].split(/\s+/))

输出带有前导和尾随空格作为单独的列表元素:

[ '', 'itm1', 'itm2', 'itm3', 'itm4', '' ]

但是使用console.log(x.match(/^(?<=[\s]*namespace[\s]*---+\s+)(.|\s)+(?=\(\s*\d+\s*rows\))/gm)[0].trim().split(/\s+/)) <-- 注意 trim()之前的split(..),输出是:

[ 'itm1', 'itm2', 'itm3', 'itm4' ]

为什么\s+前瞻组末尾的(?<=[\s]*namespace[\s]*---+\s+)不会删除 . 捕获的所需匹配组之前的所有空格(.|\s)+

标签: javascriptregex

解决方案


根本原因

正则表达式引擎从左到右解析字符串。

正则表达式在字符串的开头搜索匹配,但没有找到后向模式,它在那里失败,然后测试下一个位置,在na之间namespace。依此类推,直到-------------------.

在换行符之后的位置\n,有一个lookbehind模式匹配,\s+在lookbehind的末尾找到\s+pattern所需的空格。然后,模式的其余部分也会找到匹配项。因此,您的结果中有 15 个前导空格。

解决方案

使用消费模式。也就是说,使用捕获组。或者,确保您的消费部分以非空白字符开头。

因此,

const x = "namespace\n-------------------\n               itm1\n     itm2\n  itm3\n               itm4\n               \n(4 rows)\n";
console.log(
  x.match(/(?<=^\s*namespace\s*---+\s+)\S.*?(?=\s*\(\s*\d+\s*rows\))/gms)[0].split(/\s+/)
);

或者,使用捕获组:

const x = "namespace\n-------------------\n               itm1\n     itm2\n  itm3\n               itm4\n               \n(4 rows)\n";
console.log(
  x.match(/^\s*namespace\s*---+\s+(\S.*?)(?=\s*\(\s*\d+\s*rows\))/ms)[1].split(/\s+/)
);

注意正则表达式:

  • (.|\s)+用一个简单的.模式替换,但添加了s标志,以便.可以匹配换行符。请永远不要使用(.|\s)*,(.|\n)*(.|[\r\n])*, 这些是非常低效的正则表达式模式
  • \s*在正向前瞻的开头添加了,以便可以从匹配中删除尾随空格。
  • 我还在两种模式中都使用了一个惰性点 ,.*?来匹配两个字符串之间的最少字符数。

推荐阅读