【问题标题】:Can `eval()` be avoided? (Assign variable name at runtime)可以避免`eval()`吗? (在运行时分配变量名)
【发布时间】:2013-03-28 12:30:16
【问题描述】:

我已经编写了一个脚本,可以省去在 Matlab 中手动导入测试期间记录的数据。

每次测试运行在 .csv 文件中保存大约 2600 个变量,每个文件有 2 个标题行,两列数据,; 是分隔符。

文件名来自监控程序使用的内部 C 结构,因此属于这种类型:foo.bar.another.foo.bar.local_varname#VALUE.csv,我想用它在 Matlab 中重新创建结构,以便仅将其保存在 @ 987654324@文件。

很多时候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 提出的问题,数据结构是可用的并且不会产生任何类型的冲突,即使使用这些长变量名(假设两个连续的. 之间的每个名称* 小于 63 个字符长)

*我很抱歉没有使用更好的技术术语

【问题讨论】:

    标签: matlab eval


    【解决方案1】:

    来自 Mathworks 上的 this 页面:

    虽然 eval 函数非常强大和灵活,但它并不总是解决编程问题的最佳方法。与使用其他函数或语言结构的代码相比,调用 eval 的代码通常效率较低且更难阅读和调试。 ...

    您可以轻松地使用括号符号来完成您的任务。一个简单的例子:

    s = struct();
    myFieldName = 'test';
    s.(myFieldName) = myFieldValue;
    

    这会将结构体s 中的test 字段设置为myFieldValue

    还有 Loren 关于这个主题的 this 博客文章。

    编辑:由于您的要求是字段名称长度超过 63 个字符,另一种方法是使用 containers.Map 对象。这是一个小例子:

    >> m = containers.Map();
    >> myFieldName = repmat('abcdefg', [1 10]); % 70 chars long
    >> m(myFieldName) = 12345; 
    >> m(myFieldName)
    
    ans =
    
           12345
    

    【讨论】:

    • 不幸的是,这个解决方案产生了一种不同的问题:63 个字符的限制被施加在完整的filenames{j} 上(在某些情况下最多 180 个字符)而eval() 我必须只关心local_varname。此外,如果filenames{j} 包含.(对我来说总是这样),它会返回错误
    • eval 如何避免这种情况?我刚刚尝试过 - 当您的字段名称超过 63 个字符时,无论您是否使用 eval 都会发出警告。可能我误会你了……反正如果你真的需要这么长的字段名,你有没有考虑过使用containers.Map
    • 示例:filenames{1} = ABCDE.ABC0.ABCDE.ABC_AA_AA_AAA_00.BBB_BBB_00_BBB_CCCC_ABCDE_ABCDEFGHIJKLMNO_AAAA0.A_ABCDE_CCC_DDDD_EEEEE_AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDDDDDDDD00_DDDD0(153 个字符长)使用eval(),如果我将最后一部分(现在 71 个字符长)缩小到小于 63 个字符,我没有问题,用你的代码1) .s 有一个错误,2) 它抱怨 filenames{1} 太长
    • 啊,好吧。是否有任何特殊原因需要这些成为本地工作区中的变量?如果不是,我肯定会说 Map 是一种更有效且(也许更重要的是)可读的解决方案。
    • 从来没有听说过地图,我去看看。一般来说,我稍后将不得不进行数据后处理(例如,频率分析),是否可以使用 Maps 来完成?
    【解决方案2】:

    看到你想做的事情后,我的第一个想法是你做的很奇怪。

    变量名超过 63 个字符基本上是自找麻烦。相反,我会推荐以下简单的解决方案:

    使用具有两个字段的结构:

    • 文件名
    • 价值

    通过这种方式,您的数据结构更加自然,您的所有文件只需要一个变量。


    注意 value 可以是结构体或数组,不限于单个字符串或数字。

    我能想到的唯一真正的缺点是自动完成功能适用于变量名,但不适用于其内容,但这应该是一个很小的代价。

    【讨论】:

    【解决方案3】:

    您是否考虑过使用函数genvarnamelocal_varname 生成有效的唯一变量名?

    【讨论】:

    • 是的,但是我必须保持与原始程序中相同的结构,所以我更喜欢手写规则,以便我知道什么对应什么。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-24
    • 2019-05-15
    • 1970-01-01
    相关资源
    最近更新 更多