【问题标题】:Efficient string slicing in AWKAWK 中的高效字符串切片
【发布时间】:2022-12-18 08:06:17
【问题描述】:

我想使用 AWK 替换输入文件中的一组动态模式,如下所示:

one ^var^ two
^var^ three ^var^
four five six
seven eight ^var^

这是(相对)惯用的方法,逐行处理输入:

BEGIN {
  FS = ""
  vars["var"] = "yay!"
}

{
  while (match($0, /\^[[:alnum:]_]+\^/)) {
    var = substr($0, RSTART+1, RLENGTH-2)
    $0 = substr($0, 1, RSTART-1) vars[var] substr($0, RSTART+RLENGTH)
  }
  print
}

在这种情况下,只有一个变量 ^var^ 被替换为 yay!,但可以有许多不同的变量并且映射是动态加载的。

它在我尝试过的所有 AWK 实现上都相当快,最慢的 (GoAWK) 大约需要 320 毫秒来处理一个 4.9MiB 的测试文件,示例输入连接 1000 次。

但是,我希望能够处理很长的行,或者在 ^ 定界符内有换行符,所以这里有一种方法可以一次读取整个输入,然后在遍历时打印其中的一部分:

BEGIN {
  RS = "\x1"
  FS = ""
  vars["var"] = "yay!"
}

{
    while (match($0, /\^[[:alnum:]_]+\^/)) {
        printf "%s%s", substr($0, 1, RSTART-1), vars[substr($0, RSTART+1, RLENGTH-2)]
        $0 = substr($0, RSTART+RLENGTH)
    }
    printf "%s", $0
}

但是,它明显更慢。只有 GoAWK 能够在大约 290 毫秒内处理同一个文件。 MAWK 需要 48 秒,NAWK - ~3 分钟,而 GAWK 非常慢 - 我没有等它完成,但已经超过 10 分钟了。

考虑到 $0 = substr($0, RSTART+RLENGTH) 行的效率低下,这可能是预料之中的。我想知道 GoAWK 是如何让它变得如此之快的——也许是一些写时复制的魔法?

无论如何,我想知道在 GAWK 和/或 MAWK 中是否有一种(理想情况下可移植的)方法可以快速完成此操作。我知道使用 Perl 单行代码或 Python 双行代码也可以实现同样的效果,但我需要在 AWK 中完成:)

【问题讨论】:

  • 如果您可以提供更多样本输入和替换,可能会有所帮助,特别是解决您提到的变化;您是一次更换一个还是多次?如何将替换项加载到awk ... -v variable="value" 或从文件中加载?如果从文件加载,您打算如何区分 \n 作为替换字符串的一部分与普通行定界符?您是否需要担心您的目标定界符 (^) 出现在正常数据中(在源数据或替换数据中)?
  • 如果目标定界符 (^) 没有显示为实际数据的一部分,您可以考虑设置 FS='^',然后遍历偶数字段 (for (i=2;i<=NF;i=i+2)) 以查找与替换列表的匹配项(例如,在提供的示例中 $i=="var"$i in vars

标签: awk text replace


【解决方案1】:

你可以利用 GNU AWKRSRT 来支持多行变量,按照下面的方式,让 file.txt 内容

one two ^var
1^
three ^var
2^
four five six
seven eight ^var
3^

然后

awk 'BEGIN{RS="\^var
[0-9]+\^";arr["^var
1^"]="uno";arr["^var
2^"]="dos";arr["^var
3^"]="tres"}{printf "%s%s",$0,(RT in arr)?arr[RT]:RT}' file.txt

给出输出

one two uno
three dos
four five six
seven eight tres

说明:RS 是行分隔符,RT 是行终止符,对于每个行终止符对,我都会查看数组 arr,如果存在于数组中,我会使用相应的值。

(在 GNU Awk 5.0.1 中测试)

【讨论】:

    猜你喜欢
    • 2020-11-27
    • 1970-01-01
    • 1970-01-01
    • 2017-12-09
    • 1970-01-01
    • 2012-07-16
    • 2014-07-21
    • 2012-02-15
    • 1970-01-01
    相关资源
    最近更新 更多