3

要するに、構文解析の目的で、角かっこ/引用符を追加して基本的なコード修正を試みる関数が必要でした。つまり、結果のコードは実行可能であるとは期待されていません。

いくつかの例を見てみましょう。

[1] class Aaa { $var a = "hi";       =>  class Aaa { $var a = "hi"; }
[2] $var a = "hi"; }                 =>  { $var a = "hi"; }
[3] class { a = "hi; function b( }   =>  class { a = "hi; function b( }"}
[4] class { a = "hi"; function b( }  =>  class { a = "hi"; function b() {}}

PS:上記の4番目の例は非常に複雑に見えますが、実際には非常に簡単です。エンジンがスタックと一致しない終了ブラケットトークンを見つけた場合、そのトークンの前の反対のトークンである必要があります。ご覧のとおり、これはかなりうまく機能します。


関数シグネチャとしては、次のようになります。balanceTokens($code, $bracket_tokens, $quote_tokens)

私が書いた関数はスタックを使って動作します。まあ、それは正確には機能しません、スタックを使用します。

function balanceTokens($code, $bracket_tokens, $quote_tokens){
    $stack = array(); $last = null; $result = '';
    foreach(str_split($code) as $c){
        if($last==$c && in_array($c, $quote_tokens)){
            // handle closing string
            array_pop($stack);
        }elseif(!in_array($last, $quote_tokens)){
            // handle other tokens
            if(isset($bracket_tokens[$c])){
                // handle begining bracket
                $stack[] = $c;
            }elseif(($p = array_search($c, $bracket_tokens)) != false){
                // handle ending bracket
                $l = array_pop($stack);   
                if($l != $p)$result .= $p;
            }elseif(isset($quote_tokens[$c])){
                // handle begining quote
                $stack[] = $c;
                $last = $c;
            }// else other token...
        }
        $result .= $c;
    }
    // perform fixes
    foreach($stack as $token){
        // fix ending brackets
        if(isset($bracket_tokens[$token]))
            $result .= $bracket_tokens[$token];
        // fix begining brackets
        if(in_array($token, $bracket_tokens))
            $result = $token . $result;
    }
    return $result;
}

この関数は次のように呼び出されます。

$new_code = balanceTokens(
    $old_code,
    array(
        '<' => '>',
        '{' => '}',
        '(' => ')',
        '[' => ']',
    ),
    array(
        '"' => '"',
        "'" => "'",
    )
);

はい、それは非常に一般的であり、ハードコードされたトークンはありません。

なぜそれが機能しないのか、私には少しもわかりません...実際のところ、それが機能するかどうかさえわかりません。私はそれを書くことにあまり考えていなかったことを認めます。多分私が見ていない明らかな問題があります。

4

2 に答える 2

2

代替の実装(より積極的なバランシングを行う):

function balanceTokens($code) {
    $tokens = [
        '{' => '}',
        '[' => ']',
        '(' => ')',
        '"' => '"',
        "'" => "'",
    ];
    $closeTokens = array_flip($tokens);
    $stringTokens = ['"' => true, '"' => true];

    $stack = [];
    for ($i = 0, $l = strlen($code); $i < $l; ++$i) {
        $c = $code[$i];

        // push opening tokens to the stack (for " and ' only if there is no " or ' opened yet)
        if (isset($tokens[$c]) && (!isset($stringTokens[$c]) || end($stack) != $c)) {
            $stack[] = $c;
        // closing tokens have to be matched up with the stack elements
        } elseif (isset($closeTokens[$c])) {
            $matched = false;

            while ($top = array_pop($stack)) {
                // stack has matching opening for current closing
                if ($top == $closeTokens[$c]) {
                    $matched = true;
                    break;
                }

                // stack has unmatched opening, insert closing at current pos
                $code = substr_replace($code, $tokens[$top], $i, 0);
                $i++;
                $l++;
            }

            // unmatched closing, insert opening at start
            if (!$matched) {
                $code = $closeTokens[$c] . $code;
                $i++;
                $l++;
            }
        }
    }

    // any elements still on the stack are unmatched opening, so insert closing
    while ($top = array_pop($stack)) {
        $code .= $tokens[$top];
    }

    return $code;
}

いくつかの例:

$tests = array(
    'class Aaa { public $a = "hi";',
    '$var = "hi"; }',
    'class { a = "hi; function b( }',
    'class { a = "hi"; function b( }',
    'foo { bar[foo="test',
    'bar { bar[foo="test] { bar: "rgba(0, 0, 0, 0.1}',
);

それらを関数に渡すと、次のようになります。

class Aaa { public $a = "hi";}
{$var = "hi"; }
class { a = "hi; function b( )"}
class { a = "hi"; function b( )}
foo { bar[foo="test"]}
bar { bar[foo="test"] { bar: "rgba(0, 0, 0, 0.1)"}}
于 2012-06-18T00:22:07.373 に答える
0

コーヒーを飲んだ後:)、私は(ある程度)機能するプロトタイプ関数を思いついた。

ここで実際の動作を確認できます。ただし、いくつかの(光沢のある)デバッグ出力を追加するために少し変更されています。

    /**
     * Fix some possible issues with the code (eg, incompleteness).
     * @param string $code The code to sanitize.
     * @param array $bracket_tokens List of bracket tokens where the index is the begin bracket and the value is the end bracket.
     * @param array $quote_tokens List of quote tokens where the index is the begin quote and the value is the end quote.
     * @return string The sanitized code.
     */
    function css_sanitize($code, $bracket_tokens, $quote_tokens){
        $result = '';
        $stack = array();
        $last = '';
        foreach(str_split($code) as $c){
            if(in_array($c, $quote_tokens) && $last==$c){
                array_pop($stack);
                $last = '';
            }elseif(!in_array($last, $quote_tokens)){
                if(isset($bracket_tokens[$c])){
                    $stack[] = $c;
                }elseif(($p = array_search($c, $bracket_tokens)) != false){
                    if($last != $c){
                        $result .= $p;
                    }else{
                        array_pop($stack);
                        $last = (($p = count($stack)) > 1) ? $stack[$p] : '';
                    }
                }elseif(isset($quote_tokens[$c])){
                    $stack[] = $c;
                    $last = $c;
                }
            }
            $result .= $c;
        }
        foreach(array_reverse($stack) as $token){
            if(isset($bracket_tokens[$token])){
                $result .= $bracket_tokens[$token];
            }
            if(in_array($token, $bracket_tokens)){
                $result = $token . $result;
            }
            if(isset($quote_tokens[$token])){
                $result .= $quote_tokens[$token];
            }
        }
        return $result;
    }
于 2012-06-17T23:16:12.060 に答える