Как удалить текст в начале файла с помощью регулярного выражения?

У меня есть куча файлов с полустандартным заголовком. То есть внешне он очень похож, но текст несколько меняется.

Я хочу удалить этот заголовок из всех файлов.

Глядя на файлы, я знаю, что то, что я хочу удалить, заключено между похожими словами.

Так, например, у меня есть:

Foo bar...some text here...
more text
Foo bar...I want to keep everything after this point

Я попробовал эту команду в Perl:

perl -pi -e "s/\A.*?Foo.bar*?Foo.bar//simxg" 00ws110.txt

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


person GeoffreyF67    schedule 23.03.2009    source источник


Ответы (4)


По умолчанию ARGV (он же <>, который за кадром используется -p) читает только одну строку за раз.

Обходные пути:

  1. Сбросьте $/, что говорит Perl читать весь файл за раз.

    perl -pi -e "BEGIN{undef$/}s/\A.*?Foo.bar*?Foo.bar//simxg" 00ws110.txt
    

    BEGIN необходимо, чтобы этот код выполнялся до того, как будет выполнено первое чтение.

  2. Используйте -0, который устанавливает $/ = "\0".

    perl -pi -0 -e "s/\A.*?Foo.bar*?Foo.bar//simxg" 00ws110.txt
    
  3. Воспользуйтесь преимуществами флип-флоп оператора.

    perl -ni -e "print unless 1 ... /^Foo.bar/'
    

    Это пропустит печать, начиная со строки 1 до /^Foo.bar/.

person ephemient    schedule 23.03.2009
comment
-0 не так безопасен, как -0777, который гарантированно переводит perl в режим slurp. - person Chas. Owens; 23.03.2009
comment
Это небезопасно только для двоичных данных. Можно было бы надеяться, что *.txt на самом деле являются текстовыми файлами. - person ephemient; 23.03.2009
comment
Пробовал все три. Последний: perl -ni -e print, если 1 ... /^Project.Gutenberg/ 00ws110.txt - все равно не работает. Ничего не печатает. - person GeoffreyF67; 24.03.2009
comment
Да, но вы никогда не знаете, когда случайный нуль может оказаться в предполагаемом текстовом файле, зачем рисковать, если вы можете нажать 7 три раза и быть в безопасности. - person Chas. Owens; 24.03.2009
comment
Последний работает у меня на трех разных установках Perl. Вы уверены, что // соответствует последней строке заголовка? - person ephemient; 24.03.2009
comment
Фух. Наконец-то понял. Спасибо! - person GeoffreyF67; 24.03.2009

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

perl -0777pi.orig -e 's/your regex/your replace/s' file1 file2 file3

Параметр -0777 устанавливает perl в режим slurp, поэтому $_ будет удерживать каждый файл целиком каждый раз в цикле. Кроме того, всегда не забывайте устанавливать расширение для резервного копирования. Если вы этого не сделаете, вы можете обнаружить, что случайно стерли свои данные и не можете их восстановить. См. perldoc perlrun для получения дополнительной информации.

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

perl -ni.orig -e 'print unless 1 .. /^\*END/' 00ws110.txt

Заголовок Project Gutenberg заканчивается

*END*THE SMALL PRINT! FOR PUBLIC DOMAIN ETEXTS*Ver.04.29.93*END*

Более безопасное регулярное выражение также учитывало бы *END* в конце строки, но я ленив.

person Chas. Owens    schedule 23.03.2009

Я могу неправильно истолковать то, о чем вы просите, но мне это кажется таким простым:

perl -ni -e 'print unless 1..($. > 1 && /^Foo bar/)'
person Community    schedule 23.03.2009
comment
Или просто используйте 1.../^Foo bar/ (обратите внимание: тройная точка, а не двойная) вместо проверки $.. - person ephemient; 24.03.2009

Ну вот! Это заменяет первую строку файла:


use Tie::File;

tie my @array,"Tie::File","path_to_file" or die("can't tie the file");
$array[0] =~s/text_i_want_to_replace/replacement_text/gi;
untie @array;

Вы можете работать с массивом, и вы увидите изменения в массиве. Вы можете удалить элементы из массива, и это сотрет строку из файла. Применение замены к элементам заменит текст из строк.

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


# tie the @array before this
shift @array;
shift @array;
$array[0]=~s/foo bar\.\.\.//gi;
# untie the @array

и это сделает именно то, что вам нужно!

person Geo    schedule 23.03.2009