사전을 사용하여 파일에서 문자열 교체를 수행하는 좋은 방법은 무엇입니까많은치환된 말단 치환체 쌍? 그리고많은, 실제로는 20개 정도를 의미합니다. 많지는 않지만 깔끔하게 정리하고 싶을 만큼 충분합니다.
dictionary.txt
다음과 같은 많은 항목을 교체해야 하기 때문에 관리 가능한 방식으로 모든 치환된 최종 치환체 쌍을 파일에 수집 하고 싶습니다.
"yes" : "no"
"stop" : "go, go, go!"
"wee-ooo" : "ooooh nooo!"
"gooodbye" : "hello"
"high" : "low"
"why?" : "i don't know"
이제 특정 파일에 이러한 대체 항목을 적용하고 싶습니다 novel.txt
.
그런 다음 in의 모든 인스턴스 가 교체되고 (그래서 Even이 교체됨) in의 모든 인스턴스가 교체 magiccommand --magicflags dictionary.txt novel.txt
되도록 실행하려고 합니다 .yes
novel.txt
no
Bayesian
Banoian
goodbye
novel.txt
hello
지금까지 교체해야 할 문자열은 다음과 같습니다.아니요그 안에 따옴표가 있습니다(작은따옴표나 큰따옴표가 아님). (물론 따옴표가 포함된 문자열을 훌륭하게 처리하는 솔루션을 보면 좋을 것입니다.)
나도 알고 있고 sed
/ awk
main gawk
도 이런 일을 할 수 있지만, 이런 사전 파일도 사용할 수 있나요? gawk
적합한 후보자 인 것 같습니다 magiccommand
. 적합한 후보자는 누구입니까 magicflags
? 어떻게 포맷해야 합니까 dictionary.txt
?
답변1
방법은 다음과 같습니다 sed
.
sed '
s|"\(.*\)"[[:blank:]]*:[[:blank:]]*"\(.*\)"|\1\
\2|
h
s|.*\n||
s|[\&/]|\\&|g
x
s|\n.*||
s|[[\.*^$/]|\\&|g
G
s|\(.*\)\n\(.*\)|s/\1/\2/g|
' dictionary.txt | sed -f - novel.txt
작동 방식:
첫 번째 파일은 스크립트 파일이 sed
됩니다 (편집 명령, 한 줄에 하나씩). dictionary.txt
이는 이러한 명령을 실행하는 두 번째 명령 sed
(참고, 이는 -f -
의 읽기 명령을 의미함 stdin
), edit 으로 파이프됩니다 novel.txt
.
형식을 번역해야 합니다.
"STRING" : "REPLACEMENT"
명령 에 넣고 sed
프로세스의 모든 특수 문자를 이스케이프 합니다 LHS
.RHS
s/ESCAPED_STRING/ESCAPED_REPLACEMENT/g
그래서 첫 번째 교체
s|"\(.*\)"[[:blank:]]*:[[:blank:]]*"\(.*\)"|\1\
\2|
(개행 문자입니다) 가 됩니다 "STRING" : "REPLACEMENT"
. 그런 다음 결과를 이전 공간에 복사합니다. 첫 번째 부분을 제거하고 예약 문자(이것은)만 유지한 다음 이스케이프합니다. 그런 다음 패턴 공간을 사용하여 보유 버퍼를 변경하고 유지된 두 번째 부분만 제거하고 이스케이프합니다(즉). 그런 다음 버퍼의 내용은 패턴 공간에 추가되어 유지되므로 이제 패턴 공간 내용은 . 최종 교체STRING\nREPLACEMENT
\n
h
s|.*\n||
REPLACEMENT
s|[\&/]|\\&|g
RHS
x
s|\n.*||
STRING
s|[[\.*^$/]|\\&|g
LHS
G
ESCAPED_STRING\nESCAPED_REPLACEMENT
s|\(.*\)\n\(.*\)|s/\1/\2/g|
그것을로 변환하다s/ESCAPED_STRING/ESCAPED_REPLACEMENT/g
답변2
이것은 펄 버전입니다. 미리 컴파일된 정규식을 포함하는 해시를 생성한 다음 각 입력 줄을 반복하여 모든 정규식을 각 줄에 적용합니다. 입력 파일의 "내부 편집"을 위한 것 perl
입니다 . -i
정규식이나 대체 문자열을 쉽게 추가하거나 변경할 수 있습니다.
미리 컴파일된 정규 표현식을 사용하면 qr//
스크립트 속도가 크게 향상됩니다. 이는 처리할 정규 표현식 및/또는 입력 줄 수가 많은 경우 눈에 띄게 향상됩니다.
#! /usr/bin/perl -i
use strict;
# the dictionary is embedded in the code itself.
# see 2nd version below for how to read dict in
# from a file.
my %regex = (
qr/yes/ => 'no',
qr/stop/ => 'go, go, go!',
qr/wee-ooo/ => 'ooooh nooo!',
qr/gooodbye/ => 'hello',
qr/high/ => 'low',
qr/why\?/ => 'i don\'t know',
);
while (<>) {
foreach my $key (keys %regex) {
s/$key/$regex{$key}/g;
}
}
다음은 명령줄의 첫 번째 파일 이름에서 사전을 읽는 동시에 두 번째(및 선택적으로 후속) 파일 이름을 처리하는 또 다른 버전입니다.
#! /usr/bin/perl -i
use strict;
# the dictionary is read from a file.
#
# file format is "searchpattern replacestring", with any
# number of whitespace characters (space or tab) separating
# the two fields. You can add comments or comment out dictionary
# entries with a '#' character.
#
# NOTE: if you want to use any regex-special characters as a
# literal in either $searchpattern or $replacestring, you WILL
# need to escape them with `\`. e.g. for a literal '?', use '\?'.
#
# this is very basic and could be improved. a lot.
my %regex = ();
my $dictfile = shift ;
open(DICT,'<',$dictfile) || die "couldn't open $dictfile: $!\n";
while(<DICT>) {
s/#.*// unless (m/\\#/); # remove comments, unless escaped.
# easily fooled if there is an escaped
# '#' and a comment on the same line.
s/^\s*|\s*$//g ; # remove leading & trailing spaces
next if (/^$/) ; # skip empty lines
my($search, $replace) = split;
$regex{qr/$search/} = $replace;
};
close(DICT);
# now read in the input file(s) and modify them.
while (<>) {
foreach my $key (keys %regex) {
s/$key/$regex{$key}/g;
}
}
답변3
이것을 주석으로 작성하기 시작했지만 너무 복잡해져서 두 번째 Perl 답변이 있습니다. 소스 파일이 주어지면 깔끔한 Perl 트릭을 사용하여 정규식을 작성할 수 있습니다.
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
#build key-value pairs
my %replace = map { /"(.+)"\s*:\s*"(.+)"/ } <DATA>;
print Dumper \%replace;
#take the keys of your hash, then build into capturing regex
my $search = join ( "|", map {quotemeta} keys %replace );
$search = qr/($search)/;
print "Using match regex of: $search\n";
#read stdin or files on command line, line by line
while ( <> ) {
#match regex repeatedly, replace with contents of hash.
s/$search/$replace{$1}/g;
print;
}
__DATA__
"yes" : "no"
"stop" : "go, go, go!"
"wee-ooo" : "ooooh nooo!"
"gooodbye" : "hello"
"high" : "low"
"why?" : "i don't know"
map
해시를 생성하고 키-값 쌍을 생성하기 위해 여러 줄 패턴 일치를 사용합니다 .
검색 정규식을 작성하고 여기에 캡처된 값으로 바꿉니다.
사용되는 것은 <>
Perl의 매직 파일 핸들 STDIN
또는 명령줄에 지정된 파일입니다. sed는 이것을 어떻게 수행합니까? (파일을 사용하고 해당 스키마를 "일반적으로" 읽을 수 있습니다. 사용법은 DATA
순전히 설명을 위한 것입니다.)