在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将使用该应用程序读取外部个人提供的文件。

您可能必须编写自己的拆分function。

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

这是一个例子:

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

我有一个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 

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

快速CSV阅读器

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

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

你应该使用Microsoft.VisualBasic.FileIO.TextFieldParser 。 它将为您正确处理所有CSV内容,请参阅: 使用TextFieldParser的示例中的类似问题

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

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

这是一个简单的基于正则表达式的C#方法的链接,它将您的CSV转换为一个手动的DataTable

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

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

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

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

或者你可以在一个字符串中循环遍历字符串,一次构建字符串并以这种方式构建标记。 这是老派,但在你的情况下可能是最可靠的方式。

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

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

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

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

它将是这样的:’总统’;’1600 Penn Ave,华盛顿特区’

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

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