如何通过正则表达式将多条多行文本条目转换为单行?
问题原因分析
你原来的写法存在3个核心问题:
- 负前瞻
(?!#)位置错误,紧跟在[\s\S]+?后无法阻止匹配过程中遇到#开头的大标题边界,非贪婪模式会无规则提前截断 - 没有覆盖每个大段最后一个条目的场景,最后一个条目后没有下一个
(?[a-z0-9]+\)标识,会被正则漏掉 - 没有兼容子条目(a)、b)类)的多行匹配需求
正确实现方案
核心逻辑是匹配所有行首为(数字) 或小写字母) 开头的条目,捕获条目内容直到下一个条目边界/大标题边界/文本末尾,再将内容中的换行、多余空白替换为单个空格。
// 匹配条目的正则:m多行模式,s点号匹配换行 $pattern = '/^([(]?[a-z0-9]+[)] )(.*?)(?=$|^\(?[a-z0-9]+\)|^#)/ms'; $text = preg_replace_callback($pattern, function ($grp) { // unwrap逻辑:替换换行、制表符为单个空格,去除多余空格 $unwrapContent = preg_replace('/\s+/', ' ', trim($grp[2])); return $grp[1] . $unwrapContent . PHP_EOL; }, $text);
代码说明
- 正则修饰符用
ms:m开启多行模式让^匹配每行行首,s让.匹配换行符,代替原来的[\s\S]写法更简洁 - 用正前瞻
(?=$|^\(?[a-z0-9]+\)|^#)做边界判断:匹配到文本末尾、下一个条目开头、下一个大标题开头三个边界任意一个就停止捕获,不会漏匹配最后一个条目 - 内置unwrap逻辑直接完成换行、缩进空白的替换,不需要额外定义自定义函数
效果示例
处理前的(3)条目:
(3) Here is the problem, text for each numbered line is supposed to be on a single line like in (1) and (2), but the text often spans multiple lines of text.
处理后:
(3) Here is the problem, text for each numbered line is supposed to be on a single line like in (1) and (2), but the text often spans multiple lines of text.
内容的提问来源于stack exchange,提问作者Coffee'd Up Hacker
相关产品推荐
相关产品推荐

