用正则匹配token比split()更可靠:匹配双引号字符串、单引号字符串和非空白序列,直接获取完整参数,避免引号内空格被错误分割。

用 String.split() 拆分控制台输入的关键,是写对正则——既要准确切开参数,又要保留带空格的引号内内容(比如文件路径、带空格的选项值)。
识别常见控制台输入模式
真实命令行输入常混合以下元素:
- 普通单词:
ls -l /home/user - 带等号的键值对:
--output=file.txt - 单引号或双引号包裹的含空格字符串:
"My Document.txt"或'C:Program Files' - 转义空格:
file name.txt
但注意:split() 本身不解析引号或转义,它只按正则“切刀”位置分割。所以若需完整支持引号逻辑,建议先用更专业的工具(如 Apache Commons CLI 或自己手写词法分析器),而 split() 更适合轻量、约定清晰的场景(例如:只用双引号,且引号不嵌套、不转义)。
基础安全拆分:按空白切割,但跳过引号内空格
标准做法是不用 split("\s+")(它会错误切开 "a b"),而是用「匹配分隔符」思路,配合 Pattern + Matcher 扫描 token ——但如果你坚持用 split(),一个实用折中方案是:
先预处理:把引号内的空格临时替换成不可见标记,再 split,最后还原。例如:
String input = "cp "file one.txt" "file two.txt"";
// 替换引号内空格为 u0000(空字符,确保不干扰后续)
String safe = input.replaceAll(""([^"]*)"|'([^']*)'", (m) -> {
String quoted = m.group(1) != null ? m.group(1) : m.group(2);
return '"' + quoted.replace(" ", "u0000") + '"';
});
String[] parts = safe.split("\s+");
for (String p : parts) {
System.out.println(p.replace("u0000", " "));
}
// 输出:cp, "file one.txt", "file two.txt"
简单可靠方案:用正则直接匹配 token(推荐)
比 split() 更自然的方式是用 Pattern.compile("("[^"]*"|'[^']*'|\S+)").matcher(input) 直接找所有 token:
-
"[^"]*"匹配双引号包裹内容(不含嵌套) -
'[^']*'匹配单引号包裹内容 -
\S+匹配其余非空白连续字符
这样得到的每个 group() 就是一个完整参数,无需额外去引号 —— 如果你需要纯内容,再用 .substring(1, len-1) 去掉首尾引号即可。
注意事项和边界情况
这些细节容易出错:
- 正则中的
\S+无法匹配含制表符或换行符的参数;如需兼容,改用[^\s]+并加Pattern.DOTALL - 反斜杠转义(如
file name)需额外处理:在匹配前把\替换为特殊占位符,split 后再还原 - 空输入或连续空格会导致
split()产生空字符串,加Arrays.stream(...).filter(s -> !s.isEmpty()).toArray(String[]::new)过滤 - 末尾反斜杠(
cmd)或未闭合引号属于语法错误,正则不会报错,需业务层校验
不复杂但容易忽略:控制台输入本质是 shell 解析后的结果。Java 接收到的 args(如 main 的 String[])已经是 shell 处理好的 token,一般无需再 split —— 你真正需要 split 的,通常是读取 System.in 的一行原始输入,这时才要考虑引号与空格逻辑。

















