Удаление допустимых пробелов в PHP с использованием токенов парсера - PullRequest
4 голосов
/ 05 февраля 2011

Я пытаюсь создать простой скрипт, который удалит все ненужные пробелы из файла / строки PHP.

Мне удалось проанализировать строку с помощью токенов, но я не вижу хорошего способа удалить «лишние» пробелы.

Например,

function test() { return TRUE; }

должно быть

function test(){return TRUE;}

а НЕ

functiontest(){returnTRUE;}

Вы получите последнюю версию, если просто удалите токен T_WHITESPACE.

Есть ли что-то, чего мне не хватает, чтобы удалить пробелы, но оставляйте пробелы после таких вещей, как «функция» и «возврат». Спасибо!

Ответы [ 3 ]

3 голосов
/ 05 февраля 2011
$newSource = '';
foreach (token_get_all($source) as $i => $token) {
    if (!is_array($token)) {
        $newSource .= $token;
    }

    if ($token[0] == T_WHITESPACE) {
        if (   isset($tokens[$i - 1])      && isset($tokens[$i + 1])
            && is_array($tokens[$i - 1])   && is_array($tokens[$i + 1])
            && isLabel($tokens[$i - 1][1]) && isLabel($tokens[$i + 1][1])
        ) {
            $newSource .= ' ';
        }
    } else {
        $newSource .= $token[1];
    }
}

function isLabel($str) {
    return preg_match('~^[a-zA-Z0-9_\x7f-\xff]+$~', $str);
}

Удаление пробела всегда разрешено, за исключением случая, когда по обеим сторонам есть LABEL. Я проверяю это и либо ничего не добавляю, либо один пробел.

Есть еще один особый случай, о котором я знаю, пробелы важны: за T_END_HEREDOC должен следовать либо ;, либо \n Уплотнение или зачистка пространства здесь не допускаются. Так что, если это важно для вас, вы можете просто добавить это;)

1 голос
/ 05 февраля 2011

Ваши усилия бесполезны.

php -w

Позволяет уже удалять пробелы из сценариев. Он использует немного более сложную логику для удаления пробелов из потока токенов.
Вот функция zend_strip(), найденная в zend_highlight.c:

while ((token_type=lex_scan(&token TSRMLS_CC))) {
    switch (token_type) {
        case T_WHITESPACE:
            if (!prev_space) {
                zend_write(" ", sizeof(" ") - 1);
                prev_space = 1;
            }
                    /* lack of break; is intentional */
        case T_COMMENT:
        case T_DOC_COMMENT:
            token.type = 0;
            continue;

        case T_END_HEREDOC:
            zend_write(LANG_SCNG(yy_text), LANG_SCNG(yy_leng));
            efree(token.value.str.val);
            /* read the following character, either newline or ; */
            if (lex_scan(&token TSRMLS_CC) != T_WHITESPACE) {
                zend_write(LANG_SCNG(yy_text), LANG_SCNG(yy_leng));
            }
            zend_write("\n", sizeof("\n") - 1);
            prev_space = 1;
            token.type = 0;
            continue;

        default:
            zend_write(LANG_SCNG(yy_text), LANG_SCNG(yy_leng));
            break;
    }

    if (token.type == IS_STRING) {
        switch (token_type) {
            case T_OPEN_TAG:
            case T_OPEN_TAG_WITH_ECHO:
            case T_CLOSE_TAG:
            case T_WHITESPACE:
            case T_COMMENT:
            case T_DOC_COMMENT:
                break;

            default:
                efree(token.value.str.val);
                break;
        }
    }
    prev_space = token.type = 0;
}
1 голос
/ 05 февраля 2011

Ну, T_WHITESPACE может быть пробелами или символами новой строки и т. Д. Таким образом, одним из тривиальных подходов будет автоматическая замена всех T_WHITESPACE экземпляров на новый, состоящий ровно из одного пробела.

Но для более разумного метода просто пройдите список токенов парсера и выясните, какие из них должны иметь пробел, а какие - нет (что-то вроде этого):

foreach ($tokens as $k => $val) {
    if (is_array($val) && $val[0] == T_WHITESPACE) {
        if (!is_array($tokens[$k - 1])) {
            //remove this space
        } else {
            switch ($tokens[$k - 1][0]) {
                case T_ABSTRACT:
                case T_FUNCTION:
                //.. other keeps here:
                   continue;
                   break;
                default:
                    //remove the space
             }
         }
    }
}

И еще одно замечание, не делайте этого ради производительности.Если вы используете OPCODE Cache (например, APC), вы не увидите никакой пользы для большой работы.Если вы не используете один, почему нет?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...