하나하나 읽어야겠어전체 단어파일의 각 줄을 사용 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
노트:
- 목록에서 이전 단어가 새 단어로 대체되는 경우 새 단어와 다른 단어의 매핑이 매핑 파일에 존재하면 여전히 대체될 수 있습니다.
- 대체 문자열에는 아래와 같은 기호가 포함될 수도 있습니다. $$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로 작성된 답변입니다. 위의 내용은 -pe
sed와 유사한 자동 인쇄 명령줄 플래그를 사용합니다. 해시는 %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