对 CSV 特殊字符使用临时占位符是一种不好的做法吗?



我正在使用许多不同格式的CSV文件,通常由普通用户手动编写,因此字段中有很多;,nt之类的,这种字符通常在解析数据或生成新的CSV文件时会引起麻烦, 而且我通常会事先删除这些字符,但今天我在旧程序中发现了以下代码:

它从resultSet中读取数据并将每个值连接成一个String形成一行,并处理分隔符(我们通常使用;(,这段代码首先使用类似#TempSeparator#的临时标志来划分每个字段,然后,当行完成后,应用replaceAll(";","")来删除假分隔符, 之后,replaceAll("#TempSeparator#", ";")形成有效行

我实际上认为这是一种聪明的方法,可以避免对每个字段进行不必要的调用,并且只对整行进行替换,但我认为这不是最好甚至最佳的方法。

这真的是一种不好的做法吗?

这不是糟糕,但也不是最好的方法。

尽可能使用标准库。以下是优秀库的列表,其中SuperCSV在支持CSV变体方面特别强大。这些库遵循最佳实践:在字段中使用特殊字符时进行转义,或者将字段换行(通常使用引号(。

如果 CSV 格式已经不正确,以至于特殊字符出现在字段中而没有正确转义或换行,那么您手上有一个数据清理问题,需要通过其他方式解决。用临时占位符替换字符不会解决这个问题,因为占位符同样会出现在字段内部和字段之间。

这种方法对我来说听起来不是很优雅。您描述:

  1. 每个输入字段,使用#TempSeparator#将其连接到单个字符串
  2. 从生成的字符串中消除所有;
  3. 将所有出现的#TempSeparator#替换为;

这是 3 个步骤。不如说:

  1. 每个输入字段,去除所有;
  2. 然后,使用;将其连接到单个字符串上

少了一步。因此,更好。

一些示例代码来说明为什么这更简单:

流样式:

collection.stream().collect(Collectors.joining("#TempSeparator#"))
.replace(";", "").replace("#TempSeparator#", ";");

与。

collection.stream().map(x -> x.replace(";", ""))
.collect(Collectors.joining(";"));

它被过度设计,是一个不必要的伪影。

至少使用常量字符:

private static final char TEMP_SEPARATOR = 'u001f';
  • 通常,制表符不会出现在文本t中,它是一个理想的分隔符。
  • 否则,控制字符可以:单位分隔符u001f。可能是Unicode的。
  • 几乎无法使用的字符是u0000.

优点是其效率:

s = s.replace(';', ',').replace('u0000', ';');

最好的解决方案仍然是更换单元格值本身的分隔符。 就像换行符可能必须做的那样。

关于最后一个分隔符:恕我直言,制表符是比分号更好的选择,因为用空格替换制表符确实只会更改文本 w.r.t. 空格。也就是说:不能产生任何要求。像房间号必须是楼层";"号。

最新更新