2010-03-18 2 views
22

자바에서 정규 표현식에 java.util.regex. * 클래스를 사용하고 있으며 지금까지는 모든 장점이 있습니다. 하지만 오늘은 다른 요구 사항이 있습니다. 예를 들어 패턴을 "aabb"로 간주하십시오. 이제 입력 문자열이 aa라면 확실히 일치하지 않을 것입니다. 그러나 bb를 추가하면 aabb가되어 일치 할 가능성이 여전히 있습니다. 그러나 내가 cc로 시작한다면, 내가 추가 한 것에 상관없이 절대 일치하지 않을 것이다.java.util.regex. *로 부분 일치를 수행하려면 어떻게해야합니까?

필자는 Pattern과 Matcher 클래스를 살펴 보았지만이를 달성 할 방법을 찾지 못했습니다.

입력은 사용자의 입력이며 시스템은 패턴이 일치 할 때까지 기다려야합니다. 그렇지 않으면 어떤 입력과도 관계없이 결코 일치하지 않습니다.

단서가 있습니까?

감사합니다.

+0

지금까지 어떤 정규 표현식을 사용 했습니까? –

+0

그래서 이것을 바로 잡으려면 추가 사용자 입력을 기반으로 전체 문자열에서 정규식을 다시 수행하지 않고 중단 한 지점에서 '계속해서 정규식 바꾸기'를 원하십니까? 그렇다면 추가 제약 조건을 지정하지 않는 한이를 확인하면 설명 할 수있는 이유 때문에 가능하지 않습니다. – Cam

+0

'bb' 부분을'aa (bb)'옵션으로 만드십시오. – Amarghosh

답변

1

문자열 s가 정규식과 일치하는지 여부를 알고 싶지만 일치하는 s로 시작하는 긴 문자열이 있는지 여부를 알고 싶습니까? 미친, 정규 표현식은 정규 표현식의 내부 상태에 액세스 할 수 없기 때문에 거기에서 당신을 도울 수 없습니다. 부울 결과 및 정의한 그룹 만 가져 오므로 을 알지 못하는 이유는입니다.

JDK 라이브러리를 해킹하려는 경우 java.util.regex을 확장 (또는 아마도 포크)하고 일치 프로세스에 대한 자세한 정보를 제공 할 수 있습니다. 입력이 '사용되지 않음'으로 인해 일치가 실패한 경우 대답은 입니다. 인격 차별이나 기타 수표로 인해 실패하면 거짓이됩니다. 그래도 문제는 많은 일처럼 보입니다. 문제는 정규 표현식이하는 일과는 정반대이기 때문입니다.

다른 옵션 : 입력을 정규 표현식으로 처리하고 * aa. **에 대해 aabb과 일치시킬 수 있도록 작업을 간단히 재정의 할 수 있습니다. 하지만 정규식 메타 문자는주의해야합니다.

+0

두 번째 단락 다시 읽기 : 나는 "입력이 '매치 시도 중 언제든지 * 사용 되었기 때문에 일치하지 않았다면 * 대답은 사실 일 것이다'라고 말하고 싶습니다. 결국, 정규식 엔진은 한 번 끝까지 매치했을 것입니다. 그리고 나서 다시 돌아가서 문자열의 끝까지 돌아 가지 않고 실패했을 것입니다. ABCD에'^ A. * BC $ '를 적용 할 때처럼. –

+1

그래서 Alan Moore가 쓴 'hitEnd()'메소드가 정확히 그렇게하는 것 같습니다. 큰. –

0

예를 들어 반 패턴을 사용하여 잘못된 결과를 실격시킬 수 있습니다. 예를 들어 "^ [^ a]"는 "c ..."입력이 "aabb"의 패턴과 일치하지 않는다고 알려줍니다.

패턴에 따라 패턴을 더 작은 패턴으로 분할하여 여러 matcher를 확인하고 사용하고 하나의 일치가 발생할 때 범위를 설정하고 다음으로 이동할 수 있습니다. 이 접근법은 효과가있을 수 있지만 패턴이 복잡하고 가변 길이 하위 파트가있을 수있는 경우 일치 항목의 일부를 자신의 코드에 다시 구현하여 결국 일치 항목의 범위를 조정하여 다소 욕심을 느끼게 할 수 있습니다. 이것의 의사 코드 일반적인 생각은 다음과 같습니다

boolean match(String input, Matcher[] subpatterns, int matchStart, int matchEnd){ 
    matcher = next matcher in list; 
    int stop = matchend; 
    while(true){ 
    if matcher.matches input from matchstart -> matchend{ 
     if match(input, subpatterns, end of current match, end of string){ 
     return true; 
     }else{ 
     //make this match less greedy 
     stop--; 
     } 
    }else{ 
     //no match 
     return false; 
    } 
    } 
} 

그런 다음 안티 패턴이 아이디어를 병합 및 안티 서브 패턴을 가질 수 및 각 서브 패턴 일치 한 후, 다음 안티 패턴을 확인 그것을 경우 당신이 실패했음을 당신과 일치시키고, 그렇지 않으면 매칭 패턴을 계속합니다. 부울 (예 : ALL_MATCHED, PARTIAL_MATCH, ANTI_PATTERN_MATCH 등) 대신 열거 형을 반환하려고 할 가능성이 높습니다.

적절한 하위 패턴을 작성하려는 실제 패턴의 복잡성에 따라/안티 패턴은 불가능하지는 않더라도 어렵습니다.

-1

상태 시스템 (http://en.wikipedia.org/wiki/State_machine)으로이 작업을 수행 할 수 있습니다. 귀하의 주/전이가 유효한 입력과 하나의 오류 상태를 나타내도록하십시오.그런 다음 상태 시스템에 한 문자 (한 번에 데이터에 따라 하위 문자열)를 입력 할 수 있습니다. 언제든지 상태 시스템이 오류 상태인지 여부를 확인할 수 있습니다. 오류 상태가 아닌 경우 향후 입력이 여전히 일치 할 수 있음을 알 수 있습니다. 오류 상태에 있으면 이전에 실패한 내용을 알고 있으며 이후의 입력으로는 문자열이 유효하지 않습니다.

0

정규 표현식을 일련의 하위 정규 표현식으로 구문 분석 한 다음 부분 일치를 수행 할 수 있도록 재구성합니다. 예 : "ab c"에는 3 개의 sub-regexes "a", "b"및 "c"가 있으며 "a (b * (c)?)"로 재구성 할 수 있습니다.

입력 정규식에 대체 및 그룹이 포함될 때 상황이 더 복잡해 지지만 동일한 일반적인 접근 방식이 작동해야합니다.

이 접근법의 문제점은 결과 정규 표현식이 더 복잡하고 복잡한 입력 정규 표현식에 대해 과도한 백 트랙킹으로 이어질 수 있다는 것입니다.

0

정규 표현식의 각 문자를 선택적으로 만들고 다중성 제약 조건을 완화하면 원하는 결과를 얻을 수 있습니다. 예 "aa (abc) + bbbb"와 일치하는 패턴이있는 경우 'a? (a? b? c?) * b? b? b? b?'패턴을 가질 수 있습니다.

가능한 일치 패턴을 생성하는이 기계적 방법은 앞으로 및 뒤로 참조와 같은 고급 구문을 다루지 않습니다.

32

Matcher API를 자세히 살펴 보았습니다. hitEnd() 방법은 당신이 설명대로 작동합니다

import java.util.regex.*; 

public class Test 
{ 
    public static void main(String[] args) throws Exception 
    { 
    String[] ss = { "aabb", "aa", "cc", "aac" }; 
    Pattern p = Pattern.compile("aabb"); 
    Matcher m = p.matcher(""); 

    for (String s : ss) { 
     m.reset(s); 
     if (m.matches()) { 
     System.out.printf("%-4s : match%n", s); 
     } 
     else if (m.hitEnd()) { 
     System.out.printf("%-4s : partial match%n", s); 
     } 
     else { 
     System.out.printf("%-4s : no match%n", s); 
     } 
    } 
    } 
} 

출력 :

aabb : match 
aa : partial match 
cc : no match 
aac : no match 

는 지금까지 내가 아는 한, 자바는이 기능을 노출하는 유일한 언어입니다. requireEnd() 방법도 있습니다. 입력이 많을 경우 일치하는 항목이 일치하지 않는 항목으로 바뀔 수 있지만 귀하의 경우에는 적합하지 않다고 알려줍니다.

두 메서드 모두 Scanner 클래스를 지원하기 위해 추가되었으므로 전체 스트림을 메모리에 읽을 필요없이 스트림에 정규식을 적용 할 수 있습니다.

+2

"알다시피 Java는이 기능을 제공하는 유일한 언어입니다." - Boost의 부분 일치와 동일하지 않습니까? (http://www.boost.org/doc/libs/1_34_1/libs/regex/doc/partial_matches.html) – polygenelubricants

+0

멋지다. 'ABCD'와'A. * BC $'를 비교할 때'hitEnd()'가 반환하는 것을 시도 할 수 있습니까? –

+0

@Tim, 나는 "부분 일치"를 얻습니다. 왜냐하면 "BC"를 마지막에 추가하고 일치하는 것을 얻을 수 있기 때문입니다. –

10
Pattern p = Pattern.compile(expr); 
Matcher m = p.matcher(string); 
m.find(); 
+0

아아 나는 m.matches()를 사용하고있었습니다. 권리. 이제는 의미가 있습니다. – Kieveli

+0

내가 원했던 것은 * 문자열 *의 일부를 정규식으로 매칭시키는 방법을 찾는 것이 었습니다. 이것이 그 일을 할 방법입니다. – Brandon

관련 문제