파일에서 텍스트를 무작위로 바꾸는 방법?


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이 파일이 빈 줄로 끝나지 않는 경우 비어 있지 않은 마지막 줄을 잡습니까 (죄송합니다, 현재 테스트 할 수 없습니다)? 권장하지 않는 경우 , 값을 변수에 SO로 지정하여 파일을 한 줄씩 읽기를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

또 다른 배쉬 솔루션. 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.