파일의 모든 단어를 읽고 발견된 경우 다른 파일의 대체 단어로 바꾸는 방법

파일의 모든 단어를 읽고 발견된 경우 다른 파일의 대체 단어로 바꾸는 방법

하나하나 읽어야겠어전체 단어파일의 각 줄을 사용 sed하거나, awk해당 단어가 파일에 있는 경우 다른 파일의 단어로 바꾸십시오.

A.txt 파일의 내용:

1, This is a Record One, Value1, Dummy_val1 One, $$MOON$$
2, This is a Record Two, Value2, Dummy_val2 Two, #LATER
3, This is a Record Three, Value3, Dummy_val3 Three, #LATER
4, This is a Record Four, Value4, Dummy_val4 Four, $$MOON$$

그런 다음 Search_Replace_File.txt는 어떤 단어를 어떤 단어로 바꿔야 하는지에 대한 정보를 제공합니다.

One=Ten
Two=Twenty
Three=Thirty
Four=Forty
$$MOON$$=SUN
#LATER=SNOW

예상 출력은 다음과 같습니다.

1, This is a Record Ten, Value1, Dummy_val1 Ten, SUN
2, This is a Record Twenty, Value2, Dummy_val2 Twenty, SNOW
3, This is a Record Thirty, Value3, Dummy_val3 Thirty, SNOW
4, This is a Record Forty, Value4, Dummy_val4 Forty, SUN

노트:

  1. 목록에서 이전 단어가 새 단어로 대체되는 경우 새 단어와 다른 단어의 매핑이 매핑 파일에 존재하면 여전히 대체될 수 있습니다.
  2. 대체 문자열에는 아래와 같은 기호가 포함될 수도 있습니다. $$MOON$$=일요일 #LATER=눈

지금까지 다음 코드를 시도했지만 단어를 대체하지 않습니다.

#!/bin/bash
while read var
do
search_string=`echo "$var"|awk -F= '{print $1}'`
replace_string=`echo "$var"|awk -F= '{print $2}'`
sed "s/$searchstring/$replacestring/g" fileA.csv > fileB.csv
done < Search_Replace_File.txt

mv fileB.csv fileA.csv

답변1

모든 Unix 시스템의 모든 쉘에서 awk를 사용하십시오.

$ cat tst.awk
BEGIN { FS="=" }
NR==FNR {
    map[$1] = $2
    next
}
{
    head = ""
    tail = $0
    while ( match(tail,/[^,= ]+/) ) {
        old = substr(tail,RSTART,RLENGTH)
        new = (old in map ? map[old] : old)
        head = head substr(tail,1,RSTART-1) new
        tail = substr(tail,RSTART+RLENGTH)
    }
    print head tail
}

$ awk -f tst.awk Search_Replace_File.txt fileA.txt
1, This is a Record Ten, Value1, Dummy_val1 Ten, SUN
2, This is a Record Twenty, Value2, Dummy_val2 Twenty, SNOW
3, This is a Record Thirty, Value3, Dummy_val3 Thirty, SNOW
4, This is a Record Forty, Value4, Dummy_val4 Forty, SUN

위의 가정은 입력 단어에 ,, =또는 공백이 포함되어 있지 않지만 다른 문자는 포함된다는 것입니다.

또한 이전 단어가 새 단어에 매핑되고 해당 새 단어가 다른 새 단어에도 매핑될 수 있는 경우 위의 코드는 그렇게 하지 않습니다. 이렇게 하면 무한 재귀가 발생하고 첫 번째 매핑만 보존되기 때문입니다.

답변2

다음과 같이 awk를 사용하여 이를 수행할 수 있습니다.

awk '
BEGIN {
  d = "[$]{2}"
  w = "[[:alpha:]][_[:alnum:]]*"
  re = d w d "|" "[#]?" w
}
FS == "="{a[$1]=$2;next}
{
  z = ""
  t = $0
  gsub(re, RS "&" RS, t)
  nf = split(t, x, RS)
  for (i=1; i<=nf; i++)
    z = z ((i%2) ? x[i] : ((x[i] in a) ? a[x[i]] : x[i]))
  print z
}
' FS="=" Search_Replace_File.txt FS=" " fileA.txt
1, This is a  Record Ten, Value1, Dummy_val1 Ten, SUN
2, This is a Record Twenty, Value2, Dummy_val2 Twenty, SNOW
3, This is a Record Thirty, Value3, Dummy_val3 Thirty, SNOW
4, This is a Record Forty, Value4, Dummy_val4 Forty, SUN

  • 단어를 정의하는 정규식입니다.
  • 현재 줄의 단어를 개행 문자로 구분합니다.
  • 그런 다음 현재 줄을 개행 문자로 나눕니다.
  • 모든 단어는 짝수 필드입니다.
  • 단어가 배열 a에 있는지 확인하고 바꾸십시오.
  • 수정된 행을 인쇄합니다.

답변3

사용행복하다(이전 Perl_6)

~$ raku -pe 'BEGIN my %h = (          \ 
               "One" => "Ten",        \ 
               "Two" => "Twenty",     \
               "Three" => "Thirty",   \
               "Four" => "Forty",     \
               q[$$MOON$$] => "SUN",  \
               q[#LATER] => "SNOW");  \ 
             s:g/ [ ^ | <punct>+ | <blank>+] <( @(%h.keys) )> [ <punct>+ | <blank>+ | $ ] /%h{$/}/;'  file

Perl 계열의 프로그래밍 언어인 Raku로 작성된 답변입니다. 위의 내용은 -pesed와 유사한 자동 인쇄 명령줄 플래그를 사용합니다. 해시는 %h인라인으로 선언됩니다. 이스케이프 $해야 하지만 위와 같이 작성할 "\$\$MOON\$\$"수 있으므로 q[$$MOON$$]백슬래시의 필요성이 줄어듭니다.

교체의 핵심은 전역 수정자를 s///사용한다는 것 입니다. :g일치 도메인(왼쪽 절반) 내에서 @(%h.keys)해시 키는 -sigiled 배열로 캐스팅되며 @이는 일치 도메인 내에서 리터럴 문자열로 이해됩니다. 대체 필드(오른쪽 절반)에서 일치하는 변수 는 로 대체된 $/해당 키를 복구하는 데 사용됩니다 .value

여기서 문제는 "성격"는 일반적으로 영숫자 더하기 - _(밑줄)로 정의됩니다. 이 경우 각각 왼쪽과 오른쪽 단어 경계를 나타내기 때문에 Raku의 <<(왼쪽) 및 >>(오른쪽) 너비가 0인 정규식 앵커를 사용하게 됩니다. 이러한 경계 표시가 없는 경우, 같은 내용은 . Fourteen로 잘못 대체됩니다 Fortyteen(아래 예제 입력 파일의 마지막 줄 참조: 예제 출력은 올바른 결과를 보여줍니다).

OP가 다음으로 시작/끝나는 키를 사용하여 솔루션을 요청했기 때문에아니요-영숫자와 _문자(따라서 너비가 0인 단어 경계 앵커 사용 제외)를 사용하는 한 가지 접근 방식은 다음과 같이 가능성을 설명하는 것입니다.

s:g/ [ ^ | <punct>+ | <blank>+] <( @(%h.keys) )> [ <punct>+ | <blank>+ | $ ] /%h{$/}/;

입력 예:

1, This is a Record One, Value1, Dummy_val1 One, $$MOON$$
2, This is a Record Two, Value2, Dummy_val2 Two, #LATER
3, This is a Record Three, Value3, Dummy_val3 Three, #LATER
4, This is a Record Four, Value4, Dummy_val4 Four, $$MOON$$
5, This is a Record Fourteen, Value14, Dummy_val14 Fourteen, #LATER

예제 출력:

1, This is a Record Ten, Value1, Dummy_val1 Ten, SUN
2, This is a Record Twenty, Value2, Dummy_val2 Twenty, SNOW
3, This is a Record Thirty, Value3, Dummy_val3 Thirty, SNOW
4, This is a Record Forty, Value4, Dummy_val4 Forty, SUN
5, This is a Record Fourteen, Value14, Dummy_val14 Fourteen, SNOW

아마도 더 나은(더 안정적인) 접근 방식은 더 신중하게 선택하는 것일 것입니다.아니요-단어 키(예: 다음으로 시작/끝나는지 확인)아니요-단어 문자(예: #LATER#대신 #LATER). 그런 다음 사용해시 값은 다음과 같습니다.

~$ raku -pe 'BEGIN    my %words = ("One" => "Ten", "Two" => "Twenty", "Three" => "Thirty", "Four" => "Forty")  \
             andthen  my %non-words = (q[$$MOON$$] => "SUN", q[#LATER#] => "SNOW");  \
             s:g/ << @(%words.keys) >> /%words{$/}/;  \
             s:g/ [ ^ | <punct>+ | <blank>+] <( @(%non-words.keys) )> [ <punct>+ | <blank>+ | $ ] /%non-words{$/}/;'  file

이 코드는 동일한 샘플 입력 파일( #LATER로 업데이트됨 #LATER#)을 사용하여 위와 동일한 샘플 출력을 생성합니다.

https://docs.raku.org/언어/regexes#Regex_interpolation
https://docs.raku.org/언어/regexes
https://docs.raku.org
https://raku.org

관련 정보