多行正则匹配:匹配至下一组出现时停止的技术问题
解决许可证文件中分组匹配到下一组停止的问题
看起来你已经找到了每组的起始标识,但卡在了如何“截止”到下一组出现的位置——这其实是正则里很常见的“区间匹配”场景,核心思路是用预查断言来定义匹配的终止条件,或者用非贪婪匹配结合边界限制。
先纠正下你原正则里的小问题:你的起始行正则(\w+\n\d+\.\d+\.\d+\s<.*>)里的\n应该是\s(空格),因为样例里的起始行是packagename 1.0.5 <url>,用\s能匹配任意空白符(空格、制表符都兼容)。
接下来给你两种实用的解决方案:
方法一:正向预查+DOTALL模式(推荐)
这个方法最直观,用正向预查(?=...)来告诉正则:“匹配到下一组起始行,或者文本结尾就停止”。同时开启DOTALL模式让.能匹配换行符(否则多行文本会被截断)。
最终正则:
(\w+\s+\d+\.\d+\.\d+\s+<.*?>)(.*?)(?=\w+\s+\d+\.\d+\.\d+\s+<.*?>|$)
拆解说明:
(\w+\s+\d+\.\d+\.\d+\s+<.*?>):捕获每组的起始行(包名+版本+URL),用.*?非贪婪匹配URL避免过度延伸(.*?):非贪婪匹配中间的所有多行文本(?=\w+\s+\d+\.\d+\.\d+\s+<.*?>|$):正向预查,匹配的终止条件是“下一组起始行”或者“文本末尾”
代码示例(Python)
import re # 你的样本文本 license_text = """packagename 1.0.5 <https://github.com/user/packagename> 此处为多行文本内容 可能还有第二行、第三行 packagename2 1.1.0 <https://github.com/user/packagename2> 此处为更多多行文本内容 甚至可能有空行 或者特殊格式的行""" # 编译正则,开启DOTALL模式 pattern = re.compile(r'(\w+\s+\d+\.\d+\.\d+\s+<.*?>)(.*?)(?=\w+\s+\d+\.\d+\.\d+\s+<.*?>|$)', re.DOTALL) matches = pattern.findall(license_text) # 遍历输出每组结果 for idx, (pkg_info, content) in enumerate(matches, 1): print(f"=== 第{idx}组 ===") print(f"包信息:{pkg_info.strip()}") print(f"内容:\n{content.strip()}\n")
方法二:负向预查逐行匹配(无需DOTALL)
如果你的正则引擎不支持DOTALL,或者想更精准地逐行排除起始行,可以用负向预查(?!...)来跳过所有不是起始行的内容:
正则表达式:
(\w+\s+\d+\.\d+\.\d+\s+<.*?>)\n((?:(?!\w+\s+\d+\.\d+\.\d+\s+<.*?>).*\n?)*)
拆解说明:
- 第一部分还是捕获起始行
(?:(?!起始行正则).*\n?)*:非捕获组,逐行匹配——只要当前行不是起始行,就匹配整行(包括换行符),直到遇到下一组起始行或结尾
注意事项
- 如果包名包含连字符(比如
my-package),把正则里的\w改成[\w-],避免漏匹配 - 非贪婪匹配
.*?是关键,去掉?会变成贪婪匹配,直接从第一组起始行匹配到文本末尾 - 不同语言的正则引擎对DOTALL的开启方式不同:Python用
re.DOTALL,Java用Pattern.DOTALL,JavaScript用/s修饰符
内容的提问来源于stack exchange,提问作者user3483203
相关产品推荐
相关产品推荐

