2011-03-28 4 views
2

그래서 TCP winsock 연결을 통해 수신되는 데이터의 다음 문자열이 있으며 구조체의 벡터로 고급 토큰 화를하고 싶습니다. 각 구조체는 하나의 레코드를 나타냅니다.구조체의 벡터에 데이터 문자열을 토큰 화하는 중?

std::string buf = "44:william:adama:commander:stuff\n33:luara:roslin:president:data\n" 

struct table_t 
{ 
    std::string key; 
    std::string first; 
    std::string last; 
    std::string rank; 
    std::additional; 
}; 

문자열의 각 레코드는 캐리지 리턴으로 구분됩니다.

void tokenize(std::string& str, std::vector<string>records) 
{ 
    // Skip delimiters at beginning. 
    std::string::size_type lastPos = str.find_first_not_of("\n", 0); 
    // Find first "non-delimiter". 
    std::string::size_type pos  = str.find_first_of("\n", lastPos); 
    while (std::string::npos != pos || std::string::npos != lastPos) 
    { 
     // Found a token, add it to the vector. 
     records.push_back(str.substr(lastPos, pos - lastPos)); 
     // Skip delimiters. Note the "not_of" 
     lastPos = str.find_first_not_of("\n", pos); 
     // Find next "non-delimiter" 
     pos = str.find_first_of("\n", lastPos); 
    } 
} 

더 구조체로 (내부 필드 분리) 대장을 통해 각 레코드를 토큰 화 다시 그 모든 코드를 반복 완전히 불필요한 것 : 필드를 레코드를 분할,하지만 아직 분할에 내 시도 각 구조체를 벡터로 푸시합니다. 이렇게하는 더 좋은 방법이있을 것이라고 확신합니다. 아니면 디자인 자체가 잘못되었을 수도 있습니다.

도움 주셔서 감사합니다.

+1

오히려 깔끔하게 할 당신이 부스트를 사용할 수있는 경우이 될 것이다 tokenizer 라이브러리, 문자열 알고리즘 라이브러리 또는 가장 강력한 솔루션 인'boost.spirit'을 사용하여 다음과 같이 작성할 수 있습니다. http://www.boost.org/doc/libs/1_46_1/libs/spirit/doc /html/spirit/qi/tutorials/employee___parsing_into_structs.html – Cubbi

+0

이이 코멘트를 놓쳤습니다. +1이 경우에 사용되는 데이터 형식에 너무 무거울 때도 있습니다. – user237419

+0

[boost :: tokenizer] (http://www.boost.org/doc/libs/1_46_1/libs/tokenizer/index.html)를 사용하십시오. – user237419

답변

1

문자열을 레코드로 분할하는 경우, 만있는 경우 istringstream을 사용하면 이후에 파일을 에서 읽으려고 할 때 변경 사항이 간단해질 수 있습니다.

std::vector<table_t> parse(std::istream& input) 
{ 
    std::vector<table_t> retval; 
    std::string line; 
    while (std::getline(input, line)) { 
     static boost::regex const pattern(
      "\([^:]*\):\([^:]*\):\([^:]*\):\([^:]*\):\([^:]*\)"); 
     boost::smatch matched; 
     if (!regex_match(line, matched, pattern)) { 
      // Error handling... 
     } else { 
      retval.push_back(
       table_t(matched[1], matched[2], matched[3], 
         matched[4], matched[5])); 
     } 
    } 
    return retval; 
} 

(나는 table_t에 대한 논리적 생성자를 가정 한도 : 토큰 화를 위해 가장 확실한 해결책은 부스트 ​​: 정규식, 그래서이다. _t로 끝나는 이름은 타입 정의의의입니다 C에서 매우 오랜 전통이있다 , 그래서 당신은 다른 규칙을 찾는 떨어져 아마 더 나은 있어)

+0

당신은 Siek을 핑 (ping)해야하고 그에 대해 말해 주어야합니다. :: tokenizer는 정규식을 사용하면 아무 것도 할 수 없으므로 쓸모가 없습니다. 분명히 – user237419

+0

@adirau 그는 중복을 피하는 방법을 물었다. 기존 도구를 사용하는 것이 분명한 해결책입니다. 이 경우 가장 간단한 솔루션입니다 (적어도 오류를 확인하려는 경우). –

+0

코드 재사용으로 중복을 피하십시오. 첫 번째 토크 나이저로 getline을 사용하고 두 번째 토크 나이저로 정규 표현식을 사용하면 중복을 피할 수 있다고 말하면 안됩니다.) 가장 단순하고 명확하지 않으며 오류를 확인하고 싶지도 않습니다. 그 정규식은 토큰 수준에서 오류를 받아 들일 것입니다; 만약 그가 에러 검사가 필요하다면 :: spirit은 첫 번째 코멘트에서 언급 된 Cubbi와 같은 더 좋은 해결책입니다. – user237419

2

내 솔루션 :.

struct colon_separated_only: std::ctype<char> 
{ 
    colon_separated_only(): std::ctype<char>(get_table()) {} 

    static std::ctype_base::mask const* get_table() 
    { 
     typedef std::ctype<char> cctype; 
     static const cctype::mask *const_rc= cctype::classic_table(); 

     static cctype::mask rc[cctype::table_size]; 
     std::memcpy(rc, const_rc, cctype::table_size * sizeof(cctype::mask)); 

     rc[':'] = std::ctype_base::space; 
     return &rc[0]; 
    } 
}; 

struct table_t 
{ 
    std::string key; 
    std::string first; 
    std::string last; 
    std::string rank; 
    std::string additional; 
}; 

int main() { 
     std::string buf = "44:william:adama:commander:stuff\n33:luara:roslin:president:data\n"; 
     stringstream s(buf); 
     s.imbue(std::locale(std::locale(), new colon_separated_only())); 
     table_t t; 
     std::vector<table_t> data; 
     while (s >> t.key >> t.first >> t.last >> t.rank >> t.additional) 
     { 
      data.push_back(t); 
     } 
     for(size_t i = 0 ; i < data.size() ; ++i) 
     { 
      cout << data[i].key <<" "; 
      cout << data[i].first <<" "<<data[i].last <<" "; 
      cout << data[i].rank <<" "<< data[i].additional << endl; 
     } 
     return 0; 
} 

출력 :

44 william adama commander stuff 
33 luara roslin president data 

온라인 데모 : http://ideone.com/JwZuk


내가 여기에 사용 된 기술은 다른 질문에 대한 내 다른 솔루션에 설명되어 있습니다 :

Elegant ways to count the frequency of words in a file

+0

ctype을 아직 확인하지 않았으므로 읽어야합니다. 도와 줘서 고마워. – rem45acp