입력에서 여러 개의 완전한 문자열을 제거하는 우아하고 성능이 뛰어난 한 줄 방법이 있습니까?
나는 100만 줄 정도의 대용량 텍스트 파일을 다룹니다.입력 파일및 100,000개의 일치하는 문자열히트 파일. Perl 스크립트를 로드했습니다.히트 파일해시에 넣은 다음 각 줄의 모든 "단어"를 확인하세요.입력 파일, 그러나 내 작업 흐름에서는 스크립트보다는 간단한 명령을 선호합니다.
내가 찾고 있는 기능은 다음과 같습니다.
perl -pe 's/\b(string1|string2|string3)\b)//g'
또는 중첩된 sed를 사용하는 이 접근 방식은 다음과 같습니다.
sed -e "$(sed 's:.*:s/&//ig:' hitfile)" inputfile
또는 셸에서 반복합니다.
while read w; do sed -i "s/$w//ig" hitfile ; done < inputfile
하지만 그건 너무 비싸요. 이 약간 더 효율적인 접근 방식이 효과적입니다(텍스트 파일에서 단어 목록의 모든 항목을 제거하는 방법은 무엇입니까?) 하지만 여전히 느립니다.
perl -Mopen=locale -Mutf8 -lpe '
BEGIN{open(A,"hitfile"); chomp(@k = <A>)}
for $w (@k){s/(^|[ ,.—_;-])\Q$w\E([ ,.—_;-]|$)/$1$2/ig}' inputfile
하지만 이 작업을 더 간결하게 수행할 수 있는 다른 트릭이 있습니까? 제가 간과하고 있는 다른 Unix 명령이나 방법이 있습니까? 정규식은 필요하지 않습니다. 순수/정확한 문자열을 해시(속도를 위해)와 비교하면 됩니다. 즉, "pine"은 "pineapple"과 일치하면 안 되지만 "(pine)"과 일치해야 합니다.
예를 들어, 제가 가진 아이디어 중 하나는 파일의 단어를 별도의 줄로 확장하는 것이었습니다.
앞으로:
Hello, world!
뒤쪽에:
¶
Hello
,
world
!
그런 다음 grep -vf를 사용하여 행을 처리하고 다시 작성/연결합니다.
다른 빠르고 쉬운 아이디어는 없나요?
답변1
당신의 것은 정확히 얼마나 큽니까 hitfile
? 당신이 하려는 일에 대한 몇 가지 실제적인 예를 보여줄 수 있습니까? 입력 데이터에 대한 자세한 내용을 제공하지 않았으므로 이는 다음과 같습니다.그냥 생각시도하고실제 데이터에 대한 벤치마크.
Perl 정규식은 상당히 커질 수 있으며 단일 정규식을 사용하면 입력 파일을 한 번에 수정할 수 있습니다. 여기서는 /usr/share/dict/words
거대한 정규식을 작성하는 예로 사용하고 있습니다. 정규식에는 약 99,000개 라인이 있고 크기는 약 1MB입니다.
use warnings;
use strict;
use open qw/:std :encoding(UTF-8)/;
my ($big_regex) = do {
open my $wfh, '<', '/usr/share/dict/words' or die $!;
chomp( my @words = <$wfh> );
map { qr/\b(?:$_)\b/ } join '|', map {quotemeta}
sort { length $b <=> length $a or $a cmp $b } @words };
while (<>) {
s/$big_regex//g;
print;
}
정규식은 필요하지 않습니다. 순수/정확한 문자열을 해시(속도를 위해)와 비교하면 됩니다. 즉, "pine"은 "pineapple"과 일치하면 안 되고 "(pine)"과 일치해야 합니다.
"pine"이 "pineapple"과 일치하면 안 되는 경우 입력에서 "pine"이 나타나는 전후의 문자도 확인해야 합니다. 고정 문자열 접근 방식을 사용하는 것은 확실히 가능하지만 단어 경계에 대한 정규식 개념처럼 들립니다(\b
) 당신이 추구하는 것입니다.
우아하고 성능이 뛰어난 한 줄짜리 방법이 있습니까? 내 작업 흐름에서는 스크립트보다 간단한 명령을 선호합니다.
나는 그 감정에 동의하는지 잘 모르겠습니다. 질문이 있으신가요 perl script.pl
? 한 줄의 코드처럼 셸 리디렉션/파이핑과 함께 사용할 수 있습니다. 코드를 스크립트에 넣으면 명령줄이 정리되고 모든 것을 한 줄의 코드에 집어넣지 않고도 복잡한 작업을 수행할 수 있습니다. 또한 짧다고 해서 반드시 빠른 것은 아닙니다.
스크립트를 사용하려는 또 다른 이유는 입력 파일이 여러 개 있는 경우입니다. 위에 표시된 코드를 사용하면 정규식을 작성하는 데 비용이 많이 들기 때문에 스크립트를 여러 번 호출하는 데 비용이 많이 듭니다. 단일 스크립트에서 여러 파일을 처리하면 해당 오버헤드가 제거됩니다. 나는 UNIX 원칙을 좋아하지만 빅 데이터의 경우 여러 프로세스를 호출하고(때로는 여러 번) 프로세스 간에 데이터를 파이핑하는 것이 항상 가장 효율적인 접근 방식은 아니며 단일 프로그램에서 모든 것을 단순화하는 것이 도움이 될 수 있습니다.
고쳐 쓰다: 댓글에 따르면, 밧줄은 자신의 발을 쏠 만큼 충분합니다.