在C#中拆分字符串

时间:2010-05-11 01:37:38

标签: c#

我认为这将是微不足道的,但我不能让它发挥作用。

假设CSV文件中有一行: "Barack Obama", 48, "President", "1600 Penn Ave, Washington DC"

string[] tokens = line.split(',')

我希望如此:

 "Barack Obama"
 48
 "President"
 "1600 Penn Ave, Washington DC"

但最后一个标记是     'Washington DC'没有     "1600 Penn Ave, Washington DC"

是否有一种简单的方法可以让split函数忽略引号内的逗号?

我无法控制CSV文件但它没有发送给我。客户A将使用该应用程序读取外部个人提供的文件。

9 个答案:

答案 0 :(得分:12)

您可能必须编写自己的分割功能。

  • 遍历字符串
  • 中的每个字符
  • 当您点击"字符时,切换布尔值
  • 当你点击逗号时,如果bool为真,则忽略它,否则,你有你的令牌

以下是一个例子:

public static class StringExtensions
{
    public static string[] SplitQuoted(this string input, char separator, char quotechar)
    {
        List<string> tokens = new List<string>();

        StringBuilder sb = new StringBuilder();
        bool escaped = false;
        foreach (char c in input)
        {
            if (c.Equals(separator) && !escaped)
            {
                // we have a token
                tokens.Add(sb.ToString().Trim());
                sb.Clear();
            }
            else if (c.Equals(separator) && escaped)
            {
                // ignore but add to string
                sb.Append(c);
            }
            else if (c.Equals(quotechar))
            {
                escaped = !escaped;
                sb.Append(c);
            }
            else
            {
                sb.Append(c);
            }
        }
        tokens.Add(sb.ToString().Trim());

        return tokens.ToArray();
    }
}

然后打电话:

string[] tokens = line.SplitQuoted(',','\"');

基准

我的代码和Dan Tao代码的基准测试结果如下。如果有人想要,我很乐意对其他任何解决方案进行基准测试吗?

<强>代码:

string input = "\"Barak Obama\", 48, \"President\", \"1600 Penn Ave, Washington DC\""; // Console.ReadLine()
string[] tokens = null;

// run tests
DateTime start = DateTime.Now;
for (int i = 0; i < 1000000; i++)
    tokens = input.SplitWithQualifier(',', '\"', false);
Console.WriteLine("1,000,000 x SplitWithQualifier = {0}ms", DateTime.Now.Subtract(start).TotalMilliseconds);

start = DateTime.Now;
for (int i = 0; i<1000000;i++)
    tokens = input.SplitQuoted(',', '\"');
Console.WriteLine("1,000,000 x SplitQuoted =        {0}ms", DateTime.Now.Subtract(start).TotalMilliseconds);

<强>输出:

1,000,000 x SplitWithQualifier = 8156.25ms
1,000,000 x SplitQuoted =        2406.25ms

答案 1 :(得分:11)

我有一个SplitWithQualifier扩展方法,我在这里和那里使用,使用Regex

我对此代码的健壮性没有任何说法,但它对我来说已经有一段时间了。

// mangled code horribly to fit without scrolling
public static class CsvSplitter
{
    public static string[] SplitWithQualifier(this string text,
                                              char delimiter,
                                              char qualifier,
                                              bool stripQualifierFromResult)
    {
        string pattern = string.Format(
            @"{0}(?=(?:[^{1}]*{1}[^{1}]*{1})*(?![^{1}]*{1}))",
            Regex.Escape(delimiter.ToString()),
            Regex.Escape(qualifier.ToString())
        );

        string[] split = Regex.Split(text, pattern);

        if (stripQualifierFromResult)
            return split.Select(s => s.Trim().Trim(qualifier)).ToArray();
        else
            return split;
    }
}

用法:

string csv = "\"Barak Obama\", 48, \"President\", \"1600 Penn Ave, Washington DC\"";
string[] values = csv.SplitWithQualifier(',', '\"', true);

foreach (string value in values)
    Console.WriteLine(value);

输出:

Barak Obama
48
President
1600 Penn Ave, Washington DC

答案 2 :(得分:5)

我从大局看到你实际上是在尝试解析CSV输入。因此,我建议您使用CSV解析器来执行此类操作,而不是建议如何正确地拆分字符串。

快速CSV阅读器

我建议使用的是可从此CodeProject页面获取的库(可用源代码):http://www.codeproject.com/KB/database/CsvReader.aspx

我亲自使用它并喜欢它。它是一个.NET本机代码,比使用OLEDB快得多(它也可以为你做CSV解析,但相信我,它很慢)。

答案 3 :(得分:1)

您应该使用Microsoft.VisualBasic.FileIO.TextFieldParser。它会正确处理所有CSV内容,请参阅:A similar question with example using the TextFieldParser

PS:不要害怕在C#项目中使用Microsoft.VisualBasic dll,它都是.NET: - )

答案 4 :(得分:0)

这将是预期的行为,因为引号只是C#中的另一个字符串字符。看起来你所追求的是引用的标记或数字标记。

我认为您可能需要使用Regex来分割字符串,除非其他人知道更好的方法。

或者你可以在一个字符串中循环遍历字符串,一次构建字符串并以这种方式构建标记。这是旧学校,但在您的案例中可能是最可靠的方式。

答案 5 :(得分:0)

您无法使用简单的逗号分割来解析CSV行,因为某些单元格内容将包含逗号,这些逗号不是为了描述数据,而是实际上是单元格内容本身的一部分。

以下链接指向基于正则表达式的简单C#方法,可将您的CSV转换为便捷的DataTable

http://www.hotblue.com/article0000.aspx?a=0006

使用DataTables非常简单 - 如果您需要代码示例,请告诉我。

答案 6 :(得分:0)

我建议使用正则表达式。它将允许您以更加通用的方式提取更复杂的子串(正如您所希望的那样)。

http://www.c-sharpcorner.com/uploadfile/prasad_1/regexppsd12062005021717am/regexppsd.aspx

http://oreilly.com/windows/archive/csharp-regular-expressions.html

答案 7 :(得分:-1)

您无法更改CSV的生成方式吗?使用OpenOffice,您可以设置char分隔符(use;)以及字符串的分隔方式(使用“或”)。

就像这样:'总统';'1600 Penn Ave,华盛顿特区'

答案 8 :(得分:-2)

string temp = line.Replace(“\”“,”“);

string [] tokens = temp.Split(',')