How to parse strings character by character?
How to parse strings character by character?
(OP)
One of the more frustrating things when coming from Nice Old FORTRAN(NOF) is input/output. I have text output files from programs like NASTRAN which can vary slightly from version to version. My simple FORTRAN code can parse the text line by line and character by character until I match a key word, then the real program can take over. Another program's text output may have a text header but contain a floating point I want to capture, then have inconsistant row data (inconstant due to poor output routines of the originating code such that one line has 5 floats, the next five more, then two, then five, etc.). I am forcing myself to use Matlab as a general rule these days, but fundamental I/O like this is not obvious (to me anyway).
Has anyone conquered this (and how)???
Has anyone conquered this (and how)???





RE: How to parse strings character by character?
In step by step directions
1) Open the file with textread, and convert to a character array (using char command). Store in a character array named file.
example code: Open a file named 'fortran.dat'
fname = 'fortran.dat'
file = char(textread(deblank(fname),
'%s','delimiter','\n','whitespace',''));
2) Find key lines using strmatch command. A key line is a line with some type of a header, and the data that you want to read is a fixed number of lines from that header.
example code: Find all occurances of the header line "1EIGENVALUES"
eigen_row=strmatch('1EIGENVALUES',file);
3) Determine how many header lines were found via size command.
example code: Determine the number of 1EIGENVALUE headers
ni = size(eigen_row,1);
4) Loop through the header lines with for statement
example code: Loop through header lines
for ii=1:ni
5) Numbers can be read with the str2num command. You need to specifiy how many rows down from the header line, and the column range.
typical code: num = str2num(file(header_row+nlines,start_col:end_col));
example code:
% Start and end of eigenvalues
ic_start = eigen_row(ii)+12;
ic_end = ic_start+mxx(ii)-1;
ic_err = eigen_row(ii)-3;
% Copy data into temp array
eig_lines=file(ic_start:ic_end,:);
% Correct each line for length
eig_lines = my_adjust_eig(eig_lines);
% Read each of the eigenvalue table lines
nlines = size(eig_lines,1);
neig=0;
for iline=1:nlines % Loop over the lines
line=eig_lines(iline,:);
[im_lambda, err] = check_str(line(47:57));
if (im_lambda >= 0)
neig = neig+1;
freq_hz(neig,ii) = check_str(line(71:83));
end
end
6) If needed, use findstr to check for valid data. For fortran, you could check for stars (overflow write)
stars = findstr(str,'*');
if isempty(stars) ~= 0
num = str2num(str);
err = 0;
if length(num)~=1
num = nan;
err=1;
end
else
num = nan;
err=1;
end
Here is a complete program, you should be able to follow it
function read_freq
fname='freq9b.com.out';
[rpm,coll,f_cpm]=readcmrd(fname);
iline=0;
for icase=1:size(f_cpm,2);
% for ifreq=size(f_cpm,1):-1:1
for ifreq=size(f_cpm,1):-1:size(f_cpm,1)
iline=iline+1;
% s=sprintf('%6.4f %4.1f %4.0f', f_cpm(ifreq,icase)/rpm(icase), rpm(icase), coll(icase));
s=sprintf('%5.1f %5.1f %6.4f', coll(icase), rpm(icase), f_cpm(ifreq,icase)/rpm(icase));
ns=size(s,2);
sp(iline,1:ns)=s;
end
iline=iline+1;
end
sp
function [rotor_speed_rpm,coll_deg,freq_cpm] = readcmrd(fname)
file = char(textread(deblank(fname),'%s','delimiter','\n','whitespace',''));
eigen_row=strmatch('1EIGENVALUES',file);
performance_row=strmatch('ROTORCRAFT PERFORMANCE ',file);
mxx_row = strmatch('NUMBER OF STATES, MXX =',file);
mxx=str2num(file(mxx_row,27:30));
ni = size(eigen_row,1);
for ii=1:ni
% Read the rotor speed
rotor_speed_rpm(ii) = str2num(file(performance_row(ii)+11,112:120));
coll_deg(ii) = str2num(file(performance_row(ii)+19,25:35));
% Read the eigenvalues
% Two difficulties in reading eigenvalues
% 1) The initial spaces are skipped, so the location of the number
% depends on how much white space is on that line
% 2) Data with stars in freq, damp, real/sec or imag/sec has to be removed
% 3) Remove data with negative imaginary part
% 4) Print information if an error occurs
% Start and end of eigenvalues
ic_start = eigen_row(ii)+12;
ic_end = ic_start+mxx(ii)-1;
ic_err = eigen_row(ii)-3;
if (strcmp(file(ic_err,1:9),'*** ERROR') == 0)
% Copy data into temp array
eig_lines=file(ic_start:ic_end,:);
% Correct each line for length
eig_lines = my_adjust_eig(eig_lines);
% Read each of the eigenvalue table lines
nlines = size(eig_lines,1);
neig=0;
for iline=1:nlines % Loop over the lines
line=eig_lines(iline,:);
[im_lambda, err] = check_str(line(47:57));
if (im_lambda >= 0)
neig = neig+1;
freq_hz(neig,ii) = check_str(line(71:83));
end
end
else
end
end
freq_cpm = freq_hz*60;
function lines2 = my_adjust_eig(lines1)
% The last character in each line is in column 127
nlines = size(lines1,1);
for iline=1:nlines
sp = findstr(lines1(iline,:),' ');
lastchr = size(lines1,2);
csp = size(sp,2);
while (lastchr == sp(csp))
lastchr = lastchr-1;
csp=csp-1;
end
fchar=121;
if((lines1(iline,lastchr)== 'n') == 1)
lines2(iline,1:fchar-lastchr-12) = ' ';
lines2(iline,fchar-lastchr-12+1:fchar-12) = lines1(iline,1:lastchr);
lines2(iline,fchar-12+1:fchar) = ' ';
else
lines2(iline,1:fchar-lastchr) = ' ';
lines2(iline,fchar-lastchr+1:fchar) = lines1(iline,1:lastchr);
end
end
function [num, err] = check_str(str);
stars = findstr(str,'*');
if isempty(stars) ~= 0
num = str2num(str);
err = 0;
if length(num)~=1
num = nan;
err=1;
end
else
num = nan;
err=1;
end
RE: How to parse strings character by character?