2012-05-30 3 views
8

: 그래서빠른, 내가 같은 형식의 데이터로, 단순한 CSV 파일을 구문 분석하려고 C에서 간단한 CSV 구문 분석 ++

20.5,20.5,20.5,0.794145,4.05286,0.792519,1 
20.5,30.5,20.5,0.753669,3.91888,0.749897,1 
20.5,40.5,20.5,0.701055,3.80348,0.695326,1 

, 매우 간단하고 고정 된 형식 파일. 이 데이터의 각 열을 STL 벡터에 저장합니다. 따라서 나는 표준 라이브러리를 사용하여 C++ 상태를 유지하기 위해 노력했습니다, 그리고 루프 내에서 내 구현은 다음과 같은 :

, 이것은 매우 느린 문제가
string field; 
getline(file,line); 
stringstream ssline(line); 

getline(ssline, field, ','); 
stringstream fs1(field); 
fs1 >> cent_x.at(n); 

getline(ssline, field, ','); 
stringstream fs2(field); 
fs2 >> cent_y.at(n); 

getline(ssline, field, ','); 
stringstream fs3(field); 
fs3 >> cent_z.at(n); 

getline(ssline, field, ','); 
stringstream fs4(field); 
fs4 >> u.at(n); 

getline(ssline, field, ','); 
stringstream fs5(field); 
fs5 >> v.at(n); 

getline(ssline, field, ','); 
stringstream fs6(field); 
fs6 >> w.at(n); 

입니다 (데이터 당 1 백만 행이 파일), 그리고 나는 약간 우아하지 않은 것 같습니다. 표준 라이브러리를 사용하는 더 빠른 접근법이 있습니까? 아니면 그냥 stdio 함수를 사용해야합니까? 이 전체 코드 블록이 단일 fscanf 호출로 줄어들 것 같습니다.

미리 감사드립니다.

+1

중복 :

당신은 다음 문자열을 구문 분석 같은 것을 할 수 http://stackoverflow.com/questions/1120140/csv-parser-in-c –

+0

C CSV 파서 : http://sourceforge.net/projects/cccsvparser C CSV 작성자 : http://sourceforge.net/projects/cccsvwriter – SomethingSomething

답변

8

7 문자열 스트림을 사용하면 단 한 가지만해도 문제가 해결되지 않습니다. 공연. 대신보십시오 : 당신이 파일의 줄 수를 알고있는 경우

string line; 
getline(file, line); 

istringstream ss(line); // note we use istringstream, we don't need the o part of stringstream 

char c1, c2, c3, c4, c5; // to eat the commas 

ss >> cent_x.at(n) >> c1 >> 
     cent_y.at(n) >> c2 >> 
     cent_z.at(n) >> c3 >> 
     u.at(n) >> c4 >> 
     v.at(n) >> c5 >> 
     w.at(n); 

, 당신은 읽기 전에 벡터의 크기를 조정하고 at() 대신 operator[]를 사용할 수 있습니다. 이렇게하면 범위 검사를 피할 수 있으므로 성능이 약간 향상됩니다.

+0

완벽한! 그것은 훨씬 더 잘 작동합니다. 쉼표를 먹는 것에 대한 힌트를 주셔서 감사합니다! –

+0

@KyleLynch :'char '가 쉼표로 초기화되었는지 확인하는 것이 중요합니다. 또한 스트림이 유효한지 확인하거나 예외 플래그를 설정하여 출력이 좋지 않은 경우 경고를 받아야합니다. –

+0

작은 것 : 쉼표를 먹는 한 개의 문자로 충분할 것입니다 – IceFire

2

getline() 기반 비 버퍼링 I/O를 제외하고 주요 병목 현상이 문자열 파싱이라고 생각합니다. 구분 기호로 ","기호가 있기 때문에 문자열에 대해 선형 스캔을 수행하고 모든 ","를 "\ 0"(문자열 끝 표식, 0 종결 자)로 바꿀 수 있습니다. 이 같은

뭔가 :

// tmp array for the line part values 
double parts[MAX_PARTS]; 

while(getline(file, line)) 
{ 
    size_t len = line.length(); 
    size_t j; 

    if(line.empty()) { continue; } 

    const char* last_start = &line[0]; 
    int num_parts = 0; 

    while(j < len) 
    { 
     if(line[j] == ',') 
     { 
      line[j] = '\0'; 

      if(num_parts == MAX_PARTS) { break; } 

      parts[num_parts] = atof(last_start); 
      j++; 
      num_parts++; 
      last_start = &line[j]; 
     } 
     j++; 
    } 

    /// do whatever you need with the parts[] array 
} 
1

이 허용 대답보다 더 빨리 될 경우 나도 몰라,하지만 난뿐만 아니라 당신이 그것을 시도 할 경우 어쨌든 그것을 게시 할 수 있습니다. 일부 파일을 사용하여 단일 읽기 호출을 사용하여 파일의 전체 내용을로드 할 수 있습니다. fseek magic. 이것은 여러 읽기 호출보다 훨씬 빠릅니다. 다음과 같은 질문의

//Delimited string to vector 
vector<string> dstov(string& str, string delimiter) 
{ 
    //Vector to populate 
    vector<string> ret; 
    //Current position in str 
    size_t pos = 0; 
    //While the the string from point pos contains the delimiter 
    while(str.substr(pos).find(delimiter) != string::npos) 
    { 
    //Insert the substring from pos to the start of the found delimiter to the vector 
    ret.push_back(str.substr(pos, str.substr(pos).find(delimiter))); 
    //Move the pos past this found section and the found delimiter so the search can continue 
    pos += str.substr(pos).find(delimiter) + delimiter.size(); 
    } 
    //Push back the final element in str when str contains no more delimiters 
    ret.push_back(str.substr(pos)); 
    return ret; 
} 

string rawfiledata; 

//This call will parse the raw data into a vector containing lines of 
//20.5,30.5,20.5,0.753669,3.91888,0.749897,1 by treating the newline 
//as the delimiter 
vector<string> lines = dstov(rawfiledata, "\n"); 

//You can then iterate over the lines and parse them into variables and do whatever you need with them. 
for(size_t itr = 0; itr < lines.size(); ++itr) 
    vector<string> line_variables = dstov(lines[itr], ",");