AWK:在字典中的源术语之后插入随机选择的行目标术语

AWK:在字典中的源术语之后插入随机选择的行目标术语

注:我已经问过类似的问题AWK:在源术语后插入目标单词的快速方法而且我处于AWK的初级水平。

本问题考虑在多个随机选择的行中的源术语之后插入多个目标术语。

有了这个 AWK 代码片段

awk '(NR==FNR){a[$1];next}
    FNR in a { gsub(/\<source term\>/,"& target term") }
     1
    ' <(shuf -n 5 -i 1-$(wc -l < file)) file

我想在 5 个随机行target term之后插入一个.source termfile

例如:我有一本双语词典dict,其中左侧包含源术语,右侧包含目标术语,例如

apple     : Apfel
banana    : Banane
raspberry : Himbeere

我的file由以下几行组成:

I love the Raspberry Pi.
The monkey loves eating a banana.
Who wants an apple pi?
Apple pen... pineapple pen... pen-pineapple-apple-pen!
The banana is tasty and healthy.
An apple a day keeps the doctor away.
Which fruit is tastes better: raspberry or strawberry?

假设第一个单词apple选择了随机行 1、3、5、4、7。包含单词 apple 的输出将如下所示:

I love the Raspberry Pi.
The monkey loves eating a banana.
Who wants an apple Apfel pi?
Apple Apfel pen... pineapple pen... pen-pineapple-apple-pen!
The banana is tasty and healthy.
An apple a day keeps the doctor away.
Which fruit is tastes better: raspberry or strawberry?

然后是另外 5 条随机线; 3、3、5、6、7;对于banana将选择的单词:

I love the Raspberry Pi .
The monkey loves eating a banana .
Who wants an apple Apfel pi ?
Apple Apfel pen... pineapple pen... pen-pineapple-apple-pen!
The banana Banane is tasty and healthy .
An apple a day keeps the doctor away .
Which fruit is tastes better: raspberry or strawberry?

所有其他条目都会如此,dict直到最后一个条目匹配为止。

我想随机选择5条线。如果这些行有一个完整的源术语,就像apple我只想匹配Apfel整个apple单词(像“pineapple”这样的术语将被忽略)。如果一行包含源术语两次,例如apple,那么我也想在其后面插入目标术语。匹配应该不区分大小写,因此我还可以匹配源术语,例如appleApple

我的问题:如何重写上面的代码片段,以便我可以使用字典dict,它选择随机的file并在源术语后面插入目标术语?

答案1

以下是如何使用 awk 从输入文件中随机选择 5 个行号(第一遍使用 wc 仅计算行号):

$ awk -v numLines="$(wc -l < file)" 'BEGIN{srand(); for (i=1; i<=5; i++) print int(1+rand()*numLines)}'
7
2
88
13
18

现在你所要做的就是采取我之前的回答对于块中读取的每个“旧”字符串,ARGIND==1生成 5 个行号,如上所示,填充一个数组,将生成的行号映射到与每个行号关联的旧字符串,并在读取最终输入文件时检查当前是否行号位于数组中,如果是,则循环遍历数组中存储的该行号的“旧”,执行gsub()我之前的答案中显示的操作。

使用 GNU awk 表示ARGINDIGNORECASE、字边界、数组的数组以及 的\s简写[[:space:]]

$ cat tst.sh
#!/usr/bin/env bash

awk -v numLines=$(wc -l < file) '
    BEGIN {
        FS = "\\s*:\\s*"
        IGNORECASE = 1
        srand()
    }
    ARGIND == 1 {
        old = "\\<" $1 "\\>"
        new = "& " $2
        for (i=1; i<=5; i++) {
            lineNr = int(1+rand()*numLines)
            map[lineNr][old] = new
        }
        next
    }
    FNR in map {
        for ( old in map[FNR] ) {
            new = map[FNR][old]
            gsub(old,new)
        }
    }
    { print }
' dict file

$ ./tst.sh
I love the Raspberry Pi.
The monkey loves eating a banana Banane.
Who wants an apple Apfel pi?
Apple Apfel pen... pineapple pen... pen-pineapple-apple Apfel-pen!
The banana Banane is tasty and healthy.
An apple a day keeps the doctor away.
Which fruit is tastes better: raspberry Himbeere or strawberry?

答案2

具有扩展正则表达式模式 (-E) 和 s/// 命令的 (/e) 修饰符的 GNU sed:

n=$(< file wc -l)
sed -E '/\n/ba
  s#^(\S+)\s*:\s*(\S+)$#s/\\<\1\\>/\& \2/Ig#;h'"
  s/.*/shuf -n 5 -i '1-$n'/e;G
  :a
  s/^([0-9]+)(\n.*\n(.*))/\1 \3\2/
  /\n.*\n/!s/\n/ /
  P;D
" dict | sed -f /dev/stdin file

  • 从duct文件的内容生成GNU sed命令。
  • 将命令存储为保持状态。
  • 掷骰子并在输入文件的行长度范围内生成 5 个随机数。
  • 坚持保留模式并生成仅在这些特定行上运行的 sed 命令。
  • 应用在输入文件上生成的这些命令。

相关内容