Scala无正则解析CSV:解决引号内逗号被split误拆分的问题
Scala无依赖修复split拆分带引号CSV单元格问题
核心思路是通过单次遍历+状态标记完成合并,全程不涉及正则和第三方依赖,逻辑非常直观:
- 维护2个状态变量:
inQuotes标记当前是否处于未闭合的引号单元格区间,currentBuffer存储当前正在拼接的不完整单元格内容 - 遍历
split(",")得到的所有数组元素,按状态处理每一段内容:- 非引号状态下:
- 若当前段以双引号开头、且未以双引号结尾:说明进入了带逗号的引号单元格,开启引号状态,将当前段写入缓冲,后续拼接时补回被拆分掉的逗号
- 若当前段没有开头引号:说明是普通完整单元格,直接加入结果集
- 引号状态下:
- 若当前段以双引号结尾:说明到达引号单元格末尾,将当前段拼入缓冲后,把缓冲内容作为完整单元格加入结果集,关闭引号状态并清空缓冲
- 若当前段没有结尾引号:说明仍在引号单元格中间,直接拼入缓冲并补逗号即可
代码实现
def fixSplittedCsvRow(splitted: Array[String]): Array[String] = { import scala.collection.mutable.ListBuffer val result = new ListBuffer[String]() var inQuotes = false var currentBuffer = new StringBuilder() for (part <- splitted) { if (!inQuotes) { if (part.startsWith("\"") && !part.endsWith("\"")) { // 进入引号包裹的单元格,开始拼接 inQuotes = true currentBuffer.append(part) currentBuffer.append(',') // 补回被split掉的逗号 } else { // 普通完整单元格,直接加入结果,trim可根据需求保留或删除 result.append(part.trim) } } else { if (part.endsWith("\"")) { // 到达引号单元格末尾 currentBuffer.append(part) result.append(currentBuffer.toString().trim) // 重置状态 inQuotes = false currentBuffer.clear() } else { // 仍在引号单元格中间,继续拼接 currentBuffer.append(part) currentBuffer.append(',') } } } // 兼容异常格式:如果行末有未闭合的引号,把剩余缓冲加入结果 if (inQuotes) { result.append(currentBuffer.toString().trim) } result.toArray }
效果验证
使用你给出的示例测试:
输入:Array("\"Hello", " everyone\"", " green", " blue", " 5", " 3.2")
调用函数后输出:Array("\"Hello, everyone\"", "green", "blue", "5", "3.2"),完全符合预期。
如果后续需要处理单元格内的转义引号(比如"Hello ""World"""这种标准CSV转义格式),只需要在拼接完成后对字符串做一次转义替换即可,不需要修改核心逻辑。
内容的提问来源于stack exchange,提问作者zack cook
相关产品推荐
相关产品推荐

