将关键字后面的数字从文本文件读取到 Fortran 90 中的数组中

发布于 2024-11-14 04:49:04 字数 488 浏览 4 评论 0原文

我有许多这种格式的文本文件

....
<snip>
'FOP' 0.19 1 24 1 25 7 8  /
'FOP' 0.18 1 24 1 25 9 11 /
/ 

TURX
560231
300244
70029
200250
645257
800191
900333
600334
770291
300335
220287
110262 /

SUBTRACT
'TURX' 'TURY'/
</snip>
......

,其中我剪下的部分包含各种格式的其他各种数据。文件格式不一致(机器生成),唯一可以确定的是关键字TURX可能会出现多次。如果它单独出现在一行上,那么接下来的几行将包含我需要提取到数组中的数字。最后一个数字将有一个空格,然后是一个正斜杠 (/)。然后我可以在其他操作中使用这个数组。

如何在 Fortran 中“搜索”或解析未知格式的文件,以及如何获得循环来获取其余数据?我对此真的很陌生,我必须使用 fortran。谢谢。

I have many text files of this format

....
<snip>
'FOP' 0.19 1 24 1 25 7 8  /
'FOP' 0.18 1 24 1 25 9 11 /
/ 

TURX
560231
300244
70029
200250
645257
800191
900333
600334
770291
300335
220287
110262 /

SUBTRACT
'TURX' 'TURY'/
</snip>
......

where the portions I snipped off contain other various data in various formats. The file format is inconsistent (machine generated), the only thing one is assured of is the keyword TURX which may appear more than once. If it appears alone on one line, then the next few lines will contain numbers that I need to fetch into an array. The last number will have a space then a forward slash (/). I can then use this array in other operations afterwards.

How do I "search" or parse a file of unknown format in fortran, and how do I get a loop to fetch the rest of the data, please? I am really new to this and I HAVE to use fortran. Thanks.

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

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

发布评论

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

评论(3

十六岁半 2024-11-21 04:49:04

Fortran 95 / 2003 有很多字符串和文件处理功能,使这变得更容易。

例如,此代码片段用于处理未知长度的文件:

   use iso_fortran_env


  character (len=100) :: line
   integer :: ReadCode


ReadLoop: do
  read (75, '(A)', iostat=ReadCode )  line

  if ( ReadCode /= 0 ) then
     if ( ReadCode == iostat_end ) then
        exit ReadLoop
     else
        write ( *, '( / "Error reading file: ", I0 )' )  ReadCode
        stop
     end if
  end if

  ! code to process the line ....

end do ReadLoop

然后,“处理行”代码可以包含多个部分,具体取决于逻辑变量“Have_TURX”。如果 Have_TRUX 为 false,则您正在“寻找”...测试该行是否包含“TURX”。如果 TURX 始终位于字符串的开头,则可以使用普通的“==”,或者为了更通用,您可以使用内部函数“index”来测试字符串“line”是否包含 TURX。

一旦程序处于 Have_TRUX 为 true 的模式,则可以使用“内部 I/O”从字符串中读取数值。由于整数具有不同的长度并且左对齐,最简单的方法是使用“列表定向 I/O”:将它们组合起来:

read (line, *) integer_variable

然后您可以再次使用内部函数“index”来测试字符串是否也包含斜杠,在这种情况下,您将 Have_TRUX 更改为 false 并结束阅读模式。

如果您需要将数字放入数组中,则可能需要读取该文件两次,或者退格该文件,因为您必须分配该数组,并且在知道该数组的大小之前无法执行此操作大批。或者,您可以将数字弹出到链接列表中,然后当您点击斜杠时分配数组并从链接列表中填充它。或者,如果存在已知的最大值数,则可以使用临时数组,然后将数字传输到可分配的输出数组。这是假设您希望子例程的输出参数是正确长度的可分配数组,并且每次调用返回一组数字:

integer, dimension (:), allocatable, intent (out) :: numbers
allocate (numbers (1: HowMany) )

PS http://en.wikipedia.org/wiki/Fortran_95_language_features 并且 gfortran 手册有内部过程的摘要,从中您可以看到哪些内置函数可用于字符串处理。

Fortran 95 / 2003 have a lot of string and file handling features that make this easier.

For example, this code fragment to process a file of unknown length:

   use iso_fortran_env


  character (len=100) :: line
   integer :: ReadCode


ReadLoop: do
  read (75, '(A)', iostat=ReadCode )  line

  if ( ReadCode /= 0 ) then
     if ( ReadCode == iostat_end ) then
        exit ReadLoop
     else
        write ( *, '( / "Error reading file: ", I0 )' )  ReadCode
        stop
     end if
  end if

  ! code to process the line ....

end do ReadLoop

Then the "process the line" code can contain several sections depending on a logical variable "Have_TURX". If Have_TRUX is false you are "seeking" ... test whether the line contains "TURX". You could use a plain "==" if TURX is always at the start of the string, or for more generality you could use the intrinsic function "index" to test whether the string "line" contains TURX.

Once the program is in the mode Have_TRUX is true, then you use "internal I/O" to read the numeric value from the string. Since the integers have varying lengths and are left-justified, the easiest way is to use "list-directed I/O": combining these:

read (line, *) integer_variable

Then you could use the intrinsic function "index" again to test whether the string also contains a slash, in which case you change Have_TRUX to false and end reading mode.

If you need to put the numbers into an array, it might be necessary to read the file twice, or to backspace the file, because you will have to allocate the array, and you can't do that until you know the size of the array. Or you could pop the numbers into a linked list, then when you hit the slash allocate the array and fill it from the linked list. Or if there is a known maximum number of values you could use a temporary array, then transfer the numbers to an allocatable output array. This is assuming that you want the output argument of the subroutine be an allocatable array of the correct length, and the it returns one group of numbers per call:

integer, dimension (:), allocatable, intent (out) :: numbers
allocate (numbers (1: HowMany) )

P.S. There is a brief summary of the language features at http://en.wikipedia.org/wiki/Fortran_95_language_features and the gfortran manual has a summary of the intrinsic procedures, from which you can see what built in functions are available for string handling.

水晶透心 2024-11-21 04:49:04

我会在正确的方向上推动您,以便您能够完成您的项目。

一些基础知识:

  • Do/While需要某种循环
    循环遍历文件的结构
    然后是数字。有
    Fortran 中没有 for 循环,所以使用这个
    类型。

  • 阅读
    读取字符串。

首先,您需要这样的内容:

  program readlines
  implicit none
  character (len=30) :: rdline
  integer,dimension(1000) :: array
  !  This sets up a character array with 30 positions and an integer array with 1000
  !
  open(18,file='fileread.txt')
  do
     read(18,*) rdline
     if (trim(rdline).eq.'TURX') exit  !loop until the trimmed off portion matches TURX
  end do

请参阅此线程将字符串转换为整数的方法。

最终编辑:看起来 MSB 已经得到了我刚刚发现的大部分内容。读取的 iostat 参数是它的关键。有关示例程序,请参阅此站点

I'll give you a nudge in the right direction so that you can finish your project.

Some basics:

  • Do/While as you'll need some sort of loop
    structure to loop through the file
    and then over the numbers. There's
    no for loop in Fortran, so use this
    type.

  • Read
    to read the strings.

To start you need something like this:

  program readlines
  implicit none
  character (len=30) :: rdline
  integer,dimension(1000) :: array
  !  This sets up a character array with 30 positions and an integer array with 1000
  !
  open(18,file='fileread.txt')
  do
     read(18,*) rdline
     if (trim(rdline).eq.'TURX') exit  !loop until the trimmed off portion matches TURX
  end do

See this thread for way to turn your strings into integers.

Final edit: Looks like MSB has got most of what I just found out. The iostat argument of the read is the key to it. See this site for a sample program.

少钕鈤記 2024-11-21 04:49:04

这是我最后的解决办法。

PROGRAM fetchnumbers
    implicit none
    character (len=50) ::line, numdata
    logical ::is_numeric        
    integer ::I,iost,iost2,counter=0,number
    integer, parameter :: long = selected_int_kind(10)
    integer, dimension(1000)::numbers !Can the number of numbers be up to 1000?

    open(20,file='inputfile.txt') !assuming file is in the same location as program
    ReadLoop: do
        read(20,*,iostat=iost) line !read data line by line
        if (iost .LT. 0) exit !end of file reached before TURX was found
        if (len_trim(line)==0) cycle ReadLoop !ignore empty lines
        if (index(line, 'TURX').EQ.1) then !prepare to begin capturing
            GetNumbers: do
                read(20, *,iostat=iost2)numdata !read in the numbers one by one
                if (.NOT.is_numeric(numdata)) exit !no more numbers to read             
                if (iost2 .LT. 0) exit !end of file reached while fetching numbers
                read (numdata,*) number !read string value into a number
                counter = counter + 1
                Storeloop: do I =1,counter
                    if (I<counter) cycle StoreLoop
                    numbers(counter)=number !storing data into array
                end do StoreLoop
            end do GetNumbers
        end if
    end do ReadLoop

    write(*,*) "Numbers are:"
    do I=1,counter
      write(*,'(I14)') numbers(I)
    end do

END PROGRAM fetchnumbers

FUNCTION is_numeric(string)
  IMPLICIT NONE
  CHARACTER(len=*), INTENT(IN) :: string
  LOGICAL :: is_numeric
  REAL :: x
  INTEGER :: e
  is_numeric = .FALSE.
  READ(string,*,IOSTAT=e) x
  IF (e == 0) is_numeric = .TRUE.
END FUNCTION is_numeric

Here was my final way around it.

PROGRAM fetchnumbers
    implicit none
    character (len=50) ::line, numdata
    logical ::is_numeric        
    integer ::I,iost,iost2,counter=0,number
    integer, parameter :: long = selected_int_kind(10)
    integer, dimension(1000)::numbers !Can the number of numbers be up to 1000?

    open(20,file='inputfile.txt') !assuming file is in the same location as program
    ReadLoop: do
        read(20,*,iostat=iost) line !read data line by line
        if (iost .LT. 0) exit !end of file reached before TURX was found
        if (len_trim(line)==0) cycle ReadLoop !ignore empty lines
        if (index(line, 'TURX').EQ.1) then !prepare to begin capturing
            GetNumbers: do
                read(20, *,iostat=iost2)numdata !read in the numbers one by one
                if (.NOT.is_numeric(numdata)) exit !no more numbers to read             
                if (iost2 .LT. 0) exit !end of file reached while fetching numbers
                read (numdata,*) number !read string value into a number
                counter = counter + 1
                Storeloop: do I =1,counter
                    if (I<counter) cycle StoreLoop
                    numbers(counter)=number !storing data into array
                end do StoreLoop
            end do GetNumbers
        end if
    end do ReadLoop

    write(*,*) "Numbers are:"
    do I=1,counter
      write(*,'(I14)') numbers(I)
    end do

END PROGRAM fetchnumbers

FUNCTION is_numeric(string)
  IMPLICIT NONE
  CHARACTER(len=*), INTENT(IN) :: string
  LOGICAL :: is_numeric
  REAL :: x
  INTEGER :: e
  is_numeric = .FALSE.
  READ(string,*,IOSTAT=e) x
  IF (e == 0) is_numeric = .TRUE.
END FUNCTION is_numeric
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文