怎么通过 Scanner.skip() 配合正则在读取输入流时直接忽略掉不需要的噪音字符
`Scanner.skip()`配合正则表达式可跳过输入流中的空格、注释、BOM等噪音字符,仅移动光标而不读取内容。失败时抛出`InputMismatchException`,需用`try-catch`处理。它适合前导清理,但与`useDelimiter()`机制独立,后者用于切分而非跳过。正确使用能简化输入解析。
`Scanner.skip()` 配合正则表达式,可以说是处理输入流时跳过“噪音”的利器——比如那些恼人的空格、换行、注释、分隔符、BOM、冗余符号等。但用好它,得先理解它的脾气:它只跳过匹配的部分,不读取也不返回任何值,而且一旦跳过失败(即没有匹配到任何内容),就会直接抛出 InputMismatchException。下面我们就来拆解,怎么用才顺手,关键点在哪,容易踩哪些坑。
skip() 的核心行为:跳过,但不消费“成功匹配后的下一个字符”
举个例子,输入是 " 123"(开头有好几个空白字符),执行:
scanner.skip("\\s*");
它会跳过所有开头的空白,光标停在 '1' 前面——下次调用 nextInt() 或 next() 就能直接读到 123。
⚠️ 必须记住:skip() 不会吞掉第一个非空白字符,它只是把读取位置“推到那里”,让你后续操作从干净的地方开始。
常用噪音场景与正则写法
- 跳过所有前导空白(含 Unicode 空格、NBSP):
scanner.skip("\\p{Z}+");或更稳妥的scanner.skip("\\s+"); - 跳过 C/Ja va 风格单行注释(// ... 换行前):
scanner.skip("//[^\\r\\n]*[\\r\\n]?"); - 跳过 UTF-8 BOM(\uFEFF)或 Windows 行结束符混合噪音:
scanner.skip("\\uFEFF|\\r\\n|\\r|\\n");(可加*支持连续出现) - 跳过特定分隔符前的任意噪音(如跳过 "data:" 后的空格和冒号):
scanner.skip("data:\\s*");—— 这样后续nextLine()就从真正数据开始。
必须配合 useDelimiter() 或手动容错
单独靠 skip() 其实解决不了“中间混杂噪音”的问题。比如输入:
"name: Alice age: 30 city: Beijing"
你想提取 Alice、30、Beijing,仅用 skip("name:\\s*") 只能跳到 Alice 前面;之后还得用 next() 读值,再 skip("age:\\s*")……这样链条很容易断裂。
✅ 更稳妥的做法:
scanner.useDelimiter("\\s*[:\\s]+\\s*");
然后循环 scanner.hasNext() + scanner.next(),自动切分并忽略分隔符周围的噪音。
安全使用的三个提醒
- 始终用 try-catch 包裹 skip():没匹配到就抛异常,别让一个意外崩了程序;可以在 catch 后按默认逻辑处理(比如认为噪音不存在,继续往下读)。
- skip() 不改变 delimiter:它和
useDelimiter()是两套机制,别以为设了 delimiter 就不用 skip 了——前者管“怎么切”,后者管“开头清场”,各司其职。 - 正则要锚定开头(隐式):
skip("abc")只匹配从当前位置开始的"abc",不会往回找;所以它适合做“前导清理”,不适合做“全局过滤”。
说到底,不复杂但容易忽略的一点是:skip 是“光标快进键”,不是“过滤器”。用对地方,它能让你的输入解析干净利落,少出很多莫名其妙的 bug。


































