Чтение строк с символами продолжения
Проблема
Имеется файл с длинными строками, которые делятся на две и более строки. Символ \
означает, что данная строка продолжается на следующей. Вы хотите объединить разделенные строки.
Подобное разделение длинных строк на короткие встречается в make-файлах, сценариях командного
интерпретатора, конфигурационных файлах и многих языках сценариев.
Решение
Последовательно объединяйте прочитанные строки, пока не встретится строка без символа продолжения:
while (defined($line = <FH>) ) {
chomp $line;
if ($line =~ s/\\$//) {
$line .= <FH>;
redo unless eof(FH);
}
# Обработать полную запись в $line
}
Комментарий
Рассмотрим пример входного файла:
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) \
$(TEXINFOS) $(INFOS) $(MANS) $(DATA)
DEP_DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) \
$(TEXINFOS) $(INFO_DEPS) $(MANS) $(DATA) \
$(EXTRA,DIST)
Вы хотите обработать текст, игнорируя внутренние разрывы строк. В приведенном примере первая
запись занимает две строки, вторая — три строки и т. д.
Алгоритм работает следующим образом. Цикл while читает строки, которые могут быть, а могут и
не быть полными записями, — они могут заканчиваться символом \ (и переводом строки). Оператор
подстановки s/// пытается удалить \ в конце строки. Если подстановка заканчивается неудачей,
значит, мы нашли строку без \. В противном случае мы читаем следующую запись, приписываем ее
к накапливаемой переменной $line и возвращаемся к началу цикла while с помощью redo. Затем
выполняется команда chomp.
У файлов такого формата имеется одна распространенная проблема — невидимые пробелы между \ и
концом строки. Менее строгий вариант подстановки выглядит так:
if ($line =~ s/\\\s*$//) {
# Как и прежде
}
К сожалению, даже если ваша программа прощает мелкие погрешности, существуют и другие,
которые этого не делают. Будьте снисходительны к входным данным и строги — к выходным.
См. такжеОписание функции
chomp; описание ключевого слова
redo
Proverte kod v komentariyah gde pro list tam oshibki detskie
Оставить комментарий:
|
|