2008-11-13 5 views
1

토큰화할 문자열이 있습니다. 형식은 HHmmssff이고 H, m,, f은 자릿수입니다.역전 된 오프셋 토크 나이 자

4 자리 2 자리 숫자로 토큰 화되어 있지만, 과 같은 짧은 양식도 허용해야하므로 00000sff으로 해석합니다. boost::tokenizeroffset_separator을 사용하고 싶었지만 양의 오프셋에서만 작동하는 것으로 보이며 거꾸로 작업하고 싶습니다.

좋아, 하나의 아이디어는 왼쪽에서 0으로 문자열을 채우는 것입니다.하지만 커뮤니티에 뭔가 uber -smart가 올 수도 있습니다. ;)

편집 :추가 요구 사항이 막 시작되었습니다.

똑똑한 솔루션의 기본 요구 등 f, ssff, mssff처럼, 모든 경우를 처리 할뿐만 아니라, 예를 들어 짧은 손 형태와 HH:mm:ss:ff처럼, 더 완전한 시간 표기법을 적용했다 s:ff 또는 심지어 s: (이 사람은 s:00으로 해석되어야합니다.)

문자열이 :으로 끝나는 경우 분명히 두 개의 0을 덧붙일 수 있습니다. 그런 다음 숫자 만 남겨 놓은 모든 구분 기호를 제거하고 결과 문자열을 영혼으로 구문 분석하십시오.

오프셋 된 토크 나이저를 문자열의 끝 (오프셋 -2, -4, -6, -8)으로 되돌려 놓고 어휘 적으로 숫자를 캐스팅하는 방법이 있다면 조금 더 간단 해 보입니다. int s.

+0

"하나의 아이디어는 왼쪽에서 0으로 문자열을 채우는 것입니다." 간단하고 빠른 작품. 왜 다른 것을 찾지? –

+0

성능 괴물을 의미하지는 않지만이 솔루션에는 문자열 복사가 포함됩니다 (입력은 const 및 std :: string 임). – macbirdie

+0

은 문제가되지 않아야합니다. std :: string은 대개 쓰기가 가능할만큼 똑똑하기 때문에 실제로 추가하는 경우 성능 비용 만 발생합니다. –

답변

1

나는 BNF 표기법을 계속 설교하고있다. 문제를 정의하는 문법을 적어두면 쉽게 Boost.Spirit 파서로 변환 할 수 있습니다.

TimeString := LongNotation | ShortNotation 

LongNotation := Hours Minutes Seconds Fractions 

Hours := digit digit 
Minutes := digit digit 
Seconds := digit digit 
Fraction := digit digit 

ShortNotation := ShortSeconds Fraction 
ShortSeconds := digit 

편집 : 추가 제약은

VerboseNotation = [ [ [ Hours ':' ] Minutes ':' ] Seconds ':' ] Fraction 
+0

하지만'ssff' 나'mssff' 나 'f'가 아닌'sff'의 경우 만 처리합니다. 지금은 문자열을 채우고 실제로 그것을 구문 분석하고 있습니다. – macbirdie

+0

제품 요구 사항에서 BNF 형식으로 요구 사항을 완벽하게 지정하도록 요구할 수 있습니다. 그들이 할 수 없다면, 당신은 그들을 도울 수 있습니다. – xtofl

0

정규 표현식은 마음에 와서. "^0*?(\\d?\\d?)(\\d?\\d?)(\\d?\\d?)(\\d?\\d?)$"boost::regex 같은 것입니다. 하위 매칭은 숫자 값을 제공합니다. 숫자 사이에 콜론을 사용하여 다른 형식으로 채택하기가 어렵지 않아야합니다 (sep61.myopenid.com의 대답 참조). boost::regex은 거기서 가장 빠른 정규식 파서 중 하나입니다.

0

"성능 괴물이되는 것을 의미하지는 않지만이 솔루션은 일부 문자열 복사 (입력은 const & std :: string)"와 관련됩니다.

성능에 너무 신경을 써서 정규식과 같은 큰 오래된 라이브러리를 사용할 수 없으면 BNF 파서의 위험을 감수하지 않으므로 std :: string :: substr이 할당을 복사 (따라서 STL 문자열 함수를 사용할 수 없다), 심지어는 '0'문자 버퍼 좌 패드로 캐릭터 문자를 복사 할 수

void parse(const string &s) { 
    string::const_iterator current = s.begin(); 
    int HH = 0; 
    int mm = 0; 
    int ss = 0; 
    int ff = 0; 
    switch(s.size()) { 
     case 8: 
      HH = (*(current++) - '0') * 10; 
     case 7: 
      HH += (*(current++) - '0'); 
     case 6: 
      mm = (*(current++) - '0') * 10; 
     // ... you get the idea. 
     case 1: 
      ff += (*current - '0'); 
     case 0: break; 
     default: throw logic_error("invalid date"); 
     // except that this code goes so badly wrong if the input isn't 
     // valid that there's not much point objecting to the length... 
    } 
} 

하지만 근본적으로 단지 0- 이러한 int 변수를 초기화하는 것은 패딩을 사용하여 문자열을 char 버퍼로 복사하는 것만큼이나 많은 작업이므로 상당한 성능 차이가있을 것으로 기대하지는 않습니다.따라서 조기 최적화에서의 연습처럼 실생활에서이 솔루션을 실제로 권장하지는 않습니다.

+0

BNF 파서와 std :: string을 사용하고 있습니다. 성능이 그다지 큰 문제가 아닙니다. (정신은 주로 템플릿 라이브러리입니다.) 실제로 여러분의 예제와 비슷한 코드를 대체 할 코드를 만듭니다. 더 일반적이고 음, 멋지다. ;) – macbirdie

+0

나는 정말 깨끗한 해결책이 가능한지보고 싶었을뿐입니다. – macbirdie

+0

충분히 공정하십시오 - 한 가지 주석에 의해 암시 된 질문은 여러분이 정말로 물어 본 질문에서부터 끔찍한 바이트가 아닌 단순한 코드에 관한 것입니다. 나는 그 종류의 스위치 해킹을 좋아한다. 왜냐하면 그것은 두려워하는 사각형을 괴롭히기 때문이다 ;-) –