用split()切分文本需注意正则陷阱:英文用split("\s+"),中英文混合先清理全角空格和零宽字符,中文分词须用专用库;词频统计推荐Map.merge(word, 1, Integer::sum);频繁正则操作应缓存Pattern实例。

怎么用 String 和 split() 快速切分文本并统计词频
直接用 split() 处理简单文本(比如空格/标点分隔的英文)最省事,但要注意正则陷阱。例如 "hello, world!".split("\\W+") 会把标点全当分隔符,但开头结尾空字符串可能混入结果——得手动过滤掉空串。
常见错误是写成 split(",") 去切中文顿号或全角符号,结果完全没切开;实际得先统一替换全角标点为半角,再用 split("[\\s\\p{P}]+")(\\p{P} 匹配所有 Unicode 标点)。
- 英文文本优先用
split("\\s+"),再trim()每个词 - 中英文混合时,先
replaceAll("[\u3000\uFEFF\\s]+", " ")清理全角空格和零宽字符 - 词频统计别直接用
HashMap手动计数,改用Map.merge(word, 1, Integer::sum)更安全
为什么 Pattern.compile() 比反复调用 String.replaceAll() 更快
如果要对多段文本做相同清洗(比如去 HTML 标签、删 URL),每次调用 replaceAll() 都会隐式编译正则,性能掉得明显。提前用 Pattern.compile("]*>") 编译一次,再用 matcher(input).replaceAll(""),速度能提 3–5 倍。
特别注意:Java 8 的 String.replace()(非正则版)比 replaceAll() 快得多,纯字符替换优先用它,比如删换行符:str.replace("\n", " ").replace("\r", "")。
立即学习“Java免费学习笔记(深入)”;
- 频繁使用的正则必须缓存
Pattern实例,别在循环里重复compile() - 中文分词不推荐纯正则硬切,
Pattern对歧义切分(如“南京市长江大桥”)无能为力,得上专用库 -
Matcher.find()比replaceAll()更适合提取关键词,尤其要保留位置信息时
用 Stream 做链式文本处理时,哪些操作会意外改变原始字符串
Stream 本身不修改原字符串,但像 toLowerCase()、trim() 这些中间操作返回新字符串,容易误以为流在“就地处理”。更隐蔽的是 Collectors.groupingBy(String::length) 这类收集器,如果 key 是可变对象(比如自定义类没重写 equals/hashCode),词频统计就全乱。
- 敏感文本(如含密码字段)别在
Stream中直接map(String::toUpperCase)后打印,日志可能泄露原始值 - 大文本走
Stream.iterate()或BufferedReader.lines(),别一次性readAllLines()到内存 -
Collectors.counting()比手写reduce(0, (a,b)->a+1, Integer::sum)更简洁且线程安全
中文文本分析绕不开的编码和分词坑
读文件时没指定 StandardCharsets.UTF_8,Windows 上默认 GBK,中文直接变乱码;写结果时用 Files.write(path, lines) 默认用系统编码,Linux 和 Windows 输出不一致。
纯 String API 对中文基本无效:没法准确切词、无法识别专有名词、不能处理同音字。真要分析语义,必须引入外部分词器,比如 hanlp 或 ansj,它们返回的是 Term 列表而非字符串数组。
- 文件读取强制写
Files.readAllLines(path, StandardCharsets.UTF_8) - 分词结果别直接拼
term.word + "/" + term.nature打日志,term可能为null - 停用词过滤别用
ArrayList.contains(),换成HashSet,否则十万词文本性能崩盘
真正难的不是切分或统计,而是定义“什么是有效词”——标点算不算、数字要不要归一化、英文缩写是否保留,这些规则一旦写死,后续维护成本远高于代码本身。










