[regex] sed에서 욕심 많은 (마지 못한) 정규 표현식 일치?

sed를 사용하여 URL 줄을 정리하여 도메인 만 추출하려고합니다.

그래서 :

http://www.suepearson.co.uk/product/174/71/3816/

내가 원하는:

http://www.suepearson.co.uk/

(후행 슬래시 유무에 관계없이 중요하지 않습니다)

나는 시도했다 :

 sed 's|\(http:\/\/.*?\/\).*|\1|'

(비 욕심 많은 정량자를 피함)

sed 's|\(http:\/\/.*\?\/\).*|\1|'

그러나 나는 탐욕스럽지 않은 수량 자 ( ?)를 작동시킬 수 없으므로 항상 전체 문자열과 일치하게됩니다.



답변

기본적이거나 확장 된 Posix / GNU 정규식은 욕심없는 정량자를 인식하지 못합니다. 나중에 정규식이 필요합니다. 다행히도이 컨텍스트에 대한 Perl 정규식은 다음과 같이 쉽게 얻을 수 있습니다.

perl -pe 's|(http://.*?/).*|\1|'


답변

이 특정 경우, 욕심없는 정규식을 사용하지 않고도 작업을 수행 할 수 있습니다.

이 욕심없는 정규식 [^/]*대신 다음을 시도하십시오 .*?.

sed 's|\(http://[^/]*/\).*|\1|g'


답변

sed를 사용하면 일반적으로 구분 기호까지 구분 기호를 제외한 모든 항목을 검색하여 욕심없는 검색을 구현합니다.

echo "http://www.suon.co.uk/product/1/7/3/" | sed -n 's;\(http://[^/]*\)/.*;\1;p'

산출:

http://www.suon.co.uk

이것은:

  • 출력하지 않습니다 -n
  • 검색, 패턴 일치, 교체 및 인쇄 s/<pattern>/<replace>/p
  • 사용하는 ;검색 명령 구분을 대신 /하므로 입력하기 쉽도록하기 위해s;<pattern>;<replace>;p
  • 괄호 사이의 일치를 기억하십시오 \(\), 나중에 \1, \2
  • 시합 http://
  • 괄호 안에 아무것도 다음에 [], [ab/]의미 중 하나 a또는 b또는/
  • 처음 ^[]수단 not, 그래서 아무것도 뒤에 만의 것[]
  • 그래서 [^/]제외하고는 아무것도 의미 /의 문자를
  • *이전 그룹을 반복하는 것이므로를 [^/]*제외한 문자를 의미합니다 /.
  • 지금까지는 sed -n 's;\(http://[^/]*\)검색하고 기억하고 http://뒤에 /찾은 것을 제외한 모든 문자를 의미합니다.
  • 우리는 도메인의 끝까지 검색하고 싶기 때문에 다음에 멈추고 끝에 /다른 것을 추가 하고 싶습니다./sed -n 's;\(http://[^/]*\)/'.*
  • 이제 그룹 1 ( \1) 에서 기억 된 일치 는 도메인이므로 일치하는 줄을 그룹에 저장된 내용으로 바꾸고 \1인쇄하십시오.sed -n 's;\(http://[^/]*\)/.*;\1;p'

도메인 뒤에 백 슬래시를 포함 시키려면 그룹에 백 슬래시를 하나 더 추가하여 기억하십시오.

echo "http://www.suon.co.uk/product/1/7/3/" | sed -n 's;\(http://[^/]*/\).*;\1;p'

산출:

http://www.suon.co.uk/


답변

sed는 “욕심없는”연산자를 지원하지 않습니다.

일치에서 “/”를 제외 시키려면 “[]”연산자를 사용해야합니다.

sed 's,\(http://[^/]*\)/.*,\1,'

PS “/”를 백 슬래시 할 필요가 없습니다.


답변

에 게으른 (심지어) 수량화 시뮬레이션 sed

그리고 다른 모든 정규식 맛!

  1. 식의 첫 항목 찾기 :

    • POSIX ERE ( -r옵션 사용 )

      정규식 :

      (EXPRESSION).*|.

      sed :

      sed -r 's/(EXPRESSION).*|./\1/g' # Global `g` modifier should be on

      예 (첫 번째 숫자 찾기) 라이브 데모 :

      $ sed -r 's/([0-9]+).*|./\1/g' <<< 'foo 12 bar 34'
      12

      어떻게 작동 합니까?

      이 정규 표현식은 교대로부터 이익을 얻는다 |. 각 위치 엔진에서 그와 함께가는 의미 (이 아니라 다른 엔진의 몇 다음에하는 POSIX 표준입니다) 가장 긴 일치를 선택하려고 .일치가 발견 될 때까지 ([0-9]+).*. 그러나 질서도 중요합니다.

      여기에 이미지 설명을 입력하십시오

      글로벌 플래그가 설정되었으므로 엔진은 입력 문자열 또는 대상의 끝까지 문자별로 문자를 계속 일치시킵니다. 교대로 왼쪽의 첫 번째 및 유일한 캡처 그룹이 일치 (EXPRESSION)하자마자 나머지 라인도 즉시 소비됩니다 .*. 우리는 이제 첫 번째 캡처 그룹에서 가치를 유지합니다.

    • POSIX BRE

      정규식 :

      \(\(\(EXPRESSION\).*\)*.\)*

      sed :

      sed 's/\(\(\(EXPRESSION\).*\)*.\)*/\3/'

      예 (첫 번째 일련의 숫자 찾기) :

      $ sed 's/\(\(\([0-9]\{1,\}\).*\)*.\)*/\3/' <<< 'foo 12 bar 34'
      12

      이 버전은 ERE 버전과 유사하지만 다른 변경 사항이 없습니다. 그게 다야. 각 단일 위치에서 엔진은 숫자를 일치 시키려고합니다.

      여기에 이미지 설명을 입력하십시오

      그것이 발견되면, 다른 다음 숫자가 소비되고 캡처되고 나머지 줄은 즉시 일치합니다. 그렇지 않으면 더 많거나 0을* 의미
      하기 때문에 두 번째 캡처 그룹을 건너 뛰고 \(\([0-9]\{1,\}\).*\)*.하나에 도달 하여 단일 문자와 일치 하며이 프로세스는 계속됩니다.

  2. 구분 된 표현식 의 첫 항목 찾기 :

    이 방법은 구분 된 문자열의 첫 항목과 일치합니다. 이것을 문자열 블록이라고 부를 수 있습니다.

    sed 's/\(END-DELIMITER-EXPRESSION\).*/\1/; \
         s/\(\(START-DELIMITER-EXPRESSION.*\)*.\)*/\1/g'

    입력 문자열 :

    foobar start block #1 end barfoo start block #2 end

    -EDE : end

    -SDE : start

    $ sed 's/\(end\).*/\1/; s/\(\(start.*\)*.\)*/\1/g'

    산출:

    start block #1 end

    첫 번째 정규 표현식 \(end\).*은 첫 번째 구분 기호를 일치시키고 캡처하며, 마지막 구분 기호 인 end최근 캡처 된 문자로 모든 일치를 대체합니다. 이 단계에서 출력은 다음과 같습니다 foobar start block #1 end.

    여기에 이미지 설명을 입력하십시오

    그런 다음 \(\(start.*\)*.\)*위의 POSIX BRE 버전과 동일한 두 번째 정규식으로 결과가 전달됩니다 . 시작 구분 기호 start가 일치하지 않으면 단일 문자 와 일치하고 그렇지 않으면 시작 구분 기호와 일치하고 캡처하고 나머지 문자와 일치합니다.

    여기에 이미지 설명을 입력하십시오


질문에 직접 대답

접근법 # 2 (구분 된 표현식)를 사용하여 두 가지 적절한 표현식을 선택해야합니다.

  • EDE : [^:/]\/

  • SDE : http:

용법:

$ sed 's/\([^:/]\/\).*/\1/g; s/\(\(http:.*\)*.\)*/\1/' <<< 'http://www.suepearson.co.uk/product/174/71/3816/'

산출:

http://www.suepearson.co.uk/

참고 : 동일한 구분 기호로 작동하지 않습니다.


답변

하나 이상의 캐릭터를위한 욕심없는 해결책

이 스레드는 실제로 오래되었지만 사람들이 여전히 필요하다고 생각합니다. 의 첫 번째 발생까지 모든 것을 죽이고 싶다고 가정 해 봅시다 HELLO. 당신은 말할 수 없습니다 [^HELLO]

따라서 좋은 해결책은 입력에서 예상하지 않은 고유 한 단어를 절약 할 수 있다고 가정하면 두 단계로 구성됩니다 top_sekrit.

이 경우 다음을 수행 할 수 있습니다.

s/HELLO/top_sekrit/     #will only replace the very first occurrence
s/.*top_sekrit//        #kill everything till end of the first HELLO

물론 더 간단한 입력으로 더 작은 단어를 사용하거나 단일 문자를 사용할 수도 있습니다.

HTH!


답변

sed-Christoph Sieghart의 욕심없는 매칭

sed에서 욕심없는 일치를 얻는 트릭은 일치하는 문자를 제외하고 모든 문자를 일치시키는 것입니다. 나도 알다시피, 그러나 그것은 귀중한 시간을 낭비하고 쉘 스크립트는 결국 빠르고 쉬워야합니다. 따라서 다른 사람이 필요할 수있는 경우 :

욕심 매칭

% echo "<b>foo</b>bar" | sed 's/<.*>//g'
bar

욕심없는 매칭

% echo "<b>foo</b>bar" | sed 's/<[^>]*>//g'
foobar