如何使用正则使提取结果包含换行内容(PHP preg_match_all场景)
解决方案
核心思路
原来的问题出在没有给消息内容设置明确的终止匹配边界,所以要么匹配不到换行,要么加了单行模式就直接匹配到文件尾。我们可以用负向正向预查让消息内容匹配时,遇到下一条消息的日期头就停止,就可以完美兼容消息内换行的场景。
修正后的正则
/(?<date>(?:[0-9]{1,2}\/){2}[0-9]{1,2}),\s(?<time>(?:[0-9]{1,2}:)[0-9]{2}\s[ap]m)\s-\s(?<name>[^:]+):\s(?<message>(?s:(?!^\d{1,2}\/\d{1,2}\/\d{1,2}).)*)/m
改动点说明
- 给整个正则加了
m多行修饰符,让^可以匹配每一行的开头,用来识别下一条消息的起始位置 name分组从.*改成[^:]+,避免不必要的回溯,匹配到冒号就停止,更精准message分组逻辑改成:开启单行模式(.匹配换行)的前提下,每匹配一个字符前都检查当前位置是不是下一条消息的日期开头,如果不是就继续匹配,直到碰到消息头或者文件尾- 原来写法里
[a|p]m的竖线是多余的,字符组里不需要加或逻辑,直接写[ap]m即可
PHP调用示例
<?php $content = file_get_contents('你的消息文件路径.txt'); $pattern = '/(?<date>(?:[0-9]{1,2}\/){2}[0-9]{1,2}),\s(?<time>(?:[0-9]{1,2}:)[0-9]{2}\s[ap]m)\s-\s(?<name>[^:]+):\s(?<message>(?s:(?!^\d{1,2}\/\d{1,2}\/\d{1,2}).)*)/m'; preg_match_all($pattern, $content, $matches, PREG_SET_ORDER); // 按需处理结果 $result = []; foreach ($matches as $match) { $result[] = [ 'date' => $match['date'], 'time' => $match['time'], 'name' => $match['name'], 'message' => rtrim($match['message']) // 去掉末尾多余换行 ]; } print_r($result);
结果说明
按你的示例文件处理后,所有跨换行的消息内容都会自动拼接到对应message字段中,不会丢失内容,比如第二条消息的内容会完整保留为:
Here is yet another message where someone added a line break
内容的提问来源于stack exchange,提问作者curlygeek
相关产品推荐
相关产品推荐

