Найдите назначение в условии, используя регулярное выражение

Мне нужно регулярное выражение, с помощью которого я мог бы найти, есть ли какие-либо назначения внутри условий.

Он должен быть максимально гибким, потому что я буду запускать его на многих файлах .php, чтобы найти такие ошибки:

<?php
if ($foo = "bar") { // instead of $foo == "bar"
    //...
}

Я нашел вопрос, похожий на мой, который помог мне решить проблему с помощью этого регулярного выражения:

/if\s*\(.+[^!=<>]=[^=]/

Однако он также соответствует тому, где внутри строки есть знак '=', а это не то, что мне нужно:

<?php
if ($foo != '=') {
    //...
}

Обратите внимание, что он также должен работать в сложных условиях со множеством сравнений, таких как:

if ($foo == 0 && ($bar == 1 || $fooBar = 1) { // Instead of $fooBar == 1
    // ...
}

Найти это регулярное выражение довольно сложно, и я был бы очень благодарен, если бы мне помогли!

Спасибо @Ultimer, я никогда не думал, что PHP не станет обычным языком. Я узнаю, как использовать токенизаторы, если это лучшая альтернатива!

Kolobo 19.06.2024 16:15

Я думаю, вы не найдете ни одного регулярного выражения, которое делало бы то, что вы хотите. Я бы предложил какой-то оператор grep for if, в котором в каждой выходной строке указывается имя файла, номер строки и текст строки. Затем удалите все == и '=' из результатов. (Замена их на __EQEQ__, __CHAR_EQ__ и т. д. может быть лучше, чтобы отличить действительные от потенциально недействительных.) Затем удалите все найденные строки без =. Вы можете увидеть другие распространенные действительные шаблоны, которые можно исключить. Остальные строки должны содержать выражения, которые вы хотите найти, а также другие допустимые выражения.

AdrianHHH 19.06.2024 22:04
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
3
103
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы можете попробовать ограничить набор символов, идентифицирующих имя переменной, чтобы не использовать ., который также включает знаки равенства:

if\s*\([$\w-]+\s*[^!=<>]=[^=]

Если в ваших условиях всегда есть переменная и если вы используете несколько условий, например if ($foo == "bar" && $tmp = 'tmp'), вы можете сократить регулярное выражение следующим образом:

[$\w-]+\s*[^!=<>]=[^=]

Это хорошее предложение, спасибо! Но это не работает со сложными условиями со множеством сравнений. Добавлю уточнения к своему вопросу. Могу ли я спросить, почему вы используете группу захвата для «=» и почему вы указываете, что есть только одна открывающая скобка \({1}? Кроме того, в чем польза квантификатора {1,1}?

Kolobo 19.06.2024 15:48

На самом деле, я начал с регулярного выражения ответа на вопрос, который вы связали. Все три вещи, которые вы перечислили, лишние и их можно убрать. Можете ли вы добавить несколько примеров сложных условий, которые вы используете?

Giulia Santoiemma 19.06.2024 15:54

Вы можете использовать это

/if\s*\(\s*[^!=<>\n]*=[^=\n]*\)/

Пример

К вашему сведению: я не знаю, что вы пытаетесь заархивировать. Я предложил решение, основанное на вашем вопросе. (Регулярное выражение)

Он работает хорошо, но не работает с условиями, требующими более одного сравнения. Моя вина, мне следовало быть более точным. Должен ли я подробно рассказать, почему и как я буду это использовать? Я подумал, что будет проще сразу перейти к делу.

Kolobo 19.06.2024 16:12
Ответ принят как подходящий

Первоначальная цель — просмотреть файлы PHP и найти назначения внутри условий.

Мой первый подход заключался в использовании регулярных выражений. Однако PHP не является обычным языком, поэтому нам не следует использовать с ним регулярные выражения. (Я не считаю, что демонстрация необходима, дайте мне знать, если она нужна)

Решение, которое я нашел, включает простой цикл с использованием токенизаторов . Поделюсь, вдруг кому-то будет полезно.

$path = 'path/to/file.php';
$content = file_get_contents($path);
$tokens = token_get_all($content);

$inCondition = false;
$parenthesis = 0;

foreach ($tokens as $token) {
    if (is_array($token)) {
        $token = $token[1];
    }

    switch ($token) {
        case 'if':
            $inCondition = true;
            break;
        case '(' :
            if ($inCondition) {
                $parenthesis++;
            }
            break;
        case '=':
            if ($inCondition && $parenthesis === 1) {
                throw new Exception("Assignment in if condition !");
            }
            break;
        case ')':
            if ($inCondition) {
                $parenthesis--;
                if ($parenthesis === 0) {
                    $inCondition = false;
                }
            }
            break;
    }
}

Я считаю, что этот пример кода можно было бы улучшить, но он работает очень хорошо!

Другие вопросы по теме