首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何将子字符串替换为从由子字符串索引的字典中提取的值

如何将子字符串替换为从由子字符串索引的字典中提取的值
EN

Unix & Linux用户
提问于 2019-05-24 16:49:13
回答 1查看 256关注 0票数 1

我需要解析一个大文件,替换可能发生的子字符串,这些子字符串是可能发生的字符串的一部分,与regex匹配,它的值来自一个数组,数组的索引就是所讨论的子字符串。

该文件是一个常规文本文件,即用换行符分隔行,每一行可以在ASCII 32和ASCII 126之间有任意字符,基本上是任何可打印的字符,C语言环境中的控制字符除外。

精确匹配感兴趣字符串的扩展正则表达式是\,而所讨论的子字符串是在破折号之后出现的。

输入的样本(合成)如下:

代码语言:javascript
复制
# 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

并有一本字典样本,如:

代码语言:javascript
复制
dictionary["foo"] = 2
dictionary["bar"] = 15

预期的产出将是:

代码语言:javascript
复制
# 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记录。因此,我想出了以下脚本:

代码语言:javascript
复制
#!/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是不可行的,因为字典很大,因此效率很低。

EN

回答 1

Unix & Linux用户

回答已采纳

发布于 2019-05-25 18:25:06

作为比较,这里有一个非专家perl版本,它通过在替换中调用函数获得了很大的收益。就好像你可以说

代码语言:javascript
复制
gsub(regexp, call_function(matched_part), variable_to_change)

其中,函数返回替换字符串。

代码语言:javascript
复制
#!/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是正则表达式的捕获组(()中)。

票数 1
EN
页面原文内容由Unix & Linux提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://unix.stackexchange.com/questions/520916

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档