在 Fortran 中解析随机 "String + Integers"
Parse random "String + Integers" in Fortran
假设我要解析以下字符串:
"Compute the sum of (integer) and (integer)" 在 Fortran 90 中,我不知道其中的整数有多大。可以是3,也可以是30万。
据我所知,FORMAT 语句没有为在 运行 时推断整数大小留出空间。为小至 3 的数字选择一个太大的尺寸,比如 i5,然后程序崩溃。
我最好怎么做?
如果编译时知道整数在字符串中的位置(例如第 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
假设我要解析以下字符串:
"Compute the sum of (integer) and (integer)" 在 Fortran 90 中,我不知道其中的整数有多大。可以是3,也可以是30万。
据我所知,FORMAT 语句没有为在 运行 时推断整数大小留出空间。为小至 3 的数字选择一个太大的尺寸,比如 i5,然后程序崩溃。
我最好怎么做?
如果编译时知道整数在字符串中的位置(例如第 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