我正在尝试以下方法:我有一个字符串,看起来像这样: 'a,b,(c,d,(e,f),g),(h,i)' 我想把它分成类似第一层的逗号:
a b(c,d,(e,f),g)(h,i)
我无法弄清楚如何做到这一点。我得到的逻辑解决方案是,我必须找到逗号,它们后面有相同数量的左右括号。如何用正则表达式实现它?
最好的问候
答案 0 :(得分:1)
没有正则表达式的解决方案:
a = 'a, b, (c, d, (e, f), g), (h, i)';
a(cumsum((a=='(')-(a==')'))==0 & a==',')=';'
out = strsplit(a, ';')
结果:
{
[1,1] = a
[1,2] = b
[1,3] = (c, d, (e, f), g)
[1,4] = (h, i)
}
我们可以使用
找到每个角色的嵌套级别cumsum((a=='(')-(a==')'));
嵌套级别数组:
0000001111111222221111000111110
所以例如前6个字符'a, b, '
处于第0级,依此类推
我们只需要那些0级的字符
cumsum((a=='(')-(a==')'))==0
也应该是逗号
cumsum((a=='(')-(a==')'))==0 & a==','
将0级别的所有逗号设置为';'
a(cumsum((a=='(')-(a==')'))==0 & a==',')=';'
并拆分字符串
strsplit(a, ';')
答案 1 :(得分:0)
以下是几个选项:
选项1:如果您的数据在行之间具有一致的逗号和括号模式,您实际上可以使用a regex轻松解析它。缺点是,如果您的模式发生变化,您必须更改正则表达式。但它也很快(即使对于非常大的单元阵列):
str = {'(0, 0, 1540.4, (true, (121.96, 5)), 5.7068, 1587.0)';
'(0, 0, 1537.5, (true, (121.93, 6)), 5.7068, 1587.0)';
'(0, 0, 1537.5, (true, (121.93, 3)), 5.7068, 1587.0)';
'(0, 0, 1537.5, (true, (121.93, 4)), 5.7068, 1587.0)';
'(0, 0, 1537.5, (true, (121.93, 5)), 6.0965, 1587.0)';
'(0, 0, 1535.2, (true, (121.9, 6)), 6.0965, 1587.0)';
'(0, 0, 1535.2, (true, (121.9, 3)), 6.0965, 1587.0)';
'(0, 0, 1535.2, (true, (121.9, 4)), 6.0965, 1587.0)';
'(0, 0, 1535.2, (true, (121.9, 5)), 6.3782, 1587.0)';
'(0, 0, 1532.3, (true, (121.87, 6)), 6.3782, 1587.0)'};
tokens = regexp(str, ['^\(([-\d\.]+), ' ... % Column 1
'([-\d\.]+), ' ... % Column 2
'([-\d\.]+), ' ... % Column 3
'(\(\w+, \([-\d\.]+, [-\d\.]\)\)), ' ... % Column 4
'([-\d\.]+), ' ... % Column 5
'([-\d\.]+))'], ... % Column 6
'tokens', 'once');
str = vertcat(tokens{:});
disp(str);
这个例子的结果是:
'0' '0' '1540.4' '(true, (121.96, 5))' '5.7068' '1587.0'
'0' '0' '1537.5' '(true, (121.93, 6))' '5.7068' '1587.0'
'0' '0' '1537.5' '(true, (121.93, 3))' '5.7068' '1587.0'
'0' '0' '1537.5' '(true, (121.93, 4))' '5.7068' '1587.0'
'0' '0' '1537.5' '(true, (121.93, 5))' '6.0965' '1587.0'
'0' '0' '1535.2' '(true, (121.9, 6))' '6.0965' '1587.0'
'0' '0' '1535.2' '(true, (121.9, 3))' '6.0965' '1587.0'
'0' '0' '1535.2' '(true, (121.9, 4))' '6.0965' '1587.0'
'0' '0' '1535.2' '(true, (121.9, 5))' '6.3782' '1587.0'
'0' '0' '1532.3' '(true, (121.87, 6))' '6.3782' '1587.0'
请注意,我使用模式[-\d\.]+
来匹配可能带有负号或小数点的任意数字。
选项2:您可以使用regexprep
重复删除不包含其他括号的括号对,将其替换为空格以保持相同大小的字符串。然后,在最终处理的字符串中找到逗号的位置,并使用这些位置分解原始字符串。您不必为每个新的逗号和圆括号模式更改正则表达式,但这将比上面稍微慢一些(但对于最多15,000个单元格的数组仍然只需要一两秒):
% Using raw str from above:
str = cellfun(@(s) {s(2:end-1)}, str);
tempStr = str;
modStr = regexprep(tempStr, '(\([^\(\)]*\))', '${blanks(numel($0))}');
while ~isequal(modStr, tempStr)
tempStr = modStr;
modStr = regexprep(tempStr, '(\([^\(\)]*\))', '${blanks(numel($0))}');
end
commaIndex = regexp(tempStr, ',');
str = cellfun(@(v, s) {mat2cell(s, 1, diff([1 v numel(s)+1]))}, commaIndex, str);
str = strtrim(strip(vertcat(str{:}), ','));
disp(str);
这与选项1的结果相同。
答案 2 :(得分:0)
我知道问题是如何使用正则表达式实现它,但如果你是逐个字符地解析它,你可以随时跟踪嵌套级别。这是一个javascript片段,用于演示如何完成(https://jsfiddle.net/jf65k0jc/):
var str = 'a, b, (c, d, (e, f), g), (h, i)';
var arr = [];
var buffer = '';
var level = 0;
for (var i = 0; i < str.length; i++) {
var letter = str[i];
if (level === 0) {
if (letter === ',') {
arr.push(buffer.trim());
buffer = '';
}
else {
buffer += letter;
if (letter === '(') {
level++;
}
}
}
else {
buffer += letter;
if (letter === '(') {
level++;
}
else if (letter === ')') {
level--;
}
}
}
arr.push(buffer.trim());
var output = '';
for (var i = 0; i < arr.length; i++) {
output += arr[i] + '<br>';
}
$('.output').html(output);
// Outputs:
// a
// b
// (c, d, (e, f), g)
// (h, i)