我正在试图想出一个小解析器来读取包含算法参数的.txt文件,所以每次更改参数时我都不必重新编译它。该应用程序是通过编码器从.m生成的C代码,遗憾的是禁止我使用大量方便的matlab噱头。
到目前为止,这是我的代码:
% read textfile
string = readfile(filepath);
% do fancy rearranging
linebreaks = zeros(size(string));
equals = zeros(size(string));
% find delimiters
for n=1:size(string,2)
if strcmp(string(n),char(10))
linebreaks(n) = 1;
elseif strcmp(string(n), '=')
equals(n) = 1;
end
end
% write first key-value pair
idx_s = find(linebreaks);idx_s = [idx_s length(string)];
idx_e = find(equals);
key = string(1:idx_e(1)-1);
value = str2double(string(idx_e(1)+1:idx_s(1)-1));
parameters.(key) = value;
% find number of parameters
count = length(idx_s);
% write remaining key-value pairs
for n=2:count
key = string(idx_s(n-1)+1:idx_e(n)-1);
value = str2double(string(idx_e(n)+1:idx_s(n)-1));
parameters.(key) = value;
end
问题在于,看似编码器不支持parameters.(key) = value
等结构的动态字段名。
我有点不知道我是怎么想出一个参数结构来保存我所有的键值对而不用硬编码。如果键的名称没有动态链接到参数文件(如果添加/删除参数,则需要更多手动工作等),这有点(但不完全)会失败。如果有人知道如何解决这个问题,我将非常感激。
答案 0 :(得分:1)
正如您所说,Coder在MATLAB代码中不允许使用结构的动态字段名。我之前遇到的情况与你的情况非常相似,以及我如何处理它。
首先,我们可以列出一些Coder允许的好工具。我们被允许拥有类(值或句柄),这可能非常方便。此外,如果我们使用coder.varsize
来专门指定数据,我们就可以拥有可变大小的数据。如果我们愿意,我们也可以在switch语句中使用字符串值。但是,我们不能将coder.varsize用于类中的属性,但如果愿意,可以使用varsized持久变量。
我在你的案例中做的是创建一个句柄类来存储和检索值。以下示例非常基本,但可以工作并可以扩展。如果在方法中使用了持久变量,您甚至可以为数据创建一个varsized分配存储,但在我的示例中,它是一个属性,并且它可以存储的值的数量有限。
classdef keyval < handle %# codegen
%KEYVAL A key and value class designed for Coder
% Stores an arbitrary number of keys and values.
properties (SetAccess = private)
numvals = 0
end
properties (Access = private)
intdata
end
properties (Constant)
maxvals = 100;
maxkeylength = 30;
end
methods
function obj = keyval
%KEYVAL Constructor for keyval class
obj.intdata = repmat(struct('key', char(zeros(1, obj.maxkeylength)), 'val', 0), 1, obj.maxvals);
end
function result = put(obj, key, value)
%PUT Adds a key and value pair into storage
% Result is 0 if successful, 1 on error
result = 0;
if obj.numvals >= obj.maxvals
result = 1;
return;
end
obj.numvals = obj.numvals + 1;
tempstr = char(zeros(1,obj.maxkeylength));
tempstr(1,1:min(end,numel(key))) = key(1:min(end, obj.maxkeylength));
obj.intdata(obj.numvals).key = tempstr;
obj.intdata(obj.numvals).value = value;
end
function keystring = getkeyatindex(obj, index)
%GETKEYATINDEX Get a key name at an index
keystring = deblank(obj.intdata(index).key);
end
function value = getvalueforkey(obj, keyname)
%GETVALUEFORKEY Gets a value associated with a key.
% Returns NaN if not found
value = NaN;
for i=1:obj.numvals
if strcmpi(keyname, deblank(obj.intdata(i).key))
value = obj.intdata(i).value;
end
end
end
end
end
此类实现简单的键/值添加以及查找。关于它,有几点需要注意。首先,它在作业中非常小心,以确保我们不会超出整体存储空间。其次,它使用deblank
清除字符串存储中必需的尾随零。在这种情况下,不允许结构中的字符串具有不同的长度,因此当我们在其中放置一个键字符串时,它需要与尾随空值完全相同的长度。 Deblank为调用函数清除了这一点。
常量属性分配我们在存储阵列中允许的总空间量。显然,这些可以增加,但不能在运行时增加。
在MATLAB命令提示符下,使用此类如下所示:
>> obj = keyval
obj =
keyval with properties:
numvals: 0
>> obj.put('SomeKeyName', 1.23456)
ans =
0
>> obj
obj =
keyval with properties:
numvals: 1
>> obj.put('AnotherKeyName', 34567)
ans =
0
>> obj
obj =
keyval with properties:
numvals: 2
>> obj.getvalueforkey('SomeKeyName')
ans =
1.2346
>> obj.getkeyatindex(2)
ans =
AnotherKeyName
>> obj.getvalueforkey(obj.getkeyatindex(2))
ans =
34567
如果需要一个完全可变的存储区域,使用带有coder.varsize的持久变量会起作用,但这会限制将此类用于单个实例。持久变量很好,但你只能得到其中一个。如上所述,您可以在程序的许多不同位置使用此类来进行不同的存储。如果使用持久变量,则只能使用一次。
如果你知道一些关键名称并且稍后使用它们来确定功能,请记住你可以在MATLAB中打开字符串,这可以在Coder中使用。