1+ using System ;
2+ using System . Collections . Generic ;
3+ using System . Text ;
4+
5+ namespace TinyCSV
6+ {
7+ public static class CSVDataHelper
8+ {
9+ public const char DoubleQuoteCharacter = '\" ' ;
10+ public const char CommaCharacter = ',' ;
11+
12+ public static string [ ] GetCSVRows ( this string csvContent )
13+ {
14+ //Replace new line to \r
15+ string csvText = csvContent . Replace ( Environment . NewLine , "\r " ) ;
16+ //Trim \r
17+ csvText = csvText . Trim ( '\r ' ) ;
18+ //Replace \r\r to \r
19+ csvText = csvText . Replace ( "\r \r " , "\r " ) ;
20+ //Split by \r
21+ return csvText . Split ( '\r ' ) ;
22+ }
23+
24+ /// <summary>
25+ /// Decode csv row content.
26+ /// </summary>
27+ public static List < string > GetCSVDecodeRow ( this string rowContent , int capacity = 0 )
28+ {
29+ List < string > cellValues = new List < string > ( capacity ) ;
30+ StringBuilder cellValueBuilder = new StringBuilder ( ) ;
31+ bool isCellBeginning = true ;
32+ bool cellNeedEscape = false ;
33+ bool canAddEscapeDoubleQuote = false ;
34+ foreach ( var ch in rowContent )
35+ {
36+ switch ( ch )
37+ {
38+ case DoubleQuoteCharacter :
39+ if ( isCellBeginning ) //The cell start with \", then all \" need escape(change to \"\") and add \" to cell's beginning and ending.
40+ cellNeedEscape = true ;
41+ else if ( cellNeedEscape )
42+ {
43+ if ( canAddEscapeDoubleQuote )
44+ cellValueBuilder . Append ( ch ) ;
45+ canAddEscapeDoubleQuote = ! canAddEscapeDoubleQuote ;
46+ }
47+ else
48+ cellValueBuilder . Append ( ch ) ;
49+ break ;
50+ case CommaCharacter :
51+ //Do not need escape or can not add escape character \" means the cell is end.
52+ //能添加\"的时候代表已经经过了偶数个\"(canAddEscapeDoubleQuote从false变为true代表经过了奇数次变化,加上字段起始的\",所以是偶数个\")
53+ //csv字段内的\"必定是偶数个,而需要转义的情况下\"变为\"\",所以尾部必定有个落单的\"与起始的\"形成一对,所以而包含在字段内的\,前面必定有奇数个\"
54+ if ( ! cellNeedEscape || canAddEscapeDoubleQuote )
55+ {
56+ cellValues . Add ( cellValueBuilder . ToString ( ) ) ;
57+ //Clear. After .NET 4.0 can replace to cellValueBuilder.Clear();
58+ cellValueBuilder . Length = 0 ;
59+ isCellBeginning = true ;
60+ cellNeedEscape = false ;
61+ canAddEscapeDoubleQuote = false ;
62+ continue ;
63+ }
64+ cellValueBuilder . Append ( ch ) ;
65+ break ;
66+ default :
67+ cellValueBuilder . Append ( ch ) ;
68+ break ;
69+ }
70+ isCellBeginning = false ;
71+ }
72+ //The last cell does not have comma separator.
73+ cellValues . Add ( cellValueBuilder . ToString ( ) ) ;
74+ //Clear. After .NET 4.0 can replace to cellValueBuilder.Clear();
75+ cellValueBuilder . Length = 0 ;
76+ return cellValues ;
77+ }
78+
79+ /// <summary>
80+ /// Encode cells to csv form.
81+ /// </summary>
82+ public static string GetCSVEncodeRow ( this List < string > cellList )
83+ {
84+ if ( cellList == null || cellList . Count == 0 ) return string . Empty ;
85+ StringBuilder stringBuilder = new StringBuilder ( ) ;
86+ Queue < int > doubleQuoteInsertIndices = new Queue < int > ( ) ;
87+ for ( int i = 0 , count = cellList . Count ; i < count ; i ++ )
88+ {
89+ var cell = cellList [ i ] ;
90+ bool cellNeedParaphrase = false ;
91+ int cellStartCharIndex = stringBuilder . Length ;
92+ for ( int j = 0 , len = cell . Length ; j < len ; j ++ )
93+ {
94+ char ch = cell [ j ] ;
95+ switch ( ch )
96+ {
97+ case DoubleQuoteCharacter :
98+ if ( j == 0 )
99+ {
100+ cellNeedParaphrase = true ;
101+ stringBuilder . Append ( DoubleQuoteCharacter ) ; //Add \" to beginning.
102+ }
103+ stringBuilder . Append ( ch ) ;
104+ if ( cellNeedParaphrase )
105+ stringBuilder . Append ( ch ) ; // \" change to \"\"
106+ else //Record escape character \" insert index.
107+ doubleQuoteInsertIndices . Enqueue ( stringBuilder . Length + doubleQuoteInsertIndices . Count ) ;
108+ break ;
109+ case CommaCharacter :
110+ if ( ! cellNeedParaphrase )
111+ {
112+ cellNeedParaphrase = true ;
113+ //The cell has comma character, so the preceding \" needs to be changed to \"\" and add \" in the cell's beginning.
114+ while ( doubleQuoteInsertIndices . Count > 0 )
115+ stringBuilder . Insert ( doubleQuoteInsertIndices . Dequeue ( ) , DoubleQuoteCharacter ) ;
116+ stringBuilder . Insert ( cellStartCharIndex , DoubleQuoteCharacter ) ;
117+ }
118+ stringBuilder . Append ( ch ) ;
119+ break ;
120+ default :
121+ stringBuilder . Append ( ch ) ;
122+ break ;
123+ }
124+ }
125+ doubleQuoteInsertIndices . Clear ( ) ;
126+ if ( cellNeedParaphrase )
127+ stringBuilder . Append ( DoubleQuoteCharacter ) ; //Add \" to the ending.
128+ if ( i != count - 1 )
129+ stringBuilder . Append ( CommaCharacter ) ; //Not the last cell, then add comma separator.
130+ }
131+ return stringBuilder . ToString ( ) ;
132+ }
133+ }
134+ }
0 commit comments