我正在寻找关于如何处理正在创建的csv文件的建议,然后由我们的客户上传,并且可能在值中有逗号,如公司名称。
我们正在考虑的一些想法是:带引号的标识符(value "," values ","等等)或使用|代替逗号。最大的问题是我们必须让它变得简单,否则客户就不会这么做。
我正在寻找关于如何处理正在创建的csv文件的建议,然后由我们的客户上传,并且可能在值中有逗号,如公司名称。
我们正在考虑的一些想法是:带引号的标识符(value "," values ","等等)或使用|代替逗号。最大的问题是我们必须让它变得简单,否则客户就不会这么做。
当前回答
只需使用软电路。CsvParser在NuGet上。它将为您处理所有这些细节,并有效地处理非常大的文件。如果需要,它甚至可以通过将列映射到对象属性来导入/导出对象。此外,我的测试显示,它的平均速度比流行的CsvHelper快近4倍。
其他回答
正如其他人所说,您需要转义包含引号的值。这是c#中的一个小型CSV读取器,支持加引号的值,包括嵌入引号和回车。
顺便说一下,这是单元测试的代码。我现在发布它是因为这个问题似乎经常出现,其他人可能不想要整个库,而简单的CSV支持就可以了。
你可以这样使用它:
using System;
public class test
{
public static void Main()
{
using ( CsvReader reader = new CsvReader( "data.csv" ) )
{
foreach( string[] values in reader.RowEnumerator )
{
Console.WriteLine( "Row {0} has {1} values.", reader.RowIndex, values.Length );
}
}
Console.ReadLine();
}
}
这些是课程。注意,您可以使用Csv。Escape函数来编写有效的CSV。
using System.IO;
using System.Text.RegularExpressions;
public sealed class CsvReader : System.IDisposable
{
public CsvReader( string fileName ) : this( new FileStream( fileName, FileMode.Open, FileAccess.Read ) )
{
}
public CsvReader( Stream stream )
{
__reader = new StreamReader( stream );
}
public System.Collections.IEnumerable RowEnumerator
{
get {
if ( null == __reader )
throw new System.ApplicationException( "I can't start reading without CSV input." );
__rowno = 0;
string sLine;
string sNextLine;
while ( null != ( sLine = __reader.ReadLine() ) )
{
while ( rexRunOnLine.IsMatch( sLine ) && null != ( sNextLine = __reader.ReadLine() ) )
sLine += "\n" + sNextLine;
__rowno++;
string[] values = rexCsvSplitter.Split( sLine );
for ( int i = 0; i < values.Length; i++ )
values[i] = Csv.Unescape( values[i] );
yield return values;
}
__reader.Close();
}
}
public long RowIndex { get { return __rowno; } }
public void Dispose()
{
if ( null != __reader ) __reader.Dispose();
}
//============================================
private long __rowno = 0;
private TextReader __reader;
private static Regex rexCsvSplitter = new Regex( @",(?=(?:[^""]*""[^""]*"")*(?![^""]*""))" );
private static Regex rexRunOnLine = new Regex( @"^[^""]*(?:""[^""]*""[^""]*)*""[^""]*$" );
}
public static class Csv
{
public static string Escape( string s )
{
if ( s.Contains( QUOTE ) )
s = s.Replace( QUOTE, ESCAPED_QUOTE );
if ( s.IndexOfAny( CHARACTERS_THAT_MUST_BE_QUOTED ) > -1 )
s = QUOTE + s + QUOTE;
return s;
}
public static string Unescape( string s )
{
if ( s.StartsWith( QUOTE ) && s.EndsWith( QUOTE ) )
{
s = s.Substring( 1, s.Length - 2 );
if ( s.Contains( ESCAPED_QUOTE ) )
s = s.Replace( ESCAPED_QUOTE, QUOTE );
}
return s;
}
private const string QUOTE = "\"";
private const string ESCAPED_QUOTE = "\"\"";
private static char[] CHARACTERS_THAT_MUST_BE_QUOTED = { ',', '"', '\n' };
}
CSV格式使用逗号分隔值,包含回车、换行、逗号或双引号的值用双引号括起来。包含双引号的值会被引用,并且每个文字引号都被紧挨着的前引号转义:例如,以下3个值:
test
list, of, items
"go" he said
将被编码为:
test
"list, of, items"
"""go"" he said"
任何字段都可以加引号,但只有包含逗号、CR/NL或引号的字段必须加引号。
CSV格式没有真正的标准,但几乎所有应用程序都遵循这里记录的约定。在其他地方提到的RFC不是CSV的标准,它是一个用于在MIME中使用CSV的RFC,它包含了一些非常规的和不必要的限制,使它在MIME之外无用。
我所见过的许多CSV模块不适应的一个问题是,可以在单个字段中编码多行,这意味着您不能假设每一行都是一个单独的记录,您要么需要不允许数据中出现换行,要么准备好处理这个问题。
一个示例可能有助于说明如何在.csv文件中显示逗号。创建一个简单的文本文件,如下所示:
将此文本文件另存为后缀为“。csv”的文本文件,在Windows 10下使用Excel 2000打开。
aa、bb、cc, d, d "在电子表格演示中,下面的行应该看起来像上面的行,只是下面在d之间显示了一个逗号而不是分号。" aa,bb,cc,"d,d",即使在Excel中也适用
aa,bb,cc,"d,d",即使在Excel 2000中也是如此 aa,bb,cc,"d,d",即使在Excel 2000中也是如此 aa,bb,cc,"d, d",即使在Excel 2000中也是如此
aa,bb,cc, " d,d",这在Excel 2000中失败,因为在第一个引用之前有空格 aa,bb,cc, " d,d",这在Excel 2000中失败,因为在第一个引用之前有空格 aa,bb,cc, " d, d",这在Excel 2000中失败,因为在第一个引用之前有空格
aa,bb,cc,"d,d ",即使在Excel 2000中,即使在第2个引号前后有空格,这也是有效的。 aa,bb,cc,"d,d ",即使在Excel 2000中,即使在第2个引号前后有空格,这也是有效的。 aa,bb,cc,"d, d ",即使在Excel 2000中,即使在第2个引号前后有空格,这也是有效的。
规则:如果你想在csv文件的单元格(字段)中显示一个逗号: 用双引号开始和结束字段,但避免在第一个引号之前有空格
如果您对如何解析一般文件(以CSV为例)更有教育意义的练习感兴趣,您可以查看Julian Bucknall的这篇文章。我喜欢这篇文章,因为它把事情分解成更小的问题,这些问题不那么难以克服。首先创建一个语法,一旦您有了一个好的语法,将语法转换为代码是一个相对简单和有条理的过程。
本文使用c#,并在底部有一个下载代码的链接。
有一个可以通过nuget来处理几乎任何格式良好的CSV (.net)的库——CsvHelper
映射到类的示例:
var csv = new CsvReader( textReader );
var records = csv.GetRecords<MyClass>();
读取单个字段的示例:
var csv = new CsvReader( textReader );
while( csv.Read() )
{
var intField = csv.GetField<int>( 0 );
var stringField = csv.GetField<string>( 1 );
var boolField = csv.GetField<bool>( "HeaderName" );
}
让客户端驱动文件格式: ,是标准字段分隔符,”是用于转义包含分隔符、引号或行尾的字段的标准值。
使用(例如)#表示字段,'表示转义:
var csv = new CsvReader( textReader );
csv.Configuration.Delimiter = "#";
csv.Configuration.Quote = ''';
// read the file however meets your needs
更多的文档