최선의 방법은 무엇일을 분석하는 몸의 텍스트에 대해 여러(15+)정규표현식에 각인가?

StackOverflow https://stackoverflow.com/questions/303830

문제

내 몸의 텍스트는가를 검사하고 각 라인에 포함하는 적어도 2 가끔 네 가지 부분의 정보입니다.문제는 각 라인할 수 있습 1 15-20 다른 작업입니다.

루비에서는 현재의 코드는 다소 다음과 같다:

text.split("\n").each do |line|  #around 20 times..

..............

      expressions['actions'].each do |pat, reg| #around 20 times

.................

이것은 분명히'문제'.나는 관리인(에서는 C++를 통해 50%의 보증금)을 결합하여 모든 regexen 하나로만 여전히지 않은 속도가 필요해 분석 수천의 이러한 파일은 빠릅니다!

지금 나는 그들을 일치와 정규표현식-그러나 이것은 참을 느립니다.기 시작했으로 루비와 미가 이상하여 C++는 뜻에서 나는 속도를 그냥 일어나고 있지 않다.

나는 부담에서 읽을 못하고 문법을 기반으로 분석 하지만 그것은 보인 다소 어렵게 구현할 수 있습니다.이 이 방향으로 내 머리를해야 또는 거기에 다른 노선?

기본적으로 분석하는 포커 손 역사 및 각 라인의 손으로 일반적으로 역사가 포함 2-3 정보의 비트는 필요를 수집합니다:는 플레이어,얼마나 많은 돈이거나드는 작업이 수반된..등등....

샘플 텍스트해야 하는 구문 분석된:

buriedtens posts $5
The button is in seat #4
*** HOLE CARDS ***
Dealt to Mayhem 31337 [8s Ad]
Sherwin7 folds
OneMiKeee folds
syhg99 calls $5
buriedtens raises to $10

후에는 내가 이러한 정보를 수집합의 각 동작으로 설정되어 있는 xml 노드입니다.

바로 지금 나의 루비의 이행을보다 훨씬 더 빠르게 내 C++하지만 그 prob.그냥 발생하지 않았습 c 에서에서 작성된 코드를 잘 넘는 4-5 년

업데이트: 나는 원하지 않는 게시하는 모든 여기에 코드 하지만 지금까지는 내 손이/초은 다음과 같이 표시됩니다.

588 hands/second -- boost::spirit in c++
60 hands/second -- 1 very long and complicated regex in c++ (all the regexen put together)
33 hands/second -- normal regex style in ruby

나는 현재 테스트 antlr 루어질 수 있는지를 확인하려 더 이상 갈지만 지금은 매우 매우 행복과 성령의 결과입니다.

관련 질문: 을 효율적으로 쿼리하는 문자열이 하나에 대한 여러 regex.

도움이 되었습니까?

해결책

내가 제안 할게

행운을 빕니다

다른 팁

boost.spirit 상세한 파서 분석을 수행 할 수있는 환상적인 라이브러리이며, 파서가 코드에 바로 생성되고 컴파일되므로 동적으로 계산 된 솔루션보다 훨씬 빠릅니다. 구문은 주로 표현식 템플릿 (많은 과부하 연산자를위한 멋진 용어)으로 수행되므로 실제로 코드에 바로 쓰는 것을 의미합니다.

Perl을 사용하는 경우 다음과 같은 방법이 있습니다.
복사 perldoc perlfaq6

while (<>) {
    chomp;
    PARSER: {
        m/ \G( \d+\b    )/gcx   && do { print "number: $1\n";  redo; };
        m/ \G( \w+      )/gcx   && do { print "word:   $1\n";  redo; };
        m/ \G( \s+      )/gcx   && do { print "space:  $1\n";  redo; };
        m/ \G( [^\w\d]+ )/gcx   && do { print "other:  $1\n";  redo; };
    }
}

각 라인에 대해 PARSER 루프는 먼저 일련의 숫자와 단어 경계와 일치하려고 시도합니다. 이 경기는 마지막 경기가 끝나는 곳에서 시작해야합니다 (또는 첫 경기에서 문자열의 시작). 부터 m/ \G( \d+\b )/gcx 사용 c 플래그, 문자열이 해당 정규 표현식과 일치하지 않으면 Perl이 재설정되지 않습니다. pos() 그리고 다음 경기는 다른 패턴을 시도하기 위해 같은 위치에서 시작합니다.

보다 정규 표현 일치는 단순하고 빠를 수 있습니다 (그러나 Java, Perl, PHP, Python, Ruby, ...)에서는 느립니다.. 데이터의 양과 Regex가 얼마나 복잡한 지에 따라 자신의 구문 분석 논리를 작성하는 것이 더 빠를 수 있습니다.

나는 부담없이 페그와 문법 기반 구문 분석을 읽었지만 구현하기가 다소 어렵습니다. 이것이 내가 향해야 할 방향입니까, 아니면 다른 경로가 있습니까?

개인적으로 나는 페그를 사랑하기 위해 자랐습니다. 아마 그들과 편안하게하는 데 약간의 시간이 걸릴 것입니다. 그러나 나는 그들이 훨씬 더 많은 관리가 가능해서 분명한 승리라고 생각합니다. 구문 분석 코드는 입력에서 새로운 모서리 케이스를 찾을 때 예상치 못한 버그의 소스라는 것을 알았습니다. 비 터미널이있는 선언적 문법은 루프 및 조건이 심한 Regex 코드와 비교할 때 이런 일이 발생할 때 업데이트하기가 더 쉽습니다. 이름 지정은 강력합니다.

루비에는 있습니다 나무 꼭대기 페그를 사용하는 파서 생성기입니다. 나는 최근에 Regex Heavy Hand Wrist Parser를 짧은 문법으로 교체하는 것이 매우 유쾌하다는 것을 알았습니다.

정규 표현식이 겹치는가? 즉, 둘 이상의 레지 즈가 같은 라인과 일치 할 때 항상 라인의 다른 부분과 일치합니까 (중첩 없음)?

일치가 겹치지 않으면 지금 가지고있는 15 개의 Regexes를 결합한 하나의 정규 표현식을 사용하여 검색을 실행하십시오.

regex1|regex2|regex3|...|regex15

일치하는 15 개의 Regexes 중 어느 것을 결정할 수 있어야하는 경우 캡처 그룹을 사용하십시오.

긴 정수를 위해 데이터를 한 번 검색하는 것이 15 번 검색하는 것보다 빠릅니다. 사용중인 Regex 엔진과 정규 표현의 복잡성에 따라 얼마나 빠릅니다.

하려고 간단한 테스트에서는 Perl.읽기에 대한"학습"기능이 있습니다.내가 무엇을 하려고 할 수 있습입니다:

  • 전체 파일이나 큰 숫자의 라인 경우 이러한 파일은 매우 큰 하나의 문자열로
  • 줄을 추가 수하는 각 라인의 시작 부분으로 이동합니다.
  • "학습"문자열.이를 구축 조회 테이블로 캐릭터,크다고 할 수 있다.
  • 실 일치하는 정규 표현식 문자열에 묶여 개행 문자(사용합 m s regex 수정).식 추출해야 한 줄 수 데이터와 함께.
  • 설정 항목 배열 색인에 의해 선호하는 데이터에서 발견하는 라인,또는 뭔가 더욱 스마트하게 운영해 보세요.
  • 마지막으로 당신이 할 수있는 프로세스에 저장된 데이터 배열입니다.

나는 그것을 시도하지 않지만,그것은 흥미로운 일이 될 수 있습니다.

이를 위해 사용할 수있는 Spiffy Quad 또는 Oct Core 서버가있는 경우 또 다른 아이디어.

작업을 나누는 처리 파이프 라인을 구축하십시오. 1 단계는 파일을 하나의 게임이나 손으로 자른 다음 각각을 읽고 데이터를 읽고 처리하고 출력을 생성하는 8 단계 2 개의 파이프 중 하나에 각각을 다른 컴퓨터의 데이터베이스에 작성할 수 있습니다.

내 경험상 이러한 파이프 기반 멀티 프로세스 설계는 멀티 스레딩 디자인보다 디버깅하기가 훨씬 빠르고 훨씬 쉽습니다. 또한 파이프 대신 네트워크 소켓을 사용하여 기계 클러스터를 쉽게 설정할 수 있습니다.

좋아, 이것은 일을 더 명확하게 만듭니다 (포커 손 역사). 나는 당신이 통계 도구를 만들고 있다고 생각합니다 (침략 요인, 대결에 갔고, 자발적으로 $를 냄비 등에 넣었습니다). 왜 과도한 속도가 필요한지 잘 모르겠습니다. 16 개의 테이블로 멀티블링하더라도 손은 적당한 속도로만 간질이어야합니다.

나는 루비를 모른다. 그러나 Perl에서는 중요한 부품을 $ 1, $ 2 등으로 가져 오는 것과 동시에 작은 스위치 진술을 할 것이다. 내 경험에 따르면, 이것은 문자열 비교를 한 다음 분할하는 것보다 느리지 않습니다. 다른 수단과의 선.

HAND_LINE: for ($Line)
    { /^\*\*\* ([A-Z ]+)/ and do 
        { # parse the string that is captured in $1
          last HAND_LINE; };
      /^Dealt to (.+) \[(.. ..)\]$/ and do
        { # $1 contains the name, $2 contains the cards as string
          last HAND_LINE; };
      /(.+) folds$/ and do
        { # you get the drift
          last HAND_LINE; }; };

나는 당신이 정말로 그것을 더 빨리 만들 수 있다고 생각하지 않습니다. 첫 번째 위치에서 가장 많이 발생하는 선 (주름 진술)과 마침내 드물게 발생하는 선 (새 손을 시작하는 선을 시작하십시오. "*** NEXT PHASE ***").

실제 파일 판독 값이 병목 현상이라는 것을 알게되면 큰 파일을 처리하는 데 사용할 수있는 모듈을 살펴볼 수 있습니다. Perl, Tie::File 생각 나다.

각 손을 한 번만 읽으십시오. 각 손에 모든 데이터를 다시 읽지 말고 대신에 이미 구문 분석 된 핸드 ID의 해시 테이블을 유지하십시오.

이와 같은 문제의 경우 눈을 감고 Lexer+Parser Generator를 사용합니다. 아마도 직접 최적화로 이길 수 있지만 생성기를 사용하는 것이 훨씬 쉽습니다. 또한 입력이 갑자기 변경되면 더 유연합니다.

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