0

私は Tcl に慣れていて、その単純さが好きなので、次の形式の構成ファイルを作成して解析したいと思います。

block
{
    key1    val1
    key2    val2

    key3
    {
        subkey1 subval1
        subkey2 subval2
    }

    key4
    {
        item1
        item2
        {item3 has spaces in it}
        {item4 {has {bra{ck}ets}} in it}
    }
}

上記の例で期待する PHP 配列は次のとおりです。

[0] => "block",
[1] => (
    [0] => "key1",
    [1] => "val1",
    [2] => "key2",
    [3] => "val2",
    [4] => "key3",
    [5] => (
        [0] => "subkey1",
        [1] => "subval1",
        [2] => "subkey2",
        [3] => "subval2"
    ),
    [6] => "key4",
    [7] => (
        [0] => "item1",
        [1] => "item2",
        [2] => "item3 has spaces in it"
        [3] => (
            [0] => "item4",
            [1] => (
                [0] => "has",
                [1] => "bra{ck}ets"
            ),
            [2] => "in",
            [3] => "it"
    ),
)

blockandの内容をkey3キーと値のペアkey4として、項目の配列 (ネストされたブラケットを折りたたむ)などとして読み取るかどうかは、プログラム次第です。

絶対に中括弧 ( {}) を使用する必要はありません — たとえば、Lisp については何も知りませんが、括弧 ( ()) を使用しているようです (そして、Tcl に影響を与えたようです — 確かにここには関連する歴史がたくさんあります...)、これで問題ありません。

上記の例は一貫していると思いますが、よくわかりません。「(先頭と末尾以外に)空白がない場合は、単一のリテラルエンティティとして扱い、それ以外の場合は配列として扱う」というルールだと思います。

  1. すべてがリストであるこの種のデータの正式な用語はありますか?

  2. これを行うためにPHP関数を書き始める前に、既存の関数または上記の変換を行う巧妙な方法を知っている人はいますか?

アップデート:

@glennjackman は、私の例に一貫性がないことを指摘しています。3 番目のエンティティkey4は次のようになります。

        [2] => (
            [0] => "item3",
            [1] => "has",
            [2] => "spaces",
            [3] => "in",
            [4] => "it",
        ),

残念ながら、これは私が想像していた結果ではありませんでした。さらに考えた結果、私が望むものを得るためには、二重引用符を使用するか、リテラルとして解釈する規則として a に続く空白の欠如を使用するなど、リテラルを示す交互に区別可能な方法を導入する必要があると思います。""{

より洗練された解決策が思いつくまでは、今のところ後者を使用します。つまり、左中括弧の直後に空白以外の文字が続く場合、左中括弧のすべての内容をリテラル文字列と見なします。{

4

3 に答える 3

2

ここに解決策があります...改善できると確信しています..あなたのフォーマットは私にかなりの頭痛を与えましたが、しばらくしてそれをクラックすることができました

使用コード

$string = 'block
    {
        key1    val1
        key2    val2

        key3
        {
            subkey1 subval1
            subkey2 subval2
        }

        key4
        {
            item1
            item2
            {item3 has spaces in it}
            {item4 {has {bra{ck}ets}} in it}
        }

        key5
        {
            This  
            {
                is
                {
                    just
                    {Too Crazy {format}}
                }
            }

        }

    }';

編集前にフォーマットする

echo "<pre>";
print_r(parseTCL($string));

出力

Array
(
    [block] => Array
        (
            [0] => key1
            [1] => val1
            [2] => key2
            [3] => val2
            [key3] => Array
                (
                    [0] => subkey1
                    [1] => subval1
                    [2] => subkey2
                    [3] => subval2
                )

            [key4] => Array
                (
                    [0] => item1
                    [1] => item2
                    [2] => item3 has spaces in it <--- Item 3 not broken
                    [item4] => Array
                        (
                            [0] => has
                            [1] => bra{ck}ets 
                        )

                    [3] => in
                    [4] => it
                )

            [key5] => Array
                (
                    [This] => Array
                        (
                            [is] => Array
                                (
                                    [0] => just
                                    [1] => Too
                                    [Crazy] => Array
                                        (
                                            [0] => format
                                        )

                                )

                        )

                )

        )

)

編集後のフォーマット

echo "<pre>";
print_r(parseTCL($string,true));
                           ^----------- Additional Option included 

出力

 .....

            [key4] => Array
                (
                    [0] => item1
                    [1] => item2
                    [2] => item3  <---------- Item 3 has been broken
                    [3] => has
                    [4] => spaces
                    [5] => in
                    [item4] => Array
                        (
                            [0] => has
                            [1] => bra{ck}ets
                        )

                    [6] => in
                    [7] => it
                )



 .....

使用する機能

function parseTCL($string, $breakCurly = false) {
    $dataArray = $paths = $toks = $final = array();
    $path = $last = "";

    /**
     * Prepare Tokens
     */
    $array = array_map("trim", explode("\n", $string));
    foreach ( new ArrayIterator($array) as $value ) {
        if (strpos($value, " {") !== false) {
            $v = trim($value, " {}");
            $v = str_replace(array(" {","} "), array(" \n{","\n}\n"), $v);
            $v = explode("\n", $v);
            foreach ( $v as $n ) {
                if (strpos($n, "{") !== false && strpos($n, "}") !== false) {
                    $toks[] = $n;
                    continue;
                } else if (strpos($n, "{") !== false) {
                    $toks[] = "{";
                    $toks[] = trim($n, "{");
                } else if (strpos($n, "}") !== false) {
                    $toks[] = "}";
                    $toks[] = trim($n, "}");
                } else {
                    if (strpos($n, " ") !== FALSE) {
                        $v = explode(" ", $n);
                        foreach ( $v as $n ) {
                            $toks[] = $n;
                        }
                    } else {
                        $toks[] = $n;
                    }
                }
            }
            continue;
        }


        if (strpos($value, " ") !== FALSE && (strpos($value, "{") !== 0 || $breakCurly == true)) {
            $breakCurly === true AND $value = trim($value,"{}");
            $v = explode(" ", $value);
            foreach ( $v as $n ) {
                $toks[] = $n;
            }
            continue;
        }
        $toks[] = $value;
    }


    unset($array);

    /**
     * Convert Tokens to Paths
     */
    foreach ( new ArrayIterator($toks) as $tok ) {
        $tok = trim($tok);
        if (empty($tok))
            continue;
        if ($tok == "{") {
            $path .= $last . "/";
            continue;
        }
        if ($tok == "}") {
            $path = substr($path, 0, strrpos(trim($path, "/"), "/")) . "/";
            continue;
        }
        $tok = trim($tok, "{}");
        $paths[] = $path . $tok;
        $last = $tok;
    }

    /**
     * Convert PATH To array
     */
    $cit = new CachingIterator(new ArrayIterator($paths));
    foreach ( $cit as $path ) {
        if (empty($path))
            continue;
        if ($cit->hasNext()) {
            $in = $cit->getInnerIterator()->current();
            if (strpos($in, $path) === 0)
                continue;
        }
        $parts = array_filter(explode("/", $path));
        $value = array_pop($parts);

        $temp = &$dataArray;
        foreach ( $parts as $key ) {
            $temp = &$temp[$key];
        }
        $temp[] = $value;
    }
    unset($paths);
    return $dataArray;
}
于 2012-10-28T03:34:17.190 に答える
1

しばらく時間がかかりましたが、(正規表現を使わずに)解決策を思いつきました。

解決

function list_to_array(&$str, $detect_literals = false)
{
    $arr = array();
    while ($str = ltrim($str))
    {
        if ($str[0] === '{')
        {
            if (!$detect_literals || ctype_space($str[1]))
            {
                $str = substr($str, 1);
                $arr[] = list_to_array($str, $detect_literals);
            }
            else
            {
                $pos = -1;
                do $pos = strpos($str, '}', $pos+1);
                while ($pos && !ctype_space($str[$pos+1]));
                if (!$pos) $pos = strlen($str);
                while ($str[$pos-1] === '}') $pos--;
                $arr[] = substr($str, 1, $pos-1);
                $str = substr($str, $pos+1);
            }
        }
        elseif ($str[0] === '}' && ctype_space(substr(ltrim($str, '}'), 0, 1)))
        {
            $str = substr($str, 1);
            return $arr;
        }
        else
        {
            $pos = strlen(strtok($str, " \t\n\r\0\x0B"));
            while ($str[$pos-1] === '}') $pos--;
            $arr[] = substr($str, 0, $pos);
            $str = substr($str, $pos);
        }
    }

    return $arr;
}

ここでdetect_literals、デフォルトではfalse、すべて{...}が配列として展開され、配列としてtrueのみ展開され{ ...}(空白に注意)、それ以外の場合はリテラルとして展開されます。

簡単なテスト(入力)

元の質問からの入力文字列は次のとおりです。

$str = '
    block
    {
        key1    val1
        key2    val2

        key3
        {
            subkey1 subval1
            subkey2 subval2
        }

        key4
        {
            item1
            item2
            {item3 has spaces in it}
            {item4 {has {bra{ck}ets}} in it}
        }
    }
';

単純なテスト(出力、デフォルト)—期待どおりに見えます

Array
(
    [0] => block
    [1] => Array
        (
            [0] => key1
            [1] => val1
            [2] => key2
            [3] => val2
            [4] => key3
            [5] => Array
                (
                    [0] => subkey1
                    [1] => subval1
                    [2] => subkey2
                    [3] => subval2
                )

            [6] => key4
            [7] => Array
                (
                    [0] => item1
                    [1] => item2
                    [2] => Array
                        (
                            [0] => item3
                            [1] => has
                            [2] => spaces
                            [3] => in
                            [4] => it
                        )

                    [3] => Array
                        (
                            [0] => item4
                            [1] => Array
                                (
                                    [0] => has
                                    [1] => Array
                                        (
                                            [0] => bra{ck}ets
                                        )

                                )

                            [2] => in
                            [3] => it
                        )

                )

        )

)

単純なテスト(出力、リテラルの検出)—期待どおりに見えます

Array
(
    [0] => block
    [1] => Array
        (
            [0] => key1
            [1] => val1
            [2] => key2
            [3] => val2
            [4] => key3
            [5] => Array
                (
                    [0] => subkey1
                    [1] => subval1
                    [2] => subkey2
                    [3] => subval2
                )

            [6] => key4
            [7] => Array
                (
                    [0] => item1
                    [1] => item2
                    [2] => item3 has spaces in it
                    [3] => item4 {has {bra{ck}ets
                )

            [8] => in
            [9] => it
        )

)

[3] => item4 {has {bra{ck}etsリテラルを検出するための規則は次のとおりであるため、正しいことに注意してください。 (1)中括弧の後に空白以外の文字が続くものと、(2)最初の中括弧の後に空白文字が続くものつまり中括弧内のすべてリテラルは無視されます。

複雑なテスト(入力)

堅牢性をテストするために、次の文字列も試しました。

$str = '
    a
    {
    }
    {}
    {}{}
    {
        b
        {
        }
    }
    {
        {}
        c
    }
    {
        { {{ {d}} }}
    }
    {
        e{f
        g}h
        ij{
        }kl
        mn}
    {
        {op}}
    {qrs
';

複雑なテスト(出力、デフォルト)—期待どおりに見えます

Array
(
    [0] => a
    [1] => Array
        (
        )

    [2] => Array
        (
        )

    [3] => Array
        (
            [0] => }{
        )

    [4] => Array
        (
            [0] => b
            [1] => Array
                (
                )

        )

    [5] => Array
        (
            [0] => Array
                (
                )

            [1] => c
        )

    [6] => Array
        (
            [0] => Array
                (
                    [0] => Array
                        (
                            [0] => Array
                                (
                                    [0] => Array
                                        (
                                            [0] => d
                                        )

                                )

                        )

                )

        )

    [7] => Array
        (
            [0] => e{f
            [1] => g}h
            [2] => ij{
            [3] => }kl
            [4] => mn
        )

    [8] => Array
        (
            [0] => Array
                (
                    [0] => op
                )

        )

    [9] => Array
        (
            [0] => qrs
        )

)

複雑なテスト(出力、リテラルの検出)—期待どおりに見えます

Array
(
    [0] => a
    [1] => Array
        (
        )

    [2] => 
    [3] => }{
    [4] => Array
        (
            [0] => b
            [1] => Array
                (
                )

        )

    [5] => Array
        (
            [0] => 
            [1] => c
        )

    [6] => Array
        (
            [0] => Array
                (
                    [0] => { {d
                )

        )

)

リテラルは空白が続く[0] => { {dとすぐに閉じられるため、これは正しいことに注意してください。}結果として、次}のsは配列の終わりとして処理され、早期終了になり、入力文字列の一部が未処理のままになります。

        }
        {
            e{f
            g}h
            ij{
            }kl
            mn}
        {
            {op}}
        {qrs
于 2012-10-28T08:53:48.953 に答える
0

答えではありませんが、コメントよりも多くのフォーマットが必要です

これは難しい問題です。あなたが見るとき

    item2
    {item3 has spaces in it}

どのように生産を決定しますか

    [1] => "item2",
    [2] => "item3 has spaces in it"

それ以外の

    [1] => "item2",
    [2] => (
            [0] => "item3",
            [1] => "has"
            [2] => "spaces"
            [3] => "in"
            [4] => "it"
        ),

??

リストが本当にリストなのか単なる文字列なのかを判断するために、ドキュメントの構造に依存していますか? それは改行の存在ですか、それとも行に2つの単語しかないなどですか?

于 2012-10-28T01:51:33.400 に答える