如何准确输出从FORTRAN READ语句读入的内容?

时间:2011-03-10 17:51:51

标签: arrays io fortran

考虑这个程序,

      PROGRAM FOO

      CHARACTER(LEN=25) :: INP
      CHARACTER(LEN=50) :: C

      INP = 'The quick brown fox ...'

      READ (INP, '(A)') C
      WRITE (*, '(''['', A, '']'')') C

      STOP
      END

输出52个字符,

[The quick brown fox ...                           ]

我希望它能输出放入READ数组的C语句,而不是C缓冲区中的所有额外空格。

在上述情况下,我希望输出为[The quick brown fox ...],或者(A5)用作(A)语句的格式而不是READ ,那么我希望输出为[The q]

我希望看到READ语句

中使用的任意格式的结果

我该怎么做?

更新

由于看起来这是不可能的直接,是否可以用一些深奥的字符(即~)预先填充字符变量,然后用READ语句覆盖?

到目前为止,我的尝试似乎被Fortran READ声明所覆盖,即

      PROGRAM FOO

      CHARACTER(LEN=50) :: INP
      CHARACTER(LEN=50) :: C

      C = REPEAT('~', 50)
      INP = 'The quick brown fox ...'

      READ (INP, '(TR50, A1)') C
      WRITE (*, '(''['', A, '']'')') C

      STOP
      END

! Outputs [<50 blanks>] rather than [<50 tildas>] or [ <49 tildas>]
! which would tell me if Fortran always reads a number of characters 
! equal to the specified width or never reads any characters beyond
! the end of the record

! n.b. I am interested in actual output for individual platforms, 
! not what the spec says

4 个答案:

答案 0 :(得分:4)

普通的Fortran字符串是固定长度的,并在末尾用空格填充。因此,您无法通过稍后检查字符串来判断输入的时间长度,或者判断是否已读取尾随空白或填充以扩展字符串。这是非常基础的。它与其他语言不同,例如使用终结符。也许它是原始的,但另一方面缓冲区溢出是不可能的。

现在有四种方法可以在Fortran中使用可变长度字符串。多年来,ISO_VARYING_STRING模块一直有ISO标准。这个模块有开源实现。你“调用GET”来读取一个字符串并“调用PUT_LINE”来编写它。虽然这个模块不受欢迎,但我发现它运作良好。

最近的替代方案(Fortran 2003的一个功能)是可分配的缩放器。对于可变长度字符串的使用,我不那么熟悉了,直到最近它还得到了少数编译器的支持。在Web上,声明的语法是:

CHARACTER(LEN=:), ALLOCATABLE :: S

答案 1 :(得分:1)

如果您需要消除字符串末尾的空格,可以使用trim函数:

program foo

    character(len=24) :: inp
    character(len=50) :: c

    inp = 'The quick brown fox ...'
    read (inp, '(A5)') c
    write (*, '(''['',A,'']'')') trim(c)
    read (inp, '(A)') c
    write (*, '(''['',A,'']'')') trim(c)
end program foo

打印

[The q]
[The quick brown fox ...]

修改:如评论中所述,如果您要截断字符串中所读取的字符数,并且知道它的长度(例如,在A5中键入格式字符串)您只需选择子字符串:

read(inp, '(A5)') c
write (*, '(''['',A,'']'')') c(1:5)

适用于您希望打印空间的A4的情况。如果希望长度变化,可以存储格式字符串。在长度为4的情况下,这就像

character(len=10) :: fmt
fmt = '(A4)'
read(inp, fmt) c

然后,您可以使用整数变量构造fmt,并使用相同的整数变量作为字符串切片中的索引。

答案 2 :(得分:1)

我遇到了完全相同的问题:我必须从文件中读取行,这些行有时会留下需要保留的空白以保持程序运行,这需要某些空白。

发现使用ISO_VARYING_STRING扩展可以正常运行,但速度上对我简单且效率低下的解决方案没有任何好处:

subroutine stringread(rcache,l)
implicit none
integer :: i,l, ierr
character(80) :: rcache
l=0
do i=1,81
    read(20,'(A1)',advance='NO',iostat=ierr) rcache(i:i)
    if (ierr.ne.0) exit
    l=i
end do
write(30, '(A)') rcache(1:l)
end subroutine stringread

只需将char中的文件char行读入字符串,直到出现错误(行尾)。同时读取的字符数用l计算,所以我可以用rcache(1:l)输出我读到的内容。

与使用ISO_VARYING_STRING的优雅解决方案相比,该解决方案看起来可能看起来非常难看,但令人惊讶的是,对于大文件而言没有速度劣势。

答案 3 :(得分:0)

保留预期尾随空白的可能解决方案是将字符串与nul字符连接起来:

  PROGRAM FOO

  CHARACTER(LEN=25) :: INP
  CHARACTER(LEN=50) :: C

  INP = 'The quick brown fox ...'//CHAR(0)

  READ (INP, '(A)') C

  I=1
  DO
    IF (I.EQ.LEN(C).OR.C(I:I).EQ.CHAR(0)) EXIT
    I=I+1
  ENDDO
  WRITE (*, '(''['', A, '']'')') C(1:I)

  STOP
  END