공백으로 구분될 수 있는 두 개의 연속 문자열 인스턴스를 바꾸는 정규식

공백으로 구분될 수 있는 두 개의 연속 문자열 인스턴스를 바꾸는 정규식

나는 공백으로 분리될 수도 있고 분리되지 않을 수도 있는 두 개의 특정 연속 문자열의 모든 인스턴스를 대체하는 Perl 한 줄짜리 코드를 작성하고 싶습니다.

john paul예를 들어 두 개의 문자열이 및 이고 george이 문자열의 연속 인스턴스를 해당 순서대로 바꾸고 싶다고 가정해 보겠습니다 pete. 한 줄의 코드 실행

$ cat ~/foo

john paulgeorge
john paul george
john paul

    george

george john paul

결과가 나와야 한다

$ cat ~/foo

pete
pete
pete

george john paul

내 마음에 떠오르는 유일한 것은

$ perl -p -i -e 's/john paul\s*george/pete/g' ~/foo

하지만 이로 인해

$ cat ~/foo

pete
pete
john paul

    george

george john paul

내 회선 중 하나를 변경할 수 있는 방법이 있나요?

답변1

한 줄의 코드에 추가해야 할 유일한 것은 파일을 단일 문자열로 읽는 옵션입니다.

perl -0777 -p -i -e 's/john paul\s*george/pete/g' ~/foo
#    ^^^^^

바라보다http://perldoc.perl.org/perlrun.html#명령 스위치

답변2

perl-n옵션은 -p프로그램 주위에 변형을 배치하여 while (<>) { ... }입력을 한 줄씩 처리하게 합니다. 여러 줄에 걸쳐 바꾸려면 전체 내용을 문자열로 읽어야 하며, 이 작업은 직접 수행해야 합니다.

perl -e 'local $/;$_=<>;s/john paul\s*george/pete/g;print'

이것은 정의되지 않았습니다$/, 레코드 구분 기호, 하도록 하다<>흡연더 이상 줄이 분할되지 않고 $_전체 입력이 한 번에 읽혀지며 긴 문자열이 대체됩니다. 또한 직접 인쇄해야 합니다.

여기에는 더 이상 마법이 없습니다. 이는 완전한 Perl 프로그램을 작성하는 데 약간 불편한 방법일 뿐입니다. -i그러나 여전히 내부 교체에 사용할 수 있습니다.

큰 파일이 있는 경우 이는 상당히 비효율적(또는 메모리를 소모)이 될 수 있지만 더 나은 파서를 구축하지 않으면 이는 다소 불가피해 보입니다. 다른 대안을 살펴볼 수도 perldoc -q 'entire file'있으며 많은 사람들이 진심이 아니라고 말할 것입니다.

답변3

sed전체 파일을 차지하지 않고도 이 작업을 수행 할 수 있습니다 .

sed -e ':top' -e 's/john paul[[:space:]]*george/pete/g;$b' -e '/john paul[[:space:]]*$/!b' -e 'N;btop' input

이는 메모리 사용량이 훨씬 적습니다. 현재 행에서 시작하여 여러 행을 일치시킬 가능성이 있는 경우에만 여러 행을 흡수합니다. 그러면 일치하는 항목을 찾을 때까지 또는 더 이상 일치할 가능성이 없을 때까지 짜증이 납니다.

또한 POSIX와 호환됩니다. (Perl은 POSIX의 일부가 아닙니다.) 의견에서 이 점을 지적해 주신 mikeserv에게 감사드립니다.

설명하다:

:top라는 라벨을 설정합니다 top.

s/john paul[[:space:]]*george/pete/g패턴 공간의 모든 항목을 원하는 대로 대체합니다. (기본값은 프로그레시브입니다.)

$b현재 줄이 파일의 마지막 줄이면 끝으로 이동하여 인쇄합니다.

/john paul[[:space:]]*$/!b:

패턴은 패턴 space 의 끝에서 일치하고 /john paul[[:space:]]*$/그 뒤에 공백이 수에 상관 없이(단, 공백만 있음) 뒤따라 패턴이 반전됩니다. 따라서 여기서 효과는 멀티플렉싱 가능성이 없는 경우에만 명령을 실행하는 것입니다(스크립트 끝으로 점프하여 패턴 공간을 인쇄하고 파일에서 다음 줄을 읽고 스크립트의 맨 위에서 시작). 현재 패턴 공간 행 일치부터 시작합니다.john paul!b

N파일의 다음 줄을 패턴 공간에 추가합니다(개행 문자를 추가한 후).

btop:top패턴 공간을 지우지 않고 라벨 로 분기합니다 .

답변4

파일을 읽으려면 -0777 옵션을 사용해야 합니다. 하지만 \s도 \n과 일치하도록 하려면 끝에 m 수정자를 추가해야 합니다.

Perl이 -0을 발견하면 입력 레코드 구분 기호($/)를 다음과 같이 업데이트합니다. 예를 들어 -00을 입력하면 Perl은 $/를 단락 모드로 설정합니다. 그래서

perl -0777 -pe 's/^john paul\s*george/pete/gm' george.txt

다음과 동일:

perl  -pe 'BEGIN { undef $/ ; } s/^john paul\s*george/pete/gm' george.txt 

관련 정보