什么是返回数组(未知大小)字符串的最佳方式(在Fortran 90中)?

时间:2014-08-13 18:03:21

标签: string parsing fortran character fortran90

我想编写一个解析文件并返回"匹配"的数组的函数。线。我不在乎它是一个功能还是一个子程序,但我不确定如何做到这一点。

让我们通过一个例子来说明这一点:假设我们想要返回文件inputFile中以某个字符startingCharacter开头的所有行的数组,并返回这些行数组matchingLines。为方便起见,我们还返回此输出数组中的行数并调用该数字matchingLineCount。 (我们假设行少于256个字符。)该示例的子例程代码应如下所示:

subroutine parse_file( inputFile, startingCharacter, matchingLines, matchingLineCount )

implicit none

character(len=*), intent(in) :: inputFile
character, intent(in)        :: startingCharacter
character(len=256), dimension(*), intent(out) :: matchingLines
integer, intent(out)         :: matchingLineCount

! Open file

! While there are still lines to be read....

    ! Read in a line
    ! See if line(1) == startingCharacter
    ! If it does, add it to matchingLines

! Close file

end

我怀疑诀窍是如何返回一个可变长度数组......

谢谢!

1 个答案:

答案 0 :(得分:0)

"最佳"有点主观,取决于Fortran处理器,输入文件的性质以及您认为重要的内容(例如速度或内存占用),但作为示例......

PROGRAM ReadArrayOfUnknownSizeOfStrings
  IMPLICIT NONE
  ! Apparently we can assume this.
  INTEGER, PARAMETER :: max_string_length = 256
  ! For testing.
  CHARACTER(*), PARAMETER :: filename  &
      = 'ReadArrayOfUnknownSizeOfStrings.txt'
  CALL main
CONTAINS
  SUBROUTINE main()
    ! Logical unit number.
    INTEGER, PARAMETER :: unit = 10
    CHARACTER(max_string_length), POINTER :: an_array(:)
    INTEGER :: i
    !****
    ! Generate the file for testing.
    OPEN( UNIT=unit, FILE=filename, ACTION='WRITE',  &
        STATUS='REPLACE', POSITION='REWIND' )
    ! Write some test content.
    WRITE (unit, "(A)") 'Mary had a little lamb'
    WRITE (unit, "(A)") 'ARestricting yourself'
    WRITE (unit, "(A)") 'it''s fleece was white as snow'
    WRITE (unit, "(A)") 'Ato Fortran 90'
    WRITE (unit, "(A)") 'and every where that Mary went'
    WRITE (unit, "(A)") 'Ain this day and age is just silly'
    WRITE (unit, "(A)") 'the lamb was sure to go'
    WRITE (unit, "(A)") 'Agiven the improvements in the language'
    WRITE (unit, "(A)") 'Mary had a little lamb'
    WRITE (unit, "(A)") 'Aand the support offered by current compilers'
    WRITE (unit, "(A)") 'her father shot it dead'
    WRITE (unit, "(A)") 'AAt least use Fortran 95'
    WRITE (unit, "(A)") 'now mary takes that lamb to school'
    WRITE (unit, "(A)") 'Aplus the "Allocatable TR"'
    WRITE (unit, "(A)") 'between two chunks of bread'
    CLOSE(unit)
    ! Read back the test data.
    ! Open the file for reading.
    OPEN( UNIT=unit, FILE=filename, ACTION='READ',  &
        STATUS='OLD', POSITION='REWIND' )
    CALL read_the_array(unit, 'A', an_array)
    ! Close the file.
    CLOSE(unit)
    ! Print the results.
    DO i = 1, SIZE(an_array)
      PRINT "(A)", TRIM(an_array(i)(2:))
    END DO
    DEALLOCATE(an_array)
  END SUBROUTINE main

  SUBROUTINE read_the_array(unit, matching_char, an_array)
    ! Select a size appropriate for your data.
    INTEGER, PARAMETER :: initial_array_size = 10
    ! Logical unit connected for formatted input.
    INTEGER, INTENT(IN) :: unit
    ! Initial character of a record to match.
    CHARACTER, INTENT(IN) :: matching_char
    ! The array of matching lines.
    CHARACTER(max_string_length), POINTER :: an_array(:)
    ! A temporary for growing an_array.
    CHARACTER(max_string_length), POINTER :: tmp(:)
    INTEGER :: next_index     ! Next index to use in an_array.
    !****
    ALLOCATE(an_array(initial_array_size))
    next_index = 1
    DO
      READ (unit, "(A)", END=900) an_array(next_index)
      IF (an_array(next_index)(1:1) == matching_char) THEN
        next_index = next_index + 1
        IF (next_index > SIZE(an_array)) THEN
          tmp => an_array
          ALLOCATE(an_array(SIZE(tmp) * 2))
          an_array(:SIZE(tmp)) = tmp
          DEALLOCATE(tmp)
        END IF
      END IF
    END DO
    900 CONTINUE      ! Here on end of file.
    ! Cut result back to size.
    tmp => an_array
    ALLOCATE(an_array(next_index-1))
    an_array = tmp(:SIZE(an_array))
    DEALLOCATE(tmp)
  END SUBROUTINE read_the_array
END PROGRAM ReadArrayOfUnknownSizeOfStrings

如果你运行示例代码,你可能会得到一个潜意识信息......