注:我已经问过类似的问题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 term
file
例如:我有一本双语词典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
,那么我也想在其后面插入目标术语。匹配应该不区分大小写,因此我还可以匹配源术语,例如apple
和Apple
。
我的问题:如何重写上面的代码片段,以便我可以使用字典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 表示ARGIND
、IGNORECASE
、字边界、数组的数组以及 的\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 命令。
- 应用在输入文件上生成的这些命令。