web-dev-qa-db-fra.com

Comment remplacer du texte au hasard d'un fichier?

Comment puis-je remplacer de manière aléatoire des chaînes spécifiques d'un fichier texte par des chaînes d'un autre fichier? Par exemple:

file1.txt(file has more than 200 lines):
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]

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

output.txt:
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
9
elanozturk

Si vous vraiment voulez une sélection aléatoire, procédez comme suit: awk:

awk '
  BEGIN{FS="@"; OFS=""} 
  NR==FNR{a[NR]=$0; n++; next} 
  {$2=a[int(1 + n * Rand())]; print}
' file2.txt file1.txt
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]

OTOH si vous voulez une permutation aléatoire des adresses, je suggère quelque chose comme

paste -d '' <(cut -d'@' -f1 file1.txt) <(sort -R file2.txt)
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
9
steeldriver

Vous pouvez implémenter cet algorithme:

  • Charger le contenu de file2.txt dans un tableau
  • Pour chaque ligne de file1.txt:
    • Extraire le nom de la partie
    • Obtenir une adresse au hasard
    • Imprimer la sortie correctement formatée

Comme ça:

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

(Un merci spécial à @GlennJackman et @dessert pour les améliorations.)

10
janos

Vous pouvez utiliser shuf(vous aurez peut-être besoin de Sudo apt install shuf) pour mélanger les lignes du deuxième fichier, puis les utiliser pour remplacer:

$ awk -F'@' 'NR==FNR{a[NR]=$1;next}{print a[FNR]"@"$2} ' file1 <(shuf file2)
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]

shufrandomise simplement l'ordre de ses lignes d'entrée. La commande awklira d’abord tout le fichier1 (NR==FNR ne sera vraie que pendant la lecture du premier fichier) et enregistrera le deuxième champ (les champs sont définis par @, donc c’est le domaine) dans le tableau associatif anom__ dont les valeurs sont les domaines et dont les clés sont les numéros de ligne. Ensuite, lorsque nous arriverons au fichier suivant, il imprimera simplement ce qui était stocké dans apour ce numéro de ligne, ainsi que le contenu du fichier 2 pour le même numéro de ligne.

Notez que cela suppose que les deux fichiers ont exactement le même nombre de lignes et ne sont pas réellement "aléatoires", car cela ne permet pas de répéter quoi que ce soit. Mais cela ressemble à ce que vous vouliez demander.

5
terdon

Solution Python 2.7 et 3

Cette solution remplace la première occurrence d'une seule chaîne donnée arbitraire (l '"aiguille") dans chaque ligne du fichier d'entrée par une chaîne chaque fois choisie aléatoirement parmi l'ensemble des lignes de la liste de chaînes de remplacement.

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

Il devrait être presque trivial d’ancrer l’aiguille au début ou à la fin de la chaîne ou d’utiliser des expressions régulières.

Usage

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

Exemple:

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

ou

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

Voici un moyen 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;
3
Josh

Une autre solution bash. Il utilise la fonctionnalité de remplacement de chaîne intégrée bash. Il suppose également que file2.txt contient uniquement les chaînes de remplacement. Sinon, ils peuvent être d'abord filtrés à l'aide de grep -o <replace> file2.txt

Avec shuf

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

Sans shuf (presque pur bash)

Ici, nous devons d’abord créer une fonction qui imite shuf comme si

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

Alors c'est pareil

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

Tester:

$ for lines in $(grep $Search file1.txt); do echo ${lines/$Search/$(bshuf file2.txt)} ; done
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
$ 
2
SigmaPiEpsilon