How to convert string with complex numbers to matrix

Hi everyone!
I have read matrix from the text file and got string like this:
A= 5+6i 3-2i 1-i @ 4+i 2-0.2i 2.5-1.3i @
where @ means it's new row
So I need to write it like this:
A =
5+6i 3-2i 1-i
4+i 2-0.2i 2.5-1.3i
I use this code:
atLocation = find(A=='@');
trimmedString = strtrim(A(1:atLocation-1))
numNumbers = 1+sum(trimmedString==' ')
out = reshape(str2double(regexp(A,'\d*','match')), numNumbers,[])'
But this is working only for numbers. So, when I try this code with complex number it is not working.
If anyone knows where is the problem help me please.

 Accepted Answer

E.g. simple code assuming no blanks in the numbers,
S = '5+6i 3-2i 1-i @ 4+i 2-0.2i 2.5-1.3i @'
S(S=='@') = ';';
x = find(S=='=',1);
if( isempty(x) )
x = 0;
end
eval([S(1:x) '[' S(x+1:end) ']'])
ans =
5.0000 + 6.0000i 3.0000 - 2.0000i 1.0000 - 1.0000i
4.0000 + 1.0000i 2.0000 - 0.2000i 2.5000 - 1.3000i

2 Comments

Thank you so much for your help..it's working perfectly fine :)
Yes the evil eval ... I am quite familiar with the problems associated with over-relying on eval in code, and accept your admonition. But see per isakson's problems with textscan. "Poor" code that works is better than inbuilt code that doesn't work. It was not obvious to the casual or experienced user that the input string would need to be "fixed" before textscan would work properly. Good thing he checked and discovered this feature.

Sign in to comment.

More Answers (3)

R2013b - Replacing 1-i by 1-1i makes it possible to read the string with textscan
>> str = '5+6i 3-2i 1-1i @ 4+1i 2-0.2i 2.5-1.3i @';
>> cac = textscan( str, '%f', 'Delimiter' , {'@',' '} ...
, 'MultipleDelimsAsOne' , true ...
, 'CollectOutput' , true );
>> transpose( reshape( cac{:}, 3,[] ) )
ans =
5.0000 + 6.0000i 3.0000 - 2.0000i 1.0000 - 1.0000i
4.0000 + 1.0000i 2.0000 - 0.2000i 2.5000 - 1.3000i
&nbsp
Misleading test replaced. (It is not possible to overstrike.)
Test of reading 1-i
str = '5+6i 1-i 2.5-1.3i';
cac = textscan( str, '%f', 'CollectOutput', true );
cac{:}
displays
ans =
5.0000 + 6.0000i
1.0000 + 0.0000i
textscan halts reading after 1-i and the displays it as 1.0000 + 0.0000i. The third value is not read. This honors the documentation
Valid forms for a complex number are: ±<real>±<imag>i|j Example: 5.7-3.1i
which I had to read twice to understand. textscan halts when it encounters text, which doesn't match the format specification.
&nbsp
A better, i.e. easier to understand, solution (inspired by Stephen Cobeldick)
str = '5+6i 3-2i 1-1i @ 4+1i 2-0.2i 2.5-1.3i @';
cac = textscan( str, '%f%f%f@', 'CollectOutput', true );
cac{:}
ans =
5.0000 + 6.0000i 3.0000 - 2.0000i 1.0000 - 1.0000i
4.0000 + 1.0000i 2.0000 - 0.2000i 2.5000 - 1.3000i

2 Comments

I really don't know why your first code gives the wrong result. But I like this code inspired by Stephen Cobeldick, I don't need to fix my code and it's working perfectly fine. Thank you for doing this.
"I don't need to fix my code" &nbsp The documentation of textscan says:
Valid forms for a complex number are: ±<real>±<imag>i|j
thus 1-i is not allowed. I guess, to honor this rule it will save you trouble in the future.

Sign in to comment.

You can use textscan to convert complex numbers in a string to numeric values:
>> S = '5+6i 3-2i 1-i @ 4+i 2-0.2i 2.5-1.3i @';
>> T = regexprep(S,'(+|-)i','$11i');
>> C = textscan(T,'%f%f%f@', 'CollectOutput',true);
>> C{1}
ans =
5 + 6i 3 - 2i 1 - 1i
4 + 1i 2 - 0.2i 2.5 - 1.3i

4 Comments

Well, this is good idea, although it was not obvious to me that I first had to fix my code. But I agree that textscan is a lot better than eval. Thank you so much for helping me.
Admonition to not use eval accepted (see my comment above).
That being said, this particular textscan solution assumes a certain size for the input (3 complex numbers per row). If you don't get exactly that on the input, the code as shown above can give an answer that does not match the input with no message or warning.
The eval solution above, bad as it is, will at least either give an answer that matches the size of the input if all the rows are consistent in number, or throw an error (e.g., vertcat) if the number of elements per row does not match up. I.e., the advantage of the eval is that it is more of a WYSIWYG solution without relying on background algorithms that may or may not parse things as expected ... it gets parsed just like you would expect if you typed it into the command line. E.g., these examples
S = '5+6i 3 -2i 1-i @ 4+i 2-0.2i 2.5-1.3i @'; % inadvertent blank
S = '5+6i 3-2i 1-i @ 4+i 2-0.2i 2.5-1.3i 4+3i @'; % extra value 2nd row
eval throws an error in both of these cases. Not trying to say eval is necessarily better here, but just pointing out that parsing input can be tricky, even for inbuilt functions, and any help one can get with potential parsing problems I would gladly accept. In this case, I might even do both solutions and compare them to see if anything looks amiss before using the result downstream.
It is fairly easy to create a textscan-based solution that does not depend on knowng the number of elements per row in advance:
>> S = '5+6i 3-2i 1-i @ 4+i 2-0.2i 2.5-1.3i @';
>> T = regexprep(S,{'(+|-)i','@'},{'$11i',' '});
>> C = textscan(T,'%f');
>> reshape(C{1},[],sum(S=='@')).'
ans =
5 + 6i 3 - 2i 1 - 1i
4 + 1i 2 - 0.2i 2.5 - 1.3i
OK, so if you work hard enough you can coax regexprep / textscan to more closely mimic the parsing that eval does (which is where this is really headed, right?). But again this latest solution doesn't catch all of the number-of-row-element errors. E.g.,
S = '5+6i @ 3-2i 1-i @ 4+i 2-0.2i 2.5-1.3i @'
So then you can create an even more elaborate regexprep / textscan solution, and we can go on and on for what types of errors to check for and catch, how much you trust the input, etc etc. But this is not where I think this discussion should be headed.
Now, any input parsing scheme can probably be fooled, and I am not trying to unduly knock the regexprep / textscan solution(s). (e.g., eval will fail for 1-i if there is a variable named i in the workspace that is not sqrt(-1)). In fact, I think the regexprep / textscan solutions are quite good and am glad you introduced them in this thread. But seriously, I think using eval in this situation, at least as a check against the regexprep / textscan solution, is a perfectly valid use of eval. What is so god awful wrong about comparing a command-line based parsed solution (i.e., eval) against the regexprep / textscan solution to look for parsing errors? I am certainly not going to turn my nose up at a valid independent check of a parsing routine I wrote just because it uses the eval function.

Sign in to comment.

Hum, both solutions seem convoluted to me. What is wrong with:
S = '5+6i 3-2i 1-i @ 4+i 2-0.2i 2.5-1.3i @';
A = str2num(regexprep(S, '@', '\n'))

2 Comments

An eval call is hidden inside of str2num. Indeed the first line of the description is a box that reads: " Note str2num uses the eval function to convert the input argument. Side effects can occur if the string contains calls to functions. Using str2double can avoid some of these side effects."
As the OP states that "read matrix from the text file", then using str2num would:
  1. allow arbitrary code to be executed, as whatever code is in the datafile will be executed.
  2. still have all of the disadvantages of using eval, e.g. more difficult debugging when called from other functions, etc.
Yes, str2num uses eval. So what? At the end of the day, either the expression evaluates to the matrix and str2num returns a value, or it doesn't and str2num issues an error.
As for debugging, I'm sorry but one line of code is going to be much easier to debug and understand than your three lines with a fairly complex reshape.

Sign in to comment.

Categories

Asked:

on 20 Mar 2015

Edited:

on 22 Mar 2015

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!