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

发布于 2024-10-21 10:23:45 字数 1416 浏览 3 评论 0原文

考虑这个程序,

      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 数组中的所有额外空间>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

Consider this program,

      PROGRAM FOO

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

      INP = 'The quick brown fox ...'

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

      STOP
      END

This outputs the 52 characters,

[The quick brown fox ...                           ]

I want instead for it to output whatever the READ statement put into the C array and not all the extra space in the C buffer.

In the above case I'd like the output to be [The quick brown fox ...] or in the case where (A5) is used as the format instead of (A) for the READ statement, then I'd like the output to be [The q]

I'd like to see the result for any arbitrary format used int the READ statement

How can I do this?

UPDATE

Since it seems that this is not possible directly, is it possible to pre-populate the character variable with some esoteric character (i.e. ~) and then overwrite with the READ statement?

My attempts so far seem to be overwritten by the Fortran READ statement i.e.

      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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

一花一树开 2024-10-28 10:23:45

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

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

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

CHARACTER(LEN=:), ALLOCATABLE :: S

Normal Fortran strings are fixed length and filled on the end with blanks. So you can't tell how long the input was by examining the string later, or tell whether trailing blanks were read, or filled in to extend the string. This is fairly fundamental. It is a different strategy from some other languages, such as using a terminator character. Perhaps it is primitive, but on the other hand buffer overflows are impossible.

There are now two ways to have variable length strings in Fortran. For some years there has been an ISO standard for a module ISO_VARYING_STRING. There are open source implementations of this module. You "call GET" to read a string and "call PUT_LINE" to write it. While this module has not been popular, I found it to work well.

The more recent alternative (a feature of Fortran 2003) is allocatable scalers. I am less familar with the use of this for variable-length strings, and until recently it was supported by few compilers. From the web, the syntax for the declaration is:

CHARACTER(LEN=:), ALLOCATABLE :: S
迟月 2024-10-28 10:23:45

如果需要消除字符串末尾的空格,可以使用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

prints

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

Edit:如注释中所述,如果要截断字符串字符串与读取的字符一样多,并且您知道它有多长(例如,您输入 A5 作为格式字符串),您只需选择子字符串:

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

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

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

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

If you need to eliminate blank space at the end of the string, you can use the trim function:

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

prints

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

Edit: As noted in the comment, if you want to truncate the string for as many characters as were read, and you know how long it is (e.g. you typed in A5 for the format string) you can just select the substring:

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

works for the case of A4 where you want the space printed. If you want the length to vary, you can store the format string. In the case of length 4, this would be like

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

You could then construct fmt using an integer variable and use that same integer variable as the index in the string slice.

很酷又爱笑 2024-10-28 10:23:45

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

发现使用 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 的优雅解决方案相比,大文件没有速度劣势。

I had exactly the same problem: I have to read lines from a file which have sometimes trailing blanks that i need to preserve in order to keep the program running, which needs those blanks somehow.

found out that the use of the ISO_VARYING_STRING extension works but in speed it has no advantage to my simple and very inefficient looking solution:

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

simply reading the lines of a file char by char into a string until an error (end of line) occurs. meanwhile the chars read are counted in l, so i can output with rcache(1:l) exactly what i read.

the solution may look very ugly but surprisingly gives no speed disadvantage for big files compared to the elegant solution with ISO_VARYING_STRING.

帝王念 2024-10-28 10:23:45

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

A possible solution to preserve an intended trailing blank would be to concatenate your string with a the nul character:

  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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文