PHP纯文本内容提取难题:无法提取逗号结尾字段
解决PHP提取纯文本中逗号结尾字段的问题
嘿,我看你已经能搞定Keywords、Abstract和https字段的提取了,卡在那些以逗号结尾的字段上对吧?别担心,咱们来一步步解决这个问题。
问题根源
那些逗号结尾的字段(比如name、title、ISSN等)格式是「字段名 + 内容 + 逗号(可能前面带空格)」,你之前的正则没针对这种格式设计,所以匹配不到。另外如果有多个同名字段(比如多个name),还要注意用preg_match_all来捕获所有结果,而不是只取第一个的preg_match。
解决方案代码
我给你修改了脚本,加上了这些逗号结尾字段的提取逻辑,还做了一些鲁棒性优化:
<?php // 读取文本文件内容 $txt = file_get_contents("in.txt"); // 用更鲁棒的方式分割记录(处理不同换行符和空行前后的空格) $records = preg_split('/\s*\n\s*\n\s*/', trim($txt)); foreach($records as $key => $record) { $data = []; // 提取编号(调整正则适配可能的空格) $id_pattern = '#'.($key+1).'\.\s*(.*?)\s*,\s*\n#'; preg_match($id_pattern, $record, $id_match); $data['id'] = $id_match[1] ?? ''; // 提取所有name字段(支持多个name的情况) $name_pattern = '#name\s*(.*?)\s*,#'; preg_match_all($name_pattern, $record, $name_matches); $data['names'] = $name_matches[1] ?? []; // 提取title字段 $title_pattern = '#title\s*(.*?)\s*,#'; preg_match($title_pattern, $record, $title_match); $data['title'] = $title_match[1] ?? ''; // 提取sub-title字段 $sub_title_pattern = '#sub-title\s*(.*?)\s*,#'; preg_match($sub_title_pattern, $record, $sub_title_match); $data['sub_title'] = $sub_title_match[1] ?? ''; // 提取卷号(匹配行首数字开头的字段) $volume_pattern = '#^\s*(\d+)\s*(.*?)\s*,#m'; preg_match($volume_pattern, $record, $volume_match); $data['volume'] = trim($volume_match[1] . ' ' . ($volume_match[2] ?? '')); // 提取年份(匹配4位数字开头的行) $year_pattern = '#^\s*(\d{4})\s*(.*?)\s*,#m'; preg_match($year_pattern, $record, $year_match); $data['year'] = trim($year_match[1] . ' ' . ($year_match[2] ?? '')); // 提取编号(匹配非年份/卷号的数字行) $number_pattern = '#^\s*(\d+)\s*(.*?)\s*,#m'; preg_match($number_pattern, $record, $number_match); $data['number'] = trim($number_match[1] . ' ' . ($number_match[2] ?? '')); // 提取ISSN字段 $issn_pattern = '#ISSN\s*(.*?)\s*,#'; preg_match($issn_pattern, $record, $issn_match); $data['issn'] = $issn_match[1] ?? ''; // 提取https链接(兼容链接前的空格) $https_pattern = '#https\s*\:\s*(.*?)\s*\(#'; preg_match($https_pattern, $record, $https_match); $data['https'] = $https_match[1] ?? ''; // 提取Abstract(匹配到Keywords或记录结尾) $abstract_pattern = '#Abstract\:\s*(.*?)\s*(?=Keywords\:|\Z)#s'; preg_match($abstract_pattern, $record, $abstract_match); $data['abstract'] = trim($abstract_match[1] ?? ''); // 提取Keywords $keywords_pattern = '#Keywords\:\s*(.*?)\Z#s'; preg_match($keywords_pattern, $record, $keywords_match); $data['keywords'] = trim($keywords_match[1] ?? ''); // 这里可以处理提取到的数据,比如存入数据库或者打印调试 print_r($data); echo "-------------------------\n"; } ?>
关键说明
- 逗号结尾字段的正则:用
#字段名\s*(.*?)\s*,#,其中\s*匹配字段名后、逗号前的任意空格,(.*?)非贪婪匹配内容,避免误匹配到后面的字段。 - 多个同名字段:比如多个
name,用preg_match_all可以捕获所有匹配结果,存入数组方便后续处理。 - 鲁棒性优化:用
preg_split分割记录,兼容不同换行符(\n或\r\n)和空行前后的空格;用??运算符处理匹配失败的情况,避免出现Undefined offset报错。 - 多行匹配:对于卷号、年份这种行首的数字字段,添加
m修饰符开启多行模式,让^可以匹配每行的开头。
小提示
如果某些字段的格式有细微差别(比如卷号的数字后面内容特殊),可以根据实际文本调整正则的细节,比如缩小(.*?)的匹配范围,或者添加更精确的字符限制。
内容的提问来源于stack exchange,提问作者obi
相关产品推荐
相关产品推荐

