Сопоставление и удаление символа новой строки в регулярном выражении mutiline perl

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

У меня есть текстовый файл input.txt, который структурирован с меткой поля (обозначается обратной косой чертой) и содержимым поля, например:

\x text
\y text text
text text
\z text

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

#!/usr/bin/perl

$/ =undef; 

{
open(my $in, "<", "input.txt") or die "impossible: $!";
open(my $out, ">", "output.txt") or die "Can't open output.txt: $!"; 

while (<$in>) {
    s/\n([^\\])/ \1/g; # delete all line breaks unless followed by backslash and replace by a single space
    print $out $_ ; 
    }       
}

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

\x text
\y text text
 text text
\z text

В то время как я надеялся получить это:

\x text
\y text text text text
\z text

person jan    schedule 26.08.2018    source источник
comment
Или s{\n(?!\\.)}{}g; с соответствующим образом настроенным переводом строки, как в ответе Брайана. (?!...) - это отрицательный просмотр вперед. Он не потребляет то, что ему соответствует, поэтому вам не нужно повторно вводить его.   -  person zdim    schedule 26.08.2018
comment
$/ = undef выполняет: (1) изменяет $/ для всего блока; лучше поместить его внутрь блока и перейти local $/; (2) Поскольку $/ это undef, следующий <$in> читает (глотает) весь файл; Я полагаю, что это ваше намерение. Но тогда while вводит в заблуждение; почему не my $text = <$in> ? // Своего рода идиома: my $text = do { local $/; open ... ; <$fh> };, а затем процесс $text. Есть также модули, которые делают это в одну строку, например Path::Tiny.   -  person zdim    schedule 27.08.2018


Ответы (1)


Я думаю, что ваш ввод имеет пару возврата каретки-перевода строки. Вы только заменяете новую строку, но возврат каретки все еще существует.

Вы можете сопоставить \v для вертикального пробела (чуть больше, чем окончание строки), \R для обобщенного окончания строки Unicode, [\r\n]+ для получения одного из них (по отдельности или вместе) или \r\n, если вы уверены, что они оба будут там. Хитрость заключается в том, чтобы выбрать тот, который работает для вас, если окончание строки изменится.

И \1 на стороне замены лучше писать как $1.

person brian d foy    schedule 26.08.2018
comment
Отлично, так и было! Большое спасибо! Только одно: есть ли способ узнать, является ли конец строки \r или \n? - person jan; 26.08.2018
comment
Я либо использую шестнадцатеричный дамп, либо смотрю, что говорит мне мой редактор, если мне интересно узнать окончание строки. Многие редакторы также могут преобразовать их для вас. - person brian d foy; 26.08.2018