Java解析CSV时忽略引号内逗号的问题及解决方案咨询
问题分析
你手动实现的CSV分割逻辑存在两个关键问题:
- 循环内过早写入Set:每次处理数组元素时就调用
platforms.add(words.get(2)),但此时words列表还在构建中,尚未凑齐完整的一行数据,会导致错误元素被加入,甚至可能触发索引越界。 - 手动解析CSV的局限性:CSV规则包含引号内逗号、转义引号(
"")、跨行字段等复杂场景,手动分割逻辑无法覆盖所有情况,这正是你丢失2个唯一值的核心原因。
最优解决方案:使用专业CSV解析库
不要自己造轮子,直接用Java生态中成熟的CSV解析库,比如OpenCSV,它能完美处理所有CSV标准场景,代码简洁且可靠。
步骤1:引入依赖
如果用Maven,在pom.xml中添加:
<dependency> <groupId>com.opencsv</groupId> <artifactId>opencsv</artifactId> <version>5.6</version> <!-- 可替换为最新稳定版 --> </dependency>
如果用Gradle:
implementation 'com.opencsv:opencsv:5.6'
步骤2:重写解析代码
用CSVReader处理,自动处理引号内逗号等特殊情况:
import com.opencsv.CSVReader; import java.io.FileReader; import java.util.HashSet; public class CsvPlatformParser { public static void main(String[] args) { String file = "FinalProject/src/Data.csv"; HashSet<String> platforms = new HashSet<>(); // 用try-with-resources自动关闭流,避免资源泄漏 try (CSVReader reader = new CSVReader(new FileReader(file))) { reader.readNext(); // 跳过表头行 String[] lineData; while ((lineData = reader.readNext()) != null) { // 确保列索引有效(platforms是第3列,索引从0开始为2) if (lineData.length > 2) { platforms.add(lineData[2].trim()); // 可选:去除字段前后空格 } } } catch (Exception e) { e.printStackTrace(); // 不要吞异常,方便排查问题 } System.out.println("唯一平台数量:" + platforms.size()); } }
为什么这个方案更靠谱?
- 自动识别引号内的逗号:比如字段
"PC, PS5"会被解析为单个完整字段,不会被分割。 - 支持转义引号:比如
"John ""Doe"""会被正确解析为John "Doe"。 - 兼容跨行字段:如果某个字段包含换行符,依然能完整读取。
- 代码简洁,无需手动处理复杂的分割逻辑,大幅降低出错概率。
若必须手动实现(仅适合简单场景)
如果不能引入第三方库,至少要修正现有代码的逻辑:
String file = "FinalProject/src/Data.csv"; BufferedReader rd = null; String line = ""; HashSet<String> platforms = new HashSet<>(); try { rd = new BufferedReader(new FileReader(file)); rd.readLine(); // 跳过表头 while ((line = rd.readLine()) != null) { String[] arr = line.split("\""); ArrayList<String> words = new ArrayList<>(); for (int i = 0; i < arr.length; i++) { if (i % 2 == 0) { // 非引号部分按逗号分割,过滤空字符串(避免首尾逗号导致的无效元素) String[] parts = arr[i].split(","); for (String part : parts) { if (!part.trim().isEmpty()) { words.add(part.trim()); } } } else { // 引号内的内容直接加入,保留原始逗号 words.add(arr[i].trim()); } } // 整行解析完成后,再将有效字段加入Set if (words.size() > 2) { platforms.add(words.get(2)); } } } catch (Exception e) { e.printStackTrace(); // 不要吞异常 } finally { try { if (rd != null) rd.close(); } catch (Exception e) { throw new RuntimeException(e); } }
注意:这个手动实现依然无法处理转义引号、跨行字段等复杂场景,仅适用于结构简单的CSV文件。
内容的提问来源于stack exchange,提问作者scribre
相关产品推荐
相关产品推荐

