จะแทนที่ข้อความแบบสุ่มจากไฟล์ได้อย่างไร


9

ฉันจะสุ่มแทนที่สตริงเฉพาะในไฟล์ข้อความเดียวด้วยสตริงจากไฟล์อื่นได้อย่างไร ตัวอย่างเช่น:

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

4
นั่นไม่ใช่การสุ่มดูเหมือนว่าคุณไม่ต้องการอะไรซ้ำ คุณต้องการที่จะสุ่มจริงหรือควรแต่ละบรรทัดของไฟล์ข้อความที่สองจะใช้เพียงครั้งเดียว? นอกจากนี้ยังจำเป็นต้องทุบตีหรือคุณเปิดเครื่องมืออื่น ๆ ?
terdon

1
@terdon ดูเหมือนว่าเขาต้องการการเรียงสับเปลี่ยนแบบสุ่ม (ทั้ง 5 องค์ประกอบ แต่เรียงตามลำดับแบบสุ่ม) การเรียงสับเปลี่ยนแบบสุ่มเป็นการสุ่มคุณต้องกำจัดองค์ประกอบที่เลือกไปแล้วเมื่อทำการสุ่มเลือกองค์ประกอบถัดไป บางครั้งเรียกว่า "การจัดเรียงแบบสุ่ม"
thomasrutter

1
@ Thomasrutter ใช่ฉันรู้และนั่นคือสิ่งที่คำตอบของฉันทำ แต่นั่นคือเหตุผลที่ฉันขอให้ OP ชี้แจงเพิ่มเติมเนื่องจากทั้งการสุ่มเปลี่ยนรูปแบบและการสุ่มเลือกนั้นสมเหตุสมผลตามสิ่งที่พวกเขาต้องการ
terdon

คำตอบ:


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

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

1
ดี! ฉันกำลังมองหาที่จะทำมันpasteแต่ฉันไม่ได้ใช้cutเพื่อลบฟิลด์ที่ไม่ตรงกัน
terdon

2
ข้อเสียอย่างหนึ่งของโซลูชันการวางคือเมื่อ file1 มีบรรทัดมากกว่า file2 แทนที่จะ<(sort -R file2.txt)ใช้สิ่งที่เราชอบ<(yes "$(<file2.txt)" | head -n $(wc -l < file1.txt) | sort -R)- ซึ่งอาจทำให้การสุ่มเอียงไปทางบรรทัดใกล้กับด้านบนของ file2
glenn jackman

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

(ขอขอบคุณเป็นพิเศษสำหรับ @GlennJackman และ @dessert สำหรับการปรับปรุง)


3
คุณอาจพิจารณาเติมอาร์เรย์ด้วยmapfile -t addresses < file2.txt- โดยใช้วิธีการcatที่กำหนดให้คุณแยกคำและขยายชื่อไฟล์
glenn jackman

2
สิ่งนี้ตรวจพบบรรทัดที่ไม่ว่างสุดท้ายหรือไม่file1.txtหากไฟล์นี้ไม่ได้ลงท้ายด้วยบรรทัดว่าง (ขออภัยไม่สามารถทดสอบได้ในขณะนี้) ถ้าไม่ได้ผมขอแนะนำให้while IFS='' read -r orig || [[ -n "$orig" ]]; doดูอ่านบรรทัดไฟล์โดยสายการกำหนดค่าให้กับตัวแปร· SO
ของหวาน

2
@janos เพิ่งพบคำถามที่ดีมากในหัวข้อ: Shell สคริปต์อ่านบรรทัดสุดท้ายหายไป
ของหวาน

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

shufเพียงแค่ทำการสุ่มลำดับของอินพุตบรรทัด awkคำสั่งมีครั้งแรกจะอ่านทั้งหมดของ file1 ( NR==FNRเพียง แต่จะเป็นจริงในขณะที่ไฟล์แรกจะถูกอ่าน) และบันทึกฟิลด์ที่สอง (สาขาจะถูกกำหนดโดย@ดังนั้นนี้เป็นโดเมน) ในอาเรย์aที่มีค่าเป็นโดเมนและ ซึ่งกุญแจคือหมายเลขบรรทัด จากนั้นเมื่อเราไปที่ไฟล์ถัดไปมันก็จะพิมพ์สิ่งที่เก็บไว้ในaหมายเลขบรรทัดนี้พร้อมกับสิ่งที่อยู่ในไฟล์ 2 สำหรับหมายเลขบรรทัดเดียวกัน

โปรดทราบว่านี่ถือว่าทั้งสองไฟล์มีจำนวนบรรทัดเท่ากันและไม่ได้เป็น "สุ่ม" เนื่องจากจะไม่อนุญาตให้ทำซ้ำ แต่นั่นดูเหมือนสิ่งที่คุณต้องการจะขอ


5

Python 2.7 และ 3 solution

วิธีการแก้ปัญหานี้จะแทนที่การเกิดขึ้นครั้งแรกของสตริงที่กำหนดโดยพลการเดียว (“ เข็ม”) ในทุกบรรทัดของไฟล์อินพุตด้วยสตริงในแต่ละครั้งที่เลือกแบบสุ่มจากชุดของบรรทัดของรายการสตริงการแทนที่

#!/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))

มันเกือบจะเป็นเรื่องเล็กน้อยที่จะยึดเข็มไว้ที่จุดเริ่มต้นหรือจุดสิ้นสุดของสตริงหรือใช้การแสดงออกปกติโดยสิ้นเชิง

การใช้

python replace-random.py NEEDLE REPLACEMENTS-FILE [INPUT-FILE]

ตัวอย่าง:

python replace-random.py '@address.com' file2.txt file1.txt

หรือ

python replace-random.py '@address.com' file2.txt < file1.txt

3

นี่คือวิธี Perl:

#!/usr/bin/perl
use warnings;
use strict;
use Tie::File;

tie my @file1,'Tie::File','file1.txt' or die "Can't open file1.txt\n";
tie my @file2,'Tie::File','file2.txt' or die "Can't open file2.txt\n";

for my $file_index (0..$#file1) {
   my $suffix = $file2[int(rand($#file2+1))];
   $file1[$file_index] =~ s/@.*$/$suffix/;
}

untie @file1;
untie @file2;

2

อีกวิธีหนึ่งทุบตี มันใช้คุณสมบัติการเปลี่ยนสตริงในตัวของ bash นอกจากนี้ยังถือว่าfile2.txtมีสตริงการแทนที่เท่านั้น ถ้าไม่ใช่พวกเขาสามารถกรองโดยใช้ครั้งแรกgrep -o <replace> file2.txt

กับ shuf

#search string
Search="@address.com"
for lines in $(grep $Search file1.txt)
do 
    echo ${lines/$Search/$(shuf file2.txt -n 1)} 
done

ไม่มีshuf(เกือบบริสุทธิ์bash)

ที่นี่เราต้องสร้างฟังก์ชั่นก่อนที่เลียนแบบshufเช่นนั้น

bshuf () 
{ 
    nlines=$(( $(wc -l < $1) + 1))
    rand=0
    while [ "$rand" -eq 0 ]; do
        rand=$(( $RANDOM % nlines ))
    done
    echo $(head -n $rand $1 | tail -1)
}

จากนั้นมันจะคล้ายกัน

for lines in $(grep $Search file1.txt) 
do 
    echo ${lines/$Search/$(bshuf file2.txt)}
done

ทดสอบ:

$ for lines in $(grep $Search file1.txt); do echo ${lines/$Search/$(bshuf file2.txt)} ; done
moonwalker@adress4.com
hansolo@adress2.com
anakinskywalker@adress2.com
obiwankenobi@adress3.com
darthvader@adress5.com
$ 
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.