1
votes

I'm reading fixed-width (9 characters) data from a text file using textscan. Textscan fails at a certain line containing the string:

'   9574865.0E+10  '

I would like to read two numbers from this:

957486 5.0E+10

The problem can be replicated like this:

dat = textscan('   9574865.0E+10  ','%9f %9f','Delimiter','','CollectOutput',true,'ReturnOnError',false);

The following error is returned:

Error using textscan
Mismatch between file and format string.
Trouble reading floating point number from file (row 1u, field 2u) ==> E+10

Surprisingly, if we add a minus, we don't get an error, but a wrong result:

dat = textscan('  -9574865.0E+10  ','%9f %9f','Delimiter','','CollectOutput',true,'ReturnOnError',false);

Now dat{1} is:

    -9574865           0

Obviously, I need both cases to work. My current workaround is to add commas between the fields and use commas as a delimiter in textscan, but that's slow and not a nice solution. Is there any way I can read this string correctly using textscan or another built-in (for performance reasons) MATLAB function?

1

1 Answers

0
votes

I suspect textscan first trims leading white space, and then parses the format string. I think this, because if you change yuor format string from

'%9f%9f'

to

'%6f%9f'

your one-liner suddenly works. Also, if you try

'%9s%9s'

you'll see that the first string has its leading whitespace removed (and therefore has 3 characters "too many"), but for some reason, the last string keeps its trailing whitespace.

Obviously, this means you'd have to know exactly how many digits there are in both numbers. I'm guessing this is not desirable.

A workaround could be something like the following:

% Split string on the "dot"
dat = textscan(<your data>,'%9s%9s',...
    'Delimiter'     , '.',...
    'CollectOutput' , true,...
    'ReturnOnError' , false);

% Correct the strings; move the last digit of the first string to the 
% front of the second string, and put the dot back
dat = cellfun(@(x,y) str2double({y(1:end-1),  [y(end) '.' x]}),  dat{1}(:,2), dat{1}(:,1), 'UniformOutput', false);

% Cast to regular array
dat  = cat(1, dat{:})