Parse random "String + Integers" in Fortran

时间:2015-10-31 00:00:54

标签: fortran fortran90 fortran95

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?

1 个答案:

答案 0 :(得分:4)

如果在编译时已知字符串中整数的位置(例如第5和第7个字),我们可以使用列表导向的读取直接获取整数:

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

但是如果整数的位置未知(例如从用户输入获得),事情可能会更复杂......我已经为此编写了一些子程序,所以如果看起来有用,请尝试一下:)

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

结果:

Word counts:          12
Compute
the
sum
of
3
and
30000
then
we
get
300003
(no!!)
Int counts:           3
       3       30000      300003