Find and replace using a list in text file? [duplicate]

依然范特西╮ 提交于 2019-12-11 17:50:55

问题


I'm not even sure if this is possible, but sure am hoping that it is.

I have this line 766 times in the file backup.xml:

*** Hosting Services

I then have the file list.txt which contains 766 lines in it. I need to replace *** with the contents of each of the 766 lines in list.txt - and it needs to be in the same order if at all possible.

Thanks in advance for any help!


回答1:


Idea:

loop over the lines of the B(ackup file)
  if you (F)ind a B-line to change
     read the next line of the L(ist file)
     change
  print the line to R(result file)

Plan:

read_open B
read_open L
write_open R
while (line from B)
  if (F) {
    read replacemment from L
    change line
  }
  print line to R
}
close R, L, B

Implementation I (read_open, loop, look at B):

use strict;
use warnings;
use English qw(-no_match_vars);

my $bfn = '../data/AA-backup-xml';
open my $bfh, '<', $bfn or die "Can't read open '$bfn': $OS_ERROR";
while (my $line = <$bfh>) {
        print $line;
}
close $bfh or die "Can't read close '$bfn': $OS_ERROR";

output:

perl 01.pl
whatever
whatever
*** Hosting Services
whatever
whatever
whatever
*** Hosting Services
whatever
whatever
*** Hosting Services
whatever
whatever
whatever
*** Hosting Services

Implementation II (read/write, F, replace, first result):

use Modern::Perl;
use English qw(-no_match_vars);

my $bfn = '../data/AA-backup-xml';
open my $bfh, '<', $bfn or die "Can't read open '$bfn': $OS_ERROR";
my $lfn = '../data/AA-list.txt';
open my $lfh, '<', $lfn or die "Can't read open '$lfn': $OS_ERROR";
my $rfn = '../data/AA-result';
open my $rfh, '>', $rfn or die "Can't write open 'rlfn': $OS_ERROR";
while (my $line = <$bfh>) {
    if ($line =~ /\*{3}/) {
        my $rpl = <$lfh>;
        $rpl = substr($rpl, 0, 3);
        $line =~ s/\*{3}/$rpl/;
    }
    print $rfh $line;
}
close $rfh or die "Can't write close '$rfn': $OS_ERROR";
close $lfh or die "Can't read close '$lfn': $OS_ERROR";
close $bfh or die "Can't read close '$bfn': $OS_ERROR";

output:

type ..\data\AA-result
whatever
whatever
001 Hosting Services
whatever
whatever
whatever
002 Hosting Services
whatever
whatever
003 Hosting Services
whatever
whatever
whatever
004 Hosting Services

If this does not 'work' for you (perhaps I mis-guessed the structur of B or the F strategy is too naive), then publish a representative sample of B, L, and R.




回答2:


You can use Tie::File to look at/modify files through representing them as arrays, ie:

use strict; 
use warnings;
use Tie::File;

tie my @ra1, 'Tie::File', "test.txt" or die; #*** Hosting Services
tie my @ra2, 'Tie::File', "test1.txt" or die; #stuff you want to replace *** with

#assumes equal length
for (my $i=0; $i <= $#ra1; $i++)
{
    my $temp=$ra2[$i];
    $ra1[$i]=~s/(\*{3})/$temp/; 
}

untie @ra1;
untie @ra2;

The above code replaces *** with the corresponding line of your list file. By writing $ra1[$i]=~s/(\*{3})/$temp/ we are directly changing the file that @ra1 is tied to.




回答3:


@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET /a linenum=0
(
FOR /f "delims=" %%i IN ('findstr /n "$" ^<backup.xml') DO (
 SET "line=%%i"
 SET "line=!line:*:=!"
 IF DEFINED line (
  IF "!line!"=="*** Hosting Services" (
   SET /a linenum+=1
   FOR /f "tokens=1*delims=:" %%r IN ('findstr /n "$" ^<list.txt') DO (
    IF !linenum!==%%r (ECHO(%%s Hosting Services) 
   )
  ) ELSE (ECHO(!line!)
 ) ELSE (ECHO()
)
)>new.xml

GOTO :eof

IIUC, this should replace each "*** Hosting Services" line from backup.xml with line corresponding from list.txt *** Hosting Services, creating a new file new.xml




回答4:


It's pretty short and sweet in awk:

awk '
    NR == FNR {list[FNR]=$0; next}
    /\*\*\* Hosting Services/ {sub(/\*\*\*/, list[++count])}
    {print}
' list.txt backup.xml > new_backup.xml

a2p turns that into

#!/usr/bin/perl
eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
    if $running_under_some_shell;
            # this emulates #! processing on NIH machines.
            # (remove #! line above if indigestible)

eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z_0-9]+=)(.*)/ && shift;
            # process any FOO=bar switches

$, = ' ';       # set output field separator
$\ = "\n";      # set output record separator

line: while (<>) {
    chomp;  # strip record separator
    if ($. == ($.-$FNRbase)) {
        $list{($.-$FNRbase)} = $_;
        next line;
    }
    if (/\*\*\* Hosting Services/) {
        ($s_ = '"'.($list{++$count}).'"') =~ s/&/\$&/g, s/\*\*\*/eval $s_/e;
    }
    print $_;
}
continue {
    $FNRbase = $. if eof;
}


来源:https://stackoverflow.com/questions/16727955/find-and-replace-using-a-list-in-text-file

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!