문제

일부 Regex 풍미에서는 [부정적인] 제로 폭의 주장 (외관/외관)이 지원되지 않습니다.

이것은 배제를 진술하기가 매우 어렵습니다 (불가능한가?). 예를 들어 "모든 라인 하지 않습니다 다음과 같이 "foo"를 가지고 있습니다.

^((?!foo).)*$

전혀 외관을 사용하지 않고도 동일한 것을 달성 할 수 있습니까 (순간적으로 복잡성과 성능 문제가 따로 설정되어 있음)?

도움이 되었습니까?

해결책

업데이트: "OO 앞에 두 개의 ff로"실패합니다. @Ciantic은 의견에서 지적했습니다.


^(f(o[^o]|[^o])|[^f])*$

노트: 위의 정규식을 사용하는 대신 클라이언트 측에서 일치하는 것이 훨씬 쉽습니다.

REGEX는 C ++ 및 Grep의 Regex를 보지 않으면 각 라인이 Newline Char로 끝나는 것으로 가정합니다.

Perl, Python, C ++의 샘플 프로그램 및 grep 모두 같은 출력을 제공합니다.

  • #!/usr/bin/perl -wn
    print if /^(f(o[^o]|[^o])|[^f])*$/;
    
  • 파이썬

    #!/usr/bin/env python
    import fileinput, re, sys
    from itertools import ifilter
    
    re_not_foo = re.compile(r"^(f(o[^o]|[^o])|[^f])*$")
    for line in ifilter(re_not_foo.match, fileinput.input()):
        sys.stdout.write(line)
    
  • C ++

    #include <iostream>
    #include <string>
    #include <boost/regex.hpp>
    
    int main()
    {
      boost::regex re("^(f(o([^o]|$)|([^o]|$))|[^f])*$");
      //NOTE: "|$"s are there due to `getline()` strips newline char
    
      std::string line;
      while (std::getline(std::cin, line)) 
        if (boost::regex_match(line, re))
          std::cout << line << std::endl;
    }
    
  • grep

    $ grep "^\(f\(o\([^o]\|$\)\|\([^o]\|$\)\)\|[^f]\)*$" in.txt
    

샘플 파일 :

foo
'foo'
abdfoode
abdfode
abdfde
abcde
f

fo
foo
fooo
ofooa
ofo
ofoo

산출:

abdfode
abdfde
abcde
f

fo
ofo

다른 팁

이 질문을 발견하고 개인적인 도전으로 완전히 작동하는 정규식이 없다는 사실을 알게되었습니다. 나는 내가 그게 선세를 만들 수 있다고 믿는다 하다 모든 입력에 대한 작업 - 사용할 수있는 경우 원자 그룹화/소유 수량 자.

물론, 나는 거기에 있는지 확실하지 않습니다 ~이다 원자 그룹화를 허용하지만 룩 어라운드를 허용하지 않는 맛이지만, 룩셀러에서 제외를 제외시킬 수 있는지에 대한 질문은 다음과 같습니다. ~이다 기술적으로 가능 :

\A(?:$|[^f]++|f++(?:[^o]|$)|(?:f++o)*+(?:[^o]|$))*\Z

설명:

\A                         #Start of string
(?:                        #Non-capturing group
    $                      #Consume end-of-line. We're not in foo-mode.
    |[^f]++                #Consume every non-'f'. We're not in foo-mode.
    |f++(?:[^o]|$)          #Enter foo-mode with an 'f'. Consume all 'f's, but only exit foo-mode if 'o' is not the next character. Thus, 'f' is valid but 'fo' is invalid.
    |(?:f++o)*+(?:[^o]|$)  #Enter foo-mode with an 'f'. Consume all 'f's, followed by a single 'o'. Repeat, since '(f+o)*' by itself cannot contain 'foo'. Only exit foo-mode if 'o' is not the next character following (f+o). Thus, 'fo' is valid but 'foo' is invalid.
)*                         #Repeat the non-capturing group
\Z                         #End of string. Note that this regex only works in flavours that can match $\Z

어떤 이유로 든 원자 그룹화를 사용할 수 있지만 소유적인 정량 자나 룩아웃을 사용할 수 있다면 다음을 사용할 수 있습니다.

\A(?:$|(?>[^f]+)|(?>f+)(?:[^o]|$)|(?>(?:(?>f+)o)*)(?:[^o]|$))*\Z

그러나 다른 사람들이 지적한 바와 같이, 다른 방법을 통해 일치를 부정하는 것이 더 실용적 일 것입니다.

일반적으로 FOO를 찾고 클라이언트 코드에서 REGEX 일치 결과를 반전 할 수 있습니다.

간단한 예를 들어, 문자열에 특정 문자 만 포함되어 있는지 확인하고 싶다고 가정 해 봅시다.

다음과 같이 쓸 수 있습니다.

^[A-Za-z0-9.$-]*$

그리고 수락 true 유효하거나 좋아하는 결과 :

[^A-Za-z0-9.$-]

그리고 수락 false 유효한 결과.

물론 이것은 항상 옵션이 아닙니다. 때로는 표현식을 구성 파일에 넣거나 다른 프로그램으로 전달해야합니다. 그러나 기억할 가치가 있습니다. 예를 들어, 표현식은 많이 이와 같은 부정을 사용할 수 있다면 더 간단합니다.

나는이 질문을 우연히 발견했다. 이내에 내 성과.

이 상황에 대한 나의 초기 반응 : 예를 들어 ""foo "가없는 모든 라인" 단순히 Grep에서 -v 반전 감각 옵션을 사용하는 것이 었습니다.

grep -v foo

이것은 'foo'와 일치하지 않는 파일의 모든 줄을 반환합니다.

너무 단순해서 강한 느낌이있어 단지 당신의 질문을 잘못 읽었습니다 ....

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top