CSV解析器实现
CSV解析器实现 确切地说应该是TSV,即分隔符是Tab而不是Comma。除分隔符之外,CSV与TSV大同小异。 这里使用TSV主要原因是:Excel导出的CSV不是Unicode编码,这样会导致某些符号丢失,而导出TXT时,可以选择Unicode,但格式却是TSV。
TSV语法可以用以下文法来描述: p0:P -> Te p1:T -> RT|ε p2:R -> CMb p3:M -> tCM|ε p4:C -> s|ε
其中各非终结符与终结符的含义为: P:The Whole TSV File T:Like foobar R:One Row in TSV M:Context among One Row C:Context of One Cell in Row
e:End Of File t:Tab s:String b:LF or CRLF ε:EmptyString
该文法是一个正规文法,因为它可以用有限状态自动机来表示。m0,m1,m2,m3,m4分别为各个产生式对应的自动机。
m01->m012->m0123->m01234是将各产生式自动机组合的过程。 显然得到最后的m01234是一个有限状态自动机,该文法是一个正则文法,是可以用正则表达式来描述的。 出于简化考虑,这里把显然没有必要的两条ε边去掉,即到状态Start与B合并到A中,为各个状态标上序号后,得到M0. 边ε的存在会让程序实现极不美观,所以使用子集法去掉ε,得到状态转换矩阵:
根据转换矩阵很容易得到它的对应自动机M1.
下面是TSV的词法分析器与语法分析器的粗略实现: #define TOKEN_STRING 0 #define TOKEN_LINEBREAK 2 #define TOKEN_TAB 1 #define TOKEN_EOF 3 #define STATUS_012 0 #define STATUS_32 1 #define STATUS_12 2 #define STATUS_4 3 #define STATUS_X 4 static int GetToken( const wchar_t* pBuff,int* pLen ) { int nToken = TOKEN_EOF; const wchar_t* pos; if ( NULL == pBuff || 0 == pBuff[0] ) { *pLen = 0; nToken = TOKEN_EOF; } else { switch ( pBuff[0] ) { case 'n': nToken = TOKEN_LINEBREAK; *pLen = 1; break; case 'r': nToken = TOKEN_LINEBREAK; *pLen = ('n' == pBuff[1] ? 2 : 1); break; case 't': nToken = TOKEN_TAB; *pLen = 1; break; case '"': nToken = TOKEN_STRING; { pos = pBuff+1; while ( *pos ) { if ( '"' == pos[0] && '"' == pos[1] ) { pos+=2; } else if ( '"' == pos[0] ) { pos++; break; } else { pos++; } } *pLen = pos-pBuff; } break; default: nToken = TOKEN_STRING; { pos = pBuff+1; while ( true ) { wchar_t ch = *pos; if ( 0 == ch || 't' == ch || 'n' == ch || 'r' == ch ) break; else pos++; } *pLen = pos-pBuff; } break; } } return nToken; } // Return value: true: accept,false: grammar error static bool AutoMachine( const wchar_t* pBuff,vector<vector<wstring>>& table ) { static int statusMatrix[3][4] = { { STATUS_12,STATUS_32,STATUS_012,STATUS_4 },{ STATUS_12,STATUS_X },{ STATUS_32,}; table.clear(); vector<wstring> line; // Used to store the strings in one row int nStatus = STATUS_012; const wchar_t* pos = pBuff; bool bEpsilon = false; int nToken = TOKEN_LINEBREAK; int nLastToken = nToken; int nLen = 0; int tmpStatus; while ( STATUS_4 != nStatus && STATUS_X != nStatus ) { nToken = GetToken( pos,&nLen ); tmpStatus = nStatus; nStatus = statusMatrix[nStatus][nToken]; switch ( nToken ) { case TOKEN_STRING: if ( TOKEN_STRING == nLastToken ) // Merge the string at the last element *line.rbegin() += wstring(pos,pos+nLen); else line.push_back( wstring(pos,pos+nLen) ); break; case TOKEN_TAB: if ( TOKEN_TAB == nLastToken || TOKEN_LINEBREAK == nLastToken ) line.push_back( L"" ); break; case TOKEN_LINEBREAK: if ( TOKEN_TAB == nLastToken || TOKEN_LINEBREAK == nLastToken ) line.push_back( L"" ); table.push_back( line ); line.clear(); break; } pos += nLen; nLastToken = nToken; } return nStatus == STATUS_4; } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |