分享自己昨天写的CSV工具类,
主要实现解析CSV格式,
直接上代码
#region private /// <summary> /// 从sr当前位置解析一个栏位 /// </summary> private void JXLW(StringReader sr) { //判断首个字符是否为" ) { char c = (char)sr.Read(); this._jxcharindex++; this._lwcharstartindex = this._jxcharindex; //判断此位置字符是否为特殊字符 if (this._teshuchar.Contains(c)) { if (c != '"') { if (c == ',') { //表示栏位为空 this._lwcharendindex = this._jxcharindex; return; } else { //栏位第一个不为"Name就是有异常了 throw new Exception( string.Format("解析异常,栏位首字符为不是\"的特殊字符,异常出现在字符:{0},索引:{1}", c.ToString(), this._jxcharindex)); } } this._lwhasyhcount++; this._lwyhstart = true; } else { this._lwyhstart = false; } //根据栏位是否"开头查找结尾啊 if (this._lwyhstart) { JXYHStartLW(sr); } else { JXUnYHStartLW(sr); } } else { //这尼玛栏位中没有字符啊 } } /// <summary> /// 解析引号开始的栏位 /// </summary> /// <param name="sr"></param> private void JXYHStartLW(StringReader sr) { //找, ) { char c = (char)sr.Read(); this._jxcharindex++; if (this._teshuchar.Contains(c)) { if (c == ',') { == ) { //则正常结束 this._lwcharendindex = this._jxcharindex; return; } else { //继续找下一个, JXYHStartLW(sr); return; } } else if (c == '"') { this._lwhasyhcount++; } else if (c == '\r') { == ) { //已到栏位结尾 #region 栏位后一个是否为\n , ).FirstOrDefault(); if (nextc == '\n') { sr.Peek(); sr.Read(); this._jxcharindex++; } #endregion //则正常结束 ; this._lineend = true; return; } else { //继续找下一个, JXYHStartLW(sr); return; } } else if (c == '\n') { == ) { //已到栏位结尾 //则正常结束 this._lwcharendindex = this._jxcharindex; this._lineend = true; return; } else { //继续找下一个, JXYHStartLW(sr); return; } } else { //抛出异常 throw new Exception( string.Format("解析异常,包含特殊字符的栏位,没有使用双引号括住!,异常字符:{0}索引:{1}", c.ToString(), this._jxcharindex)); } } else { continue; } } } /// <summary> /// 解析非引号开始的栏位 /// </summary> /// <param name="sr"></param> private void JXUnYHStartLW(StringReader sr) { //找, ) { char c = (char)sr.Read(); this._jxcharindex++; if (this._teshuchar.Contains(c)) { if (c == ',') { == ) { //则正常结束 this._lwcharendindex = this._jxcharindex; return; } else { throw new Exception("解析异常,包含\"的栏位,双引号不成对!"); } } else if (c == '"') { throw new Exception("解析异常,栏位未使用\"包裹,但栏位中解析到\"字符!"); } else if (c == '\r') { #region 栏位后一个是否为\n , ).FirstOrDefault(); if (nextc == '\n') { sr.Peek(); sr.Read(); this._jxcharindex++; } #endregion //则正常结束 ; this._lineend = true; return; } else if (c == '\n') { //则正常结束 this._lwcharendindex = this._jxcharindex; this._lineend = true; return; } else { //抛出异常 throw new Exception( string.Format("解析异常,包含特殊字符的栏位,没有使用双引号括住!,异常字符:{0}索引:{1}", c.ToString(), this._jxcharindex)); } } else { continue; } } } #endregion
/// <summary> /// 解析CSV文本 /// 会补齐与解析到的最长列,以空在最后补齐 /// </summary> /// <returns></returns> public IEnumerable<IEnumerable<string>> Parse() { if (string.IsNullOrEmpty(this._csvTxt)) { throw new Exception("传入的csv字符串不能为空!"); } List<List<string>> lss = new List<List<string>>(); using (StringReader sr = new StringReader(this._csvTxt)) { List<string> ls = new List<string>(); ; < this._csvTxt.Length) { if (this._lineend) { #region 行结束 lss.Add(ls); ls = new List<string>(); this._rownum++; this._lineend = false; ; #endregion } this._lwnum++; this._lwjxcomplete = false; ; ; //开始解析 JXLW(sr); this._lwjxcomplete = true; //结束索引等于0时 == this._csvTxt.Length) { //csv字符串已到结尾 ? : this._lwcharendindex; } ls.Add(this._csvTxt.Substring(this._lwcharstartindex, this._lwcharendindex - this._lwcharstartindex)); } if (ls.Any()) { lss.Add(ls); } } #region 整理,与最长的补齐,在最后补空 var maxcount = lss.Max(d => d.Count); List<List<string>> lss1 = new List<List<string>>(); ; i < lss.Count; i++) { var item = lss[i]; if (item.Count != maxcount) { //补齐 ; j < maxcount - item.Count; j++) { item.Add(""); } } lss1.Add(item); } #endregion return lss1; }
直接调用Parse方法即可将csv文本解析为IEnumerable<IEnumerable<string>>类型。
剩下的结合C#神器-Linq就ok了。
完整代码请访问:https://coding.net/u/huawu/p/HXXCommonLibrary/git/blob/master/HXXTools/Tools/CSVTools.cs
代码昨天写的,只测试了简单的解析,不保证能用于生产环境,
测试项目:https://coding.net/u/huawu/p/HXXCommonLibrary/git/tree/master/TestProject/CSVTestProject
如有问题,请联系我,邮箱:h_xuxu@sina.com
Q:245112656