2013-03-28 68 views
2

我寫了一個腳本,可以幫助我在Matlab中手動導入測試期間記錄的數據。可以避免`eval()`嗎? (在運行時分配變量名稱)

每個測試運行都會在.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():爲什麼會這樣呢?在上述情況下,我能避免嗎?

由於

EDIT 如所建議的通過@wakjah,我測試了containers.Map()方法。不幸的是不適合我們的需要,因爲那時需要一個密鑰列表,並且訪問數據不是很友好(記住我有〜2600個變量,意味着至少有相同數量的密鑰)

至於@Dennis Jaheruddin提出的要求是,數據結構是可用的並且不會產生任何類型的衝突,即使使用這些長的varnames(假設兩個連續的.之間的每個名稱*小於63個字符長)

*我很抱歉沒有使用更好的技術術語

回答

3

this頁面上Mathworks:

儘管eval函數非常強大且靈活,但並不總是解決編程問題的最佳解決方案。與使用其他函數或語言結構的代碼相比,調用eval的代碼通常效率更低,更難以閱讀和調試。 ...

您可以很容易地使用圓括號表示法來完成您的任務。一個簡單的例子:

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

這將在struct s設置test字段myFieldValue

也有this Loren在這個主題的博客文章。

編輯:由於您的要求是字段名稱長度超過63個字符,另一種方法是使用containers.Map對象。這裏有一個小例子:

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

ans = 

     12345 
+0

不幸的是,這個解決方案創建了一個不同的問題:63個字符的限制被強加在完整的'filenames {j}'上(在某些情況下達到180個字符),而'eval()'我必須只關心'local_varname'。另外,如果'filenames {j}'包含一個'.'(對我來說總是如此),它會返回一個錯誤 – Federico

+0

如何避免使用'eval'?我只是試了一下 - 當你的字段名長於63個字符時,MATLAB會發出警告,不管你是否使用'eval'。也許我誤解了你......無論如何,如果你確實需要長時間的域名,你是否考慮過使用['containers.Map'](http://www.mathworks.co.uk/help/matlab/map- containers.html)? – wakjah

+0

實施例:'文件名{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)它抱怨'文件名{1}'太長 – Federico

0

你有使用功能genvarnamelocal_varname產生有效的唯一變量名稱考慮?

+0

是的,但我必須保持與原始程序相同的結構,所以我更喜歡手寫規則,以便我知道與什麼相對應。 – Federico

3

看過你想要做的事情後,我的第一個想法是,你做的很奇怪。

擁有超過63個字符的變量名基本上是在尋求麻煩。相反,我會推薦以下簡單的解決方案:

使用結構有兩個字段:

  • 價值

這樣,你的數據更自然的結構,你只需要一個變量適用於所有文件。


請注意,值可以是結構或數組,並且不限於單個字符串或數字。

我在這裏可以想到的唯一真正的缺點是自動完成工作的變量名稱,但不是他們的內容,但這應該是一個小的代價。

+0

此解決方案的示例代碼位於以下位置:http://stackoverflow.com/a/15439593/931379 – Pursuit

相關問題