如何从文件中随机替换文本?

ela*_*urk 9 command-line text-processing

如何用另一个文件中的字符串随机替换一个文本文件中的特定字符串?例如:

file1.txt(file has more than 200 lines):
moonwalker@address.com
hansolo@address.com
anakinskywalker@address.com
obiwankenobi@address.com
darthvader@address.com

file2.txt(file has 10-20 lines):
@adress1.com
@adress2.com
@adress3.com
@adress4.com
@adress5.com

output.txt:
moonwalker@address4.com
hansolo@address1.com
anakinskywalker@address5.com
obiwankenobi@address2.com
darthvader@address3.com
Run Code Online (Sandbox Code Playgroud)

jan*_*nos 10

你可以实现这个算法:

  • 将 的内容加载file2.txt到数组
  • 对于 中的每一行file1.txt
    • 提取名称部分
    • 获取随机地址
    • 打印输出格式正确

像这样:

mapfile -t addresses < file2.txt
while IFS='' read -r orig || [[ -n "$orig" ]]; do
    ((index = RANDOM % ${#addresses[@]}))
    name=${orig%%@*}
    echo "$name${addresses[index]}"
done < file1.txt
Run Code Online (Sandbox Code Playgroud)

(特别感谢 @GlennJackman 和 @dessert 的改进。)

  • 您可能会考虑使用`mapfile -t addresses &lt; file2.txt` 填充数组——使用`cat` 就像这样会使您进行分词和文件名扩展。 (3认同)
  • 如果此文件不以空行结尾,这是否会捕获 `file1.txt` 的最后一个非空行(抱歉,目前无法测试)?如果不是,我建议`while IFS='' read -r orig || [[ -n "$orig" ]]; do`,请参阅[逐行读取文件将值分配给变量·SO](/sf/ask/765061741/ -to-a-变量)。 (2认同)
  • @janos 刚刚发现了一个关于该主题的非常好的问题:[Shell script read missing last line](/sf/ask/904144671/) (2认同)

ste*_*ver 9

如果您真的想要随机选择,那么这是使用的一种方法awk

awk '
  BEGIN{FS="@"; OFS=""} 
  NR==FNR{a[NR]=$0; n++; next} 
  {$2=a[int(1 + n * rand())]; print}
' file2.txt file1.txt
moonwalker@adress2.com
hansolo@adress2.com
anakinskywalker@adress5.com
obiwankenobi@adress1.com
darthvader@adress3.com
Run Code Online (Sandbox Code Playgroud)

OTOH如果你想要地址的随机排列,我建议像

paste -d '' <(cut -d'@' -f1 file1.txt) <(sort -R file2.txt)
moonwalker@adress2.com
hansolo@adress1.com
anakinskywalker@adress5.com
obiwankenobi@adress4.com
darthvader@adress3.com
Run Code Online (Sandbox Code Playgroud)

  • 粘贴解决方案的一个缺点是文件 1 的行数多于文件 2。代替 `&lt;(sort -R file2.txt)` 我们可以使用类似 `&lt;(yes "$(&lt;file2.txt)" | head -n $(wc -l &lt;​​ file1.txt) | sort -R) ` -- 这可能会使随机性偏向更靠近 file2 顶部的行。 (2认同)

ter*_*don 5

您可以使用shuf(您可能需要sudo apt install shuf)将第二个文件的行打乱,然后使用它们来替换:

$ awk -F'@' 'NR==FNR{a[NR]=$1;next}{print a[FNR]"@"$2} ' file1 <(shuf file2)
moonwalker@adress3.com
hansolo@adress1.com
anakinskywalker@adress5.com
obiwankenobi@adress4.com
darthvader@adress2.com
Run Code Online (Sandbox Code Playgroud)

shuf简单地随机化其输入行的顺序。awk那里的命令将首先读取 file1 的所有内容(NR==FNR仅在读取第一个文件时为真),并将第二个字段(字段由 定义@,因此这是域)保存在关联数组中,a其值为域和其键是行号。然后,当我们到达下一个文件时,它会简单地打印存储在a此行号中的任何内容,以及文件 2 中相同行号的内容。

请注意,这假设两个文件的行数完全相同,并且实际上并不是“随机”的,因为它不允许重复任何内容。但这看起来像你想要的。


Dav*_*ter 5

Python 2.7 和 3 解决方案

该解决方案每次都从替换字符串列表的行集中随机选择一个字符串,将输入文件每一行中第一次出现的单个任意给定字符串(“针”)替换为一个字符串。

#!/usr/bin/python
from __future__ import print_function
import sys, random

needle = sys.argv[1]

if sys.argv[2] == '-':
    f_replacements = sys.stdin
else:
    f_replacements = open(sys.argv[2])
with f_replacements:
    replacements = [l.rstrip('\n') for l in f_replacements]
if not replacements:
    raise ValueError('No replacement strings given')

if len(sys.argv) <= 3 or sys.argv[3] == '-':
    f_in = sys.stdin
else:
    f_in = open(sys.argv[3])
with f_in:
    for s in f_in:
        rep = replacements[random.randrange(len(replacements))]
        print(s.rstrip('\n').replace(needle, rep, 1))
Run Code Online (Sandbox Code Playgroud)

将针锚定到字符串的开头或结尾或完全使用正则表达式应该几乎是微不足道的。

用法

python replace-random.py NEEDLE REPLACEMENTS-FILE [INPUT-FILE]
Run Code Online (Sandbox Code Playgroud)

例子:

python replace-random.py '@address.com' file2.txt file1.txt
Run Code Online (Sandbox Code Playgroud)

或者

python replace-random.py '@address.com' file2.txt < file1.txt
Run Code Online (Sandbox Code Playgroud)