Andy K.
Andy K.

Reputation: 365

Format statement with unknown columns

I am attempting to use fortran to write out a comma-delimited file for import into another commercial package. The issue is that I have an unknown number of data columns. My output needs to look like this:

a_string,a_float,a_different_float,float_array_elem1,float_array_elem2,...,float_array_elemn

which would result in something that might look like this:

L1080,546876.23,4325678.21,300.2,150.125,...,0.125
L1090,563245.1,2356345.21,27.1245,...,0.00983

I have three issues. One, I would prefer the elements to be tightly grouped (variable column width), two, I do not know how to define a variable number of array elements in the format statement, and three, the array elements can span a large range--maybe 12 orders of magnitude. The following code conceptually does what I want, but the variable 'n' and the lack of column-width definition throws an error (of course):

WRITE(50,900) linenames(ii),loc(ii,1:2),recon(ii,1:n)
900 FORMAT(A,',',F,',',F,n(',',F))

(I should note that n is fixed at run-time.) The write statement does what I want it to when I do WRITE(50,*), except that it's width-delimited.

I think this thread almost answered my question, but I got quite confused: SO. Right now I have a shell script with awk fixing the issue, but that solution is...inelegant. I could do some manipulation to make the output a string, and then just write it, but I would rather like to avoid that option if at all possible.

I'm doing this in Fortran 90 but I like to try to keep my code as backwards-compatible as possible.

Upvotes: 2

Views: 2111

Answers (2)

Bálint Aradi
Bálint Aradi

Reputation: 3812

In order to make sure that no space occurs between the entries in your line, you can write them separately in character variables and then print them out using theadjustl() function in fortran:

program csv
  implicit none

  integer, parameter :: dp = kind(1.0d0)
  integer, parameter :: nn = 3
  real(dp), parameter :: floatarray(nn) = [ -1.0_dp, -2.0_dp, -3.0_dp ]
  integer :: ii
  character(30) :: buffer(nn+2), myformat

  ! Create format string with appropriate number of fields.
  write(myformat, "(A,I0,A)") "(A,", nn + 2, "(',',A))"
  ! You should execute the following lines in a loop for every line you want to output
  write(buffer(1), "(F20.2)") 1.0_dp  ! a_float
  write(buffer(2), "(F20.2)") 2.0_dp  ! a_different_float
  do ii = 1, nn
    write(buffer(2+ii), "(F20.3)") floatarray(ii)
  end do
  write(*, myformat) "a_string", (trim(adjustl(buffer(ii))), ii = 1, nn + 2)

end program csv

The demonstration above is only for one output line, but you can easily write a loop around the appropriate block to execute it for all your output lines. Also, you can choose different numerical format for the different entries, if you wish.

Upvotes: 1

agentp
agentp

Reputation: 6989

the format close to what you want is f0.3, this will give no spaces and a fixed number of decimal places. I think if you want to also lop off trailing zeros you'll need to do a good bit of work.

The 'n' in your write statement can be larger than the number of data values, so one (old school) approach is to put a big number there, eg 100000. Modern fortran does have some syntax to specify indefinite repeat, i'm sure someone will offer that up.

----edit the unlimited repeat is as you might guess an asterisk..and is evideltly "brand new" in f2008

Upvotes: 2

Related Questions