3

I am reading from a file in Fortran which has an undetermined number of floating point values on each line (for now, there are about 17 values on a line). I would like to read the 'n'th value on each line to a given floating point variable. How should i go about doing this?

In C the way I wrote it was to read the entire line onto the string and then do something like the following:

for(int il = 0; il < l; il++)
{
    for(int im = -il; im <= il; im++)
        pch = strtok(NULL, "\t ");
}
for(int im = -l; im <= m; im++)
    pch = strtok(NULL, "\t ");
dval = atof(pch);

Here I am continually reading a value and throwing it away (thus shortening the string) until I am ready to accept the value I am trying to read.

Is there any way I can do this in Fortran? Is there a better way to do this in Fortran? The problem with my Fortran code seems to be that read(tline, '(f10.15)') tline1 does not shorten tline (tline is my string holding the entire line and tline1 what i am trying to parse it into), thus I cannot use the same method as I did in my C routine.

Any help?

1
  • Surely there must be some libraries already to do this for you? No need to re-invent the wheel. Commented Feb 6, 2012 at 16:04

3 Answers 3

2

The issue is that Fortran is a record-based I/O system while C is stream-based.

If you have access to a Fortran 2003 compliant compiler (modern versions of gfortran should work), you can use the stream ACCESS specifier to do what you want.

An example can be found here.

Of course, if you were really inclined, you could just use your C function directly from Fortran. Interfacing the two languages is generally simple, typically only requiring a wrapper with a lowercase name and an appended underscore (depending on compiler and platform of course). Passing arrays or strings back and forth is not so trivial typically; but for this example that wouldn't be needed.

Once the data is in a character array, you can read it into another variable as you are doing with the ADVANCE=no signature, ie.

do i = 1, numberIWant
   read(tline, '(F10.15)', ADVANCE="no") tline1
end do

where tline should contain your number at the end of the loop.

Because of the record-based I/O, a READ statement will typically throw out what is after the end of the record. But the ADVANCE=no tells it not to.

Sign up to request clarification or add additional context in comments.

4 Comments

i see that i can open a file with stream access, but i am trying to read these values from a string. is there a way to treat a string as a stream?
You posted you were reading from a file -- how does the data get from the file to the string? Can't you read only what you want from the file, or do you need the entire thing and only portions at certain times?
Using an advance= specifier with an internal file read is not standard conforming.
Quite true; the preferred method of getting this done is to just read in from the file what is needed rather than taking the entire thing and pulling out what is needed.
0

If you know exactly at what position the value you want starts, you can use the T edit descriptor to initiate the next read from that position.
Let's say, for instance, that the width of each field is 10 characters and you want to read the fifth value. The read statement will then look something like the following.

read(file_unit, '(t41, f10.5)') value1

P.s.: You can dynamically create a format string at runtime, with the correct number after the t, by using a character variable as format and use an internal file write to put in this number.
Let's say you want the value that starts at position n. It will then look something like this (I alternated between single and double quotes to try to make it more clear where each string starts and stops):

write(my_format, '(a, i0, a)') "(t", n, ', f10.5)'
read(file_unit, my_format) value1

Comments

0

Alternatively, the string can be generated directly as an output by means of the WRITE statement to strip whatever character is unwelcome:

character(len=12), dimension(  12) :: file_name        ! filename
character(len=24), dimension(  12) :: files            ! directory path + filename
character(len= 8), dimension(  14) :: short            ! stores filename without path & file extension

...

do i=1,m
   files(i)= './debug/emi/'//file_name(i)
   write(short(i),"(a8)")    file_name(i)
end do
call show(io_unit, files, short)
!.. Generates the output
    file #: 1  ./debug/emi/cicle_a2.dat  cicle_a2
    file #: 2  ./debug/emi/cicle_a5.dat  cicle_a5

2 Comments

I do not really understand the connection between this answer and the question. The code probably answers some question, but likely not this one. Perhaps it is a reaction to one of the answers? I suggest taking the tour to see how this site is used.
You are right, my apologies, I was only guided by the title (parsing strings in fortran), I needed to handle strings and did not see anything useful in the answers. I remembered that using Write as output converts from real to string or vice versa, chopping characters, etc. It's very flexible and I thought it might be useful. No time for a site tour, ignore the post. Last comment, why stil refer to fortran in upper case?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.