【问题标题】:How to output exactly what is read in from a FORTRAN READ statement?如何准确输出从 FORTRAN READ 语句中读取的内容?
【发布时间】:2011-03-10 17:51:50
【问题描述】:

考虑一下这个程序,

      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 ...                           ]

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

在上述情况下,我希望输出为[The quick brown fox ...],或者在READ 语句使用(A5) 而不是(A) 格式的情况下,那么我希望输出成为[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

【问题讨论】:

    标签: arrays io fortran


    【解决方案1】:

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

    现在有两种方法可以在 Fortran 中使用可变长度字符串。多年来,模块 ISO_VARYING_STRING 一直存在 ISO 标准。该模块有开源实现。您“调用 GET”来读取字符串并“调用 PUT_LINE”来写入它。虽然这个模块并不流行,但我发现它运行良好。

    最近的替代方案(Fortran 2003 的一项功能)是可分配的缩放器。我不太熟悉将它用于可变长度字符串,直到最近它才被少数编译器支持。从网上,声明的语法是:

    CHARACTER(LEN=:), ALLOCATABLE :: S
    

    【讨论】:

    • 啊,你说的是this module吗?
    • ISO/IEC 1539-2 是文档/规范。这是一个实现:fortran.com/iso_varying_string.f95
    • 似乎没有办法将这些字符串与READ 语句一起使用,只有它自己的GET 语句 - 我的代码的目的是测试READ 语句的行为方式各种平台上的各种格式...
    【解决方案2】:

    如果需要消除字符串末尾的空格,可以使用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,并将该整数变量用作字符串切片中的索引。

    【讨论】:

    • 啊,不幸的是,一些读入的字符串可能以空格结尾,即如果在READ 语句中使用(A4),我希望返回[The ],而不是@ 987654330@ ...
    • 感谢您的额外输入,但是在示例中,未使用裸 A 编辑描述符指定宽度。同样在更复杂的情况下——例如格式为(TR5, A4)——读取字符串的宽度不仅仅是A描述符的宽度。我试图尽可能不知道所使用的格式,因为我会自动生成大型注解 Fortran 测试(使用 Python),这些测试输入各种不寻常的 Format 语句以确定各种 Fortran 平台上 Read 语句的行为
    【解决方案3】:

    我遇到了完全相同的问题:我必须从一个文件中读取行,这些行有时有尾随空格,我需要保留这些行以保持程序运行,这需要以某种方式使用这些空格。

    发现使用 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
    

    只需逐个字符地将文件的行读取到字符串中,直到发生错误(行尾)。同时读取的字符以 l 计,所以我可以用 rcache(1:l) 准确地输出我读到的内容。

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

    【讨论】:

      【解决方案4】:

      保留预期尾随空白的可能解决方案是将字符串与 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
      

      【讨论】:

      • 有趣,有点像模拟 C 字符串。不幸的是,例如,如果编辑描述符是A4,那么空字符就不会出现在末尾。
      • 好吧,你知道字符串的长度是I 和输入格式的最小长度,所以在这种情况下A4MIN(4,I)
      猜你喜欢
      • 2012-02-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-05
      • 1970-01-01
      • 2020-03-07
      • 2014-12-29
      • 2014-08-04
      相关资源
      最近更新 更多