2

Say I want to parse the following string:

"Compute the sum of (integer) and (integer)" in Fortran 90, of which I have no way of telling how large the integer will be. It can be 3, just as well as 300,000.

As far as I can tell the FORMAT statement does not leave room for inferring the size of an integer at run-time. Choose a too large size, say i5, for a number as small as 3 however and the program crashes.

How would I best go about this?

0

1 Answer 1

4

If the location of integers in the string is known at compile time (e.g. 5th and 7th words), we can get the integers directly using list-directed read:

character(256) :: line, words( 50 )
integer :: i1, i2

line = "Compute the sum of 3 and 30000, then we get..."

read( line, * ) words( 1 : 7 )   !! get the first seven words from a line
read( words( 5 ), * ) i1         !! convert the 5th and 7th words to integer
read( words( 7 ), * ) i2         !! so that i1 = 3, i2 = 30000

But if the location of integers is not known (e.g. when obtained from user input), things are probably more complicated... I have written some subroutines for this, so if it may seem useful please try it :)

module strmod
contains

subroutine split ( line, words, nw )
    implicit none
    character(*), intent(in)  :: line
    character(*), intent(out) :: words(:)
    integer,      intent(out) :: nw
    character(len(words)) :: buf( size(words) )
    integer :: k, ios

    nw = 0 ; words(:) = ""

    do k = 1, size(words)
        read( line, *, iostat=ios ) buf( 1 : k )
        if ( ios /= 0 ) exit
        nw = k
        words( 1 : nw ) = buf( 1 : nw )
    enddo

endsubroutine

subroutine words_to_ints ( words, ints, ni )
    implicit none
    character(*), intent(in)  :: words(:)
    integer,      intent(out) :: ints(:)
    integer,      intent(out) :: ni
    integer :: k, val, ios

    ni = 0 ; ints(:) = 0

    do k = 1, size(words)
        read( words( k ), *, iostat=ios ) val
        if ( ios /= 0 ) cycle
        ni = ni + 1
        if ( ni > size(ints) ) stop "size(ints) too small"
        ints( ni ) = val
    enddo

endsubroutine

endmodule

program main
    use strmod
    implicit none
    character(80) :: line, words( 50 )  !! works also with size 5 or 7 etc
    integer :: ints( 50 ), nw, ni, k

    line = "Compute the sum of 3 and 30000, then we get 300003 (no!!)"
            !... Note: spaces and commas serve as delimiters. Better to avoid "/".

    call split ( line, words, nw )
    call words_to_ints ( words, ints, ni )

    print *, "Word counts:", nw
    do k = 1, nw
        print *, trim( words( k ) )
    enddo

    print *, "Int counts:", ni
    print *, ints( 1 : ni )
end

Results:

Word counts:          12
Compute
the
sum
of
3
and
30000
then
we
get
300003
(no!!)
Int counts:           3
       3       30000      300003
Sign up to request clarification or add additional context in comments.

Comments

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.