Поиск всех типов разделителей конца строки в файле

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

function ddtt_get_file_eol( $file_contents, $incl_code = true ) {
    $types = [
        '\r\n',
        '\n',
        '\r'
    ];
    $found = [];
    foreach ( $types as $type ) {
        if ( $type == '\r\n' ) {
            $regex = "/\r\n/";
        } elseif ( $type == '\n' ) {
            $regex = "/(?<!\r)\n/";
        } else {
            $regex = "/\r(?!\n)/";
        }
        if ( preg_match( $regex, $file_contents ) ) {
            $found[] = ( $incl_code ) ? '<code class = "hl">'.$type.'</code>' : $type;
        }
    }
    return $found;
} // End ddtt_get_php_eol()

Проблема, с которой я столкнулся, заключается в том, что он распознает \r\n как два отдельных типа и выводит [ '\n', '\r' ]. Я хочу вывести [ '\r\n' ], если он использует только этот тип, или [ '\r\n', '\n' ], если используются оба типа и т. д. Как мне изменить свой код, чтобы правильно получать все используемые типы?

Просто замечание к вашему коду: ваш массив типов можно записать как массив с ключами, а не как простой массив. Это позволит избежать этого if, elseif, else. Ключом может быть тип и значение регулярного выражения.

Patrick Janser 24.06.2024 21:01

Такой результат может получиться, если файл представляет собой смесь обоих типов окончания строк. К сожалению, у меня было такое несколько раз, когда я работал над некоторыми крупными проектами на Git, когда пользователи работали в Windows, другие — в Linux, и репозиторий Git не был настроен должным образом для автоматического преобразования окончаний строк при коммитах. Будет ли этот результат получен, если вы отредактируете несколько тестовых файлов, в которых используете только один тип окончания строк?

Patrick Janser 24.06.2024 21:06

Я не могу воспроизвести проблему. Когда я звоню ddtt_get_file_eol("foo\r\nbar\r\n", false), я получаю только ["\r\n"]. Предоставьте образец входных данных, который дал неверный результат.

Barmar 24.06.2024 21:10

@PatrickJanser Им нужен такой результат, если в файле есть разные разрывы строк. Вот почему он возвращает массив.

Barmar 24.06.2024 21:13

@Barmar: Да, я понял, что этого хочет Аристокл. Но мой вопрос состоит в том, чтобы убедиться, что он действительно тестирует файл, имеющий оба окончания строк, и что это не может быть ошибкой в ​​его функции.

Patrick Janser 24.06.2024 21:20

Точно. Вот почему я попросил образец ввода.

Barmar 24.06.2024 21:21

Ладно, я слишком долго шел к этому и не думал возвращаться к основам. Я протестировал код с тем, что использовал @Barmar, и он отлично работает во всех случаях. Значит, с моим кодом что-то еще не так. Я пытаюсь обновить файл, который разбивает строки на массив, обновляет определенные строки, а затем объединяет их обратно в строку. При этом я использую это, чтобы определить, какой разделитель eol используется, чтобы я мог поддерживать те же разделители, но выдавать предупреждение, если используются смешанные eol-разделители. Если это имеет смысл.

Aristocles 24.06.2024 21:44

Спасибо @PatrickJanser за предложение по вводу массива. Изначально я так и сделал, и на протяжении всего тестирования я просто делал оператор if и не возвращался назад. 👍

Aristocles 24.06.2024 21:45

В Википедии есть страница о различных стилях новой строки, на ней есть LF-CR, которого нет в вашем списке. Несколько лет назад я использовал систему, использующую CR-CR-LF, ее тоже нет в вашем списке. Чтобы частично ответить на ваш вопрос, я бы поискал вхождения [\r\n]+ и добавил их в список $types.

AdrianHHH 24.06.2024 21:54

Честно говоря, если ваш ввод смешивает разные типы окончания строк, это проблема, которую нужно решить, в идеале в источнике, а не танцевать в коде.

Sammitch 24.06.2024 21:58

@Sammitch: к сожалению, это случается чаще, чем можно было бы подумать. Его инструмент мог бы эффективно возвращать результат сразу после первого совпадения, а не проверять все случаи, чтобы быть более эффективным. Но это было бы неправильно. Тестирование всех типов окончания строк кажется хорошим способом сделать это. Даже такие инструменты Linux, как file, вернут информацию о нескольких типах окончания строк, если они смешаны.

Patrick Janser 24.06.2024 22:06

@Саммитч, верно, поэтому я обнаруживаю это и предупреждаю. Чего я не упомянул, так это того, что когда я соберу его обратно, он будет использовать только один тип, указанный пользователем, но будет рекомендовать текущее значение PHP_EOL, если пользователь не знает, какой из них выбрать.

Aristocles 24.06.2024 22:07

@Aris Я не понимаю, почему мой ответ помечен как бесполезный, но если вы собираетесь очистить и обеспечить согласованность последовательностей новой строки, \R - это именно то решение. Сопоставьте все символы \R, затем замените их предпочтительной последовательностью новой строки — готово и без каких-либо ошибок.

mickmackusa 25.06.2024 23:28
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать 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
13
94
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

На мой взгляд, ваш код в порядке. Это просто ваш вклад, который представляет собой смесь.

<?php

$LINE_TYPES = [
    '\\r\\n' => '/\\r\\n/',
    '\\n' => '/(?<!\\r)\\n/',
    '\\r' => '/\\r(?!\\n)/',
];

$inputs = [
    'Windows' => "Dog\r\nCat\r\nMouse",
    'Linux' => "Bicycle\nCar\nTrain\nAirplane",
    'Mac' => "iPhone\riPod\rMacBook",
    'Win + Linux' => "int main() {\n   return 0;\r\n}\n",
    'All mixed up' => "This is a Windows new line\r\n, followed by a Linux new line\n and finally an old Mac with a single carriage return\rat the end",
];

foreach ($inputs as $label => $input) {
    $found_types = [];
    foreach ($LINE_TYPES as $type => $regex) {
        if (preg_match($regex, $input)) {
            $found_types[] = $type;
        }
    }
    print "Found types for $label is " . implode(', ', $found_types) . PHP_EOL;
}

Выводит следующее:

Found types for Windows is \r\n
Found types for Linux is \n
Found types for Mac is \r
Found types for Win + Linux is \r\n, \n
Found types for All mixed up is \r\n, \n, \r

что кажется совершенно нормальным.

Вы можете протестировать/поиграть с ним здесь: https://onlinephp.io/c/4ce47

Ответ принят как подходящий

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

В PHP уже давно есть решение этой проблемы, и оно не связано с миноксидилом; просто используйте \R. Я заменю каждую последовательность новой строки звездочкой, чтобы показать, как она надежно учитывает все возможные последовательности новой строки во всех средах и обрабатывает их как целые последовательности новой строки, когда это необходимо.

Код: (Демо)

$inputs = [
    'Windows' => "Dog\r\nCat\r\nMouse",
    'Linux' => "Bicycle\nCar\nTrain\nAirplane",
    'Mac' => "iPhone\riPod\rMacBook",
    'Win + Linux' => "int main() {\n   return 0;\r\n}\n",
    'All mixed up' => "This is a Windows new line\r\n, followed by a Linux new line\n and finally an old Mac with a single carriage return\rat the end",
];

var_export(
    preg_replace('/\R/', '*', $inputs)
);

Выход:

array (
  'Windows' => 'Dog*Cat*Mouse',
  'Linux' => 'Bicycle*Car*Train*Airplane',
  'Mac' => 'iPhone*iPod*MacBook',
  'Win + Linux' => 'int main() {*   return 0;*}*',
  'All mixed up' => 'This is a Windows new line*, followed by a Linux new line* and finally an old Mac with a single carriage return*at the end',
)

Если вам нужен массив последовательностей новой строки, просто используйте preg_match_all() с тем же единственным шаблоном. Демо

foreach ($inputs as $env => $input) {
    preg_match_all('/\R/', $input, $matches);
    var_dump(
        $env,
        json_encode($matches[0])
    );
}

Соответствующее чтение о реализации \R:

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

Barmar 25.06.2024 23:47

Я также покажу, как сопоставить последовательности новой строки. Я не понимаю, как это не решает эту (xy) проблему. Спрашивающий говорит: «Проблема, с которой я столкнулся, заключается в том, что он распознает \r\n как два отдельных типа» — \R — это самый прямой и элегантный способ решить эту проблему.

mickmackusa 26.06.2024 01:00

@mickmackusa, я только сейчас вижу, что ты ответил. Я тоже не минусовал ваш ответ. Кто-то тоже проголосовал против моего вопроса.

Aristocles 26.06.2024 06:06

@ Аристокл, я считаю, что мое решение - самое лучшее решение для твоей задачи. Вы надеетесь стандартизировать свой текст, верно? Вам не нужно сканировать весь документ на наличие вариантов перевода строки, просто замените последовательности перевода строки на preg_replace() и \R. Этот ответ гораздо более прямой, чем ваш принятый ответ, если я чего-то не понимаю.

mickmackusa 26.06.2024 07:26

@mickmackusa Вы правы. Я уже принял лучший ответ до того, как вы добавили свой, и увидел ваш только вчера вечером около полуночи в мое время, поэтому я не собирался переходить в рабочий режим. Сегодня утром, прочитав ваш ответ, он показался мне лучшим решением, и я принял его как таковое. До сих пор я не знал о \R. Вся эта чушь с EOL для меня в новинку. XD

Aristocles 26.06.2024 17:33

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