How to convert string with complex numbers to matrix

27 views (last 30 days)
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

James Tursa
James Tursa on 20 Mar 2015
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
Lolipop
Lolipop on 20 Mar 2015
Thank you so much for your help..it's working perfectly fine :)
James Tursa
James Tursa on 20 Mar 2015
Edited: James Tursa on 20 Mar 2015
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)

per isakson
per isakson on 20 Mar 2015
Edited: per isakson on 21 Mar 2015
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
Lolipop
Lolipop on 20 Mar 2015
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.
per isakson
per isakson on 20 Mar 2015
Edited: per isakson on 21 Mar 2015
"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.


Stephen23
Stephen23 on 20 Mar 2015
Edited: Stephen23 on 21 Mar 2015
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
Stephen23
Stephen23 on 21 Mar 2015
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
James Tursa
James Tursa on 21 Mar 2015
Edited: James Tursa on 21 Mar 2015
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.


Guillaume
Guillaume on 21 Mar 2015
Edited: Guillaume on 21 Mar 2015
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
Stephen23
Stephen23 on 21 Mar 2015
Edited: Stephen23 on 22 Mar 2015
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.
Guillaume
Guillaume on 21 Mar 2015
Edited: Guillaume on 21 Mar 2015
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.

Community Treasure Hunt

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

Start Hunting!