फ़ाइल से बेतरतीब ढंग से टेक्स्ट को कैसे बदलें?


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
यह यादृच्छिक नहीं है, ऐसा लगता है कि आप कुछ भी दोहराया नहीं चाहते हैं। क्या आप चाहते हैं कि यह वास्तव में यादृच्छिक हो, या दूसरी पाठ फ़ाइल की प्रत्येक पंक्ति को केवल एक बार उपयोग किया जाना चाहिए? इसके अलावा, क्या इसे काटने की जरूरत है, या क्या आप अन्य उपकरणों के लिए खुले हैं?
टेराडॉन

1
@terdon ऐसा लगता है कि वह एक यादृच्छिक क्रमचय (सभी 5 तत्वों पर एक यादृच्छिक क्रम में) चाहता है। एक यादृच्छिक क्रमचय वास्तव में यादृच्छिक होता है, आपको बस पहले से चुने हुए तत्वों को समाप्त करने की आवश्यकता होती है जब यादृच्छिक रूप से अगले तत्व का चयन किया जाता है। कभी-कभी एक "यादृच्छिक प्रकार" कहा जाता है
थोमसट्रेटर

1
@thomasrutter हां, मुझे पता है कि और मेरा जवाब यही है। लेकिन यही कारण है कि मैं ओपी को एक यादृच्छिक क्रमपरिवर्तन के बाद से स्पष्ट करने के लिए कह रहा था और एक यादृच्छिक पिक उचित होगा जो उनके लिए आवश्यक है।
टेराडन

जवाबों:


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गैर-मिलान क्षेत्र को हटाने के लिए इसका उपयोग करने के लिए मेरे साथ ऐसा नहीं हुआ ।
टेराडॉन

2
पेस्ट समाधान के लिए एक नकारात्मक पक्ष यह है कि फ़ाइल 1 में फ़ाइल 2 की तुलना में अधिक लाइनें हैं। इसके बजाय <(sort -R file2.txt)हम कुछ का उपयोग कर सकते हैं <(yes "$(<file2.txt)" | head -n $(wc -l < file1.txt) | sort -R)- जैसे कि फ़ाइल 2 के शीर्ष के करीब लाइनों के पक्ष में यादृच्छिकता को तिरछा कर सकता है।
ग्लेन जैकमैन

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 और @ डेज़र्ट के लिए विशेष धन्यवाद।)


3
आप उस विषय के साथ सरणी को पॉप्युलेट करने पर विचार mapfile -t addresses < file2.txtकर सकते हैं cat, जैसे कि आप शब्द विभाजन और फ़ाइल नाम विस्तार का उपयोग कर रहे हैं।
ग्लेन जैकमैन

2
file1.txtअगर यह फ़ाइल एक खाली लाइन के साथ समाप्त नहीं होती है (क्षमा करें, फिलहाल परीक्षण नहीं कर सकता है) तो क्या यह अंतिम गैर-खाली रेखा को पकड़ता है ? यदि मैं अनुशंसा नहीं करता हूं while IFS='' read -r orig || [[ -n "$orig" ]]; do, तो एक चर के मान को असाइन करने वाली रेखा द्वारा एक फ़ाइल लाइन पढ़ें
डेसर्ट

2
@janos बस इस विषय पर एक बहुत अच्छा सवाल मिला: शेल स्क्रिप्ट आखिरी पंक्ति में गायब पढ़ा
डेसर्ट

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

पायथन 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))

यह सुई को स्ट्रिंग की शुरुआत या अंत में सुई लगाने या पूरी तरह से नियमित अभिव्यक्ति का उपयोग करने के लिए लगभग तुच्छ होना चाहिए।

प्रयोग

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

यहाँ एक शानदार तरीका है:

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

एक और बैश समाधान। यह बैश बिल्ट-इन स्ट्रिंग रिप्लेसमेंट फीचर का उपयोग करता है। यह भी मानता 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
$ 
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.