【问题标题】:How can I Split(',') a string while ignore commas in between quotes?如何在忽略引号之间的逗号时拆分(',')字符串?
【发布时间】:2014-02-16 01:17:28
【问题描述】:

我在一个字符串上使用.Split(',') 方法,我知道该字符串具有由逗号分隔的值,我希望将这些值分隔并放入string[] 对象中。这对像这样的字符串很有用:

78,969.82,GW440,.

但是当第二个值超过 1000 时,这些值开始看起来不同,就像在这个例子中发现的那样:

79,"1,013.42",GW450,....

这些值来自电子表格控件,我在其中使用 ExportToCsv(...) 方法中内置的控件,这解释了为什么实际数值的格式化版本。

问题

有没有办法让.Split(',') 方法忽略引号内的逗号?我实际上不希望将值 "1,013.42" 拆分为 "1013.42"

有什么想法吗?谢谢!

更新

我真的很想在不包含第 3 方工具的情况下执行此操作,因为我的用例确实不涉及除此之外的许多其他案例,即使它是我工作解决方案的一部分,但包含这样的工具并没有目前真的对任何人都有益。我希望有一些东西可以快速解决我错过的这个特殊用例,但现在是周末,我会看看我是否不能在周一用我最终来的解决方案再更新这个问题跟上。谢谢大家到目前为止的帮助,我将在周一进一步评估每个答案。

【问题讨论】:

标签: c# string split


【解决方案1】:

这是我们在此处的几个项目中使用的一个相当简单的 CSV 阅读器实现。易于使用并处理您所说的那些情况。

首先是 CSV 类

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' };

}

然后是一个非常好的 Reader 实现 - 如果您需要它。您应该能够只使用上面的 CSV 类来做您需要的事情。

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(@"^[^""]*(?:""[^""]*""[^""]*)*""[^""]*$");

}

那你就可以这样使用了。

var reader = new CsvReader(new FileStream(file, FileMode.Open));

注意:这会打开一个现有的 CSV 文件,但可以很容易地修改为您需要的 string[]

【讨论】:

    【解决方案2】:

    您可能应该阅读这篇文章:Regular Expression for Comma Based Splitting Ignoring Commas inside Quotes 虽然是针对Java的,但是正则表达式是一样的。

    【讨论】:

    • 用 RegEx 处理 CSV 就像用工业起重机在你的后院建造一个工具棚。
    【解决方案3】:

    由于您正在阅读 CSV 文件,因此最好的做法是使用现有的 CSV 阅读器。 CSV 不仅仅是引号之间的逗号。找到您需要处理的所有案例将比它的价值更多。

    Here's a CSV reader question on SO.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-12-25
      • 1970-01-01
      • 2020-07-01
      • 2010-12-17
      相关资源
      最近更新 更多