将棘手的字符串转义为CSV格式

本文关键字:CSV 格式 转义 字符串 | 更新日期: 2023-09-27 17:59:16

我必须从Web服务输出创建一个CSV文件,该CSV文件使用带逗号分隔符的引号字符串我无法更改格式。。。

所以如果我有一个string,它就变成了"string"。。。如果该值已经有引号,则用双引号替换。例如,str"ing变成"str""ing"。。。

然而,最近我的进口一直失败,因为以下

  • 原始输入字符串为:"","word1,word2,..."
  • 每个单引号都被双引号替换,结果为:"""",""word1,word2,...""
  • 然后在写入CVS文件之前以引号作为前缀和后缀:""""",""word1,word2,..."""

正如你所看到的,最终结果是:

""""",""word1,word2,..."""

这打破了我的导入(将其视为另一个领域)。。。我认为问题在于原始输入字符串中出现了","

对于这种情况,是否有CVS转义序列?

更新

上述中断的原因是BCP映射文件(BCP实用程序用于将CSV文件加载到SQL数据库中)的终止符定义为","。因此,它看到的不是1个字段,而是2…但我无法更改映射文件。。。

将棘手的字符串转义为CSV格式

我使用这个代码,它一直有效:

/// <summary>
/// Turn a string into a CSV cell output
/// </summary>
/// <param name="str">String to output</param>
/// <returns>The CSV cell formatted string</returns>
public static string StringToCSVCell(string str)
{
    bool mustQuote = (str.Contains(",") || str.Contains("'"") || str.Contains("'r") || str.Contains("'n"));
    if (mustQuote)
    {
        StringBuilder sb = new StringBuilder();
        sb.Append("'"");
        foreach (char nextChar in str)
        {
            sb.Append(nextChar);
            if (nextChar == '"')
                sb.Append("'"");
        }
        sb.Append("'"");
        return sb.ToString();
    }
    return str;
}

基于Ed Bayiates的回答:

/// <summary>
/// Turn a string into a CSV cell output
/// </summary>
/// <param name="value">String to output</param>
/// <returns>The CSV cell formatted string</returns>
private string ConvertToCsvCell(string value)
{
    var mustQuote = value.Any(x => x == ',' || x == ''"' || x == ''r' || x == ''n');
    if (!mustQuote)
    {
        return value;
    }
    value = value.Replace("'"", "'"'"");
    return string.Format("'"{0}'"", value);
}

我的想法:

String[] lines = new String[] { "'"'",'"word'",word,word2,1,34,5,2,'"details'"" };
for (int j = 0; j < lines.Length; j++)
{
    String[] fields=lines[j].Split(',');
    for (int i =0; i<fields.Length; i++)
    {
        if (fields[i].StartsWith("'"") && fields[i].EndsWith("'""))
        {
            char[] tmp = new char[fields[i].Length-2];
            fields[i].CopyTo(1,tmp,0,fields[i].Length-2);
            fields[i] =tmp.ToString();
            fields[i] = "'""+fields[i].Replace("'"","'"'"")+"'"";
        }
        else
            fields[i] = fields[i].Replace("'"","'"'"");
    }
    lines[j]=String.Join(",",fields);

}

基于"Ed Bayiates"的贡献,这里有一个有用的类来构建csv文档:

/// <summary>
/// helpful class to build csv document
/// </summary>
public class CsvBuilder
{
    /// <summary>
    /// create the csv builder
    /// </summary>
    public CsvBuilder(char csvSeparator)
    {
        m_csvSeparator = csvSeparator;
    }
    /// <summary>
    /// append a cell
    /// </summary>
    public void appendCell(string strCellValue)
    {
        if (m_nCurrentColumnIndex > 0) m_strBuilder.Append(m_csvSeparator);
        bool mustQuote = (strCellValue.Contains(m_csvSeparator)
                        || strCellValue.Contains(''"') 
                        || strCellValue.Contains(''r') 
                        || strCellValue.Contains(''n'));
        if (mustQuote)
        {
            m_strBuilder.Append(''"');
            foreach (char nextChar in strCellValue)
            {
                m_strBuilder.Append(nextChar);
                if (nextChar == '"') m_strBuilder.Append(''"');
            }
            m_strBuilder.Append(''"');
        }
        else
        {
            m_strBuilder.Append(strCellValue);
        }
        m_nCurrentColumnIndex++;
    }
    /// <summary>
    /// end of line, new line
    /// </summary>
    public void appendNewLine()
    {
        m_strBuilder.Append(Environment.NewLine);
        m_nCurrentColumnIndex = 0;
    }
    /// <summary>
    /// Create the CSV file
    /// </summary>
    /// <param name="path"></param>
    public void save(string path )
    {
        File.WriteAllText(path, ToString());
    }
    public override string ToString()
    {
        return m_strBuilder.ToString();
    }
    private StringBuilder m_strBuilder = new StringBuilder();
    private char m_csvSeparator;
    private int m_nCurrentColumnIndex = 0;
}

如何使用:

void exportAsCsv( string strFileName )
{
    CsvBuilder csvStringBuilder = new CsvBuilder(';');
    csvStringBuilder.appendCell("#Header col 1 : Name");
    csvStringBuilder.appendCell("col 2 : Value");
    csvStringBuilder.appendNewLine();
    foreach (Data data in m_dataSet)
    {
        csvStringBuilder.appendCell(data.getName());
        csvStringBuilder.appendCell(data.getValue());
        csvStringBuilder.appendNewLine();
    }
    csvStringBuilder.save(strFileName);
}

解析这个的第一步是删除字符串周围额外添加的"。一旦完成了这一操作,您就应该能够处理嵌入的"以及。

经过深思熟虑,决定需要修复导入实用程序格式。字符串的转义是正确的(如用户所示),但导入实用程序使用的格式文件不正确,导致它中断导入。

感谢所有人,特别感谢@dbt(支持投票)