나는 공백으로 분리될 수도 있고 분리되지 않을 수도 있는 두 개의 특정 연속 문자열의 모든 인스턴스를 대체하는 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
# ^^^^^
답변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