PAYATHON 2026

PHP 如何按方括号中的分组名将文件内容转换为多维数组?

数据小许

可以直接使用 parse_ini_file()。示例中的 [People]、[Person_1] 是 INI 分组,后面的 key=value 是配置项。将第二个参数设为 true,就可以按分组生成二维关联数组,无需自己用 explode() 拆分。

使用 parse_ini_file() 解析

假设文件内容符合 INI 语法,要把 Name=Joe 解析为 'Name' => 'Joe',可以这样写:

<?php

$filename = 'data.txt';
$finalarray = parse_ini_file($filename, true, INI_SCANNER_RAW);

if ($finalarray === false) {
    throw new RuntimeException('无法读取或解析文件:' . $filename);
}

print_r($finalarray);

参数分别表示:

  • $filename:待解析的文件路径。
  • true:保留分组,将每个分组解析为一个子数组。
  • INI_SCANNER_RAW:使用原始扫描模式,避免对配置值进行 INI 特殊值解释,示例中的数字也会保留为字符串。

示例数据对应的数组结构如下:

[
    'People' => [
        'people_count' => '5',
        'male_count' => '3',
        'female_count' => '2',
    ],
    'Person_1' => [
        'Name' => 'Joe',
        'Sex' => 'male',
        'Age' => '55',
        'Other' => 'X',
    ],
    'Person_2' => [
        'Name' => 'Jill',
        'Sex' => 'female',
        'Age' => '25',
    ],
    'Person_3' => [
        'Name' => 'Bob',
        'Age' => '15',
    ],
]

每个分组可以有不同数量的配置项,无需预先定义字段。读取某个人的姓名时,可以直接使用:

echo $finalarray['Person_1']['Name']; // Joe

原来的循环为什么没有正确分组?

原代码识别了方括号,却没有记录当前正在处理的分组。

$data = array($matches);
array_push($finalarray, $data);

$matches 本身已经是数组,再用 array($matches) 包装会增加一层嵌套。随后调用:

array_push($finalarray, $val);

又把普通数据行追加到了最外层数组,导致标题和数据无法组成对应的父子结构。另外,$data 是数组,不能用作 $finalarray[$data] 的数组键。

手动解析时,需要保存当前分组名,再将数据写入对应位置。例如,下面的循环会保留每条原始数据行:

$finalarray = [];
$section = null;

foreach ($array as $val) {
    $val = trim($val);

    if ($val === '') {
        continue;
    }

    if (preg_match('/^\[([^\]]+)\]$/', $val, $matches)) {
        $section = $matches[1];
        $finalarray[$section] = [];
        continue;
    }

    if ($section === null) {
        throw new RuntimeException('数据行之前缺少分组标题');
    }

    $finalarray[$section][] = $val;
}

这个版本得到的是字符串列表,例如:

[
    'Person_1' => [
        'Name=Joe',
        'Sex=male',
        'Age=55',
        'Other=X',
    ],
]

如果需要关联数组,可以将循环末尾的追加语句替换为:

$pair = explode('=', $val, 2);

if (count($pair) !== 2) {
    throw new RuntimeException('无效的数据行:' . $val);
}

$key = trim($pair[0]);
$value = trim($pair[1]);
$finalarray[$section][$key] = $value;

explode('=', $val, 2) 只按第一个等号拆分,因此值中即使包含 =,也能保留下来。这种手动处理适用于自行约定的简单文本格式,不具备完整的 INI 引号、注释等解析规则。

使用时需要注意什么?

对于题目给出的格式,优先使用 parse_ini_file()。如果实际文件包含不符合 INI 语法的自定义内容,可以按明确的文件规则自行解析。

同一分组内若出现重复键,关联数组无法保留这些键的所有独立记录;上面转换为关联数组的手动版本也会用后一个值覆盖前一个值。需要保留重复数据时,应使用列表结构。

原代码在 print_r($finalarray); 后还有一个多余的 }。如果所贴代码就是完整脚本,需要删除它。示例中的 people_count=5 也只会作为配置值读取,解析过程不会检查它是否与实际的 Person_X 分组数量一致。

备注:内容仅供参考。