準標準CSVフォーマットの紹介と分析及び解析アルゴリズム

7580 ワード

CSVは古いデータ転送フォーマットですそのフルネームはComma-Separated Value(カンマ区切り値)です.その標準が欠けていた荒れ果てた時代に生まれ、CSVの標準はずっと(2005年まで)はNULL--世の中にはN種類のCSVフォーマットが存在し、それらは独自のシステムであり、互いに互換性がない.例えば、CSVは少なくともカンマで区切られたフォーマットであると考えられるが、実際には、あるCSVフォーマットはセミコロン(;)区切りをつける.もし、一つの基準が存在しなければ、これは最終的に破片化のために発展が遅く、没落することもあります.本明細書で論じたCSVフォーマットは、2005年に発表されたRFC 4180仕様に基づいている.この規範が発表された後、皆さんはもっと自覚的にこの規範に従って開発するべきだと思います.この基準には依然として致命的な欠陥がありますが.(転載breaksoftwareからのcsdnブログを明記してください)
CSVフォーマット定義を含むドキュメントはIETFから入手できます.もちろん、英語のドキュメントを読むのが面倒だと思ったら、私の下を直接見てもいいです.
  • 改行文字(CRLFすなわちr)を含まない単一情報の場合、データは1行に保持され、rで終了する.aaa,bbb,ccc,dddCRLF合法aaa,bコンテンツに改行文字はないが、単一情報は改行され、合法bb.cc,dddCRLF
  • .
  • 最後の情報は改行文字なし(もちろん改行文字も合法)aaa,bbb,ccc,dddCRLF eee,fff,gg,hhh合法aaa,bbb,ccc,dddCRLF eee,fff,gg,hhhCRLF合法
  • の最初の情報は、ヘッダ情報である可能性がある.このヘッダ情報はその後の情報フォーマットと同じで、また、以降の情報と同じモジュール数(前例ではaaaおよびbbbおよびcccおよびdddはそれぞれ1つのモジュールとみなされる)がある.(個人的にはRFCがこのCSVフォーマットを設計する欠陥だと思います.このルールは私たちにルールの角度から最初の情報がヘッダ情報なのか普通の情報なのかを確認させることができないからです.もちろんRFCがこのように設計するのはきっとその原因があります.)index、characterは合法的で、字面の意味から私たちはこれがヘッダだと考えることができて、もちろん私たちもそれがヘッダだと考えることができます.ヘッド1ではなく、aCRLF 2、bCRLF indexCRLFは不正であり、モジュール数が統一されていない1、aCRLF
  • 各情報は、半角カンマ(,)を使用していくつかのモジュールを区切ります.各情報のモジュール数は同じです.各情報の最後のモジュールの後に半角カンマを使用することはできません.スペース記号は、モジュールの内容として無視できません.(この規則に含まれる情報量は比較的多い)aaa,bbbCRLFは合法的にccc,ddd,CRLFは不法で、1つの情報の最後のモジュールは半角カンマeeeを使用することはできません;ffffCRLFは不法で、半角カンマで区切らなければならなくて、セミコロンgg,h h h CRLFは合法的で、hhhモードに注意しますブロックのいくつかのスペースは、iii、jjj、kkkkCRLFが不正であることを無視できないモジュールの内容に属し、モジュール数と上が
  • に統一されていない.
  • 各モジュールの先頭と末尾には二重引用符を使用して拡張できます(もちろん使用しなくてもいいです).二重引用符を使用して拡張されたモジュールを使用しない場合、モジュールに二重引用符を使用することはできません.(言外に、モジュールに二重引用符が表示された場合、このモジュールは二重引用符で先頭と末尾を拡張します)「aaa」、bbbCRLFは合法的にa「aa,bbbCRLFはa」aaに二重引用符が含まれているため、このモジュールは二重引用符で
  • に拡張されていない.
  • モジュールに二重引用符、半角カンマ、または改行文字が含まれている場合は、モジュールの先頭と末尾を二重引用符で拡張します."ara"a,bbCRLFは合法的で、最初のモジュールは改行文字を含んで、二重引用符で"a,aa"を含んで、bbCRLFは合法的です
  • 二重引用符がモジュールに表示されると、モジュールの先頭と末尾を二重引用符で拡張し、モジュールの二重引用符を二重引用符のペアにします.「a」「aa」bbCRLFは合法的で、元のデータは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
    } 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>構造を抽出します.上記の名前のように、私のこの機能はCSVファイルをjsonフォーマットに変換することであり、それに応じてjsonフォーマットからCSVフォーマットファイルに変換するコードも作成しました.これらのコードはすべて工事中です.