我编写了一个脚本,可以节省我在Matlab中手动导入测试期间记录的数据。
每个测试运行在.csv
个文件中保存大约2600个变量,每个变量有2个标题行,两列数据,;
是分隔符。
文件名来自监控程序使用的内部C结构,因此属于这种类型:foo.bar.another.foo.bar.local_varname#VALUE.csv
我想用它在Matlab中重新创建结构,以便只保存一个test_name.mat
文件。
很多时候local_varname
超过63个字符长,所以我有一些替换规则,以便在没有Matlab截断名称的情况下缩短名称(因此试图避免命名冲突)。
这是代码
clear all
clc
% Main names
path_self = pwd;
backslash_indices = strfind(path_self,'\');
test_name = path_self(backslash_indices(end)+1:end); % the directory name gives me the test_name
% Preallocation
filenames = cell(1,2600);
addresses = cell(1,2600);
i=0;
% Full list
MyFiles = dir(path_self);
% Discard subdirectories and non interesting files
for k=1:length(MyFiles)
if ~MyFiles(k).isdir,
if ~isempty(strfind(MyFiles(k).name,'#VALUE.csv'))
i=i+1;
% Too many files
if i > length(filenames)
filenames = [filenames cell(1,100)];
addresses = [addresses cell(1,100)];
end
% Naming Substitution Rules
%%% INSERT HERE BUNCH OF RULES
% Addresses and names
filenames{i} = strrep(filename,'#VALUE.csv','');
addresses{i} = fullfile(path_self, MyFiles(k).name);
end
end
end
filenames = filenames(1:i);
addresses = addresses(1:i);
% Check that no conflicts are created
if length(filenames) ~= length(unique(filenames))
error('filenames not unique')
end
% Housekeeping #1
clear MyFiles backslash_indices i k path_self
% Import data
for j=1:length(filenames)
% Read data
Data = importdata(addresses{j}, ';', 2);
% Assign data
eval([filenames{j}, '.time = Data.data(:,1)./1000000;']); % Converted in seconds
eval([filenames{j}, '.values = Data.data(:,2);']);
% Let's avoid data corruption
clear Data
end
% Housekeeping #2
clear filenames addresses j
% Save data struct
save(test_name, '-regexp', '^((?!name).)*$')
现在我的问题
在研究信息并帮助编写上述代码时,我经常发现人们对eval()
的使用不满意:为什么会如此?在上述情况下,我可以避免吗?
由于
修改
正如@wakjah所建议的,我测试了containers.Map()
方法。遗憾的是不适合我们的需求,因为此时需要一个键列表并且访问数据并不完全友好(记住我有~2600个变量,意味着至少有相同数量的键)
至于@Dennis Jaheruddin所提出的问题,数据结构是可用的,并且不会产生任何类型的冲突,即使这些长varnames(假设两个连续.
之间的每个名称*小于63个字符长)
*我对没有使用更好的技术术语表示歉意
答案 0 :(得分:4)
Mathworks上的this页面:
虽然eval功能非常强大且灵活,但它并不总是编程问题的最佳解决方案。与使用其他函数或语言结构的代码相比,调用eval的代码通常效率较低,难以读取和调试。 ...
您可以轻松使用括号表示法来完成任务。一个简单的例子:
s = struct();
myFieldName = 'test';
s.(myFieldName) = myFieldValue;
这会将结构test
中的s
字段设置为myFieldValue
。
Loren还有关于这个主题的this博客文章。
编辑:由于您的要求是字段名称长度超过63个字符,因此另一种方法是使用containers.Map
对象。这是一个小例子:
>> m = containers.Map();
>> myFieldName = repmat('abcdefg', [1 10]); % 70 chars long
>> m(myFieldName) = 12345;
>> m(myFieldName)
ans =
12345
答案 1 :(得分:3)
在看到你想要做的事情后,我首先想到的是你做得很奇怪。
变量名超过63个字符基本上是在寻找麻烦。相反,我会推荐以下简单的解决方案:
使用包含两个字段的结构:
这样,您的数据结构更自然,您只需要一个变量用于所有文件。
请注意,值可以是结构或数组,并且不限于单个字符串或数字。
我能想到的唯一真正的缺点是自动完成功能适用于变量名称,但不适用于其内容,但这应该是一个很小的代价。
答案 2 :(得分:0)
您是否考虑过使用genvarname
函数从local_varname
生成有效的唯一变量名称?