How to convert string with complex numbers to matrix
Show older comments
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
More Answers (3)
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
 
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.
 
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
on 20 Mar 2015
per isakson
on 20 Mar 2015
Edited: per isakson
on 21 Mar 2015
"I don't need to fix my code"   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.
>> 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
Lolipop
on 20 Mar 2015
James Tursa
on 20 Mar 2015
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.
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
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.
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:
- allow arbitrary code to be executed, as whatever code is in the datafile will be executed.
- 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.
Categories
Find more on Data Type Conversion in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!