【问题标题】:Read numbers following a keyword into an array in Fortran 90 from a text file从文本文件中将关键字后面的数字读入 Fortran 90 中的数组
【发布时间】:2011-06-07 02:14:19
【问题描述】:

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

....
<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。谢谢。

【问题讨论】:

  • 只是需要读入TURX标头的部分吗?
  • @jonsca:是的,这是我需要阅读的唯一部分。
  • 到目前为止你有没有尝试过什么或者...?
  • :(这只是程序中的一个小模块,我用fortran不太好,但我已经在PHP中有效地做到了。不幸的是我真的必须在fortran中完成它。这就是为什么我我在问是否有用于大海捞针的 Fortran 函数(如 PHP 的 strstr)。如果没有,如何解决这个问题?此外,我不知道如何在 Fortran 中使用数组。我可能不需要被喂食。如果我得到了指点,我可能会找到自己的路,因为我学得很快。一直在网上搜索无济于事。
  • 你知道大概会有多少个数字吗?

标签: parsing file-io fortran fortran90


【解决方案1】:

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 为假,您正在“寻找”...测试该行是否包含“TURX”。如果 TURX 始终位于字符串的开头,则可以使用普通的“==”,或者为了更通用,您可以使用内部函数“index”来测试字符串“line”是否包含 TURX。

一旦程序处于模式 Have_TRUX 为真,然后您使用“内部 I/O”从字符串中读取数值。由于整数具有不同的长度并且左对齐,因此最简单的方法是使用“列表导向 I/O”:结合这些:

read (line, *) integer_variable

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

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

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

附: http://en.wikipedia.org/wiki/Fortran_95_language_features 有语言特性的简要总结,gfortran 手册有内在过程的总结,从中您可以看到哪些内置函数可用于字符串处理。

【讨论】:

  • 不错的一个。我不知道 iostat 的东西。
  • :( 不幸的是,我在 Fortran 90 中继承了这段代码,我的老板现在在我的脖子上喘不过气来:D 所以我正在试验 jonsca 建议的 do 循环,似乎找不到 fortran 90 的 iostat 模块.
  • 你的想法对我也很有用,谢谢。虽然我遵循了 jonsca 的模式,所以我把这个奖励给了他 :)
【解决方案2】:

我会给你一个正确的方向,这样你就可以完成你的项目。

一些基础知识:

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

  • Read 读取字符串。

首先你需要这样的东西:

  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

请参阅this thread 了解将字符串转换为整数的方法。

最终编辑:看起来 MSB 已经掌握了我刚刚发现的大部分内容。读取的iostat 参数是它的关键。示例程序见this site

【讨论】:

    【解决方案3】:

    这是我最后的解决方法。

    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
    

    【讨论】:

    • 我确实承认通过避免可分配的数组(没有足够的时间来正确完成)以及将数字放入数组中来使用一些狡猾的 :P。我没有在链表上找到足够的材料,我的时间很短。而且我不想再次循环数据。我确信有更好的方法,但现在我保住了我的工作。哈哈,在“继承的 Fortran 代码”耸耸肩 :)
    猜你喜欢
    • 2018-03-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-05
    • 2013-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多