我有大约十万个文件,对于每个文件我想执行以下操作:
在具有以下 ascii 代码的文件中的第五个和第六个字符之间0x1f
存在一个字符串。现在我希望应用程序打开一个包含所有替换列表的特定文件,请参阅稍后该替换文件的格式。如果替换不在文件中,请将文件名写入 stderr,以便我稍后可以手动修复该文件。现在在ascii代码的第16个和第17个字符之间,0x1f
要替换的内容将再次出现,但是这次字段不仅仅是要替换的内容,而是一串包含要替换的内容的html字符串,可以替换一次到多次。我只想替换该字段中的第一次出现。
替换文件的格式相当简单,每个替换都占自己的一行,并且用空格分隔。它们是按照要替换的东西的长度排序的。
例子
替换文件:
CCCC 3
BCC 233
CCA 331
CCB 332
ACC 133
AA 11
AB 12
BA 21
BB 22
CC 33
A 1
B 2
请注意,它不保证是上面那样的字符和数字,这只是一个示例,可能包含 UTF-8。
文件:(以下示例中0x1f字符写为^_)
field1^_field2^_field3^_field4^_field5^_BB^_field7^_hai
this field contains a newline^_some UTF-8オイ^_the next field is empty^_^_
another newline^_field14^_field15^_<b>BB</b>stuff BB^_the previous field contains something to replace^_^_^_more fields...
该文件将变成
field1^_field2^_field3^_field4^_field5^_22^_field7^_hai
this field contains a newline^_some UTF-8オイ^_the next field is empty^_^_
another newline^_field14^_field15^_<b>22</b>stuff BB^_the previous field contains something to replace^_^_^_more fields...
我已经上传了我输入的真实示例这里。该文件所需的输出是这里(RYO
应替换为リョ
)。
一点背景
某个白痴决定不在我们的数据库中创建单独的列,而是创建一个列并用 0x1f 字符分隔字段。他还认为可以在两个不同的字段中复制我想要更改的信息。我将数据库中的信息提取到文件 pr 中。行只包含带有字段的列,因为我怀疑这更容易使用,但是如果你可以做出一个我可以给 SQLite 数据库的语句,那也很好。
答案1
这个 Perl 脚本应该可以做到。我在您在pastebin上的示例上进行了测试,它按预期工作:
#!/usr/bin/env perl
use strict;
my %k; ## This hash will store the target/replacement pairs
## Read the list of replacements
open(my $r,"$ARGV[0]")||die "Couldn't open replacements list\n";
while(<$r>){
chomp;
my @F=split(/\s+/);
$k{$F[0]}=$F[1]
}
close($r);
$/=undef;
open(my $fh, "$ARGV[1]")||die "Couldn't open input file\n";
while(<$fh>){
## Read the entire file at once
$/=undef;
my @F=split(/\x1f/);
## If this exists in the replacements list
if (defined($k{$F[5]})) {
## Modify the 17th field. This will only replace the first
## occurence. Use 's///g' for all.
$F[16]=~s/$F[5]/$k{$F[5]}/;
## Replace the 6th field
$F[5]=$k{$F[5]};
}
## If it doesn't
else {
## Print the file name to STDERR unless the 5th field
## was empty.
print STDERR "Problematic file: $ARGV[1]\n" unless $F[5]=~/^\s*$/;
}
## print each field separated by '0x1f' again.
print join "\x1f",@F;
}
close($fh);
将其保存fixidiocy.pl
在您的$HOME
目录中,并cd
保存到包含目标文件的目录中。现在,在每个文件上运行它,并给出文件名和替换文件的路径作为参数:
for file in *; do
perl ~/fixidiocy.pl /path/to/replacements "$file" > "$file".fixed
done