문자열 목록과 해당 교체 목록을 기반으로 파일의 정확한 문자열을 교체합니다.

문자열 목록과 해당 교체 목록을 기반으로 파일의 정확한 문자열을 교체합니다.

사전 기반 검색 및 바꾸기를 수행하려고 하는데 대소문자를 구분/정확하게 일치시키는 방법을 알 수 없지만 매우 어려운 것으로 판명되었습니다.

세 개의 파일이 있는데, fileA는 편집할 텍스트, FileB는 검색할 단어 목록, FileC는 바꿀 단어 목록입니다.

paste -ds///g /dev/null /dev/null <(sed 's|[[\.*^\b$\b/]|\\&|g' fileB) <(sed 's|[\&/]|\\\b&\b|g' fileC) /dev/null /dev/null | sed -f - fileA

내가 아는 한, sed에서 정확한 일치 항목을 검색하고 바꾸려면 다음과 같은 작업을 수행해야 합니다.sed 's/\<exact_word_to_replace\>/exact_replacement/g' filename

\<하지만 위 코드의 어디에 있는지 잘 모르겠습니다. \>가야 합니다!

더 좋아 질까 \b? 그렇다면 그건 어디로 가는 걸까요?

누군가가 나를 올바른 방향으로 밀어줄 수 있기를 바랍니다...

건배, 니오븀

이는 다음을 기반으로 합니다. https://unix.stackexchange.com/a/271108

답변1

나는 paste이것을 전혀 사용하지 않을 것입니다. sed나는 awk나 perl을 사용할 것이다. 예를 들어:

먼저, 일부 샘플 입력 파일입니다. (나의 편의를 위해) File[ABC]파일 A와 B는 검색 패턴과 해당 대체 항목의 의미를 변경했음을 참고하세요. FileC는 수정할 입력 텍스트 파일입니다.

중요한 것은 검색어가 포함된 파일이 스크립트의 첫 번째 인수이고 대체 문자열이 포함된 파일이 두 번째 인수라는 것입니다. 수정될 실제 입력은 세 번째(있는 경우 후속) 인수 및/또는 표준 입력에서 옵니다.

$ cat FileA
house

$ cat FileB
dwelling

$ cat FileC
Mr House does not live in a land-based house, his house is a houseboat.

Perl 스크립트도 있습니다. 다른 이름으로 저장 replace.pl하고 실행 가능하게 만듭니다 chmod +x replace.pl.

$ cat replace.pl 
#!/usr/bin/perl

use strict;

# Variables to hold the first two filenames.
my $FileA = shift;
my $FileB = shift;

# An associative array ("hash") called %RE. The keys are the search 
# regexes and the values are the replacements.
my %RE;

# Read both FileA and FileB at the same time, to build a
# hash of pre-compiled regular expressions (%RE) and their
# replacements.

open(my $A,'<',$FileA) || die "Couldn't open $FileA for read: $!\n";
open(my $B,'<',$FileB) || die "Couldn't open $FileB for read: $!\n";
while(my $a = <$A>) { # loop reading lines from first file
  die "$FileA is longer than $FileB" if (eof $B);
  my $b = <$B>; # read in a line from 2nd file
  die "$FileB is longer than $FileA" if (eof $A && ! eof $B);

  chomp($a,$b);

  # Uncomment only ONE of the following four lines:
  $RE{qr/\b$a\b/} = $b;                 # regular expression match
  #$RE{qr/\b\Q$a\E\b/} = $b;            # exact-match version.
  #$RE{qr/(?<!-)\b$a\b(?!-)/} = $b;     # regexp match, no hyphen allowed
  #$RE{qr/(?<!-)\b\Q$a\E\b(?!-)/} = $b; # exact match, no hyphen allowed.

}
close($A);
close($B);

# process stdin and/or any remaining filename argument(s) on
# the command line (e.g. FileC).
while (<>) {
  foreach my $a (keys %RE) {
    s/$a/$RE{$a}/g;
  };
  print;
}

노트:

  • Perl의 chomp기능은 변수 또는 변수 목록에서 후행 입력 레코드 구분 기호( $/-텍스트 파일 유형 및 운영 체제에 따라 개행 또는 CR+LF와 같은 줄 끝 문자)를 제거합니다. 바라보다 perldoc -f chomp.

  • Perl의 qr참조 연산자는 컴파일된 정규식을 반환합니다. perldoc -f qr자세히보다.

  • 검색, 바꾸기 및 텍스트 파일이 모두 작은 경우 미리 컴파일된 정규식은 별 차이가 없습니다. 검색 및 바꾸기 목록(파일 A 및 B)이 길거나 입력(파일 C)이 큰 경우 성능에 큰 차이가 있습니다. 정규식을 반복적으로 컴파일하는 오버헤드로 인해 CPU 처리 능력과 시간이 크게 소모됩니다.

  • 정규식은 FileA에서 컴파일되므로 \b$a\bFileA의 값 주위에 너비가 0인 단어 경계 표시가 포함되어 있습니다. 보기 man perlre및 검색 word boundary"너비 없음"은 \b실제로 입력 텍스트를 일치시키거나 사용하지 않고 거기에서 볼 것으로 예상되는 것만 주장하는 것을 의미합니다. 너비가 0인 어설션의 다른 예로는 ^(Row Anchor Start) 및 $(Row Anchor End)가 있습니다. Assertions동일한 매뉴얼 페이지 내에서 검색하십시오.

  • FileA의 패턴을 고정 문자열로 처리하려면(즉, 모든 정규식 메타 문자가 특별한 의미가 없는 리터럴 문자열 *로 처리됨 ) 패턴을 및로 묶어 메타 문자를 비활성화(따옴표)하십시오. 중요한 것은 무엇인가?\Q\E\b외부\Q\E. 주석 처리된 예제를 추가했습니다. 이는 에도 문서화되어 있습니다 man perlre.

  • FileA의 패턴이 \이스케이프되지 않은 문자로 끝나면 스크립트가 중단됩니다. 또한 \E고정 문자열 버전을 사용하는 경우 포함된 패턴으로 인해 버전이 손상될 수 있습니다. 또한 \Q고정되지 않은 문자열 버전에서도 문제가 발생할 수 있습니다. 쓰레기는 들어가고 쓰레기는 나옵니다. 입력 내용을 정리하세요.

  • 또한 man perlre: Perl에서는 문자( \w)라는 단어를 다음과 같이 정의합니다.영숫자 문자와 "_", 기타 연결 구두점 문자 및 유니코드 태그

  • 하이픈과 대부분의 기타 구두점 문자는 단어를 끝냅니다. houseboatFileC의 내용은 동일하게 유지되지만 로 house-boat변경되며 dwelling-boat이는 이상적이지 않습니다.share-houseshare-dwelling

    이 문제는 RE의 하이픈 문자(예: 또는 )에 대해 너비가 0인 부정 예측 및 뒤돌아보기 어설션(각각 및 )을 사용하도록 스크립트를 변경하여 (?!pattern)해결할 수 있습니다. 간단히 말해서, 이는 Perl의 정규식 엔진에 "우리가 찾고 있는 패턴이 그 앞이나 뒤에 존재한다면 일치하지 않습니다."라고 알려줍니다.(?<!pattern)$RE{qr/(?<!-)\b$a\b(?!-)/} = $b;$RE{qr/(?<!-)\b\Q$a\E\b(?!-)/} = $b;-

    RE가 다음 문자를 집어삼키는 것을 방지하려면 여기서 너비가 0인 어설션을 사용하는 것이 중요합니다(그렇게 부정된 문자 클래스뿐만 아니라 [^-])(같은 이유로 너비가 0인 어설션은 \b실제로 입력을 일치하거나 소비하지 않습니다). 이번에도 로그인이 되어 man perlre검색을 해보세요 Lookaround Assertions.

    이 예제도 스크립트에 추가했습니다.

  • 수정자는 사용되지 않으므로 /i정규식 일치는 대소문자를 구분합니다.

  • 스크립트에는 매우 원시적인 매개변수 처리 기능이 있습니다. 더 나은 것이 필요하다면 Perl의 많은 명령줄 인수/옵션 처리 모듈 중 하나를 사용하십시오.GetSelect::표준또는Getopt::긴. 이는 핵심 Perl 모듈이며 Perl에 포함되어 있습니다.

마지막으로 일부 샘플 출력은 다음과 같습니다.

$ ./replace.pl FileA FileB FileC
Mr House does not live in a land-based dwelling, his dwelling is a houseboat.

스크립트가 실제로 각 개별 입력 파일을 변경하도록 하려면(단순히 표준 출력으로 인쇄하는 대신) 첫 번째 줄을 다음과 같이 변경합니다.

#!/usr/bin/perl

도착하다

#!/usr/bin/perl -i

또는 (원본 파일을 .bak로 저장하려는 경우):

#!/usr/bin/perl -i.bak

그런데 -i내부 편집 옵션을 사용하더라도 입력이 파일 대신 표준 입력에서 오는 경우 스크립트는 계속 작동합니다.

관련 정보