PCRE-regex는 grep을 사용하여 캡처 그룹을 제외합니다.

PCRE-regex는 grep을 사용하여 캡처 그룹을 제외합니다.

파일의 문자열을 일치시키기 위해 GNU grepPCRE 정규식 지원을 사용하고 있습니다 . -P입력 파일에는 다음 문자열이 포함된 줄이 포함되어 있습니다.

FOO_1BAR.zoo.2.someString:More-RandomString (string here too): 0.45654343

위 행의 숫자 2와 숫자를 캡처하고 싶습니다. 0.45654343정규식을 사용했어요

grep -Po ".zoo.\K[\d+](.*):\ (.*)$" file

하지만 나에게 있어서 결과는

2.someString:More-RandomString (string here too): 0.45654343

첫 번째 캡처 그룹에서 첫 번째 숫자를 가져올 수 2있으며 줄 끝의 캡처 그룹과도 일치시킬 수 있습니다. 하지만 두 캡처 그룹 사이의 단어/줄을 건너뛸 수는 없습니다.

저는 (.*)이 단어들을 중간에 포착하고 있는 그룹이 있다는 것을 알고 있습니다. 내가 하려는 것은 \K그것을 무시하기 위해 다른 것을 포함시키는 것입니다.

grep -Po ".zoo.\K[\d+](.*):\K (.*)$" file

하지만 이것은 나에게 두 번째 캡처 그룹을 0.556984.

(?:)구문이 다음 과 같은 비캡처 그룹도 있습니다.

grep -Po ".zoo.\K[\d+](?=.someString:More-RandomString (string here too)):\ (.*)$"

그러나 그것은 나에게 아무것도 가져오지 못했습니다. 내가 여기서 무엇을 놓치고 있는 걸까요?

답변1

grep이름은 g/re/p ed명령 뒤에 나타납니다. 주요 목적은 정규식과 일치하는 행을 인쇄하는 것입니다. 그 작업은 이 줄의 내용을 편집하는 것이 아닙니다. 당신은 sed(스트림 편집기) 또는 awk이것을 위해 있습니다.

이제 grepGNU부터 일부 구현에서는 각 줄의 일치하는 부분(캡처링 그룹의 일치하는 부분이 아니라 정규식이 일치하는 부분)을 인쇄하는 옵션을 grep추가합니다 . -o이미 grepGNU와 유사한 구현( 사용 -P) 또는 pcregrepPCRE에 대한 정규식 지원이 있습니다.

pcregrep실제로 -o<n>캡처 그룹의 내용을 인쇄하는 옵션이 추가되었습니다. 그래서 당신은 이것을 할 수 있습니다 :

pcregrep -o1 -o2 --om-separator=' ' '.zoo.(\d+).*:\s+(.*)'

그러나 여기서 확실한 표준 솔루션은 다음을 사용하는 것입니다 sed.

sed -n 's/^.*\.zoo\.\([0-9]\{1,\}\).*:[[:space:]]\{1,\}/\1 /p'

또는 perl 정규식을 원하면 perl을 사용하십시오.

perl -lne 'print "$1 $2" if /\.zoo\.(\d+).*:\s+(.*)/'

GNU를 사용하여 grep일치 항목이 다른 줄에 나타나는 것이 마음에 들지 않으면 다음을 수행할 수 있습니다.

$ grep -Po '\.zoo\.\K\d+|:\s+\K.*' < file
2
0.45654343

일치하는 구간의 시작 부분이 재설정된다고 해서 \K교대로 겹치는 두 구간을 제거할 수 있는 것은 아닙니다.

grep -Po '.zoo.(\K\d+|.:\케이.)'

작동하지 않습니다. 작동하지 않습니다( 및 echo foobar | grep -Po 'foo|foob'둘 다 인쇄 ). 먼저 일치한 다음 이후 입력에서 잠재적인 다른 일치 항목을 찾습니다 . 따라서 of로 시작하므로 그 이후에는 더 이상 일치하는 항목을 찾을 수 없습니다.foofoobfoo|foobfoogrepfoobbar

위에서 우리는 grep -Po '\.zoo\.\K\d+|:\s+\K.*'교대의 두 번째 부분만 살펴보았습니다. :<spaces><anything>이는 다음 부분과 일치 하지만, 뒤따르는 부분뿐만 아니라 입력의 어느 곳에서나 해당 부분을 찾는다는 .zoo.<digits>의미이기도 합니다 .:<spaces><anything>.zoo.<digits>

그러나 이 문제를 해결하는 방법은 또 다른 PCRE 특수 연산자인 를 사용하는 것입니다 \G. \G주제의 시작 부분과 일치합니다. 단일 일치의 경우 이는 동일 ^하지만 여러 일치의 경우( sed/ perl플래그를 생각해 보세요) 행에서 모든 일치 항목을 찾으려고 시도하는 것과 같으며 이전 일치가 끝난 후에도 일치합니다. 그렇다면 다음과 같이 하세요.gs/.../.../g-ogrep

grep -Po '\.zoo\.\K\d+|(?!^)\G.*:\s+\K.*'

(?!^)부정 예측 연산자는 어디에 있습니까?줄의 시작 부분에 있지 않음, \G마지막으로 성공한(비어 있지 않은) 일치 이후에만 일치하므로 .*:\s+\K.*마지막으로 성공한 일치 이후에만 일치하며, .foo.<digits>교체의 다른 부분이 줄의 끝까지 일치하기 때문에 이 일치만 일치합니다.

다음과 같이 입력하면:

.zoo.1.zoo.2 tar: blah

그러면 다음이 출력됩니다:

1
2
blah

하지만. 이를 원하지 않는 경우 교대의 첫 번째 부분이 줄의 시작 부분에서만 일치하도록 할 수도 있습니다. 그것은 마치

grep -Po '^.*?\.zoo\.\K\d+|(?!^)\G.*:\s+\K.*'

또는 와 같은 입력에서는 여전히 출력됩니다 2. 교체의 첫 번째 부분에서 미리보기 연산자를 사용하고 그 뒤에 공백이 아닌 하나 이상을 찾아 이 문제를 해결할 수 있습니다(문자가 아닌 문제를 방지하는 데에도 사용할 수 있음)..zoo.2 no colon character.zoo.2 blah::<spaces>$

grep -Po '^.*?\.zoo\.\K\d+(?=.*:\s+\S.*$)|(?!^)\G.*:\s+\K\S.*$'

sed해당 정규식을 설명하려면 여러 페이지의 주석이 필요할 수 있으므로 여전히 직접 / 솔루션 을 사용하겠습니다 perl.

관련 정보