我正在寻找关于如何处理正在创建的csv文件的建议,然后由我们的客户上传,并且可能在值中有逗号,如公司名称。

我们正在考虑的一些想法是:带引号的标识符(value "," values ","等等)或使用|代替逗号。最大的问题是我们必须让它变得简单,否则客户就不会这么做。


当前回答

我通常在CSV文件解析例程中这样做。假设“line”变量是CSV文件中的一行,所有列的值都用双引号括起来。执行以下两行代码后,您将在“values”集合中获得CSV列。

// The below two lines will split the columns as well as trim the DBOULE QUOTES around values but NOT within them
    string trimmedLine = line.Trim(new char[] { '\"' });
    List<string> values = trimmedLine.Split(new string[] { "\",\"" }, StringSplitOptions.None).ToList();

其他回答

正如其他人所说,您需要转义包含引号的值。这是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' };
}

我知道已经13年了,但我们遇到了类似的情况,客户端向我们输入了一个CSV,值带有逗号,有2个用例:

如果客户端使用windows Excel客户端来编写CSV(通常在windows环境中是这种情况),则会自动将逗号添加到值中。

CSV的实际文本值:

3786962,1st Meridian Care Services,John,"Person A,Person B, Person C, Person D",Voyager

如果客户是通过编程的方式向你发送excel,那么他应该遵循RFC4180并将值用引号括起来。例子:

科尔1,科尔2,a, b, c,科尔4

添加对Microsoft的引用。VisualBasic(是的,它说的是VisualBasic,但它在c#中也一样好用——记住,最后它都是IL)。

使用Microsoft.VisualBasic.FileIO.TextFieldParser类来解析CSV文件。

 Dim parser As TextFieldParser = New TextFieldParser("C:\mar0112.csv")
 parser.TextFieldType = FieldType.Delimited
 parser.SetDelimiters(",")      

   While Not parser.EndOfData         
      'Processing row             
      Dim fields() As String = parser.ReadFields         
      For Each field As String In fields             
         'TODO: Process field                   

      Next      
      parser.Close()
   End While 

您可以在字段周围加上双引号。我不喜欢这种方法,因为它增加了另一个特殊字符(双引号)。只需定义一个转义字符(通常是反斜杠),并在需要转义的地方使用它:

data,more data,more data\, even,yet more

您不必尝试匹配引号,而且需要解析的异常也更少。这也简化了您的代码。

实际上,CSV格式有一个规范,RFC 4180以及如何处理逗号:

包含换行符(CRLF)、双引号和逗号的字段应该用双引号括起来。

http://tools.ietf.org/html/rfc4180

所以,要有值foo和bar,baz,你这样做:

foo,"bar,baz"

另一个需要考虑的重要需求(同样来自规范):

如果使用双引号括起字段,则使用双引号 在字段中出现时,必须在字段前面加上 另一个双引号。例如: “aaa级”、“b”“bb”、“ccc”