WatcherOfAll
WatcherOfAll

Reputation: 21

Variable format statement when porting from Intel to GNU gfortran

Suppose I'm trying to write out a CSV file header that looks like this:

STRING1     2001,     2002,     2003,     2004,

And some variable-format Fortran90 code that does this is

INTEGER X<Y
X=2001
Y=2004
WRITE(6,'(A,(999(5X,I4,",")))') ' STRING1',(y,y=X,Y)

The "999" repeats the (5X,I4,",") format structure as many times as it needs to (up to 999 times, at least) to complete. Assume X and Y are subject to change and therefore the number of loop iterations may also change.

But if I want the header to look like this, with an additional string on the end of the sequence, like

STRING1     2001,     2002,     2003,     2004, STRING2

...I have tried adding another A toward the end of the format string, but that repeated variable format structure apparently doesn't know that it needs to "escape" when the integers are done with and so it errors out.

I can work around this by including 'ADVANCE="no"' in the format string and printing the second string using a new WRITE statement to get what I fundamentally want, but is there a way I can do this all with a single format structure?

[NOTE: no angle-bracket answers please; this is for GNU gfortran, which doesn't support that extension]

Upvotes: 2

Views: 1264

Answers (3)

Steve Lionel
Steve Lionel

Reputation: 7267

C'mon folks, get with the program!

This is standard Fortran 2008:

WRITE(6,'(A,*(5X,G0,:,","))') ' STRING1',(y,y=X,Y), ' STRING2'

I am fairly sure that gfortran supports the "indefinite group repeat count". G format was extended in Fortran 2008 to support any intrinsic data type, and a width of zero means "minimum number of characters." The colon is a F77 feature that stops the trailing comma from being emitted.

With this, ifort gives me:

 STRING1     2001,     2002,     2003,     2004,      STRING2

FWIW, I am not happy with your reuse of y as the loop control variable, since this is NOT a statement entity and will get set to 2005 at the end of the loop. Use a separate variable, please!

Upvotes: 5

Matt P
Matt P

Reputation: 2347

It's a shame that the variable-format extension isn't standard. Since it isn't, most people recommend the approach shown by @anonymous. That is, instead of using <N>, you first convert the integer into a string using an internal-write statement. This string representation of N is then inserted within the format expression to be used in the write or print statements.1

Alternatively, you could convert the numerical values from the array into a string.2 It's also pretty straightforward. In the example below, I've shown both of these approaches.

program writeheader
    implicit none
    character(len=80) :: string1, string2, string3, fmt, num
    integer, dimension(10) :: array
    integer :: x,y,len
continue
    string1 = "begin"
    string3 = "end"
    array = [1:10]
    x = 3
    y = 7

    !! Method 1: Convert the variable number of values into a string, then use it
    !! to create the format expression needed to write the line.
    write(num, "(i)") y - x + 1
    fmt = "(a,', ',(" // trim(adjustl(num)) // "(i0:', ')), a)"
    print fmt, trim(string1), array(x:y), trim(string3)

    !! Method 2: Convert the desired range of array values into a character string.
    !! Then concat, and write the entire line as a string.
    write(string2, "(*(', ',i0))" ) array(x:y)
    len = len_trim(string2) + 1
    print "(a)", trim(string1) // string2(1:len) // trim(string3)

end program writeheader

In either case shown in the example, the output looks like: begin, 3, 4, 5, 6, 7, end


1 If I can find it, I'll add a link to a nice solution here on SO that created a function to generate the format expression.

2 I've used the array bounds directly here, as an alternative to implied do-loops.

Upvotes: 1

anonymous
anonymous

Reputation: 11

program test
 character(len=20)      ::  N_number
 integer                ::  X,Y 
 X=2001
 Y=2004
 write(N_number,*) Y-X+1
 write(6,'(A,('//TRIM(N_number)//'(5X,I4,","))A)') ' STRING1',(y,y=X,Y),' STRING2'
end program test

Upvotes: 1

Related Questions