程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 規范CSV格式的引見和剖析以及解析算法實例詳解

規范CSV格式的引見和剖析以及解析算法實例詳解

編輯:關於C++

規范CSV格式的引見和剖析以及解析算法實例詳解。本站提示廣大學習愛好者:(規范CSV格式的引見和剖析以及解析算法實例詳解)文章只能為提供參考,不一定能成為您想要的結果。以下是規范CSV格式的引見和剖析以及解析算法實例詳解正文


     CSV是一種陳舊的數據傳輸格式,它的全稱是Comma-Separated Values(逗號分隔值)。出生在那個規范缺失的蠻荒年代,CSV的規范不斷(到2005年)是NULL——人間存在著N種CSV格式,它們自成體系,互相不兼容。比方我們從名字可以以為CSV至多是一種運用逗號分隔的格式,但是實踐上,有的CSV格式卻是運用分號(;)去做分隔。假設,不存在一種規范,那麼這東西最終會由於碎片化而開展遲緩,甚至衰敗。本文討論的CSV格式是基於2005年發布的RFC4180標准。我想,在這個標准發布之後,大家應該會愈加盲目的服從這套標准去開發——雖然這套規范照舊存在著一些致命的缺陷

   我們可以從IETF上取得包括了CSV格式定義的文檔。當然,假如你覺得看英文文檔費事,你可以直接看我的下文。

1.在不包括換行符(CRLF即 \r\n)的單條信息時,數據要堅持在一行,並且運用\r\n完畢。

aaa,bbb,ccc,dddCRLF   合法

aaa,b   內容中無換行符,而單條信息被換行,不合法

bb.ccc,dddCRLF

2.最後一條信息可以沒有換行符(當然有換行符也是合法的)

aaa,bbb,ccc,dddCRLF

eee,fff,ggg,hhh 合法

aaa,bbb,ccc,dddCRLF
eee,fff,ggg,hhhCRLF     合法

3.第一條信息能夠是一個頭信息。這個頭信息和之後信息格式是相反的,並且和之後的信息有相反的模塊數(上例中,aaa和bbb和ccc和ddd各被視為一個模塊)。(團體以為這是RFC設計這個CSV格式的一個缺陷,由於這個規則將無法讓我們從規則的角度去確認第一條信息究竟是頭信息還是普通訊息。當然RFC這麼設計一定有它的緣由。)

index,character     合法,從字面意思上我們可以以為這個是頭,當然我們也可以以為它不是頭

1,aCRLF
2,bCRLF

indexCRLF  合法,模塊數不一致
1,aCRLF

4.每條信息都要運用半角逗號(,)分隔出若干模塊。每條信息的模塊數要相等。每條信息的最後一個模塊之後不可以運用半角逗號。空格符被視為一個模塊的內容而不可被疏忽。(這條規則包括的信息量絕對較多)

aaa,bbbCRLF 合法
ccc,ddd,CRLF 合法,一條信息的最後一個模塊不可以運用半角逗號
eee;ffffCRLF    合法,要運用半角逗號分隔,而不是分號
ggg,  h h h  CRLF     合法,留意hhh模塊的若干個空格,它屬於模塊內容而不可以被疏忽
iii,jjj,kkkkCRLF     合法,模塊數和下面不一致

5.每個模塊首尾可以運用雙引號擴住(當然也可以不運用)。假如不運用雙引號擴住的模塊,模塊中不可以呈現雙引號。(弦外之音:假如模塊中呈現雙引號,則這個模塊要用雙引號將首尾擴住)

“aaa”,bbbCRLF   合法
a"aa,bbbCRLF    不合法,由於a"aa中包括了雙引號,而這個模塊沒有被雙引號擴住

6.假如模塊中包括雙引號、半角逗號或換行符,則模塊首尾要用雙引號擴住。

"a\r\na"a,bbbCRLF  合法,第一個模塊包括了換行符,要用雙引號包括
"a,aa",bbbCRLF  合法

7.當雙引號呈現在模塊中,要將模塊的首尾用雙引號擴住,並且將模塊中的一個雙引號變成一對雙引號。

“a""aa”,bbbCRLF     合法,原始數據為a"aa,bbb

   有了以上規則,我們可以編寫出相應的提取算法。以下是我在任務中編寫的一套從CSV文件中提取信息的中心代碼

BOOL CCSV2Json::Parse() 
{ 
  BOOL bSuc = FALSE; 
  do { 
    if ( INVALID_HANDLE_VALUE == m_hFile ) { 
      break; 
    } 
    OVERLAPPED ov; 
    memset(&ov, 0, sizeof(OVERLAPPED)); 
    BYTE lpBuffer[BUFFERSIZE] = {0}; 
    DWORD dwHaveRead = 0; 
    std::string strSingle; 
    BOOL bFirstDoubleQuotes = FALSE;  // 第一個字符能否為" 
    BOOL bBeforeIsDoubleQuotes = FALSE;  
    BOOL bBeforeIsX0D = FALSE; 
    ListString Liststr; 
    BOOL bPairDoubleQuotes = FALSE; 
    while ( ReadFile(m_hFile, lpBuffer, sizeof(lpBuffer), &dwHaveRead, &ov ) ) { 
      ov.Offset += dwHaveRead; 
      for ( DWORD dwIndex = 0; dwIndex < dwHaveRead; dwIndex++ ) { 
        BYTE& by = *(lpBuffer + dwIndex); 
 
        if ( bFirstDoubleQuotes ) { 
          // 有前置" 
          if ( IsDoubleQuotes(by) ) { 
            bBeforeIsX0D = FALSE; 
            if ( bBeforeIsDoubleQuotes ) { 
              strSingle.append(1, (char)(by)); 
              bBeforeIsDoubleQuotes = FALSE; 
            } 
            else { 
              bBeforeIsDoubleQuotes = TRUE; 
            } 
          } 
          else { 
            if ( bBeforeIsDoubleQuotes ) { 
              bFirstDoubleQuotes = FALSE; 
            } 
            bBeforeIsDoubleQuotes = FALSE; 
            if ( IsCRLF( by ) ){ 
              if ( bFirstDoubleQuotes ) { 
                strSingle.append(1, (char)(by)); 
              } 
              else if (FALSE == bBeforeIsX0D) { 
                Liststr.push_back(strSingle); 
                m_Listliststr.push_back(Liststr); 
                Liststr.clear(); 
                strSingle.clear(); 
                bFirstDoubleQuotes = FALSE; 
              } 
              bBeforeIsX0D = IsX0D(by); 
            } 
            else if ( IsSep(by) ) { 
              bBeforeIsX0D = FALSE; 
              if ( bFirstDoubleQuotes ) { 
                strSingle.append(1, (char)(by)); 
              } 
              else { 
                bBeforeIsX0D = FALSE; 
                Liststr.push_back(strSingle); 
                strSingle.clear(); 
              } 
            } 
            else { 
              bBeforeIsX0D = FALSE; 
              strSingle.append(1, (char)(by)); 
            } 
          } 
        } 
        else{ 
          // 假如無前置" 
          if ( IsDoubleQuotes(by) ) { 
            bBeforeIsX0D = FALSE; 
            if ( strSingle.empty() ) { 
              // 空串,第一個是" 
              bFirstDoubleQuotes = TRUE; 
              bBeforeIsDoubleQuotes = FALSE; 
            } 
            else { 
              strSingle.append(1,(char)(by)); 
              continue; 
            } 
          } 
          else { 
            bBeforeIsDoubleQuotes = FALSE; 
            if ( IsCRLF( by ) ){ 
              if (FALSE == bBeforeIsX0D) { 
                Liststr.push_back(strSingle); 
                m_Listliststr.push_back(Liststr); 
                Liststr.clear(); 
                strSingle.clear(); 
                bFirstDoubleQuotes = FALSE; 
                bBeforeIsDoubleQuotes = FALSE; 
              } 
              else { 
                // 延續\r\n不思索設置為新的行 
              } 
              bBeforeIsX0D = IsX0D(by); 
            } 
            else if ( IsSep(by) ) { 
              bBeforeIsX0D = FALSE; 
              Liststr.push_back(strSingle); 
              strSingle.clear(); 
            } 
            else { 
              bBeforeIsX0D = FALSE; 
              strSingle.append(1, (char)(by)); 
            } 
          } 
        } 
 
      } 
      memset(lpBuffer, 0, sizeof(lpBuffer));    
    } 
     
    if ( false == strSingle.empty() ) { 
//       while ( IsCRLF(strSingle.at(strSingle.length() - 1) ) && strSingle.length() > 0) { 
//         strSingle = strSingle.substr(0, strSingle.length() - 1 ); 
//       } 
      Liststr.push_back(strSingle); 
      m_Listliststr.push_back(Liststr); 
      Liststr.clear(); 
      strSingle.clear(); 
    } 
 
    bSuc = TRUE; 
  } while (0); 
   
  if ( NULL != m_hFile ) { 
    CloseHandle(m_hFile); 
    m_hFile = NULL; 
  } 
   
  return bSuc; 
} 

   這段代碼將CSV文件提取出來一個std::list<std::list<std::string>>構造。如下面名字所示,我這個功用是要將CSV文件轉換為json格式,相應的我也編寫了從json格式轉換為CSV格式文件的代碼。這些代碼都在工程中。

感激閱讀,希望能協助到大家,謝謝大家對本站的支持!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved