Данные в текстовом файле хранятся одна строка за другой, поэтому вы не можете писать столбец за столбцом. Сначала необходимо определить ширину столбцов и написать заголовок метки / единицы измерения, а затем записать все данные. Все, что нам нужно, это правильная строка формата для fprintf: формат с фиксированной шириной и fprintf чрезвычайно полезны для экспорта данных с разделителями столбцов.
Первая часть кода в порядке, чтобы определить ширину столбцов (при условии, что данные имеют только положительные выборки). Вам нужно только сохранить его в массиве.
nCol=length(this.colLabels);
colWidth = zeros(1,nCol);
for col = 1:nCol
colLen = length(this.colLabels{col}); % find the longest string in labels
v = max(this.data(:,col)); % find the longest double in data
n = num2str(v, '%.4f'); % precision of 4 after decimal place
dataLen = length(n);
% find max width for column and add white space
colWidth(col)=max(colLen,dataLen);
end
Теперь нам нужно построить строку формата для меток и данных, чтобы использовать их с sprintf. Строка формата будет выглядеть как '%6s %8s %10s\n'
для заголовка и '%6.4f %8.4f %10.4f\n'
для данных.
fmtHeader=sprintf('%%%ds ',colWidth);
fmtData=sprintf('%%%d.4f ',colWidth);
%Trim the triple space at the end and add the newline
fmtHeader=[fmtHeader(1:end-3) '\n'];
fmtData =[fmtData(1:end-3) '\n'];
Мы используем тот факт, что, когда sprintf получает массив в качестве входных данных, он будет перебирать все значения для получения длинной строки. Мы можем использовать тот же трюк для записи данных, но если мы пишем строку за строкой, а Matlab сохраняет данные в главном порядке столбцов, необходима транспонирование.
fid=fopen('myFile.txt');
fprintf(fid,fmtHeader,this.colLabels{:});
fprintf(fid,fmtHeader,this.colUnits{:});
fprintf(fid,fmtData,transpose(this.data));
fclose(fid);
Для заголовков ячейка может быть преобразована в список через запятую с помощью {:}. Это то же самое, что написать fprintf(fid,fmtHeader,this.colLabels{1},this.colLabels{2},...)
Используя те же тестовые данные из ответа @Jimbo и fid=1;
, чтобы вывести fprintf на экран, код дает:
test cheese variable really long string
ml cm C kg
1.2346 6.0000 11.0000 16.0000
2.0000 7.0000 12.0000 17.0000
3.0000 8.0000 13.0000 18.0000
4.0000 9.0000 14.0000 19.0000
1000.0000 10.0000 15.0000 20.0000
Наконец, самая компактная версия кода:
fid=1; %print to screen for test purpose
colWidth =max( cellfun(@length,this.colLabels(:)') , max(1+floor(log10(max(this.data,[],1))) , 1) + 5); %log10 to count digits, +5 for the dot and decimal digits ; works for data >=0 only
fprintf(fid,[sprintf('%%%ds ',colWidth(1:end-1)) sprintf('%%%ds\n',colWidth(end))],this.colLabels{:},this.colUnits{:}); %print header
fprintf(fid,[sprintf('%%%d.4f ',colWidth(1:end-1)) sprintf('%%%d.4f\n',colWidth(end))],this.data'); %print data