0

我想创建一个类,用于将平面文件数据库信息解析为一个大型的类似多维数组。我想到了将数据库格式化为一种 python-esque 格式,如下所示:

"tree #1":
    "key" "value"
    "sub-tree #1":
        "key" "value"
        "key #2" "value"
        "key #3" "value"

我试图让它解析这个并构建和数组,同时解析它以将键/值投入其中,我希望它非常动态和可扩展。我尝试了许多不同的技术,但每次尝试都被难住了。这是我最近的:

function parse($file=null) {
    $file = $file ? $file : $this->dbfile;

    ### character variables

    # get values of 
    $src = file_get_contents($file);
    # current character number
    $p = 0;

    ### array variables

    # temp shit
    $a = array();
    # set $ln keys
    $ln = array("q"=>0,"k"=>null,"v"=>null,"s"=>null,"p"=>null);
    # indent level
    $ilvl = 0;

    ### go time

    while (strlen($src) > $p) {
        $chr = $src[$p];
        # quote
        if ($chr == "\"") {
            if ($ln["q"] == 1) { // quote open?
                $ln["q"] = 0; // close it
                if (!$ln["k"]) { // key yet?
                    $ln["k"] = $ln["s"]; // set key
                    $ln["s"] = null;
                    $a[$ln["k"]] = $ln["v"]; // write to current array
                } else { // value time
                    $ln["v"] = $ln["s"]; // set value
                    $ln["s"] = null;
                }
            } else {
                $ln["q"] = 1; // open quote
            }
        }

        elseif ($chr == "\n" && $ln["q"] == 0) {
            $ln = array("q"=>0,"k"=>null,"v"=>null,"s"=>null,"p"=>null);
            $llvl = $ilvl;

        }
        # beginning of subset
        elseif ($chr == ":" && $ln["q"] == 0) {
            $ilvl++;
            if (!array_key_exists($ilvl,$a)) { $a[$ilvl] = array(); }
            $a[$ilvl][$ln["k"]] = array("@mbdb-parent"=> $ilvl-1 .":".$ln["k"]);
            $ln = array("q"=>0,"k"=>null,"v"=>null,"s"=>null,"p"=>null);
            $this->debug("INDENT++",$ilvl);
        }
        # end of subset
        elseif ($chr == "}") {
            $ilvl--;
            $this->debug("INDENT--",$ilvl);
        }
        # other characters
        else {
            if ($ln["q"] == 1) {
                $ln["s"] .= $chr;
            } else {
                # error
            }
        }
        $p++;
    }
    var_dump($a);
}

老实说,我不知道从这里去哪里。最困扰我的是设置多维值,就像$this->c["main"]["sub"]["etc"]我在这里的方式一样。甚至可以做到吗?当数据嵌套在 db 文件中时,如何实际嵌套数组?

4

2 回答 2

1

这一切都将取决于您希望“平面文件”的可读性如何。

想要人类可读?

  • XML
  • yaml

半人类可读?

  • JSON

不是真正的人类可读?

  • 序列化 PHP(也仅限 PHP)
  • mysql转储

编写自己的格式会很痛苦。除非您想纯粹为了学术经验而这样做,否则我说不要打扰。

看起来 JSON 对你来说可能是一个快乐的媒介。

$configData = array(
    'tree #1' => array(
        'key'         => 'value'
      , 'sub-tree #1' => array(
          'key'    => 'value'
        , 'key #2' => 'value'
        , 'key #3' => 'value'
      )
  )
);

//  Save config data
file_put_contents( 'path/to/config.json', json_format( json_encode( $configData ) ) );

//  Load it back out
$configData = json_decode( file_get_contents( 'path/to/config.json' ), true );

//  Change something
$configData['tree #1']['sub-tree #1']['key #2'] = 'foo';

//  Re-Save (same as above)
file_put_contents( 'path/to/config.json', json_format( json_encode( $configData ) ) );

你可以在这里json_format()得到这个函数,它只是为了便于人类阅读而进行了漂亮的格式化。如果你不关心人类可读性,你可以跳过它。

于 2009-12-11T23:42:55.640 回答
0

好吧,您可以使用序列化反序列化,但这并不好玩,对吧?您应该使用专门为此目的设计的格式,但为了练习,我会尝试看看我能想出什么。

您的平面文件中似乎有两种数据类型,键值对和数组。键值对用两组引号和数组表示,一组引号和一个冒号。在浏览文件时,您必须解析每一行并确定它代表什么。使用正则表达式很容易。困难的部分是跟踪我们正在达到的水平并采取相应的行动。这是一个解析您提供的树的函数:

function parse_flatfile($filename) {
    $file = file($filename);

    $result = array();
    $open = false;
    foreach($file as $row) {
        $level = strlen($row) - strlen(ltrim($row));
        $row = rtrim($row);
        // Regular expression to catch key-value pairs
        $isKeyValue = preg_match('/"(.*?)" "(.*?)"$/', $row, $match);        
        if($isKeyValue == 1) {
            if($open && $open['level'] < $level) {
                $open['item'][$match[1]] = $match[2];
            } else {
                $open = array('level' => $level - 1, 'item' => &$open['parent']);                
                if($open) {
                    $open['item'][$match[1]] = $match[2];
                } else {
                    $result[$match[1]] = $match[2];
                }
            }
        // Regular expression to catch arrays
        } elseif(($isArray = preg_match('/"(.*?)":$/', $row, $match)) > 0) {
            if($open && $open['level'] < $level) {
                $open['item'][$match[1]] = array();
                $open = array('level' => $level, 'item' => &$open['item'][$match[1]], 'parent' => &$open['item']);
            } else {
                $result[$match[1]] = array();
                $open = array('level' => $level, 'item' => &$result[$match[1]], 'parent' => false);
            }
        }    
    }    
    return $result;
}

我不会更详细地介绍它是如何工作的,但它很简短,随着我们深入到数组中,上一层存储在引用中$open,依此类推。这是使用您的符号的更复杂的树:

"tree_1":
    "key" "value"
    "sub_tree_1":
        "key" "value"
        "key_2" "value"
        "key_3" "value"
    "key_4" "value"
    "key_5" "value"
"tree_2":
   "key_6" "value"
    "sub_tree_2":
        "sub_tree_3":
            "sub_tree_4":
                "key_6" "value"
                "key_7" "value"
                "key_8" "value"
                "key_9" "value"
                "key_10" "value"

要解析该文件,您可以使用:

$result = parse_flatfile('flat.txt');
print_r($result);

这将输出:

Array
(
[tree_1] => Array
    (
    [key] => value
    [sub_tree_1] => Array
        (
        [key] => value
        [key_2] => value
        [key_3] => value
        )    
    [key_4] => value
    [key_5] => value
    )    
[tree_2] => Array
    (
    [key_6] => value
    [sub_tree_2] => Array
        (
        [sub_tree_3] => Array
            (
            [sub_tree_4] => Array
                (
                [key_6] => value
                [key_7] => value
                [key_8] => value
                [key_9] => value
                [key_10] => value
                )    
            )    
        )    
    )    
)

我想我的测试文件涵盖了所有的基础,它应该可以正常工作而不会破坏。但我不会给出任何保证。

使用此表示法将多维数组转换为平面文件将留给读者作为练习:)

于 2009-12-11T23:35:38.077 回答