How to convert string with complex numbers to matrix

15 Ansichten (letzte 30 Tage)
Lolipop
Lolipop am 20 Mär. 2015
Bearbeitet: Stephen23 am 22 Mär. 2015
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.

Akzeptierte Antwort

James Tursa
James Tursa am 20 Mär. 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 Kommentare
Lolipop
Lolipop am 20 Mär. 2015
Thank you so much for your help..it's working perfectly fine :)
James Tursa
James Tursa am 20 Mär. 2015
Bearbeitet: James Tursa am 20 Mär. 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.

Melden Sie sich an, um zu kommentieren.

Weitere Antworten (3)

per isakson
per isakson am 20 Mär. 2015
Bearbeitet: per isakson am 21 Mär. 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 Kommentare
Lolipop
Lolipop am 20 Mär. 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 am 20 Mär. 2015
Bearbeitet: per isakson am 21 Mär. 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.

Melden Sie sich an, um zu kommentieren.


Stephen23
Stephen23 am 20 Mär. 2015
Bearbeitet: Stephen23 am 21 Mär. 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 Kommentare
Stephen23
Stephen23 am 21 Mär. 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 am 21 Mär. 2015
Bearbeitet: James Tursa am 21 Mär. 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.

Melden Sie sich an, um zu kommentieren.


Guillaume
Guillaume am 21 Mär. 2015
Bearbeitet: Guillaume am 21 Mär. 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 Kommentare
Stephen23
Stephen23 am 21 Mär. 2015
Bearbeitet: Stephen23 am 22 Mär. 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 am 21 Mär. 2015
Bearbeitet: Guillaume am 21 Mär. 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.

Melden Sie sich an, um zu kommentieren.

Kategorien

Mehr zu Data Type Conversion finden Sie in Help Center und File Exchange

Community Treasure Hunt

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

Start Hunting!

Translated by