如何在某些元素中处理带有nul char的CSV行?

时间:2016-02-22 12:41:38

标签: c++ windows visual-c++ encoding fgets

在读取和解析CSV文件行时,我需要处理显示为某些行字段值的nul字符。有时CSV文件采用windows-1250编码,有时使用UTF-8,有时采用UTF-16,这一点很复杂。因此,我已经开始了某种方式,然后发现了nul char问题 - 见下文。

详情:我需要将第三方的CSV文件清理为数据提取器常用的格式(即该实用程序可用作过滤器 - 将一个CSV格式存储到另一个CSV格式)

我最初的方法是以二进制模式打开CSV文件,并检查第一个字节是否形成BOM。我知道所有给定的Unicode文件都以BOM开头。如果没有BOM,我知道它是在windows-1250编码中。 转换后的CSV文件应使用windows-1250编码。因此,在检查输入文件后,我使用相关模式打开它,如下所示:

DataTrigger t = new DataTrigger();
                        t.Binding = new Binding("Weight");
                        t.Value = 0;
                        Setter s = new Setter();
                        s.Property = DataGridCell.ContentStringFormatProperty;
                        s.Value = new Binding(null) { StringFormat = "N02" };
                        t.Setters.Add(s);

                        Sty.Triggers.Add(t);
                        DGC.CellStyle = Sty;

成功打开后,输入行将被读取或通过// Open the file in binary mode first to see whether BOM is there or not. FILE * fh{ nullptr }; errno_t err = fopen_s(&fh, fnameIn.string().c_str(), "rb"); // const fs::path & fnameIn assert(err == 0); vector<char> buf(4, '\0'); fread(&buf[0], 1, 3, fh); ::fclose(fh); // Set the isUnicode flag and open the file according to that. string mode{ "r" }; // init bool isUnicode = false; // pessimistic init if (buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF) // UTF-8 BOM { mode += ", ccs=UTF-8"; isUnicode = true; } else if ((buf[0] == 0xFE && buf[1] == 0xFF) // UTF-16 BE BOM || (buf[0] == 0xFF && buf[1] == 0xFE)) // UTF-16 LE BOM { mode += ", ccs=UNICODE"; isUnicode = true; } // Open in the suitable mode. err = fopen_s(&fh, fnameIn.string().c_str(), mode.c_str()); assert(err == 0); fgets - 取决于是否检测到Unicode。然后想法是如果先前检测到unicode,则将缓冲区内容从Unicode转换为1250,或者让缓冲区在1250中。fgetws变量应该包含windows-1250编码中的字符串。需要转换时会使用s

ATL::CW2A(buf, 1250)

它工作正常......直到出现一个带有nul字符的文件作为行中的值。问题是,当 const int bufsize = 4096; wchar_t buf[bufsize]; // Read the line from the input according to the isUnicode flag. while (isUnicode ? (fgetws(buf, bufsize, fh) != NULL) : (fgets(reinterpret_cast<char*>(buf), bufsize, fh) != NULL)) { // If the input is in Unicode, convert the buffer content // to the string in cp1250. Otherwise, do not touch it. string s; if (isUnicode) s = ATL::CW2A(buf, 1250); else s = reinterpret_cast<char*>(buf); ... // Now processing the characters of the `s` to form the output file } 变量被分配时,s会切断该行的其余部分。在观察到的情况下,它发生在使用1250编码的文件中。但它也可能发生在UTF编码的文件中。

如何解决问题?

1 个答案:

答案 0 :(得分:1)

使用C ++或Windows函数解决NUL字符问题。在这种情况下,最简单的解决方案是MultiByteToWideChar,它将接受明确的字符串长度,因此它不会在NUL上停止。