Есть ли эффективный способ заменить текст, соответствующий всему содержимому одного файла, всем содержимым другого файла?

awk не может этого сделать (без использования какого-либо цикла), но perl может.

Однако помните, что массивы perl отсчитываются от нуля (в то время как индексы массивов awk начинаются с 1).

Например, при использовании параметра -a в perl для awk -подобного автоматического разделения:

$ echo p1 p2 p3 p4 p5 p6 p7 | perl -ane 'print "@F[3..$#F]\n";'
p4 p5 p6 p7 

$ echo p1 p2 p3 p4 p5 p6 p7 | perl -ane 'print "@F[2,4,6]\n";'
p3 p5 p7

$ echo p1 p2 p3 p4 p5 p6 p7 | perl -ane 'print "@F[1..3]\n";'
p2 p3 p4

см. man perldata или perldoc perlvar для получения дополнительной информации о массивах и срезах массивов.

Поскольку фрагменты массива печатаются внутри строки, заключенной в двойные кавычки, для разделения элементов массива используется значение $ ", также известное как $ LIST_SEPARATOR . Если они были напечатаны / используется вне строки, заключенной в двойные кавычки, между элементами вообще не будет разделителя. См. man perlvar или perldoc perlvar и поиск LIST_SEPARATOR.

Наконец, не надо t используйте perl -a , если ваш разделитель полей не является пробелом ( \ s + в PCRE).Разбейте его самостоятельно следующим образом:

$ echo "p1:p2:p3:p4:p5:p6:p7" | perl -n -e '@F=split /:/; print "@F[0..4]\n";'
p1 p2 p3 p4 p5
7
26.05.2019, 02:17
4 ответа

Перл спешит на помощь!

Считайте пары замен в хэш. Затем прочитайте ввод построчно и попробуйте заменить совпадения.

#!/usr/bin/perl
use warnings;
use strict;

open my $ot, '<', 'old-text.txt' or die $!;
chomp( my @lines = <$ot> );
open my $nt, '<', 'new-text.txt' or die $!;
my %replace;
@replace{@lines} = <$nt>;
chomp for values %replace;

my $regex = join '|', map quotemeta, @lines;
open my $in, 'naive-file.txt' or die $!;
while (<$in>) {
    s/($regex)/$replace{$1}/;
    print;
}

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

my $regex = join '|', map quotemeta, sort { length $b <=> length $a } @lines;
5
27.01.2020, 20:16

Вот GNU awkодин -вкладыш:

awk 'NR==FNR{old[++k]=$0}FILENAME=="new-text.txt"{new[FNR]=$0}
     FILENAME=="naive-file.txt"{for(i=1;i<k;i++)if(old[i]==$0)$0=new[i];print}'\
     old-text.txt new-text.txt naive-file.txt

Может не подходить для очень больших файлов, так как все шаблоны сначала сохраняются в массивах.

Выход:

Sed id ligula quis est convallis tempor.

This is the new text.

It could also have multiple lines and special characters like these \ { & %
etc...


Nunc aliquet, augue nec adipiscing interdum, lacus tellus malesuada massa, quis
varius mi purus non odio.
2
27.01.2020, 20:16

Баш

Заменить первое совпадение:

target=$(cat naive-file.txt)
old=$(cat old-text.txt)
new=$(cat new-text.txt)
echo "${target/"$old"/"$new"}"

Заменить все совпадения:

echo "${target//"$old"/"$new"}"

Заменить начальное совпадение:

echo "${target/#"$old"/"$new"}"

Заменить конец совпадения:

echo "${target/%"$old"/"$new"}"
4
27.01.2020, 20:16
$ perl -0777ne '
     $A[@ARGV] = $_;
     @ARGV and next;
     my($naive, $new, $old) = @A;
     while ( index($naive,$old,$p) > -1 ) {
        substr($naive, index($naive,$old,$p), length($old)) = $new;
        $p = index($naive,$old,length($old)) ;
      }
      print $naive;
' old.txt new.txt naive.txt
0
27.01.2020, 20:16

Теги

Похожие вопросы