如何在Rust中合并Vec中含引号的元素以处理Shell输入
处理Shell输入中的引号拆分问题
当处理类似test "one two" three这样的Shell命令输入时,使用split_whitespace()会把引号包裹的内容拆分成多个元素(比如变成["test", "\"one", "two\"", "three"]),我们需要实现search_quotes函数,将引号内的元素合并为单个元素,最终生成包含正确关键字和参数的Command结构体。
现有代码框架
struct Command { keyword: String, args: Vec<String>, } fn main() { let mut c: String = String::from("test \"one two\" three"); let cmd: Vec<String> = c.split_whitespace().map(|s| s.to_string()).collect(); let command: Command = search_quotes(cmd); } fn search_quotes(c: Vec<String>) -> Command { // 需将引号包裹的元素合并为一个 Command { keyword: "test".to_string(), args: ["\"one two\"".to_string(), "three".to_string()].to_vec() } }
未完成的尝试代码
let cmd = vec!["test", "\"one", "two\"", "three"]; let mut n: Vec<usize> = vec![]; for i in 0..cmd.len() { let bytes = cmd[i+1].as_bytes(); for (j, &item) in bytes.iter().enumerate() { if item == b'"' { if j == 0 || j == bytes.len()-1 { let n = n.push(i+1); } } } }
正确实现方案
通过遍历拆分后的元素,跟踪引号包裹状态来合并对应内容:
struct Command { keyword: String, args: Vec<String>, } fn main() { let c: String = String::from("test \"one two\" three"); let cmd: Vec<String> = c.split_whitespace().map(|s| s.to_string()).collect(); let command = search_quotes(cmd); println!("Keyword: {}", command.keyword); println!("Args: {:?}", command.args); } fn search_quotes(mut parts: Vec<String>) -> Command { let mut merged = Vec::new(); let mut in_quote = false; let mut current_quoted = String::new(); for part in parts.drain(..) { if in_quote { // 处于引号中,继续拼接当前部分 current_quoted.push(' '); current_quoted.push_str(&part); // 检查是否到达引号结尾 if part.ends_with('"') { let trimmed = current_quoted.trim_matches('"'); merged.push(trimmed.to_string()); in_quote = false; current_quoted.clear(); } } else { if part.starts_with('"') { if part.ends_with('"') { // 单个元素就是完整引号内容,直接去引号加入 let trimmed = part.trim_matches('"'); merged.push(trimmed.to_string()); } else { // 开启引号包裹状态,保存当前部分 in_quote = true; current_quoted.push_str(&part); } } else { // 普通元素直接加入结果 merged.push(part); } } } // 处理未闭合的引号(直接保留原始拼接内容) if in_quote { merged.push(current_quoted); } // 提取命令关键字和参数列表 let keyword = merged.remove(0); Command { keyword, args: merged, } }
实现说明
- 用
in_quote标记是否处于引号包裹状态,遍历所有拆分后的元素 - 遇到开头引号且未结尾的元素时,开始拼接后续元素,直到遇到结尾引号
- 拼接完成后去除首尾引号,作为单个参数加入结果列表
- 最后从合并后的列表中提取第一个元素作为命令关键字,剩余元素作为参数
内容的提问来源于stack exchange,提问作者h1kkar
相关产品推荐
相关产品推荐

