Rust正则提取ffmpeg音频设备名:嵌套引号匹配异常问题
Rust环境下提取ffmpeg音频设备名的解决方案
针对ffmpeg -list_devices输出中含嵌套引号的设备名(如""What U Hear" (Sound Blaster Audigy 5/Rx)"),原正则".*?"无法完整匹配的问题,提供两种可靠实现:
一、改进正则表达式匹配
利用ffmpeg用双引号""转义单个引号的规则,编写能识别转义引号的正则,提取后再还原转义内容:
实现代码
use regex::Regex; fn extract_audio_devices(ffmpeg_output: &str) -> Vec<String> { // 匹配被双引号包裹的内容,支持内部的""转义 let device_re = Regex::new(r#""((?:[^"]|"")*)""#).unwrap(); device_re.captures_iter(ffmpeg_output) .filter_map(|cap| { let raw_device = cap.get(1)?.as_str(); // 将转义的""替换为单个" Some(raw_device.replace("\"\"", "\"")) }) .collect() } // 测试示例 fn main() { let sample_output = r#" [dshow @ 0000021a7f0a4500] DirectShow audio devices [dshow @ 0000021a7f0a4500] ""What U Hear" (Sound Blaster Audigy 5/Rx)" [dshow @ 0000021a7f0a4500] "Microphone (Realtek Audio)" "#; let devices = extract_audio_devices(sample_output); devices.iter().for_each(|d| println!("{}", d)); }
说明
- 正则
"((?:[^"]|"")*)"的核心是(?:[^"]|""):匹配非引号字符,或连续两个引号(转义的单个引号) - 提取后通过
replace("\"\"", "\"")还原设备名的原始格式
二、状态机解析(更可控)
如果担心正则的边缘情况,可通过手动遍历字符、维护状态的方式解析,逻辑更直观:
实现代码
fn extract_audio_devices_state(ffmpeg_output: &str) -> Vec<String> { let mut devices = Vec::new(); let mut in_device_name = false; let mut current_device = String::new(); let mut chars = ffmpeg_output.chars().peekable(); while let Some(c) = chars.next() { match c { '"' if !in_device_name => { in_device_name = true; } '"' if in_device_name => { // 检查下一个字符是否也是",是则为转义引号 if let Some(&next_c) = chars.peek() { if next_c == '"' { current_device.push('"'); chars.next(); // 跳过第二个" continue; } } // 不是转义引号,结束当前设备名 devices.push(current_device.clone()); current_device.clear(); in_device_name = false; } _ if in_device_name => { current_device.push(c); } _ => {} } } devices } // 测试示例 fn main() { let sample_output = r#" [dshow @ 0000021a7f0a4500] DirectShow audio devices [dshow @ 0000021a7f0a4500] ""What U Hear" (Sound Blaster Audigy 5/Rx)" [dshow @ 0000021a7f0a4500] "Microphone (Realtek Audio)" "#; let devices = extract_audio_devices_state(sample_output); devices.iter().for_each(|d| println!("{}", d)); }
说明
- 通过
in_device_name标记是否处于设备名的引号区间内 - 遇到单个引号时切换状态,遇到连续两个引号则视为单个引号添加到设备名中
选择建议
- 若ffmpeg输出格式稳定,正则方案简洁高效
- 若需要处理更多不可预见的格式异常,状态机方案更灵活可靠
内容的提问来源于stack exchange,提问作者Mypantsrtooobig
相关产品推荐
相关产品推荐

