CSV 解析包含双引号和逗号的字符串
CSV Parsing Strings containing double quotes and commas
如果此问题重复,我们深表歉意。
我正在尝试创建一个 CSV 文件,例如,包含“标题”、“名称”和“评论”列。 CSV 的每一行都有从数据库中读取到相关变量的每一列的值,然后将这些变量(用逗号分隔)添加到变量 'newline' 中,然后将其附加到 csv 中,如下所示:
string title = reader[0]
string name = reader[1]
string comments = reader[2]
var csv = new StringBuilder();
var headerLine = "Title,Name,Comments"
csv.AppendLine(headerLine);
var newline = title + "," + name + "," + comments;
csv.AppendLine(newline);
最初我采用了上述方法,但很快 运行 遇到了问题,如果从数据库中读取的任何字段中包含逗号,该字段将在中间拆分,例如如果 comments = "Comment, goes, here" 将分布在输出 CSV 中的 3 列而不是 1.
为了尝试克服这个问题,我更改了我的代码,以便所有字段都用双引号引起来,这意味着字段中的逗号将不再拆分 CSV,如下所示:
var newline = "\"" + title + "\",\"" + name + "\",\"" + comments + "\""
现在,有了这个,我遇到了一个问题,如果从数据库中读入的任何值包含双引号,这会搞乱一切,因为数据库中的双引号显示为 \"当字段被转换成一个字符串时,我已经使用它来用双引号将每个字段的开头和结尾括起来,以防止逗号拆分包含逗号的字段。
您需要对双引号进行转义。你用什么来逃避它们取决于你打算用什么来阅读它们。转义序列可能应该是一个反斜杠后跟一个双引号,但是如果使用 Excel 它将是两个连续的双引号。这可以使用 string.Replace
.
来完成
var newline = "\"" + title.Replace("\"", "\"\"") +
"\",\"" + name.Replace("\"", "\"\"") +
"\",\"" + comments.Replace("\"", "\"\"") + "\"";
或使用string.Format
var newline = string.Format(
"\"{0}\",\"{1}\",\"{2}\"",
title.Replace("\"", "\"\""),
name.Replace("\"", "\"\""),
comments.Replace("\"", "\"\""));
规则很简单:如果项目包含 ,
(逗号)或 "
(引号),则应将其放在引号中;项目中的每个 "
应加倍:
abcde -> abcde // or "abcde", quotation is not mandatory, however
abc,de -> "abc,de"
abc"de -> "abc""de"
abc","de -> "abc"",""de"
可能的实现:
public static String EncodeCsvItem(String value) {
if (String.IsNullOrEmpty(value))
return "";
StringBuilder Sb = new StringBuilder(value.Length + 2);
bool wrap = false;
foreach (var ch in value) {
if (ch == '"') {
Sb.Append('"');
wrap = true;
}
else if (ch == ',')
wrap = true;
Sb.Append(ch);
}
if (wrap) {
Sb.Insert(0, '"');
Sb.Append('"');
}
return Sb.ToString();
}
....
var newline = String.Join(",",
EncodeCsvItem(reader[0]),
EncodeCsvItem(reader[1]),
EncodeCsvItem(reader[2])
);
csv.AppendLine(newline);
您将来自数据库的任何现有双引号加倍,因此它们被视为包含在字段(列)中,而不是表示字段的开头或结尾。
查看此答案以获取在字段中同时包含双引号和逗号的 CSV 示例:
如果此问题重复,我们深表歉意。
我正在尝试创建一个 CSV 文件,例如,包含“标题”、“名称”和“评论”列。 CSV 的每一行都有从数据库中读取到相关变量的每一列的值,然后将这些变量(用逗号分隔)添加到变量 'newline' 中,然后将其附加到 csv 中,如下所示:
string title = reader[0]
string name = reader[1]
string comments = reader[2]
var csv = new StringBuilder();
var headerLine = "Title,Name,Comments"
csv.AppendLine(headerLine);
var newline = title + "," + name + "," + comments;
csv.AppendLine(newline);
最初我采用了上述方法,但很快 运行 遇到了问题,如果从数据库中读取的任何字段中包含逗号,该字段将在中间拆分,例如如果 comments = "Comment, goes, here" 将分布在输出 CSV 中的 3 列而不是 1.
为了尝试克服这个问题,我更改了我的代码,以便所有字段都用双引号引起来,这意味着字段中的逗号将不再拆分 CSV,如下所示:
var newline = "\"" + title + "\",\"" + name + "\",\"" + comments + "\""
现在,有了这个,我遇到了一个问题,如果从数据库中读入的任何值包含双引号,这会搞乱一切,因为数据库中的双引号显示为 \"当字段被转换成一个字符串时,我已经使用它来用双引号将每个字段的开头和结尾括起来,以防止逗号拆分包含逗号的字段。
您需要对双引号进行转义。你用什么来逃避它们取决于你打算用什么来阅读它们。转义序列可能应该是一个反斜杠后跟一个双引号,但是如果使用 Excel 它将是两个连续的双引号。这可以使用 string.Replace
.
var newline = "\"" + title.Replace("\"", "\"\"") +
"\",\"" + name.Replace("\"", "\"\"") +
"\",\"" + comments.Replace("\"", "\"\"") + "\"";
或使用string.Format
var newline = string.Format(
"\"{0}\",\"{1}\",\"{2}\"",
title.Replace("\"", "\"\""),
name.Replace("\"", "\"\""),
comments.Replace("\"", "\"\""));
规则很简单:如果项目包含 ,
(逗号)或 "
(引号),则应将其放在引号中;项目中的每个 "
应加倍:
abcde -> abcde // or "abcde", quotation is not mandatory, however
abc,de -> "abc,de"
abc"de -> "abc""de"
abc","de -> "abc"",""de"
可能的实现:
public static String EncodeCsvItem(String value) {
if (String.IsNullOrEmpty(value))
return "";
StringBuilder Sb = new StringBuilder(value.Length + 2);
bool wrap = false;
foreach (var ch in value) {
if (ch == '"') {
Sb.Append('"');
wrap = true;
}
else if (ch == ',')
wrap = true;
Sb.Append(ch);
}
if (wrap) {
Sb.Insert(0, '"');
Sb.Append('"');
}
return Sb.ToString();
}
....
var newline = String.Join(",",
EncodeCsvItem(reader[0]),
EncodeCsvItem(reader[1]),
EncodeCsvItem(reader[2])
);
csv.AppendLine(newline);
您将来自数据库的任何现有双引号加倍,因此它们被视为包含在字段(列)中,而不是表示字段的开头或结尾。
查看此答案以获取在字段中同时包含双引号和逗号的 CSV 示例: