解析包含 3 个分隔符的格式化字符串以创建多个平面数组

Parse formatted strings containing 3 delimiters to create multiple flat arrays

我有以下格式的字符串:

$strings[1] = cat:others;id:4,9,13
$strings[2] = id:4,9,13;cat:electric-products
$strings[3] = id:4,9,13;cat:foods;
$strings[4] = cat:drinks,foods;

其中 cat 表示类别,id 是产品标识号。

我想拆分这些字符串并转换成数组 $cats = array('others');$ids = array('4','9','13');

我知道可以通过foreach和explode函数分多步完成。我想我就在附近,但下面的代码不起作用。

此外,我想知道是否可以通过 preg_matchpreg_split 以更少的步骤完成。或者任何其他更简单的方法。

foreach ($strings as $key=>$string) {
   $temps = explode(';', $string);
   foreach($temps as $temp) {
      $tempnest = explode(':', $temp);
      $array[$tempnest[0]] .= explode(',', $tempnest[1]);
   }
}

我想要的结果应该是:

$cats = ['others', 'electric-products', 'foods', 'drinks';

$ids = ['4','9','13'];

一个选项可能是对 catid 展开后的第一项进行字符串比较,以将值设置为正确的数组。

$strings = ["cat:others;id:4,9,13", "id:4,9,13;cat:electric-products", "id:4,9,13;cat:foods", "cat:drinks,foods"];

foreach ($strings as $key=>$string) {
    $temps = explode(';', $string);
    $cats = [];
    $ids = [];
    foreach ($temps as $temp) {
        $tempnest = explode(':', $temp);

        if ($tempnest[0] === "cat") {
            $cats = explode(',', $tempnest[1]);
        }
        if ($tempnest[0] === "id") {
            $ids = explode(',', $tempnest[1]);
        }
    }
    print_r($cats);
    print_r($ids);
}

Php demo

例如,第一项的输出看起来像

Array
(
    [0] => others
)
Array
(
    [0] => 4
    [1] => 9
    [2] => 13
)

如果您想聚合 2 个数组中的所有值,您可以 array_merge 结果,最后使用 array_unique.

获得唯一值
$strings = ["cat:others;id:4,9,13", "id:4,9,13;cat:electric-products", "id:4,9,13;cat:foods", "cat:drinks,foods"];
$cats = [];
$ids = [];
foreach ($strings as $key=>$string) {
    $temps = explode(';', $string);

    foreach ($temps as $temp) {
        $tempnest = explode(':', $temp);

        if ($tempnest[0] === "cat") {
            $cats = array_merge(explode(',', $tempnest[1]), $cats);
        }
        if ($tempnest[0] === "id") {
            $ids = array_merge(explode(',', $tempnest[1]), $ids);
        }
    }

}
print_r(array_unique($cats));
print_r(array_unique($ids));

输出

Array
(
    [0] => drinks
    [1] => foods
    [3] => electric-products
    [4] => others
)
Array
(
    [0] => 4
    [1] => 9
    [2] => 13
)

Php demo

我一般不建议使用可变变量,但您正在寻找一个使用正则表达式来避免多次 explode() 调用的圆滑片段。

这是一个不使用 explode() 调用和嵌套 foreach() 循环的脚本。

您可以通过调用 var_export($matches); 查看 \G(“继续”元字符)如何允许相对于“桶”标签(idcat)的连续匹配.

如果这是我自己的代码,我可能不会创建单独的变量,而是创建一个包含 idcat 的数组——这将减少对可变变量的需求。

通过使用遇到的值作为要添加到桶中的元素的键,您可以确保任何桶中没有重复值——如果您想重新索引,只需调用 array_values()桶元素。

代码:(Demo) (Regex101)

$count = preg_match_all(
    '/(?:^|;)(id|cat):|\G(?!^),?([^,;]+)/',
    implode(';', $strings),
    $matches,
    PREG_UNMATCHED_AS_NULL
);

$cat = [];
$id = [];
for ($i = 0; $i < $count; ++$i) {
    if ($matches[1][$i] !== null) {
        $arrayName = $matches[1][$i];
    } else {
        ${$arrayName}[$matches[2][$i]] = $matches[2][$i];
    }
}
var_export(array_values($id));
echo "\n---\n";
var_export(array_values($cat));

综上所述,我可能不会依赖正则表达式,因为它对新手正则表达式开发人员来说可读性不高。使用嵌套循环和爆炸,所需的逻辑要简单得多,也更容易维护。这是我对你的代码的调整。

代码:(Demo)

$result = ['id' => [], 'cat' => []];
foreach ($strings as $string) {
   foreach (explode(';', $string) as $segment) {
      [$key, $values] = explode(':', $segment, 2);
      array_push($result[$key], ...explode(',', $values));
   }
}

var_export(array_unique($result['id']));
echo "\n---\n";
var_export(array_unique($result['cat']));

P.s。您发布的编码尝试使用组合运算符 .=(赋值和连接)而不是更合适的组合运算符 +=(赋值和数组联合)。