我认为这将是微不足道的,但我不能让它发挥作用。
假设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将使用该应用程序读取外部个人提供的文件。
答案 0 :(得分:12)
您可能必须编写自己的分割功能。
"
字符时,切换布尔值以下是一个例子:
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解析器来执行此类操作,而不是建议如何正确地拆分字符串。
我建议使用的是可从此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
答案 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(',')