PHP preg_match_all仅提取首个字段,其余匹配失败求助
从PDF转换文本中提取联系人字段的问题解决
问题描述
需要从PDF转换的文本中提取Navn(姓名)、Telefon(电话)、E-postadresse(邮箱)和Adresse(地址)字段的值,文本以空行分隔内容。但使用PHP的preg_match_all提取时,仅能获取首个Navn字段的值,其余字段匹配失败。
原始文本内容
Kontaktperson: Navn: Johan Wathne Telefon: 99566530 99566530 E-postadresse: johancqöhwheno
现有PHP代码
if (preg_match('/Kontaktperson:\s*(.*?)\n\n/ms', $fileContent, $matches)) { $kontaktpersonSection = trim($matches[1]); // Extract Tiltakshaver fields if (preg_match_all('/(Navn|Telefon|E-postadresse|Adresse):\s*([^\n]+)\s*(?:\n\n|$)/', $kontaktpersonSection, $kontaktMatches, PREG_SET_ORDER)) { $kontaktpersonInfo = "Kontaktperson\n"; $currentkontakt = ""; foreach ($kontaktMatches as $kontaktMatch) { if ($kontaktMatch[1] === "Navn") { $currentkontakt = "Navn"; $kontaktValue = $kontaktMatch[2]; $kontaktpersonInfo .= "$currentkontakt: $kontaktValue\n"; } elseif ($kontaktMatch[1] === "Telefon") { $currentkontakt = "Telefon"; $kontaktValue = explode("\n", $kontaktMatch[2])[0]; $kontaktpersonInfo .= "$currentkontakt: $kontaktValue\n"; } elseif ($kontaktMatch[1] === "E-postadresse") { $currentkontakt = "E-postadresse"; $kontaktValue = $kontaktMatch[2]; $kontaktpersonInfo .= "$currentkontakt: $kontaktValue\n"; } elseif ($kontaktMatch[1] === "Adresse") { $currentkontakt = "Adresse"; $kontaktValue = $kontaktMatch[2]; $kontaktpersonInfo .= "$currentkontakt: $kontaktValue\n"; } } $extractedInfo .= $kontaktpersonInfo; } }
问题原因分析
- 第一个正则截断内容:
/Kontaktperson:\s*(.*?)\n\n/ms中的.*?是惰性匹配,遇到第一个空行就停止捕获,导致$kontaktpersonSection只包含Navn部分,Telefon及之后的内容完全没进入处理流程。 - 第二个正则匹配范围不足:
([^\n]+)仅匹配单行内容,即便内容完整传入,也无法处理Telefon这种跨两行的字段值,且匹配终止条件的逻辑也不够严谨。
修正方案与代码
核心修正点
- 调整第一个正则的捕获范围,确保拿到完整的
Kontaktperson区块,使用正向预查判断终止位置:/(?=\n\n\w+:|\z),即捕获到下一个空行加字段名或文本结尾为止。 - 调整第二个正则,允许字段值跨多行,同样用正向预查匹配到下一个空行或结尾,确保完整捕获字段内容。
修正后的代码
if (preg_match('/Kontaktperson:\s*(.*?)(?=\n\n\w+:|\z)/ms', $fileContent, $matches)) { $kontaktpersonSection = trim($matches[1]); if (preg_match_all('/(Navn|Telefon|E-postadresse|Adresse):\s*(.*?)\s*(?=\n\n|\z)/ms', $kontaktpersonSection, $kontaktMatches, PREG_SET_ORDER)) { $kontaktpersonInfo = "Kontaktperson\n"; foreach ($kontaktMatches as $kontaktMatch) { $field = $kontaktMatch[1]; $value = trim($kontaktMatch[2]); // 针对Telefon字段的多行内容,这里示例取第一行,可根据需求调整(比如合并去重) if ($field === "Telefon") { $value = explode("\n", $value)[0]; } $kontaktpersonInfo .= "$field: $value\n"; } $extractedInfo .= $kontaktpersonInfo; } }
代码说明
- 第一个正则的正向预查
(?=\n\n\w+:|\z)避免了提前截断,确保捕获Kontaktperson下的所有相关内容。 - 第二个正则的
.*?配合(?=\n\n|\z),能完整捕获每个字段的所有内容(包括换行),之后可根据业务需求处理多行值(如示例中的Telefon取第一行)。 - 简化了循环逻辑,无需逐个判断字段类型,通用处理更简洁高效。
内容的提问来源于stack exchange,提问作者objelland
相关产品推荐
相关产品推荐

