etc./StackOverFlow

단어가 포함되지 않은 줄과 일치하는 정규식

청렴결백한 만능 재주꾼 2021. 9. 26. 10:52
반응형

질문자 :Community Wiki


grep -v )를 사용하여 일치 항목을 뒤집는 것이 가능하다는 것을 알고 있습니다. 그러나 정규식을 사용하여 특정 단어를 포함하지 않는 행(예: hede

입력:

 hoho hihi haha hede

암호:

 grep "<Regex for 'doesn't contain hede'>" input

원하는 출력:

 hoho hihi haha


답변자 : Community Wiki


정규식이 역 일치를 지원하지 않는다는 개념은 완전히 사실이 아닙니다. 부정적인 둘러보기를 사용하여 이 동작을 모방할 수 있습니다.

 ^((?!hede).)*$

위의 정규식은 (하위) 문자열 'hede'를 포함 하지 않는 모든 문자열 또는 줄 바꿈이 없는 줄과 일치합니다. 언급 한 바와 같이,이 정규식에서 "좋은"(또는해야 할) 것이 아닙니다,하지만 여전히, 그것은 가능하다.

줄 바꿈 문자도 일치시켜야 하는 경우 DOT-ALL 수정자 (다음 패턴의 후행 s )를 사용합니다.

 /^((?!hede).)*$/s

또는 인라인으로 사용하십시오.

 /(?s)^((?!hede).)*$/

(여기서 /.../ 는 정규식 구분 기호입니다. 즉, 패턴의 일부가 아닙니다.)

DOT-ALL 수정자를 사용할 수 없는 경우 문자 클래스 [\s\S] 하여 동일한 동작을 모방할 수 있습니다.

 /^((?!hede)[\s\S])*$/

설명

n 문자 목록일 뿐입니다. 각 문자 앞과 뒤에 빈 문자열이 있습니다. 따라서 n 문자 n+1 빈 문자열이 있습니다. "ABhedeCD" 문자열을 고려하십시오.

 ┌──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┐ S = │e1│ A │e2│ B │e3│ h │e4│ e │e5│ d │e6│ e │e7│ C │e8│ D │e9│ └──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┘ index 0 1 2 3 4 5 6 7

여기서 e 는 빈 문자열입니다. 정규식 (?!hede). "hede" 가 없는지 확인하기 위해 앞을 내다보고, 그런 경우(다른 것이 표시됨) . (점)은 줄 바꿈을 제외한 모든 문자와 일치합니다. 둘러보기는 문자를 사용 하지 않기 때문에 너비가 0인 주장이라고도 합니다. 그들은 단지 무언가를 주장/검증합니다.

따라서 제 예에서 모든 빈 문자열은 먼저 "hede" 가 없는지 확인하기 위해 . (점). 정규식 (?!hede). 한 번만 수행하므로 그룹으로 래핑되고 0번 이상 반복됩니다. ((?!hede).)* . 마지막으로 전체 입력이 사용되도록 시작 및 입력 끝이 고정됩니다. ^((?!hede).)*$

당신이 볼 수 있듯이, 입력 "ABhedeCD" 때문에 실패합니다 e3 , 정규 표현식 (?!hede) 실패 (가 "hede" 까지 앞으로!).



답변자 : Community Wiki


에 대한 솔루션 "hede"로 시작하지 않습니다 .

 ^(?!hede).*$

일반적으로 "hede"를 포함 하지 않는 솔루션보다 훨씬 효율적입니다.

 ^((?!hede).)*$

전자는 모든 위치가 아니라 입력 문자열의 첫 번째 위치에서만 "hede"를 확인합니다.



답변자 : Community Wiki


그냥 GREP을 위해 그것을 사용하는 경우 사용할 수 있습니다 grep -v hede HEDE를 포함하지 않는 모든 라인을 얻을 수 있습니다.

ETA 아, 질문을 다시 읽으면 grep -v "도구 옵션"이 의미하는 것일 수 있습니다.



답변자 : Community Wiki


답변:

 ^((?!hede).)*$

설명:

^ 문자열의 시작, ( 그룹화하여 \1로 캡처(0회 이상(최대한 일치)),
(?! 없는지 미리 확인하고,

당신의 끈에 hede

) 미리보기 종료, . \n을 제외한 모든 문자,
)* \1의 끝(참고: 이 캡처에서 수량자를 사용하고 있기 때문에 캡처된 패턴의 마지막 반복만 \1에 저장됩니다.)
$ 선택적 \n 앞, 그리고 문자열의 끝



답변자 : Community Wiki


주어진 답변은 완벽하게 훌륭하며 학문적 요점입니다.

이론적 컴퓨터 과학의 의미에서 정규 표현식은 다음과 같이 그것을 할 수 없습니다. 그들에게는 다음과 같이 보여야 했습니다.

 ^([^h].*$)|(h([^e].*$|$))|(he([^h].*$|$))|(heh([^e].*$|$))|(hehe.+$)

이것은 전체 일치만 수행합니다. 하위 경기를 위해 그것을 하는 것은 훨씬 더 어색할 것입니다.



답변자 : Community Wiki


전체 문자열이 일치하는 경우 에만 정규식 테스트가 실패하도록 하려면 다음이 작동합니다.

 ^(?!hede$).*

예 -- "foo"를 제외한 모든 값을 허용하려면(예: "foofoo", "barfoo" 및 "foobar"는 통과하지만 "foo"는 실패함) 다음을 사용합니다. ^(?!foo$).*

물론 정확한 같음을 확인하는 경우 이 경우 더 나은 일반적인 솔루션은 문자열 같음을 확인하는 것입니다.

 myStr !== 'foo'

정규식 기능이 필요한 경우 부정을 테스트 외부에 둘 수도 있습니다(여기서는 대소문자 구분 및 범위 일치).

 !/^[af]oo$/i.test(myStr)

그러나 이 답변의 맨 위에 있는 정규식 솔루션은 긍정적인 정규식 테스트가 필요한 상황에서(아마도 API로) 도움이 될 수 있습니다.



답변자 : Community Wiki


FWIW, 정규 언어(합리적 언어라고도 함)는 보완으로 닫혀 있기 때문에 다른 표현식을 부정하는 정규식(합리적 표현이라고도 함)을 찾는 것이 항상 가능합니다. 그러나 이를 구현하는 도구는 많지 않습니다.

Vcsn 은 이 연산자를 지원합니다( {c} , 접미사를 나타냄).

먼저 표현식의 유형을 정의합니다. 레이블은 a 에서 z 까지 선택 lal_char )이며(보완 작업을 할 때 알파벳을 정의하는 것은 물론 매우 중요합니다) 각 단어에 대해 계산된 "값"은 다음과 같습니다. 그냥 부울: true 단어는 허용되고 false , 거부됩니다.

파이썬에서:

 In [5]: import vcsn c = vcsn.context('lal_char(az), b') c Out[5]: {a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z} →

그런 다음 표현식을 입력합니다.

 In [6]: e = c.expression('(hede){c}'); e Out[6]: (hede)^c

이 표현식을 자동으로 변환:

 In [7]: a = e.automaton(); a

해당 오토마톤

마지막으로 이 자동 장치를 간단한 표현식으로 다시 변환합니다.

 In [8]: print(a.expression()) \e+h(\e+e(\e+d))+([^h]+h([^e]+e([^d]+d([^e]+e[^]))))[^]*

여기서 + 는 일반적으로 | , \e 는 빈 단어를 나타내며 [^] 는 일반적으로 씁니다 . (모든 문자). 따라서 약간의 재작성으로 ()|h(ed?)?|([^h]|h([^e]|e([^d]|d([^e]|e.)))).* .

이 예제를 볼 수 있습니다 여기에 , 온라인 Vcsn 시도 .



답변자 : Community Wiki


다음은 임의의 정규식을 부정하는 것이 쉽지 않은 이유에 대한 좋은 설명입니다. 하지만 다른 답변에 동의해야 합니다. 이것이 가상의 질문이 아닌 경우 정규식은 여기에서 올바른 선택이 아닙니다.



답변자 : Community Wiki


부정 미리보기를 사용하면 정규식이 특정 패턴을 포함하지 않는 것과 일치할 수 있습니다. 이것은 Bart Kiers가 답변하고 설명합니다. 훌륭한 설명!

그러나 Bart Kiers의 답변으로 예견 부분은 단일 문자와 일치하면서 1~4자를 미리 테스트합니다. 우리는 이것을 피할 수 있고 lookhead 부분이 전체 텍스트를 확인하고 'hede'가 없는지 확인하면 normal 부분(.*)이 전체 텍스트를 한 번에 모두 먹을 수 있습니다.

개선된 정규식은 다음과 같습니다.

 /^(?!.*?hede).*$/

부정적인 예측 부분의 (*?) 지연 수량자는 선택 사항이므로 데이터에 따라 대신 (*) 탐욕 수량자를 사용할 수 있습니다. 'hede'가 있고 텍스트의 시작 부분에 있는 경우 지연 수량자는 더 빨리; 그렇지 않으면 욕심 많은 수량자가 더 빠릅니다. 그러나 'hede'가 없으면 둘 다 느릴 것입니다.

여기 데모 코드가 있습니다.

lookahead에 대한 자세한 내용은 다음 기사를 확인하세요. Mastering Lookahead and Lookbehind .

또한 복잡한 정규식을 구성하는 데 도움이 되는 JavaScript 정규식 생성기인 RegexGen.js 를 확인하십시오. RegexGen.js를 사용하면 더 읽기 쉬운 방식으로 정규식을 구성할 수 있습니다.

 var _ = regexGen; var regex = _( _.startOfLine(), _.anything().notContains( // match anything that not contains: _.anything().lazy(), 'hede' // zero or more chars that followed by 'hede', // ie, anything contains 'hede' ), _.endOfLine() );


답변자 : Community Wiki


벤치마크

제시된 옵션 중 일부를 평가하고 성능을 비교하고 몇 가지 새로운 기능을 사용하기로 결정했습니다. .NET Regex 엔진의 벤치마킹: http://regexhero.net/tester/

벤치마크 텍스트:

처음 7행은 검색된 표현식을 포함하므로 일치하지 않아야 하고 하위 7행은 일치해야 합니다!

 Regex Hero is a real-time online Silverlight Regular Expression Tester. XRegex Hero is a real-time online Silverlight Regular Expression Tester. Regex HeroRegex HeroRegex HeroRegex HeroRegex Hero is a real-time online Silverlight Regular Expression Tester. Regex Her Regex Her Regex Her Regex Her Regex Her Regex Her Regex Hero is a real-time online Silverlight Regular Expression Tester. Regex Her is a real-time online Silverlight Regular Expression Tester.Regex Hero egex Hero egex Hero egex Hero egex Hero egex Hero egex Hero Regex Hero is a real-time online Silverlight Regular Expression Tester. RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRegex Hero is a real-time online Silverlight Regular Expression Tester. Regex Her egex Hero egex Hero is a real-time online Silverlight Regular Expression Tester. Regex Her is a real-time online Silverlight Regular Expression Tester. Regex Her Regex Her Regex Her Regex Her Regex Her Regex Her is a real-time online Silverlight Regular Expression Tester. Nobody is a real-time online Silverlight Regular Expression Tester. Regex Her o egex Hero Regex Hero Reg ex Hero is a real-time online Silverlight Regular Expression Tester.

결과:

결과는 3회 실행의 중앙값인 초당 반복입니다. - 숫자가 클수록 더 좋습니다.

 01: ^((?!Regex Hero).)*$ 3.914 // Accepted Answer 02: ^(?:(?!Regex Hero).)*$ 5.034 // With Non-Capturing group 03: ^(?>[^R]+|R(?!egex Hero))*$ 6.137 // Lookahead only on the right first letter 04: ^(?>(?:.*?Regex Hero)?)^.*$ 7.426 // Match the word and check if you're still at linestart 05: ^(?(?=.*?Regex Hero)(?#fail)|.*)$ 7.371 // Logic Branch: Find Regex Hero? match nothing, else anything P1: ^(?(?=.*?Regex Hero)(*FAIL)|(*ACCEPT)) ????? // Logic Branch in Perl - Quick FAIL P2: .*?Regex Hero(*COMMIT)(*FAIL)|(*ACCEPT) ????? // Direct COMMIT & FAIL in Perl

.NET은 동작 동사(*FAIL 등)를 지원하지 않기 때문에 솔루션 P1 및 P2를 테스트할 수 없습니다.

요약:

대부분의 제안된 솔루션을 테스트하려고 시도했지만 일부 최적화는 특정 단어에 대해 가능합니다. 예를 들어 검색 문자열의 처음 두 문자가 동일하지 않은 경우 응답 03은 ^(?>[^R]+|R+(?!egex Hero))*$ 로 확장되어 성능이 약간 향상될 수 있습니다.

그러나 전반적으로 가장 읽기 쉽고 성능 면에서 가장 빠른 솔루션은 조건문을 사용하는 05 또는 소유 수량자를 사용하는 04인 것 같습니다. Perl 솔루션은 훨씬 더 빠르고 쉽게 읽을 수 있어야 한다고 생각합니다.



답변자 : Community Wiki


정규식은 아니지만 파이프와 함께 직렬 grep을 사용하여 노이즈를 제거하는 것이 논리적이고 유용하다는 것을 알았습니다.

예를 들어 모든 주석 없이 아파치 구성 파일 검색-

 grep -v '\#' /opt/lampp/etc/httpd.conf # this gives all the non-comment lines

그리고

 grep -v '\#' /opt/lampp/etc/httpd.conf | grep -i dir

직렬 grep의 논리는 (주석이 아님) 및 (dir과 일치)



답변자 : Community Wiki


이를 통해 각 위치에 대한 예측 테스트를 피할 수 있습니다.

 /^(?:[^h]+|h++(?!ede))*+$/

(.net의 경우)에 해당:

 ^(?>(?:[^h]+|h+(?!ede))*)$

이전 답변:

 /^(?>[^h]+|h+(?!ede))*$/


답변자 : Community Wiki


(?:(?!hede).)* 는 고정할 수 있기 때문에 훌륭합니다.

 ^(?:(?!hede).)*$ # A line without hede foo(?:(?!hede).)*bar # foo followed by bar, without hede between them

그러나 이 경우에는 다음으로 충분합니다.

 ^(?!.*hede) # A line without hede

이 단순화는 "AND" 절을 추가할 준비가 되었습니다.

 ^(?!.*hede)(?=.*foo)(?=.*bar) # A line with foo and bar, but without hede ^(?!.*hede)(?=.*foo).*bar # Same


답변자 : Community Wiki


내가 하는 방법은 다음과 같습니다.

 ^[^h]*(h(?!ede)[^h]*)*$

다른 답변보다 정확하고 효율적입니다. 그것은 Friedl의 "unrolling-the-loop" 효율성 기술을 구현하고 훨씬 적은 역추적을 필요로 합니다.



답변자 : Community Wiki


내 의견으로는 최고 답변의 더 읽기 쉬운 변형입니다.

 ^(?!.*hede)

기본적으로 "'hede'가 없는 경우에만 줄의 시작 부분에서 일치" - 따라서 요구 사항은 거의 직접 정규식으로 변환됩니다.

물론 여러 실패 요구 사항이 있을 수 있습니다.

 ^(?!.*(hede|hodo|hada))

세부 정보: ^ 앵커는 정규식 엔진이 모든 문자열과 일치하는 문자열의 모든 위치에서 일치를 다시 시도하지 않도록 합니다.

시작 부분의 ^ 앵커는 줄의 시작을 나타냅니다. grep 도구는 여러 줄 문자열로 작업하는 컨텍스트에서 "m" 플래그를 사용할 수 있습니다.

 /^(?!.*hede)/m # JavaScript syntax

또는

 (?m)^(?!.*hede) # Inline flag


답변자 : Community Wiki


부정 문자 클래스와 유사한 단어를 부정하기 위해 문자를 일치시키려면:

예를 들어, 문자열:

 <? $str="aaa bbb4 aaa bbb7"; ?>

사용하지 마세요:

 <? preg_match('/aaa[^bbb]+?bbb7/s', $str, $matches); ?>

사용하다:

 <? preg_match('/aaa(?:(?!bbb).)+?bbb7/s', $str, $matches); ?>

"(?!bbb)." 주목하십시오. lookbehind도 lookhead도 아니며 lookcurrent입니다. 예를 들면 다음과 같습니다.

 "(?=abc)abcde", "(?!abc)abcde"


답변자 : Community Wiki


다른 사람이 묻는 질문에 직접적인 대답을 하지 않았기 때문에 그렇게 하겠습니다.

대답은 POSIX grep 을 사용하면 이 요청을 문자 그대로 충족하는 것이 불가능하다는 것입니다.

 grep "<Regex for 'doesn't contain hede'>" input

그 이유는 POSIX grep 이 해당 작업을 수행하기에 충분히 강력하지 않은 기본 정규식 으로 작업하는 데만 필요하기 때문입니다(교체가 없기 때문에 모든 일반 언어를 구문 분석할 수 없음).

그러나 GNU grep 은 이를 허용하는 확장을 구현합니다. 특히 \| GNU의 BRE 구현에서 대체 연산자입니다. 정규식 엔진이 대체, 괄호 및 Kleene 별을 지원하고 문자열의 시작과 끝에 고정할 수 있는 경우 이 접근 방식에 필요한 모든 것입니다. 그러나 음수 집합 [^ ... ] 은 그 외에도 매우 편리합니다. 그렇지 않으면 해당 집합을 포함하는 모든 문자를 나열 (a|b|c| ... ) 매우 지루하고 지나치게 긴 집합에 포함되지 않습니다. 전체 문자 집합이 유니코드인 경우에는 더욱 그렇습니다.

형식 언어 이론 덕분에 그러한 표현이 어떻게 생겼는지 알 수 있습니다. GNU grep 을 사용하면 답은 다음과 같습니다.

 grep "^\([^h]\|h\(h\|eh\|edh\)*\([^eh]\|e[^dh]\|ed[^eh]\)\)*\(\|h\(h\|eh\|edh\)*\(\|e\|ed\)\)$" input

(Grail 과 손으로 만든 몇 가지 추가 최적화에서 발견).

egrep 와 같은 확장 정규식 을 구현하는 도구를 사용하여 백슬래시를 제거할 수도 있습니다.

 egrep "^([^h]|h(h|eh|edh)*([^eh]|e[^dh]|ed[^eh]))*(|h(h|eh|edh)*(|e|ed))$" input

다음은 테스트할 스크립트입니다(현재 디렉토리에 testinput.txt 제시된 몇 가지 표현이 이 테스트에 실패했습니다.

 #!/bin/bash REGEX="^\([^h]\|h\(h\|eh\|edh\)*\([^eh]\|e[^dh]\|ed[^eh]\)\)*\(\|h\(h\|eh\|edh\)*\(\|e\|ed\)\)$" # First four lines as in OP's testcase. cat > testinput.txt <<EOF hoho hihi haha hede h he ah head ahead ahed aheda ahede hhede hehede hedhede hehehehehehedehehe hedecidedthat EOF diff -s -u <(grep -v hede testinput.txt) <(grep "$REGEX" testinput.txt)

내 시스템에서는 다음을 인쇄합니다.

 Files /dev/fd/63 and /dev/fd/62 are identical

예상대로.

세부 사항에 관심이 있는 사람들을 위해 사용된 기술은 단어와 일치하는 정규식을 유한 자동자(finite automaton)로 변환한 다음 모든 승인 상태를 비수락 상태로 또는 그 반대로 변경하여 자동자를 반전시킨 다음 결과 FA를 다시 다음으로 변환하는 것입니다. 정규식.

모두가 언급했듯이 정규식 엔진이 부정 미리보기를 지원하면 정규식이 훨씬 간단합니다. 예를 들어, GNU grep의 경우:

 grep -P '^((?!hede).)*$' input

그러나 이 방법은 역추적 정규식 엔진이 필요하다는 단점이 있습니다. 이로 인해 RE2 와 같은 보안 정규식 엔진을 사용하는 설치에는 적합하지 않습니다. 이는 일부 상황에서 생성된 접근 방식을 선호하는 이유 중 하나입니다.

Grail과 유사한 기능을 제공하는 PHP로 작성된 Kendall Hopkins의 뛰어난 FormalTheory 라이브러리와 직접 작성한 단순화기를 사용하여 입력 문구(영숫자 및 공백 현재 지원되는 문자): http://www.formauri.es/personal/pgimeno/misc/non-match-regex/

hede 를 위해 다음을 출력합니다.

 ^([^h]|h(h|e(h|dh))*([^eh]|e([^dh]|d[^eh])))*(h(h|e(h|dh))*(ed?)?)?$

이는 위와 동일합니다.



답변자 : Community Wiki


OP는 Regex가 사용될 컨텍스트(프로그래밍 언어, 편집기, 도구)를 나타내기 위해 게시물을 지정하거나 태그를 지정하지 않았습니다.

Textpad 사용하여 파일을 편집하는 동안 때때로 이 작업을 수행해야 합니다.

Textpad 는 일부 Regex를 지원하지만 lookahead 또는 lookbehind를 지원하지 않으므로 몇 단계가 필요합니다.

문자열 hede 포함하지 않는 모든 행을 유지하려면 다음과 같이 하십시오.

1. 전체 파일을 검색/바꾸어 텍스트가 포함된 각 줄의 시작 부분에 고유한 "태그"를 추가합니다.

 Search string:^(.) Replace string:<@#-unique-#@>\1 Replace-all

hede 문자열이 포함된 모든 줄을 삭제합니다(교체 문자열은 비어 있음).

 Search string:<@#-unique-#@>.*hede.*\n Replace string:<nothing> Replace-all

3. 이 시점에서 나머지 모든 줄 hede 문자열이 포함 되지 않습니다 . 모든 줄에서 고유한 "태그"를 제거합니다(교체 문자열은 비어 있음).

 Search string:<@#-unique-#@> Replace string:<nothing> Replace-all

hede 문자열을 포함하는 모든 행이 제거된 원본 텍스트가 있습니다.


hede 포함되어 있지 않은 행에만 다른 작업을 수행하려는 경우 다음과 같이 수행합니다.

1. 전체 파일을 검색/바꾸어 텍스트가 포함된 각 줄의 시작 부분에 고유한 "태그"를 추가합니다.

 Search string:^(.) Replace string:<@#-unique-#@>\1 Replace-all

hede 문자열을 포함하는 모든 줄에 대해 고유한 "Tag"를 제거합니다.

 Search string:<@#-unique-#@>(.*hede) Replace string:\1 Replace-all

3. 이 시점에서 고유한 "Tag"로 시작하는 모든 줄 hede 문자열이 포함 되지 않습니다 . 나는 이제 그 라인에 대해서만 뭔가를 할 수 있습니다.

4. 완료되면 모든 줄에서 고유한 "태그"를 제거합니다(교체 문자열은 비어 있음).

 Search string:<@#-unique-#@> Replace string:<nothing> Replace-all


답변자 : Community Wiki


또 다른 옵션은 긍정적인 hede 을 추가하고 heed가 입력 라인의 아무 곳에나 있는지 확인하는 것입니다. 그런 다음 다음과 유사한 표현식으로 이를 무효화합니다.

 ^(?!(?=.*\bhede\b)).*$

단어 경계와 함께.


표현식은 regex101.com의 오른쪽 상단 패널에 설명되어 있으며 탐색/단순화/수정하려는 경우 이 링크 에서 원하는 경우 일부 샘플 입력과 어떻게 일치하는지 볼 수 있습니다.


정규식 회로

jex.im은 정규 표현식을 시각화합니다.

여기에 이미지 설명 입력



답변자 : Community Wiki


ruby-2.4.1이 도입된 이후로 Ruby의 정규식에서 새로운 Absent Operator를 사용할 수 있습니다.

공식 문서에서

 (?~abc) matches: "", "ab", "aab", "cccc", etc. It doesn't match: "abc", "aabc", "ccccabc", etc.

따라서 귀하의 경우 ^(?~hede)$ 가 귀하를 위해 일합니다.

 2.4.1 :016 > ["hoho", "hihi", "haha", "hede"].select{|s| /^(?~hede)$/.match(s)} => ["hoho", "hihi", "haha"]


답변자 : Community Wiki


PCRE를 통해 동사 (*SKIP)(*F)

 ^hede$(*SKIP)(*F)|^.*$

hede 를 포함하는 줄을 완전히 건너뛰고 나머지 모든 줄과 일치합니다.

데모

부품 실행:

위의 정규식을 두 부분으로 나누어 생각해 봅시다.

  1. 이전 부분 | 상징. 부분 이 일치하지 않아야 합니다 .

     ^hede$(*SKIP)(*F)
  2. 다음 부분 | 상징. 부분 이 일치해야 합니다 .

     ^.*$

1 부

Regex 엔진은 첫 번째 부분부터 실행을 시작합니다.

 ^hede$(*SKIP)(*F)

설명:

  • ^ 우리가 시작에 있다고 주장합니다.
  • hede 문자열 일치 hede
  • $ 우리가 라인 끝에 있다고 주장합니다.

hede 가 포함된 행이 일치합니다. 정규식 엔진이 다음 (*SKIP)(*F) ( 참고: (*F)(*FAIL) 로 쓸 수 있음) 동사를 보면 건너뛰고 일치를 실패로 만듭니다. | 모든 경계와 일치하는 PCRE 동사 옆에 추가된 변경 또는 논리적 OR 연산자라고 하는 행이 정확한 문자열 hede 포함하는 것을 제외하고 모든 행의 모든 문자 사이에 존재합니다. 여기 에서 데모를 참조하십시오. 즉, 나머지 문자열의 문자를 일치시키려고 합니다. 이제 두 번째 부분의 정규식이 실행됩니다.

2 부

 ^.*$

설명:

  • ^ 우리가 시작에 있다고 주장합니다. hede 줄에 있는 줄을 제외한 모든 줄 시작과 일치합니다. 여기 에서 데모를 참조하십시오.
  • .* 모드에서 . 개행 문자 또는 캐리지 리턴 문자를 제외한 모든 문자와 일치합니다. 그리고 * 는 이전 문자를 0번 이상 반복합니다. 따라서 .* 는 전체 줄과 일치합니다. 여기 에서 데모를 참조하십시오.

    .+ 대신 .*를 추가한 이유는 무엇입니까?

    .* 는 빈 줄과 일치하지만 .+ 는 공백과 일치하지 않기 때문입니다. hede 제외한 모든 라인을 일치시키길 원합니다. 입력에도 공백 라인이 있을 가능성이 있습니다. .+ 대신 .* 를 사용해야 합니다. .+ 는 이전 문자를 한 번 이상 반복합니다. .* 는 여기 에서 빈 줄과 일치함을 참조하십시오.

  • $ 끝 앵커는 필요하지 않습니다.



답변자 : Community Wiki


코드에서 두 개의 정규식을 유지 관리하는 것이 더 쉬울 수 있습니다. 하나는 첫 번째 일치를 수행하고 일치하는 경우 두 번째 정규식을 실행하여 차단하려는 이상치 사례를 확인합니다 ^.*(hede).* 그런 다음 적절한 코드의 논리.

좋아, 나는 이것이 게시 된 질문에 대한 답변이 아니며 단일 정규식보다 약간 더 많은 처리를 사용할 수 있음을 인정합니다. 그러나 이상치 사례에 대한 빠른 긴급 수정을 찾기 위해 여기에 온 개발자의 경우 이 솔루션을 간과해서는 안 됩니다.



답변자 : Community Wiki


TXR 언어 는 정규식 부정을 지원합니다.

 $ txr -c '@(repeat) @{nothede /~hede/} @(do (put-line nothede)) @(end)' Input

더 복잡한 예: a 시작하고 z 끝나는 모든 행을 일치하지만 하위 문자열 hede 포함하지 않습니다.

 $ txr -c '@(repeat) @{nothede /a.*z&~.*hede.*/} @(do (put-line nothede)) @(end)' - az <- echoed az abcz <- echoed abcz abhederz <- not echoed; contains hede ahedez <- not echoed; contains hede ace <- not echoed; does not end in z ahedz <- echoed ahedz

Regex 부정은 그 자체로는 특히 유용하지 않지만 교차도 있을 때 boolean 집합 연산의 전체 집합이 있기 때문에 상황이 흥미로워집니다. "이것과 일치하는 것을 제외하고 이것과 일치하는 집합"을 표현할 수 있습니다.



답변자 : Community Wiki


아래 기능은 원하는 출력을 얻는 데 도움이 됩니다.

 <?PHP function removePrepositions($text){ $propositions=array('/\bfor\b/i','/\bthe\b/i'); if( count($propositions) > 0 ) { foreach($propositions as $exceptionPhrase) { $text = preg_replace($exceptionPhrase, '', trim($text)); } $retval = trim($text); } return $retval; } ?>


답변자 : Community Wiki


문자열 X 를 포함하지만 문자열 Y 도 포함하지 않는 전체 행을 일치시키려는 경우에 대한 또 다른 예를 추가하고 싶었습니다.

예를 들어, URL/문자열에 " tasty-treats "가 포함되어 있는지 확인하고 싶다고 가정해 보겠습니다. 단 , " chocolate "도 포함하지 않는 한.

이 정규식 패턴은 작동합니다(JavaScript에서도 작동)

 ^(?=.*?tasty-treats)((?!chocolate).)*$

(예에서 전역, 여러 줄 플래그)

대화식 예: https://regexr.com/53gv4

성냥

(이 URL에는 "tasty-treats"가 포함되어 있고 "chocolate"도 포함되어 있지 않습니다.)

  • example.com/tasty-treats/strawberry-ice-cream
  • example.com/desserts/tasty-treats/banana-pudding
  • example.com/tasty-treats-overview

일치하지 않음

(이 URL에는 어딘가에 "초콜릿"이 포함되어 있으므로 "맛있는 간식"이 포함되어 있어도 일치하지 않습니다.)

  • example.com/tasty-treats/chocolate-cake
  • example.com/home-cooking/oven-roasted-chicken
  • example.com/tasty-treats/banana-chocolate-fudge
  • example.com/desserts/chocolate/tasty-treats
  • example.com/chocolate/tasty-treats/desserts


답변자 : Community Wiki


^((?!hede).)*$ 는 문자를 소비하기 때문에 다른 기준과 결합할 수 없다는 점을 제외하면 우아한 솔루션입니다. 예를 들어 "hede"가 없는지 확인하고 "haha"가 있는지 확인하고 싶다고 가정해 보겠습니다. 이 솔루션은 문자를 사용하지 않기 때문에 작동합니다.

 ^(?!.*\bhede\b)(?=.*\bhaha\b)


답변자 : Community Wiki


라인을 다루는 한, 단순히 부정적인 일치를 표시하고 나머지를 대상으로 지정하십시오 .

^((?!hede).)*$ 가 지원하지 않는 것처럼 보이기 때문에 sed와 함께 이 트릭을 사용합니다.

원하는 출력을 위해

  1. 전체 텍스트에 전혀 포함되지 않은 문자를 사용하여 부정 일치를 표시합니다(예: hede 이모티콘은 아마도 이러한 목적에 좋은 선택이 될 수 있습니다.

     s/(.*hede)/\1/g
  2. 나머지(표시되지 않은 문자열: 예: hede 없는 줄)를 대상으로 지정합니다. 원하는 대로 대상만 유지 하고 나머지는 삭제한다고 가정합니다.

     s/^.*//g

더 나은 이해를 위해

대상 을 삭제한다고 가정합니다.

  1. 전체 텍스트에 전혀 포함되지 않은 문자를 사용하여 부정 일치를 표시합니다(예: hede 이모티콘은 아마도 이러한 목적에 좋은 선택이 될 수 있습니다.

     s/(.*hede)/\1/g
  2. 나머지(표시되지 않은 문자열: 예: hede 없는 줄)를 대상으로 지정합니다. 대상 을 삭제한다고 가정합니다.

     s/^[^].*//g
  3. 표시 제거:

     s///g


답변자 : Community Wiki


PCRE의 역추적 제어 동사를 사용하여 단어가 포함되지 않은 줄과 일치시키는 방법

다음은 이전에 사용된 적이 없는 방법입니다.

 /.*hede(*COMMIT)^|/

작동 방식

먼저, 라인의 어딘가에서 "heed"를 찾으려고 시도합니다. 성공하면 이 시점에서 (*COMMIT) 실패 시 역추적하지 않을 뿐만 아니라 이 경우 더 이상 일치를 시도하지 않도록 엔진에 지시합니다. 그런 다음 일치할 수 없는 항목을 일치시키려고 합니다(이 경우 ^ ).

행에 "hede"가 포함되어 있지 않으면 두 번째 대안인 빈 하위 패턴이 주제 문자열과 성공적으로 일치합니다.

이 방법은 부정적인 전망보다 더 효율적이지 않지만 누군가가 이 방법이 멋지고 다른 더 흥미로운 응용 프로그램에 대한 용도를 찾을 경우를 대비하여 여기에 던지고 싶습니다.



답변자 : Community Wiki


더 간단한 해결책은 not 연산자를 사용하는 것입니다 !

if 문은 "포함"과 일치해야 하고 "제외"와 일치하지 않아야 합니다.

 var contains = /abc/; var excludes =/hede/; if(string.match(contains) && !(string.match(excludes))){ //proceed...

나는 RegEx의 설계자가 not 연산자의 사용을 예상했다고 생각합니다.



답변자 : Community Wiki


부분 문자열을 포함 하지 않는 줄의 세그먼트(전체 줄과 반대)를 일치시킬 수 있는 정규식을 작성하는 동안 Google에서 이것을 찾을 수 있습니다. 알아내는 데 시간이 걸렸으므로 공유하겠습니다.

주어진 문자열: <span class="good">bar</span><span class="bad">foo</span><span class="ugly">baz</span>

하위 문자열 "bad"를 포함하지 않는 <span> 태그와 일치시키고 싶습니다.

/<span(?:(?!bad).)*?> <span class=\"good\"><span class=\"ugly\"> 와 일치합니다.

두 개의 괄호 세트(레이어)가 있습니다.

  • 가장 안쪽에 있는 것은 부정적인 예측을 위한 것입니다(캡처 그룹이 아님).
  • 가장 바깥쪽은 Ruby에 의해 캡처 그룹으로 해석되었지만 캡처 그룹이 되는 것을 원하지 않으므로 시작 부분에 ?:를 추가했으며 더 이상 캡처 그룹으로 해석되지 않습니다.

Ruby의 데모:

 s = '<span class="good">bar</span><span class="bad">foo</span><span class="ugly">baz</span>' s.scan(/<span(?:(?!bad).)*?>/) # => ["<span class=\"good\">", "<span class=\"ugly\">"]


출처 : Here


출처 : http:www.stackoverflow.com/questions/406230/regular-expression-to-match-a-line-that-doesnt-contain-a-word">

반응형