sed에서 욕심 많은 (reluctant) 정규 표현식 일치?
sed를 사용하여 URL 줄을 정리하여 도메인 만 추출하려고합니다.
그래서 :
http://www.suepearson.co.uk/product/174/71/3816/
내가 원하는:
(훈련 슬래시 유무에 관계없이 중요하지 않습니다)
나는 시도했다 :
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
그리고 다른 모든 정규식 맛!
식의 첫 항목 찾기 :
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
어떻게 작동 합니까?
이 정규 표현식은 교대로부터 이익을 얻는다
|
. 각 위치에서 엔진은 교대의 첫 번째면 (우리의 목표)을 찾고, 교대의 두 번째면이 일치하지 않으면.
다음 즉시 문자와 일치 하는 점이 있습니다.글로벌 플래그가 설정되었으므로 엔진은 입력 문자열 또는 대상의 끝까지 문자별로 문자를 계속 일치시킵니다. 교대 왼쪽의 첫 번째이자 유일한 캡처 그룹이 일치
(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,\}\).*\)*
점.
하나에 도달 하여 단일 문자와 일치 하며이 프로세스는 계속됩니다.
구분 된 표현식 의 첫 항목 찾기 :
이 방법은 구분 된 문자열의 첫 항목과 일치합니다. 이것을 문자열 블록이라고 부를 수 있습니다.
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!
이것은 cut을 사용하여 수행 할 수 있습니다.
echo "http://www.suepearson.co.uk/product/174/71/3816/" | cut -d'/' -f1-3
sed-Christoph Sieghart의 욕심없는 매칭
sed에서 욕심없는 일치를 얻는 트릭은 일치하는 문자를 제외하고 모든 문자를 일치시키는 것입니다. 나도 알다시피, 그러나 그것은 귀중한 시간을 낭비하고 쉘 스크립트는 결국 빠르고 쉬워야합니다. 따라서 다른 사람이 필요할 수있는 경우 :
욕심 매칭
% echo "<b>foo</b>bar" | sed 's/<.*>//g'
bar
욕심없는 매칭
% echo "<b>foo</b>bar" | sed 's/<[^>]*>//g'
foobar
정규식을 사용하지 않는 또 다른 방법은 필드 / 구분 기호 방법을 사용하는 것입니다.
string="http://www.suepearson.co.uk/product/174/71/3816/"
echo $string | awk -F"/" '{print $1,$2,$3}' OFS="/"
sed
확실히 그 자리가 있지만 이것은 그들 중 하나가 아닙니다!
Dee가 지적했듯이 : 그냥 사용하십시오 cut
. 이 경우 훨씬 간단하고 안전합니다. 다음은 Bash 구문을 사용하여 URL에서 다양한 구성 요소를 추출하는 예입니다.
url="http://www.suepearson.co.uk/product/174/71/3816/"
protocol=$(echo "$url" | cut -d':' -f1)
host=$(echo "$url" | cut -d'/' -f3)
urlhost=$(echo "$url" | cut -d'/' -f1-3)
urlpath=$(echo "$url" | cut -d'/' -f4-)
당신에게 제공합니다 :
protocol = "http"
host = "www.suepearson.co.uk"
urlhost = "http://www.suepearson.co.uk"
urlpath = "product/174/71/3816/"
보다시피, 이것은 훨씬 더 유연한 접근법입니다.
(디에게 모든 크레딧)
순수한 sed를 사용 하여이 문제를 해결하기를 희망합니다. 이것이 일반적인 해결책은 아니지만 "루프"를 사용하여 다음과 같이 문자열의 불필요한 부분을 모두 제거 할 수 있습니다.
sed -r -e ":loop" -e 's|(http://.+)/.*|\1|' -e "t loop"
- -r : 확장 정규식 사용 (+ 및 이스케이프 처리되지 않은 괄호)
- ": loop": "loop"라는 새 레이블을 정의하십시오.
- -e : sed에 명령 추가
- "t loop": 대체가 성공한 경우 "loop"레이블로 다시 이동
여기서 유일한 문제는 마지막 구분 문자 ( '/')도 자르는 것이지만 실제로 필요한 경우 "루프"가 끝난 후에도 간단히 다시 넣을 수 있습니다. 이전 명령 끝에 추가 명령을 추가하십시오. 명령 줄 :
-e "s,$,/,"
sed 's|(http:\/\/[^\/]+\/).*|\1|'
sed -E는 정규식을 확장 (현대) 정규식으로 해석합니다.
업데이트 : MacOS X의 경우 -E, GNU sed의 경우 -r
펄, 컷 등 대신에 sed를 사용하려한다고 명시 했으므로 그룹화를 시도하십시오. 이로 인해 탐욕스럽지 않은 식별자가 인식되지 않을 수 있습니다. 첫 번째 그룹은 프로토콜입니다 (예 : 'http : //', 'https : //', 'tcp : //'등). 두 번째 그룹은 도메인입니다.
에코 "http://www.suon.co.uk/product/1/7/3/"| sed "s | ^ \ (. * // \) \ ([^ /] * \). * $ | \ 1 \ 2 |"
그룹화에 익숙하지 않은 경우 여기 에서 시작 하십시오 .
나는 이것이 오래된 항목이라는 것을 알고 있지만 누군가가 유용하다고 생각할 수 있습니다. 전체 도메인 이름은 총 253자를 초과 할 수 없으므로. *를. \ {1, 255 \}로 바꾸십시오.
이것은 sed를 사용하여 다중 문자 문자열을 욕심스럽지 않게 일치시키는 방법입니다. 당신이 모든을 변경하고 싶은 말은하자 foo...bar
에 <foo...bar>
너무 예를 들어이 입력 :
$ cat file
ABC foo DEF bar GHI foo KLM bar NOP foo QRS bar TUV
이 출력이되어야합니다 :
ABC <foo DEF bar> GHI <foo KLM bar> NOP <foo QRS bar> TUV
그렇게하려면 foo와 bar를 개별 문자로 변환 한 다음 그 문자의 부정을 사용하십시오.
$ sed 's/@/@A/g; s/{/@B/g; s/}/@C/g; s/foo/{/g; s/bar/}/g; s/{[^{}]*}/<&>/g; s/}/bar/g; s/{/foo/g; s/@C/}/g; s/@B/{/g; s/@A/@/g' file
ABC <foo DEF bar> GHI <foo KLM bar> NOP <foo QRS bar> TUV
위 :
s/@/@A/g; s/{/@B/g; s/}/@C/g
변환되고{
그리고}
그 후, 문자를 변환 가능하도록 입력에 존재할 수없는 자리 문자열로foo
하고bar
것이다.s/foo/{/g; s/bar/}/g
변환된다foo
및bar
에{
그리고}
각각s/{[^{}]*}/<&>/g
변환 - 우리가 원하는 연산을 수행foo...bar
에<foo...bar>
s/}/bar/g; s/{/foo/g
변환된다{
하고}
다시foo
와bar
.s/@C/}/g; s/@B/{/g; s/@A/@/g
자리 표시 자 문자열을 다시 원래 문자로 변환합니다.
위의 내용은 첫 번째 단계에서 이러한 문자열을 제조 할 때 입력에 존재하지 않는 특정 문자열에 의존하지 않으며 {[^{}]*}
필요한만큼 여러 번 사용할 수 있으므로 일치하는 특정 정규 표현식의 발생을 신경 쓰지 않습니다. 표현식에서 원하는 실제 일치 및 / 또는 seds 숫자 일치 연산자를 분리합니다 (예 : 두 번째 항목 만 대체).
$ sed 's/@/@A/g; s/{/@B/g; s/}/@C/g; s/foo/{/g; s/bar/}/g; s/{[^{}]*}/<&>/2; s/}/bar/g; s/{/foo/g; s/@C/}/g; s/@B/{/g; s/@A/@/g' file
ABC foo DEF bar GHI <foo KLM bar> NOP foo QRS bar TUV
아직이 답을 보지 못했다, 그래서 여기에 당신이 할 수있는 방법 vi
이나 vim
:
vi -c '%s/\(http:\/\/.\{-}\/\).*/\1/ge | wq' file &>/dev/null
이렇게하면 vi
:%s
전역 적으로 대체 (후행 g
) 가 실행되고 패턴을 찾을 수없는 경우 오류가 발생하지 않도록하고 ( e
) 결과 변경 사항을 디스크에 저장하고 종료합니다. 이렇게 &>/dev/null
하면 GUI가 화면에서 잠깐 동안 깜박이지 않아 성 가실 수 있습니다.
나는 vi
(1) perl이 죽어 가고, (2) vim은 매우 고급 정규식 엔진을 가지고 있으며, (3) 이미 vi
일상적인 사용법 편집에서 정규식에 친숙 합니다. 서류.
echo "/home/one/two/three/myfile.txt" | sed 's|\(.*\)/.*|\1|'
귀찮게, 나는 다른 포럼에서 그것을 얻었다 :)
sed 's|\(http:\/\/www\.[a-z.0-9]*\/\).*|\1|
너무 작동
다른 sed 버전 :
sed 's|/[:alphanum:].*||' file.txt
그것은 일치 /
영숫자 문자 (그렇게하지 다른 슬래시)뿐만 아니라 라인의 끝까지 문자의 나머지 하였다. 그 후에는 아무것도 대체하지 않습니다 (즉, 삭제합니다).
다음은 2 단계 접근 방식과 awk로 수행 할 수있는 작업입니다.
A=http://www.suepearson.co.uk/product/174/71/3816/
echo $A|awk '
{
var=gensub(///,"||",3,$0) ;
sub(/\|\|.*/,"",var);
print var
}'
희망이 도움이됩니다!
참고 URL : https://stackoverflow.com/questions/1103149/non-greedy-reluctant-regex-matching-in-sed
'Programming' 카테고리의 다른 글
Mac OS X에 Java 7을 설치했지만 터미널에서 여전히 버전 6을 사용하고 있습니다. (0) | 2020.02.23 |
---|---|
Set과 List의 차이점은 무엇입니까? (0) | 2020.02.23 |
브라우저의 "F5"및 "Ctrl + F5"새로 고침은 어떤 요청을 생성합니까? (0) | 2020.02.23 |
Git에서 오래된 (마지막이 아닌) 커밋에 변경된 파일을 추가하는 방법 (0) | 2020.02.23 |
dex를 실행할 수 없음 : 여러 dex 파일이 Lcom / myapp / R $ array를 정의합니다. (0) | 2020.02.23 |