%EB%A5%BC%20%EC%88%98%ED%96%89%ED%95%98%EB%8A%94%20%EB%B0%A9%EB%B2%95%EC%9D%80%20%EB%AC%B4%EC%97%87%EC%9E%85%EB%8B%88%EA%B9%8C%3F%20%EC%97%AC%EB%9F%AC%20%EB%8B%A8%EC%96%B4%EB%A5%BC%20%ED%95%B4%EB%8B%B9%ED%95%98%EB%8A%94%20%EB%8B%A4%EB%A5%B8%20%EB%8B%A8%EC%96%B4%EB%A1%9C%20%EB%B0%94%EA%BF%94%EC%95%BC%20%ED%95%A9%EB%8B%88%EB%8B%A4..png)
sed
나는 이 질문이 이전에 요청된 적이 없다고 생각하므로 이것이 가능한지 모르겠습니다 .
문장에 단어로 확장해야 하는 숫자가 많이 있다고 가정합니다. 실제적인 예는 일반적인 에세이에서 번호가 매겨진 인용을 MLA 형식으로 바꾸는 것입니다.
essay.txt
:
Sentence 1 [1]. sentence two [1][2]. Sentence three[1][3].
Key.txt
(이것은 탭으로 구분된 파일입니다):
1 source-one
2 source-two
3 source-three
...etc
예상되는 Result.txt
:
Sentence 1 [source-one]. sentence two [source-one][source-two]. Sentence three[source-one][source-three]
다음은 의사 코드 시도이지만 제대로 이해하지 못 sed
하거나 tr
제대로 수행하지 못했습니다.
cat essay.txt | sed s/$(awk {print $1} key.txt)/$(awk {print $2} key.txt)/g
추신: 여러 용어를 사용하여 대량 찾기 및 바꾸기를 위한 메모장++의 트릭이 있다면 좋을 것입니다. 현재로서는 찾기 및 바꾸기가 한 번에 한 용어에 대해서만 작동하는 것처럼 보이지만 한 번에 여러 용어에 대해 일괄적으로 수행할 수 있는 방법이 필요합니다.
답변1
대신 다음을 사용해야 합니다 perl
.
$ perl -ne '
++$nr;
if ($nr == $.) {
@w = split;
$k{$w[0]} = $w[1];
}
else {
for $i (keys %k) {
s/(\[)$i(\])/$1.$k{$i}.$2/ge
}
print;
}
close ARGV if eof;
' key.txt essay.txt
Sentence 1 [source-one]. sentence two [source-one][source-two]. Sentence three[source-one][source-three]
답변2
awk
perl
여기 와 똑같이 효과적으로 할 수 있습니다조금 더 간단하다, GNU 이외의 구현에서는 (큰?) 텍스트 파일을 불필요하게 분할하여 약간의 CPU 시간을 낭비할 수 있습니다.
awk 'NR==FNR{a["\\["$1"\\]"]="["$2"]";next} {for(k in a) gsub(k,a[k]);print}' key.txt essay.txt
당신이 요청했기 때문에설명:
awk
패턴-액션 쌍으로 구성된 '스크립트'를 사용하여 작동한 다음 하나 이상의 파일(또는 표준 입력)을 한 번에 하나의 '레코드'로 읽습니다. 기본적으로 각 레코드는 한 줄이고 각 레코드에 대해 다음과 같이 필드로 나눕니다. 기본적으로 공백(탭 포함)을 사용하고 (별도의 지시가 없는 한) 각 패턴을 테스트하고(종종 현재 레코드 및/또는 해당 필드를 확인함) 작업 실행과 일치하는지(종종 다음 작업을 수행함) 스크립트를 적용합니다. 또는 해당 레코드 및/또는 필드와 함께). 여기서는 두 파일을 지정하여key.txt essay.txt
해당 두 파일을 한 줄씩 순서대로 읽습니다. 스크립트~할 수 있다명령줄 대신 파일에 넣을 수 있지만 여기서는 그렇게 하지 않기로 결정했습니다.첫 번째 패턴은 입니다
NR==FNR
.NR
처리 중인 레코드의 번호를 나타내는 내장 변수입니다.FNR
마찬가지로 현재 입력 파일 내의 레코드 번호입니다. 첫 번째 파일(key.txt
)의 경우 이는 동일합니다. 두 번째 파일(및 기타 파일)의 경우 동일하지 않습니다.첫 번째 작업은 입니다
{a["\\["$1"\\]"]="["$2"]";next}
.awk
'연관' 또는 '해시' 배열이 있습니다. 문자열 값 표현식은 배열의 요소를 읽거나 설정합니다arrayname[subexpr]
. 예를 들어 등은 필드를 참조하고 전체 레코드를 참조합니다. 위의 내용에 따라 이 작업은 의 행에 대해서만 실행됩니다. 예를 들어 해당 파일의 마지막 행은 과 is 이며 , 이는 아래 첨자 및 내용이 있는 배열 항목을 저장합니다 . 내가 이 값을 선택한 이유는 아래를 참조하세요. and 는 실제 값이 와 while 인 이스케이프를 사용하는 문자열 리터럴이며 , 사이에 연산자가 없는 문자열 피연산자가 연결됩니다. 마지막으로 이 작업이 실행됩니다. 즉, 이 레코드에 대한 나머지 스크립트를 건너뛰고 루프의 맨 위로 돌아가서 다음 레코드에서 시작하면 됩니다.subexpr
$number
$1 $2
$0
key.txt
$1
3
$2
source-three
\[3\]
[source-three]
"\\["
"\\]"
\[
\]
"[" "]"
[ ]
next
두 번째 패턴은 비어 있으므로 두 번째 파일의 모든 줄과 일치하고 작업을 실행합니다
{for(k in a) gsub(k,a[k]);print}
. 이for(k in a)
구성은 Bourne 유형 쉘이 에서 수행하는 것과 매우 유사한 루프를 생성합니다for i in this that other; do something with $i; done
. 단, 여기에서 의 값은k
다음 과 같습니다.아래첨자배열의a
. 각 값에 대해gsub
주어진 정규식과 일치하는 모든 항목을 찾아 주어진 문자열로 바꾸는 (전역 대체)를 실행합니다. 예를 들어\[3\]
텍스트 문자열과 일치하는 정규식[3]
과[source-three]
이러한 모든 일치 항목을 대체하려는 텍스트 문자열이 되도록 배열(위)에서 아래 첨자와 내용을 선택했습니다. 기본적으로gsub
현재 레코드에서 작동합니다 .$0
모든 값에 대해 이 대체를 수행한 후 기본적으로 현재 상태 그대로 출력하고 원하는 모든 대체가 수행된 상태로a
실행됩니다 .print
$0
참고: 특히 Linux에서 일반적이지만 보편적이지는 않은 GNU awk(gawk)에는 실행된 패턴이나 작업에 필드 값이 필요한 항목이 없는 경우 실제로 필드 분할을 수행하지 않는 최적화 기능이 있습니다. 다른 구현에서는 약간의 CPU 시간이 낭비될 수 있으며, cuonglm의 perl
방법은 이를 방지하지만 파일이 엄청나지 않으면 눈에 띄지도 않을 것입니다.
답변3
bash$ sed -f <( sed -rn 's#([0-9]+)\s+(.*)#s/\\[\1]/[\2]/g#p' key.txt ) essay.txt
Sentence 1 [source-one]. sentence two [source-one][source-two]. Sentence three[source-one][source-three].
답변4
이를 달성하기 위해 루프 내에서 내부 sed 대체를 사용할 수 있습니다.
$ cp essay.txt Result.txt
$ while read n k; do sed -i "s/\[$n\]/\[$k\]/g" Result.txt; done < key.txt
$ cat Result.txt
Sentence 1 [source-one]. sentence two [source-one][source-two]. Sentence three[source-one][source-three].