Проблемы с использованием preg_match с текстом из файла - PullRequest
0 голосов
/ 28 апреля 2020

Я пытаюсь сопоставить текст из файла, но preg_match просто не работает.

  • Тип файла: .cfg
  • Кодировка: utf8

Файл содержит только одну строку. Скриншот файла

Мой объект:

public function checkConfig()
{

    $file = dirname(__FILE__) . "log_checker.cfg";
    $handle = fopen($file, "r");
    $file_text = fread($handle, filesize($file));
    fclose($handle);
    if (!$this->checkValidity($file_text)) {
        return;
    }

}
private function checkValidity(string $config_text)
{

    $config_array = explode("\n", $config_text);

    foreach ($config_array as $row) {
        if (preg_match('/^\{\"dirs\"\:\[$/', $row)) {               
            continue;
        }else{
            return false;
        }
    }
     return true;
}

Preg_match просто не работает с $ row, но работает с '{"dirs": ['.

Я пытался изменить кодирование , изменить функцию загрузки файлов и многое другое. PS: я знаю, если в checkValidity может выглядеть лучше с отрицанием, но я показываю только часть кода.

РЕДАКТИРОВАТЬ.

Проблема была в белом символе подряд линии.

1 Ответ

0 голосов
/ 28 апреля 2020

Во-первых, поскольку вы читаете текстовый файл, лучше и проще будет:

$file_text = file_get_contents($file);

Это особенно верно, если файл содержит символы не ascii, закодированные в кодировке UTF-8.

Проблема в вашем текущем логи c. Пока один из элементов массива не пройдёт тест preg_match, вы вернете значение False. Но если строка {"dirs":[ завершается символом новой строки, после "взрыва" вы получите config_array:

Array
(
    [0] => {"dirs":[
    [1] =>
)

И, очевидно, последний элемент указанного массива не пройдет проверку на регулярное выражение.

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

private function checkValidity(string $config_text)
{

    $config_array = explode("\n", $config_text);
    n = count($config_array);
    if (n > 0 && $config_array[n - 1] == '') {
        // remove trailing empty string
        array_splice($config_array, n - 1, 1);
    }

    foreach ($config_array as $row) {
        if (preg_match('/^{"dirs":\[$/', $row)) {               
            continue;
        }else{
            return false;
        }
    }
     return true;
}

Обратите внимание, что регулярное выражение было упрощено выше (вам не нужны все используемые вами escape-символы).

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

private function checkValidity(string $config_text)
{
    return preg_match('/^({"dirs":\[)(?:\n\1)*$/', $config_text) ? True : False);
}

См. Демонстрационное выражение Regex

^               # start of string
(               # start of capture group 1
    {"dirs":\[  # match {"dirs":[
)               # end of capture group 1
(?:             # start of non-capture group
    \n\1        # match newline followed by capture group 1, i.e. \n{"dirs":\[
)*              # end of non-capture group repeated 0 or more times
$               # matches end of string or newline followed by end of string

Но если вы ожидаете только затем одна строка в файле:

private function checkValidity(string $config_text)
{
     return preg_match('/^{"dirs":\[$/', $config_text) ? True : False;
}

$ в регулярном выражении будет соответствовать либо концу строки, либо символу новой строки перед концом строки. Таким образом, приведенное выше регулярное выражение будет соответствовать {"dirs":[ с последующим переводом строки или без него.

...