2009-11-25 2 views
3

regex VS "string".contains("anotherString") 및/또는 다른 String API 호출을 사용하는 경우 일반 지침이 있는지 궁금합니다.정규 표현식 VS 연습 반복을위한 모범 사례

.contains()에 대한 위의 결정은 간단합니다 (단 한 번의 호출로이 작업을 수행 할 수 있다면 정규 표현식을 왜 귀찮게하는지). 실제 생활은 더 복잡한 선택을합니다. 예를 들어 두 개의 .contains() 호출 또는 단일 정규식을 수행하는 것이 더 좋습니까?

나의 어법은 단일 API 호출로 대체 할 수 없다면 항상 regex를 사용하는 것이 었습니다. 이렇게하면 코드가 부풀어 오르는 것을 막을 수 있습니다. 코드 가독성 측면에서 보면별로 좋지 않을 수 있습니다. 특히 정규 표현식이 커지는 경향이있는 경우에는 특히 그렇습니다.

흔히 간과되는 또 다른 주장은 성과입니다. 이 정규 표현식을 사용하려면 얼마나 많은 반복 ("Big O"에서처럼)이 필요한지 어떻게 알 수 있습니까? 반복되는 것보다 더 빠릅니까? 어떻게 든 모든 사람들은 정규 표현식이문장보다 짧아지면 더 빠르다고 가정합니다. 하지만 항상 그렇습니까? regex를 사전에 미리 컴파일 할 수없는 경우 특히 유용합니다.

답변

-1

대답은 (평소와 같이) 의존하는 것입니다.

특별한 경우에, 나는 "this | that"정규식을 수행 한 다음 찾을 수있는 대안이 있다고 생각합니다. 이 특정 구성은 실제로 정규 표현식의 약점을 나타냅니다. 이 경우 "OR"는 서브 패턴이 무엇을하려하는지 알지 못하므로 쉽게 최적화 할 수 없습니다.그것은 (의사 코드로)의 동등한 일을 끝낸다.

for(i = 0; i < stringLength; i++) { 
    if(stringAt pos i starts with "this") 
     found! 
    if(stringAt pos i starts with "that") 
     found! 
} 

거의 그렇게 느리지 않다. 이 경우 두 개의 contains() 호출이 훨씬 빠릅니다.

반면에 전체 일치 : ".*this.*|.*that.*"이 더 최적화 될 수 있습니다.

그렇지 않으면 코드가 복잡하거나 다루기 힘들 때 정규 표현식을 사용해야합니다. 따라서 대상 문자열에서 두 개 또는 세 개의 문자열 중 하나를 찾으려면 contains를 사용하십시오. 하지만 'A'또는 'B'로 시작하여 'g'- 'm'로 끝나는 단어를 찾으려면 정규식을 사용하십시오.

그리고 나서 여기저기서 몇 사이클을 걱정하지 않아도됩니다.

+3

귀하의 대답은 전혀 이해가되지 않습니다. 이 정규 표현식은 "th"가 발생했을 때 약간의 여분의 논리만으로 문자열을 통해 한 번의 선형 검색을 수행하고이 첫 번째 일치에서 중지합니다. 두 개의 contains() 호출은 문자열을 통해 두 개의 선형 검색을 수행하므로 첫 번째 단어가 들어 있지 않은 경우 전체 문자열을 검색해야합니다. 항상 성능이 저하됩니다. . * this. * |. *. *. *는 처음부터. *가 전체 문자열과 끝까지 일치하므로 단어를 찾기 위해 역 추적하기 때문에 훨씬 간단하게 만드는 것보다 명확하게 최적화되지 않습니다. –

+0

최악의 경우는 같은 방법으로 모든 패턴이 관련 문자 위치마다 시도됩니다. 소수의 직선 검색의 경우 "this | that"에 더 최적의 사례가 있습니다 (예 : 'that'는 문자열에 있지만 'this'에는 없음). 패턴의 목록이 증가하고 잘못된 시작의 기회가 커지면 변경됩니다. 이 경우에는 아마 기지를 벗어 났을 것입니다. 직접적인 문자 일치는 항상 정규 표현식을 선호 할 수 있습니다 (Java의 특정 구현은 경험을 통해 수백 가지 패턴에 대해 비정상적으로 수행하는 것처럼 보이지만). – PSpeed

+1

그 자체가 비싸지 않은 비 문자 패턴의 경우, 하나의 큰 정규식 대신에 여러 별도의 연산을 수행하는 데 비용을 지불 할 수 있습니다. 특히 가장 초기의 일치 (위치 별)를 신경 쓰지 않는 경우 특히 그렇습니다. – PSpeed

1

두 가지 코드를 작성하고 시간을 기록 할 것을 강력히 제안합니다. 이 작업을 수행하는 것은 매우 간단하며 일반적인 "경험 법칙"이 아닌 문제 영역에 대한 매우 구체적인 대답을 얻을 수 있습니다.

밴스 모리슨

http://msdn.microsoft.com/en-us/magazine/cc500596.aspx

당신이 내 개인 "규칙을 싶다면 ... 마이크로 벤치마킹에 대한 훌륭한 포스트를 가지고 있으며,이 같은 질문에 대답 할 것이 정말 간단하게하는 도구가 있습니다 엄지 손가락 "을 선택하면 RegEx가 종종 이런 종류의 작업에는 속도가 느려지므로 나를 무시하고 직접 측정해야합니다 :-)

성능상의 이유로 정규 표현식을 계속 사용하면 정말 좋습니다. 두가지. 프로파일 러 (예 : ANTS)를 가져 와서 프로덕션에서 코드가하는 것을 확인하십시오. 그런 다음, 정규식 코드를 속도에가 팁의 부하를 가지고로 ...

http://www.amazon.co.uk/Regular-Expressions-Cookbook-Jan-Goyvaerts/dp/0596520689/ref=sr_1_1?ie=UTF8&s=books&qid=1259147763&sr=8-1

을 정규 표현식 요리 책의 사본을 얻을. 이 책의 팁에 따라 RegEx 코드를 10 배로 최적화했습니다.

+0

정규 표현식 요리 책을 듣고 기쁩니다. 어떤 친구가 아직 사본을 가지고 있지 않다면, O'Reilly와 나는 regexguru.com에서 공짜로 제공하고 있습니다. 누구든지 이달 말까지 참여할 수 있습니다 (2010 년 2 월 28 일). –

+0

@Jay Cool. 나는 이것을 앞으로 나아갈 것이다. 팁 - 오프 주셔서 감사. –

3

프로파일 러를 사용하지 않고 성능을 예측하기는 어렵지만, 일반적으로 가장 논리적 인 의미를 지니고 이해하기 쉽도록/읽는 것이 가장 좋습니다. 만약 두 개의 .contains() 호출이 논리적으로 이해하기가 더 쉽다면 그것은 더 나은 경로이며, 정규 표현식이 더 이해가된다면 같은 논리가 적용됩니다.

팀원 중 다른 개발자가 정규식에 대해 잘 이해하지 못할 수도 있습니다. 나중에 프로덕션 환경에서 .contains() (또는 그 반대로)를 사용하는 것이 병목 현상으로 밝혀지면 둘 다 시도하고 프로파일 링하십시오.

규칙 : 읽을 수 있도록 코드를 작성하고 병목 현상을 식별하기 위해 프로파일 러를 사용하고 더 빠른 코드로만 읽을 수있는 코드를 바꿉니다.

+0

+1 성급하게 최적화하지 마십시오. –

3

RegexBuddy에는 내장 정규식 디버거가 있습니다. 정규 표현식 엔진이 일치 항목을 찾거나 일치 항목을 찾지 못하는 데 필요한 단계를 나타냅니다. 다양한 길이의 문자열에서 디버거를 사용하면 정규 표현식의 복잡성 (big O)에 대한 아이디어를 얻을 수 있습니다. 당신이 RegexBuddy 도움말 파일의 인덱스에서 "벤치 마크"를 찾으면 이것을 해석하는 방법에 대한 더 많은 정보를 얻을 수 있습니다.

정규 표현식의 성능을 판단 할 때 정규 표현식 이 (가)에 실패한 상황을 테스트하는 것이 특히 중요합니다. 선형 시간에 일치하는 항목을 찾는 정규식을 작성하는 것은 매우 쉽지만 catastrophic backtracking이라고하는 상황에서는 기하 급수적 인 시간에 실패합니다.

은 5 예로 문, 추가 작업을 조금하고 한 번 입력 문자열을 검색 one|two|three|four|five 정규식, o, t, 또는 f가 발생 될 때 경우를 사용합니다. 그러나 문자열에 단어가 포함되어 있는지 확인하는 문장의 5 if는 단어를 찾을 수없는 경우 전체 문자열을 5 번 검색합니다. five이 문자열의 시작 부분에서 발생하면 정규 표현식은 즉시 일치를 찾습니다. 반면에 첫 번째 4 if 문은 5 번째 if 문이 일치하는 것을 찾기 전에 전체 문자열을 헛되이 검색합니다.