In a matlab program I have an external parameter file that needs to be read in. Like
a = 1/3
b = 'test'
Currently I use textscan to read this file and use str2num to parse the values of a. However, I read that str2num use eval inside, which is undesirable for safety reason: what if someone made a = 'delete something', and then str2num will execute the string as a side effect. str2double does not work for fractional numbers. Is there any better way to parse 1/3 from external file into matlab?
If you are going to parse input that can only be a simple number or a division, the str2double/str2double approach may be sufficient. However if you want to parse input safely in general, I would recommend restricting the input.
For example like so:
rawString= 'dir+3/5'
safeCharacters = ['0':'9' '+-*/\^eEij. '];
if all(ismember(rawString,safeCharacters))
str2num(junkString)
end
Of course this may filter out some potentially good input like: str2num('rand')
Personally, I'd use str2num (which is based on eval if you read the documentation). However, another option is sym. The Symbolic Math toolbox is based on eval as well of course, but it has input validation to avoid the potential dangers you're worried about. It is very robust and simple to use for what you need:
a = '1/3';
a = double(sym(a))
This also handles converting cell arrays of strings to vectors and matrices gracefully:
a={'1/3','1/33','1/333'; ...
'2/3','2/33','2/333'};
a = double(sym(a))
The following unlikely input will return warnings and an error (and not delete a in memory):
b = 'delete a';
a = double(sym(b))
Thus you may want to use a try/catch statement to gracefully handle cases when a user may provide invalid input:
try
Xs = double(sym(X));
catch err
if strcmp(err.id,'MATLAB:UndefinedFunction')
error('YourFunctionName:UnknownInput','Your helpful message here.');
else
rethrow(err);
end
end
You could equally replace the Xs = double(sym(X)); line with a call to str2num.
You can explicitly search for the backslash with strfind.
if ~isempty(strfind(X, '/'))
% then use str2num
else
% use str2double, and if this returns a NaN, then it is a string
end
Or use strtok to split the string using '/' as a token, and use str2double on all resulting elements.
Related
I want to load an ASCII-file using this syntax:
load('10-May-data.dat')
The returned output variable name should be X10_May_data.
Is there a way to get the variable name in Matlab? If I want to use regular expression to do the translation, how can I do it? For example, put an X before any underscores or digits in the filename and replace any other non-alphabetic characters with underscores.
The who function returns the names of variables in matlab. It also has a built-in regexp for selecting certain items:
X10_May_data = [1 2 3];
save X10_May_data.mat X10_May_data
clear
load X10_May_data.mat
w = who('-regexp','X*')
w =
'X10_May_data'
You can then operate on w{1} to do any substitutions you want. For example, use the strrep function for simple modifications of a string:
newvar = strrep(w{1},'May','latest')
newvar =
X10_latest_data
For more complex modifications, use regexp or regexprep. When you have the new name, you can assign it with eval:
eval([newvar '=' w{1}]) % like typing "X10_latest_data = X10_May_data"
X10_latest_data =
1 2 3
[edit] PS I agree with the comments that eval is usually a bad idea; but sometimes you just need to get something done :) For alternative approaches, see the matlab page on the topic.
I would like to save the output of several evals ( don't know the input of those ) in a file. Now I don't know the tpye of those evals They could be arrays or strings or integer or anything, so I can not really write fprinft(fileID, '%s\n', eval(somethingsomething)); since I don't know what the second parameter should be. Is there a way a for me to save those in a file?
You can save the results of the eval in a local variable and check the resulting type with class(v) and use printf accordingly.
I believe you can just save result of eval with fwrite(), why would you use fprintf?
I'm trying to export a matrix f that is double. My data in f are real numbers in three columns. I want a txt file as an output with the columns separated by tabs. However, when I try the dlmwrite function, just the first column appears as output.
for k = 1:10
f = [idx', firsttime', sectime'];
filename = strcat(('/User/Detection_rerun/AF_TIMIT/1_state/mergedlabels_train/'),(files_train{k,1}),'.lab');
dlmwrite(filename,f,'\t') ;
end
When I use dlmwrite(filename,f,'\t','newline','pc') ; I keep getting an error Invalid attribute tag: \t . I even tried 'tab' instead of '\t' but a similar error appears. Please let me know if you have any suggestions. thank you
This is because you are not calling dlmwrite properly. To specify the delimiter, you must use the delimiter flag, followed by the specific delimiter you want. In your case, you use \t. In other words, you need to do this:
for k = 1:10
f = [idx', firsttime', sectime'];
filename = strcat(('/User/Detection_rerun/AF_TIMIT/1_state/mergedlabels_train/'),(files_train{k,1}),'.lab');
dlmwrite(filename,f,'delimiter','\t') ;
end
BTW, you are using the newline flag with pc, meaning that you are specifying carriage returns that are recognized by a PC. I suggest you leave this out and allow MATLAB to automatically infer this. Only force the newline characters if you know what you're doing.
FWIW, the MATLAB documentation is pretty clear about delimiters and other quirks about the function: http://www.mathworks.com/help/matlab/ref/dlmwrite.html
So I'm reading multiple text files in Matlab that have, in their first columns, a column of "times". These times are either in the format 'MM:SS.milliseconds' (sorry if that's not the proper way to express it) where for example the string '29:59.9' would be (29*60)+(59)+(.9) = 1799.9 seconds, or in the format of straight seconds.milliseconds, where '29.9' would mean 29.9 seconds. The format is the same for a single file, but varies across different files. Since I would like the times to be in the second format, I would like to check if the format of the strings match the first format. If it doesn't match, then convert it, otherwise, continue. The code below is my code to convert, so my question is how do I approach checking the format of the string? In otherwords, I need some condition for an if statement to check if the format is wrong.
%% Modify the textdata to convert time to seconds
timearray = textdata(2:end, 1);
if (timearray(1, 1) %{has format 'MM.SS.millisecond}%)
datev = datevec(timearray);
newtime = (datev(:, 5)*60) + (datev(:, 6));
elseif(timearray(1, 1) %{has format 'SS.millisecond}%)
newtime = timearray;
You can use regular expressions to help you out. Regular expressions are methods of specifying how to search for particular patterns in strings. As such, you want to find if a string follows the formats of either:
xx:xx.x
or:
xx.x
The regular expression syntax for each of these is defined as the following:
^[0-9]+:[0-9]+\.[0-9]+
^[0-9]+\.[0-9]+
Let's step through how each of these work.
For the first one, the ^[0-9]+ means that the string should start with any number (^[0-9]) and the + means that there should be at least one number. As such, 1, 2, ... 10, ... 20, ... etc. is valid syntax for this beginning. After the number should be separated by a :, followed by another sequence of numbers of at least one or more. After, there is a . that separates them, then this is followed by another sequence of numbers. Notice how I used \. to specify the . character. Using . by itself means that the character is a wildcard. This is obviously not what you want, so if you want to specify the actual . character, you need to prepend a \ to the ..
For the second one, it's almost the same as the first one. However, there is no : delimiter, and we only have the . to work with.
To invoke regular expressions, use the regexp command in MATLAB. It is done using:
ind = regexp(str, expression);
str represents the string you want to check, and expression is a regular expression that we talked about above. You need to make sure you encapsulate your expression using single quotes. The regular expression is taken in as a string. ind would this return the starting index of your string of where the match was found. As such, when we search for a particular format, ind should either be 1 indicating that we found this search at the beginning of the string, or it returns empty ([]) if it didn't find a match. Here's a reproducible example for you:
B = {'29:59.9', '29.9', '45:56.8', '24.5'};
for k = 1 : numel(B)
if (regexp(B{k}, '^[0-9]+:[0-9]+\.[0-9]+') == 1)
disp('I''m the first case!');
elseif (regexp(B{k}, '^[0-9]+\.[0-9]+') == 1)
disp('I''m the second case!');
end
end
As such, the code should print out I'm the first case! if it follows the format of the first case, and it should print I'm the second case! if it follows the format of the second case. As such, by running this code, we get:
I'm the first case!
I'm the second case!
I'm the first case!
I'm the second case!
Without knowing how your strings are formatted, I can't do the rest of it for you, but this should be a good start for you.
I'm going to read some function from a Unicode text file in matlab and calculate there answer with my own variables. first i use fopen to read the text file, then what should i do to convert each line of that text file to a function? for example the func.txt contains:
(x^2)-3y
sin(x+z)+(y^6)
and i need to write an m.file which read func.txt and process that like this:
function func1[x,y] = (x^2)-3y
function func2[x,y,z] = sin(x+z)+(y^6)
Preamble: if your final aim is to use those functions in matlab (i.e. evaluate them for some values of x,y,...), I would rather suggest the following approach that looks more robust to me.
In principle, in fact, you don't need to manipulate the file funct.txt to evaluate the functions defined therein.
First problem: each line of your file funct.txt must define an inline function.
Say that the first function (i.e., the first line) of the file funct.txt has been copied into a string str,
str = '(x^2)-3y',
you can obtain a function from it using the command inline:
f1 = inline(str,'x','y');
which gives to you (matlab output)
f1 =
Inline function:
f1(x,y) = (x^2)-3y.
Now you can use f1 just calling it as f1(x,y), for whatever values x,y.
Second problem: you have to parse your file funct.txt to obtain the strings str containing the definitions of your functions. That's easier, you may want to consider the function fgets.
Third problem: the functions in funct.txt may depend on 2,3 (or more?) independent variables. As far as I know there is no easy way to parse the string to discover it. Thus, you may want to define each inline function as depending on all your independent variables, i.e.
f1 = inline('(x^2)-3y','x','y','z');
the variable z will play no active role, by the way. Nonetheless, you need to specify a third dummy parameter when you call f1.