如何用正则表达式多行捕获连续以星号开头的行
如何用正则捕获所有连续以星号开头的行?
需求说明
我有如下格式的字符串:
foobar * Level1-1 * Level1-2 ** Level2-1 ** Level2-2 *** Level3-1 *** Level3-2 foo foo foo bar * Level1-1 foo bar foo bar * Level1-1 ** Level2-1 foo bar
希望用正则多行捕获所有连续以星号(*)开头的行,得到3组结果:
结果1:
* Level1-1 * Level1-2 ** Level2-1 ** Level2-2 *** Level3-1 *** Level3-2
结果2:
* Level1-1
结果3:
* Level1-1 ** Level2-1
尝试的方案
我用了带/m(多行模式)的正则表达式:
^(?<Content>\*(.|\n|\r|\n\r)+)(?=[\n\r]+[^\*]+)
对这个正则的理解:
^:匹配行/字符串起始(?<Content>\*(.|\n|\r|\n\r)+):捕获所有以星号开头的行的捕获组(?=[\n\r]+[^\*]+):正向预查,匹配不以星号开头的行来结束匹配
但实际匹配结果是除了前2行和最后一行外的整个字符串,不符合预期。我知道(^\*.*)能匹配单行,但需要把连续的星号行放到同一个捕获组里。
问题
不清楚哪里出错了,尤其是正向预查部分,希望得到实现需求的建议。
解决方案
原正则的问题
- 贪婪匹配导致过度捕获:
(.|\n|\r|\n\r)+是贪婪模式,会尽可能匹配更多内容,包括中间的非星号行——只要后面还存在[\n\r]+[^\*]+的结构,就会一直往后匹配,不会在第一个非星号行处停止。 - 未限定每行必须以星号开头:原正则只保证起始行是星号开头,后续内容允许任意字符(包括非星号行),这就导致连续星号行之外的内容也被包含进来。
正确的正则表达式
使用多行模式(/m),搭配全局匹配(/g,根据正则引擎调整),用以下正则:
^\*.*(?:\R^\*.*)*
如果你的正则引擎不支持\R(表示任意换行符,包括\n、\r\n),可以替换为(?:\n|\r\n):
^\*.*(?:(?:\n|\r\n)^\*.*)*
正则解释
^:多行模式下,匹配行开头(而非整个字符串开头)\*.*:匹配一行中以*开头的内容,.*匹配该行剩余所有字符(?:\R^\*.*)*:非捕获组,匹配0或多个「换行符 + 以*开头的行」,从而把连续的星号行合并为一个匹配项
使用说明
在支持全局匹配的正则引擎中(比如JavaScript的g标志、.NET的Matches方法、Python的re.findall),运行这个正则会直接得到你需要的3组连续星号行结果。
内容的提问来源于Stack Exchange,提问作者PowershellNinja
相关产品推荐
相关产品推荐

