Matlab用regexp解析大型元胞数组无匹配场景的高效方法咨询
非结构化键值对字符串正则提取解决方案
问题1:无需UniformOutput,false的实现方案
原生Matlab的regexp没有无匹配返回自定义值的参数,最简洁的实现是将匹配逻辑封装为返回标量的自定义函数,这样cellfun检测到所有输出都是同类型标量,就不需要关闭UniformOutput校验:
- 先定义通用提取函数
function val = extract_thing(str, expr) match = regexp(str, expr, 'tokens', 'once'); if isempty(match) val = 'Unknown'; else val = match{1}; % 直接解包tokens返回字符串,避免嵌套 end end
- 直接调用
cellfun无需额外参数
out3 = cellfun(@(x) extract_thing(x, expr3), mycell);
返回的out3本身就是标量元胞数组,每个元素都是字符串,可直接传入unique等函数。
问题2:UniformOutput,false方案转标量元胞数组
你当前的嵌套结构是因为regexp的tokens参数返回的匹配结果本身是元胞,空匹配你回填了字符串,才出现混合结构。一行代码即可完成解包:
out_scalar = cellfun(@(x) ifelse(iscell(x), x{1}, x), out, 'UniformOutput', false);
- 标量元胞数组的定义:每个元胞内仅存储单个基础类型元素(单个字符串、单个数值等),不存在嵌套元胞/数组结构,这类元胞数组支持所有标准元胞操作函数。
问题3:更优的整体实现思路
针对你10万条的量级,更推荐类JSON清洗解析方案,比正则适配各种边界情况的容错性更高,性能也不差:
你的输入字符串本身是接近JSON的结构,只需少量清洗即可转为合法JSON直接解析:
% 逐行清洗后jsondecode mycell_clean = strrep(mycell, '''''', '"'); % 两个单引号替换为双引号 mycell_clean = regexprep(mycell_clean, ',\s*"+$', '}'); % 末尾多余的引号和逗号替换为闭合括号 mycell_clean = strcat('{', mycell_clean); % 开头补左括号 % 逐行解析 out = cellfun(@(x) jsondecode(x), mycell_clean, 'UniformOutput', false);
解析后可直接按字段名取值,不存在漏匹配、格式适配的问题。
问题4:一次性提取三个字段的实现方案
先写包含三个捕获组的正则,可选匹配thing3字段:
expr_all = '(?<=thing1''):\s?''?-?([\w\d().]*?)''?,.+?(?<=thing2''):\s?''?-?([\w\d().]*?)''?,.+?(?:(?<=thing3''):\s?''?-?([\w\d().]*?)''?,)?'; % 批量提取 out_all = regexp(mycell, expr_all, 'tokens', 'once', 'UniformOutput', false); % 统一回填空值并解包 out_all = cellfun(@(x) { ifelse(isempty(x{1}), 'Unknown', x{1}), ... ifelse(isempty(x{2}), 'Unknown', x{2}), ... ifelse(length(x)<3 || isempty(x{3}), 'Unknown', x{3}) }, out_all, 'UniformOutput', false); % 转为N行3列的标量元胞数组,直接建表 out_mat = vertcat(out_all{:}); mytable = table(out_mat(:,1), out_mat(:,2), out_mat(:,3), 'VariableNames', {'thing1','thing2','thing3'});
内容的提问来源于stack exchange,提问作者skratch
相关产品推荐
相关产品推荐

