我需要解析一个大文件,替换可能发生的子字符串,这些子字符串是可能发生的字符串的一部分,与regex匹配,它的值来自一个数组,数组的索引就是所讨论的子字符串。
该文件是一个常规文本文件,即用换行符分隔行,每一行可以在ASCII 32和ASCII 126之间有任意字符,基本上是任何可打印的字符,C语言环境中的控制字符除外。
精确匹配感兴趣字符串的扩展正则表达式是\,而所讨论的子字符串是在破折号之后出现的。
输入的样本(合成)如下:
# arbitrary number of comment lines of any length
:prefix-foo ; arbitrary strings
# arbitrary number of comment lines of any length foo -prefix-foo-
-bar -foo-xx arbitrary string -yet-more strings prefix-foo-bar MORE strings
YET more --STRINGS prefix-bar -prefix-foo-STRingS--
even MORE strings ; prefix -foo -yy--more-and-prefix-bar-and-more并有一本字典样本,如:
dictionary["foo"] = 2
dictionary["bar"] = 15预期的产出将是:
# arbitrary number of comment lines of any length
:prefix-2 ; arbitrary strings
# arbitrary number of comment lines of any length foo -prefix-2-
-bar -foo-xx arbitrary string -yet-more strings prefix-2-bar MORE strings
YET more --STRINGS prefix-15 -prefix-2-STRingS--
even MORE strings ; prefix -foo -yy--more-and-prefix-15-and-more我认为awk将是最好的工具,特别是因为它可以通过替换单个$1...$n字段来重写整个D6记录。因此,我想出了以下脚本:
#!/usr/bin/gawk -f
BEGIN {
# first fill in dictionary
while ("cmd-providing-dictionary" | getline) {
dictionary[$1] = $2
}
close("cmd-providing-dictionary")
# pattern that matches interesting fields
field_regex = "\\"
# I don't care default splitting of line
FS = OFS = ""
}
{
# split line in fields as per regex
if (patsplit($0, fields, field_regex, seps)) {
FS = OFS = "-"
# for each field, split it on dash character,
# modify its substring as per dictionary,
# and finally rebuild it
for (fn in fields) {
$0 = fields[fn]
if ($2 in dictionary) {
$2 = dictionary[$2]
fields[fn] = $0
}
}
FS = OFS = ""
# clear whole record and rebuild it with
# fields computed above + original separators
$0 = ""
for (fn in fields)
$fn = seps[fn - 1] fields[fn]
$(fn+1) = seps[fn]
}
print
}尽管我在Awk方面并不强,但上面的这些似乎足够快地完成了正确的工作,但是看起来有点笨拙,并且感觉我在强迫awk以一种不自然的方式做事情。我想知道是否有更好的方法来获得同样的结果。或者是更好的工具。
我的第一个想法是使用gsub()或gensub()进行简单的正则表达式替换,但是我发现没有(干净)方法使用regex的子表达式(即\)作为查找数组并在替换字符串中使用该值的键。另一方面,遍历所有的字典键来应用所有的gsubs是不可行的,因为字典很大,因此效率很低。
发布于 2019-05-25 18:25:06
作为比较,这里有一个非专家perl版本,它通过在替换中调用函数获得了很大的收益。就好像你可以说
gsub(regexp, call_function(matched_part), variable_to_change)其中,函数返回替换字符串。
#!/usr/bin/perl
use strict;
my %d;
sub fix{
my ($prefix,$str) = @_;
$str = $d{$str} if defined $d{$str};
return "$prefix$str";
}
open(D,"dictionary") or die;
while(){
$d{$1} = $2 if $_ =~ m/^([^ ]+) ([^ \n]+)/;
}
close(D);
while(<>){
$_ =~ s/\b(prefix-)([[:alnum:]]{2,})\b/fix($1,$2)/ge;
print;
}在这里,替换命令$_ =~ s/regex/fix($1,$2)/ge全局地更改当前行$_ (g),并执行(e)替换字符串fix(),其中$1和$2是正则表达式的捕获组(()中)。
https://unix.stackexchange.com/questions/520916
复制相似问题