我需要解析一个大文件,替换可能出现的子字符串,这些子字符串是可能出现的与正则表达式匹配的字符串的一部分,其值取自数组,其索引是相关子字符串。
该文件是一个普通的文本文件,即有换行符分隔的行,每行可以有任何介于 ASCII 32 和 ASCII 126 之间的字符,基本上是任何可打印字符,除了 C 语言环境中的控制字符。
精确匹配有趣字符串的扩展正则表达式是\<prefix-[[:alnum:]]{2,}\>
,而有问题的子字符串是破折号之后的任何内容。
使用样本(合成)输入,例如:
# 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
来重写整个记录的本机能力。因此,我想出了以下脚本:$0
$1...$n
#!/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 = "\\<prefix-[[:alnum:]]{2,}\\>"
# 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()
or进行简单的正则表达式替换,gensub()
但我发现没有(干净的)方法可以使用正则表达式的子表达式(将是\<prefix-([[:alnum:]]{2,})\>
)作为查找数组并在替换字符串中使用该值的键。另一方面,遍历所有字典键以始终应用所有gsub
s 并不是真正可行的,因为字典非常大,因此效率非常低。
只是为了比较,这是一个非专家 perl 版本,它通过能够从替换中调用函数而获得很多。好像你可以说
其中函数返回替换字符串。
在这里,substitute 命令全局
$_ =~ s/regex/fix($1,$2)/ge
更改当前行$_
(g),并执行 (e) 替换字符串fix()
,其中$1
和$2
是正则表达式的捕获组(在 内()
)。