以下函数适用于任意数组、任何嵌套结构和任何形状的数组,只要它们都是二维数组即可。不支持多维数组(同mat2str)。
该函数还允许为元胞数组指定任意行和列分隔符(例如,在逗号和空格之间进行选择),并且还可以选择强制非元胞数组使用这些分隔符(从而覆盖mat2str'behaviour)。元胞数组中的默认分隔符是 ' ' 用于列,'; ' 用于行。
function y = array2str(x, col_sep, row_sep, sep_noncell)
% Converts a (possibly cell, nested) array to string representation
%
% Optional inputs col_sep and row_sep specify separators for the cell arrays.
% They can be arbitrary strings (but they should be chosen as per Matlab rules
% so that the output string evaluates to the input). Optional flag sep_noncell
% can be used to force those separators with non-cell arrays too, instead of
% the separators produced by mat2str (space and semicolon)
% Default values
if nargin<4
sep_noncell = false;
end
if nargin<3
row_sep = '; ';
end
if nargin<2
col_sep = ' ';
end
x = {x}; % this is to initiallize processing
y = {[]}; % [] indicates content unknown yet: we need to go on
done = false;
while ~done
done = true; % tentatively
for n = 1:numel(y);
if isempty(y{n}) % we need to go deeper
done = false;
if ~iscell(x{1}) % we've reached ground
s = mat2str(x{1}); % final content
if sep_noncell % replace mat2str's separators if required
s = regexprep(s,'(?<=^[^'']*(''[^'']*'')*[^'']*) ', col_sep);
s = regexprep(s,'(?<=^[^'']*(''[^'']*'')*[^'']*);', row_sep);
end
y{n} = s; % put final content...
x(1) = []; % ...and remove from x
else % advance one level
str = ['{' repmat([{[]}, col_sep], 1, numel(x{1})) '}'];
ind_sep = find(cellfun(@(t) isequal(t, col_sep), str));
if ~isempty(ind_sep)
str(ind_sep(end)) = []; % remove last column separator
ind_sep(end) = [];
end
step_sep = size(x{1}, 2);
str(ind_sep(step_sep:step_sep:end)) = {row_sep};
y = [y(1:n-1) str y(n+1:end)]; % mark for further processing...
x = [reshape(x{1}.', 1, []) x(2:end)]; % ...and unbox x{1},
% transposed and linearized
end
end
end
end
y = [y{:}]; % concatenate all strings
上面的函数使用正则表达式来强制在非单元格数组中指定分隔符。由于受支持的后向模式的限制,这在 Matlab 中有效,但在 Octave 中无效。下面的修改版本避免了正则表达式,因此可以在 Matlab 和 Octave 中使用。只有if sep_noncell 和匹配的end 之间的部分相对于第一个版本发生了变化。
function y = array2str(x, col_sep, row_sep, sep_noncell)
% Converts a (possibly cell, nested) array to string representation.
% Octave-friendly version
%
% Optional inputs col_sep and row_sep specify separators for the cell arrays.
% They can be arbitrary strings (but they should be chosen as per Matlab rules
% so that the output string evaluates to the input). Optional flag sep_noncell
% can be used to force those separators with non-cell arrays too, instead of
% the separators produced by mat2str (space and semicolon)
% Default values
if nargin<4
sep_noncell = false;
end
if nargin<3
row_sep = '; ';
end
if nargin<2
col_sep = ' ';
end
x = {x}; % this is to initiallize processing
y = {[]}; % [] indicates content unknown yet: we need to go on
done = false;
while ~done
done = true; % tentatively
for n = 1:numel(y);
if isempty(y{n}) % we need to go deeper
done = false;
if ~iscell(x{1}) % we've reached ground
s = mat2str(x{1}); % final content
if sep_noncell % replace mat2str's separators if required
for k = flip(find(~mod(cumsum(s==''''),2) & s==' ')) % process
% backwards, because indices to the right will become invalid
s = [s(1:k-1) col_sep s(k+1:end)];
end
for k = flip(find(~mod(cumsum(s==''''),2) & s==';'))
s = [s(1:k-1) row_sep s(k+1:end)];
end
end
y{n} = s; % put final content...
x(1) = []; % ...and remove from x
else % advance one level
str = ['{' repmat([{[]}, col_sep], 1, numel(x{1})) '}'];
ind_sep = find(cellfun(@(t) isequal(t, col_sep), str));
if ~isempty(ind_sep)
str(ind_sep(end)) = []; % remove last column separator
ind_sep(end) = [];
end
step_sep = size(x{1}, 2);
str(ind_sep(step_sep:step_sep:end)) = {row_sep};
y = [y(1:n-1) str y(n+1:end)]; % mark for further processing...
x = [reshape(x{1}.', 1, []) x(2:end)]; % ...and unbox x{1},
% transposed and linearized
end
end
end
end
y = [y{:}]; % concatenate all strings
工作原理
我选择了非递归方法,因为我通常更喜欢迭代而不是递归。
通过将子字符串或空数组 ([]) 保存在元胞数组 (y) 中逐渐构建输出。 y 单元格中的空数组表示“需要进一步处理”。子字符串定义了“结构”,或者最终定义了单元格嵌套最深层次中的数字、字符或逻辑内容。
在每次迭代中,y 中找到的第一个空数组将被实际内容替换,或者替换为稍后处理的子字符串和其他空数组。当y不包含任何空数组时,过程结束,将y的所有子字符串串联起来得到最终的字符串输出。
例如,给定输入x = {[10 20], {'abc'; false; true;}}; 并调用y = array2str(x),每个步骤中的数组y 是一个包含以下内容的元胞数组:
'{' [] ', ' [] '}'
'{' '[10 20]' ', ' [] '}'
'{' '[10 20]' ', ' '{' [] '; ' [] '; ' [] '}' '}'
'{' '[10 20]' ', ' '{' ''abc'' '; ' [] '; ' [] '}' '}'
'{' '[10 20]' ', ' '{' ''abc'' '; ' 'false' '; ' [] '}' '}'
'{' '[10 20]' ', ' '{' ''abc'' '; ' 'false' '; ' 'true' '}' '}'
最后将后者拼接成字符串
'{[10 20] {''abc''; false; true}}'
以自定义分隔符为例,array2str(x, ', ', '; ', true) 会给出
'{[10, 20], {''abc''; false; true}}'