如何正确使用Scanner.useDelimiter仅读取run()内的指定内容?
原代码问题
你写的分隔符逻辑存在三个硬伤,根本没法实现提取run()括号内容的需求:
- 分隔符规则
run\\W匹配范围不可控:\W代表任意非单词字符,除了(之外,run后面跟的空格、标点、特殊符号都会被识别为分隔符的一部分,很容易出现误匹配。 - 就算把分隔符改成精确匹配
run\\(,也只能把run(作为内容分割边界,后续读取到的内容会带上右括号以及run()块后面的其他文本,没法精准截出括号内部的内容。 - Scanner的分隔符机制本身就不适合做定向内容提取:当输入以
run(开头时,开头的run(会被识别为前置分隔符直接跳过,再叠加你没有处理右边界的逻辑,自然读不到有效内容。
实现方案
别折腾Scanner分隔符了,直接用正则捕获或者字符串边界匹配的方式提取内容,不管输入是不是以run(开头、run()在输入的什么位置都能正常识别。
普通场景(括号内无嵌套括号)
用正则非贪婪匹配直接捕获括号内的内容,代码最简单:
import java.util.Scanner; import java.util.regex.Matcher; import java.util.regex.Pattern; public class ExtractRunParam { public static void main(String[] args) { Scanner sc = new Scanner(System.in); // 读取整行输入,需要读取多行输入的话可以改成sc.useDelimiter("\\A")再调用sc.next() String input = sc.nextLine(); sc.close(); // 匹配规则:定位run(...)片段,用捕获组拿括号里的内容 Pattern runPattern = Pattern.compile("run\\((.*?)\\)"); Matcher matcher = runPattern.matcher(input); if (matcher.find()) { String innerContent = matcher.group(1); // 需要去掉内容首尾空格的话,在这里调用innerContent.trim()即可 System.out.println(innerContent); } else { System.out.println("未识别到符合格式的run(...)片段"); } } }
测试效果:
- 输入
前置内容run(测试内容123)后置内容,输出测试内容123 - 输入
run(直接以run开头的输入),输出直接以run开头的输入 - 输入
run( 内容前后带空格 ),输出内容前后带空格
复杂场景(括号内存在嵌套括号)
如果括号里可能出现多层括号嵌套(比如run(calc(1,2), print(3))这类内容),正则非贪婪匹配会提前匹配到第一个右括号导致内容截断,这时候用括号计数的方式找配对右括号更可靠:
import java.util.Scanner; public class ExtractRunParamWithNest { public static void main(String[] args) { Scanner sc = new Scanner(System.in); String input = sc.nextLine(); sc.close(); int runStartIdx = input.indexOf("run("); if (runStartIdx == -1) { System.out.println("未识别到符合格式的run(...)片段"); return; } int leftBracketPos = runStartIdx + 4; // run(共4个字符,后面就是左括号的下一个位置 int bracketLevel = 1; int rightBracketPos = -1; // 遍历找配对的右括号 for (int i = leftBracketPos; i < input.length(); i++) { char current = input.charAt(i); if (current == '(') bracketLevel++; if (current == ')') bracketLevel--; if (bracketLevel == 0) { rightBracketPos = i; break; } } if (rightBracketPos == -1) { System.out.println("括号不配对,内容格式错误"); return; } String innerContent = input.substring(leftBracketPos, rightBracketPos); System.out.println(innerContent); } }
这个实现可以准确识别多层嵌套的括号边界,比如输入run(sum(1,2,max(3,4)), log("test")),可以完整提取括号内的sum(1,2,max(3,4)), log("test")内容。
补充说明
- Scanner的useDelimiter只适合简单的固定分隔符切分场景,用来提取指定格式的结构化内容不仅逻辑绕,还很容易出边界问题,不如正则或者字符串遍历的方式可控。
- 如果输入里存在多个run(...)片段,只要循环调用matcher.find()(正则方案)或者循环查找下一个run(的位置(计数方案),就能批量提取所有片段的括号内内容。
内容的提问来源于stack exchange,提问作者theworld
相关产品推荐
相关产品推荐

