java中scanner不直接结合fileinputstream做分词或正则匹配,而是通过构造时传入fileinputstream(或更推荐的file/path)作为输入源,再利用delimiter、next()、findinline()、usepattern()等方法实现按需切分和正则提取。

Java 中 Scanner 本身不直接“结合” FileInputStream 做分词或正则匹配,而是通过构造 Scanner 时传入 FileInputStream(或更推荐的 File 或 Path),让 Scanner 从文件读取内容;再利用 Scanner 的 delimiter、next()、findInLine()、usePattern() 等能力完成按需切分和正则提取。关键在于理解 Scanner 是基于输入源的令牌化器(tokenizer),不是通用正则引擎。
用 FileInputStream 初始化 Scanner 并设置分词边界
Scanner 默认以空白字符(空格、换行、制表符等)为分隔符。若想按自定义规则(如标点、非字母数字)分词,需调用 useDelimiter() 设置正则分隔模式:
- 例如按所有非字母数字字符切分:
scanner.useDelimiter("[^a-zA-Z0-9u4e00-u9fa5]+")(含中文) - 注意:分隔符匹配的内容会被跳过,不会出现在 next() 结果中
- 建议用
new Scanner(Files.newInputStream(Paths.get("file.txt")))替代原始 FileInputStream,更简洁且自动处理编码(配合 useLocale 和 useRadix 可控)
用 next() + hasNext() 实现基础分词流
这是最常用方式:逐个获取符合当前 delimiter 规则的“词元”(token):
while (scanner.hasNext()) { String word = scanner.next(); /* 处理 word */ }- 若 delimiter 设为
"\s+",效果类似按空格拆分;设为"[.,!?;:\s]+"则能过滤常见标点 - 注意:next() 遇到分隔符即停,不会跨行吞掉内容;但若某行全是分隔符,可能跳过整行
用 findInLine() 或 findAll() 进行正则匹配(不依赖 delimiter)
当需要保留原始文本结构、或做子串级匹配(如提取邮箱、手机号、特定格式日期),应绕过分词逻辑,直接用正则扫描:
scanner.usePattern(Pattern.compile("\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b"));- 然后循环调用
scanner.findInLine(pattern)(返回首个匹配字符串)或 Java 9+ 的scanner.findAll(pattern).forEach(mr -> ...) - findAll() 返回 Stream
,可链式处理: .map(MatchResult::group).filter(s -> s.length() > 3).collect(Collectors.toList()) - 注意:findInLine() 从当前位置开始搜索,匹配后 scanner 位置会移到匹配末尾;findAll() 也是顺序扫描,不会回溯
实际使用中的关键细节
避免常见陷阱:
- 文件编码必须与 Scanner 一致:显式指定
new Scanner(fileInputStream, "UTF-8"),否则中文易乱码 - Scanner 不自动关闭底层流,务必在 try-with-resources 中使用:
try (Scanner sc = new Scanner(Files.newInputStream(p), "UTF-8")) { ... } - delimiter 和 pattern 是互斥设计重点:设了 delimiter 后 next() 按其切分;设了 pattern 后 findInLine/findAll 按其匹配——二者可共存,但语义不同,别混淆用途
- 对大文件,Scanner 性能尚可,但若需全文正则替换或复杂语法解析,建议改用 BufferedReader + Pattern.compile(...).matcher(text) 更灵活可控
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











