
本文介绍如何通过 `preg_match_all` 配合命名捕获组正则,从多行营养标签文本中准确分离出成分名称(如 "total lipid (fat)")、浮点数值(如 22.163422468932)和单位(如 "g"),避免错误切分标点与空格。
直接使用 preg_split 按数字或空格分割容易破坏语义完整性——例如将 "Total lipid (fat)" 错误拆成 ["Total", "lipid", "(fat)"],且难以保留数值与单位的边界。更可靠的做法是匹配(match)而非分割(split):用正则主动识别每行中“非数字开头的类别名 + 空格 + 浮点数 + 空格 + 单位”的结构,并通过命名捕获组提取三部分。
推荐正则模式如下:
$pattern = '~^(?P\D+)\s+(?P [\d.]+)\s+(?P .+)~m';
- ^ 和 m 修饰符:使 ^ 匹配每一行开头(多行模式);
- (?P
gory>\D+):捕获一个或多个非数字字符(\D),完美兼容含空格、逗号、括号的成分名(如 "Sugars, total" 或 "Sodium, Na"); - \s+:匹配一个或多个空白符(含空格、制表符),作为分隔;
- (?P
[\d.]+):捕获由数字和小数点组成的数值(注意:未限定小数点个数,适用于科学记数法外的常规浮点格式;若需更严格校验,可改为 (?P \d+(?:\.\d+)?)); - (?P
.+):捕获剩余所有字符作为单位(如 "kcal"、"mg"),自动包含末尾换行前的内容。
完整 PHP 示例代码:
\D+)\s+(?P[\d.]+)\s+(?P .+)~m'; preg_match_all($pattern, $content, $matches, PREG_SET_ORDER); // 输出结构化结果 foreach ($matches as $match) { echo sprintf( "[%s] => %s\n[%s] => %s\n[%s] => %s\n\n", 'category', trim($match['category']), 'value', $match['value'], 'unit', trim($match['unit']) ); } ?>
✅ 输出效果示例(首行):
立即学习“PHP免费学习笔记(深入)”;
[category] => Weight [value] => 229.6104534866 [unit] => g
⚠️ 注意事项:
- 若输入中存在无单位行(如纯数值)或格式不一致(如缺失空格),该正则会跳过不匹配行——建议先用 trim() 清理每行首尾空白,并对 $matches[0] 进行空值检查;
- 如需支持国际单位中的逗号千位分隔符(如 "1,234.56"),应将 [\d.]+ 替换为更健壮的 [\d,]+(?:\.\d+)? 并预处理去除逗号;
- preg_match_all 返回的 $matches 是二维数组,PREG_SET_ORDER 保证每个子数组对应一行完整匹配,键名为 category/value/unit,便于后续 JSON 序列化或数据库插入。
这种方法语义清晰、容错性强,是解析结构化标签文本的标准实践。











