文本文件内容包含子级别的数组

时间:2018-09-18 07:01:04

标签: php arrays

我有一个文件(200多行),其中包含以下设备类别。我需要将文件转换为sql才能将其插入数据库。

Video / Camera
Video / Camera / 4K
Video / Other
Other
Other / sub1
Other / sub2
Other / Camera

类别可以具有子类别(最多可以包含10个子类别),这些子类别可能具有与其他名称相同的名称,例如“视频”具有“摄像机”类别,“其他”也是如此(这不是真实数据)。我正在寻找的输出是:

INSERT INTO `category` (`id`, `name`, `parent`) VALUES
(1, 'VIDEO', NULL),
(2, 'CAMERA', 1),
(3, '4K', 2),
(4, 'OTHER', 1),
(5, 'OTHER', NULL),
(6, 'sub1', 5);

我没有指望我制作了多少个版本,但这是最后一个无法按需工作的版本,我还认为代码可以变得更轻巧...

<?php
$level = array();

function doesCategoryExist($data, $level, $prevlevel, $name, $prevname) {
  if (empty($data)) {
    return array(0, 'null');
  }
  foreach ($data as &$value) {
    if ($name == $value['name']) {
      if ($level == $value['level']) {
        return array(1, 0);
      } else {
        return array(0, 'null');
      }
    } else {
      if ($prevname == $value['name'] && $prevlevel == $value['level']) {
        return array(0, $value['id']);
      }
    }
  }
}


$data = array();
$counter = 1;
foreach (new SplFileObject('/home/username/categories5.txt') as $line) {
  $tmp = explode(" / ", trim($line));
  for ($x = 0; $x < count($tmp); $x++) {
    if ($tmp[$x] != "") {
      if ($x == 0) {
        $data2 = doesCategoryExist($data, $x, 0, $tmp[$x], '');
      } else {
        $data2 = doesCategoryExist($data, $x, $x-1, $tmp[$x], $tmp[$x-1]);
      }
      if ($data2[0] == 0) {
         $data[] = array('level'=>$x,'id'=>$counter,'name'=>$tmp[$x],'parent'=>$data2[1]);
         $counter++;
      } else {
         if ($data2[1]!=0){
           $data[] = array('level'=>$x,'id'=>$counter,'name'=>$tmp[$x],'parent'=>'null');
           $counter++;
         }
      }
    }
  }
}
print_r($data);
?>

有什么建议吗?

1 个答案:

答案 0 :(得分:0)

您可以使用以下内容作为起点。它有两个功能,一个用于解析输入文件(返回嵌套数组)。另一个将结构映射到有用的东西。

<?php
declare(strict_types=1);

error_reporting(-1);
ini_set('display_errors', 'On');

/**
 * @param string $input
 * @param string $branchSeparator
 * @param string $lineSeparator
 *
 * @return array
 */
function buildMap(string $input, string $branchSeparator = '/', string $lineSeparator = "\n"): array {
    $result = [
        'id' => null,
        'children' => [],
    ];
    $id = 1;

    foreach (explode($lineSeparator, $input) as $line) {
        $path = array_map('trim', explode($branchSeparator, $line));

        $parent =& $result;
        foreach ($path as $branch) {
            if (!array_key_exists($branch, $parent['children'])) {
                $parent['children'][$branch] = [
                    'id' => $id++,
                    'parent' => $parent['id'],
                    'children' => [],
                ];
            }

            $parent =& $parent['children'][$branch];
        }
    }

    return $result['children'];
}

/**
 * Map the structure from `buildMap` to a flat array using a supplied render function.
 * 
 * @param array    $map
 * @param callable $renderer
 * @param array    $result
 *
 * @return array
 */
function mapToValues(array $map, callable $renderer, array &$result = []): array {
    foreach ($map as $key => $def) {
        $result[] = $renderer($def['id'], $key, $def['parent']);

        if (\count($def['children']) > 0) {
            $result = mapToValues($def['children'], $renderer, $result);
        }
    }

    return $result;
}

// $input = file_get_contents('/home/username/categories5.txt');
$input = <<<DATA
Video / Camera
Video / Camera / 4K
Video / Other
Other
Other / sub1
Other / sub2
Other / Camera
DATA;

$map = buildMap($input);

$sql = sprintf(
    'INSERT INTO `category` (`id`, `name`, `parent`) VALUES %s',
    implode(', ', mapToValues($map, function (int $id, string $name, ?int $parent = null) {
        return sprintf(
            "(%d, '%s', %s)",
            $id,
            $name, // do some escaping here!
            $parent ?? 'NULL'
        );
    }))
);

echo $sql;

演示:https://3v4l.org/I5qk2