【问题标题】:Reading and writing into a file in fortran95在fortran95中读取和写入文件
【发布时间】:2018-08-06 14:20:03
【问题描述】:

我正在尝试在 Fortran 中执行以下操作:

  1. 逐行读取文本文档
  2. 通过“交换”每个字母来逐字编码每一行 在字母表中出现在它后面 l 位的那个,l= 的长度 词
  3. 将编码的行写入新的输出文档

我的循环似乎无限期地运行,并且没有任何文字被写入输出文档

我的测试输入文档只有 2 行:

  • 一些东西
  • 还有一些东西

第一行被正确读取和编码

PROGRAM zeichen
USE PufferMod
IMPLICIT NONE 
CHARACTER(LEN=132) :: z
CHARACTER(maxlen):: x
INTEGER:: a,e,i,l


OPEN(UNIT=39,FILE="intext.txt",ACTION="READ", STATUS="OLD")
OPEN(UNIT=40, FILE="outext.txt", ACTION="WRITE")

DO 
2 READ(39,"(A)", end=10) z
    a=1;
    DO WHILE(a<133)
     WRITE(*,*) z
     WRITE(*,*) a
     CALL Suche_Wort(z,a,e)
         l=e-a+1
         WRITE(*,*) a,e,l
                DO i=a,e
                    IF(z(i:i)/="") THEN
                    CALL Codiere(z(i:i),l)
                    END IF
                END DO
                a=e+1
    END DO 
 WRITE(40,*) z
 END DO
10 CLOSE(UNIT=39)
   CLOSE(UNIT=40)

END PROGRAM zeichen









    MODULE PufferMod
IMPLICIT NONE
PRIVATE
PUBLIC :: maxlen, Codiere, Suche_Wort

INTEGER, PARAMETER :: maxlen = 132

CONTAINS

FUNCTION Kleinbuchstabe(z)
    CHARACTER(LEN=1) :: z
    LOGICAL :: Kleinbuchstabe
    Kleinbuchstabe= "a" <= z .AND. z <= "z"
END FUNCTION Kleinbuchstabe

FUNCTION Grossbuchstabe(z)
    CHARACTER(LEN=1) :: z
    LOGICAL :: Grossbuchstabe
    Grossbuchstabe= "A" <= z .AND. z <= "Z"
END FUNCTION Grossbuchstabe

FUNCTION Buchstabe(z)
    CHARACTER(LEN=1) :: z
    LOGICAL :: Buchstabe
    Buchstabe=  (("a" <= z .AND. z <= "z") .OR. ("A" <= z .AND. z <= "Z"))
END FUNCTION Buchstabe

SUBROUTINE Codiere(z, Verschiebung)
    CHARACTER(LEN=1) :: z
    INTEGER, INTENT(IN) :: Verschiebung
    INTEGER :: CodevonA
    IF ( Kleinbuchstabe(z) ) THEN
    CodevonA= ICHAR("a")
    ELSE IF ( Grossbuchstabe(z) ) THEN
    CodevonA= ICHAR("A")
    END IF
    z= CHAR( CodevonA + MOD( ICHAR(z) - CodevonA + Verschiebung, 26 ) )
END SUBROUTINE Codiere

SUBROUTINE Suche_Wort(z,a,e)
CHARACTER(LEN=maxlen), INTENT(in):: z
INTEGER, INTENT(inout):: a
INTEGER, INTENT(out):: e
CHARACTER:: x, temp*1
INTEGER:: i
i=1
temp=z(a:a)
!WRITE(*,*) "a before loop",a, "temp", temp
 DO WHILE(temp == " ")    !Find start of next word
    temp=z(a+i:a+i)
    i=i+1
    a=a+1
 END DO
 !WRITE(*,*) "a after loop", a
 e=a+1
 i=1
 temp=z(e:e)
DO WHILE(temp/= "")      !find where the word ends by finding a space
    temp=z(e+i:e+i)
    i=i+1
    e=e+1
    IF(temp == " ") EXIT
END DO
END SUBROUTINE Suche_Wort

END MODULE PufferMod

【问题讨论】:

  • 我以为读完最后一行就结束了;当输入文档结束时。
  • 10是输入文档读完后要去的地方。
  • 当我运行你的代码时,我遇到了分段错误,当代码离开z 的末尾时。尝试在打开错误边界检查的情况下重新编译,然后再试一次。
  • 我该怎么做?
  • 您查阅编译器文档,搜索短语array bounds 或bounds check。或者在 SO 上查看其他问题,该主题大约每周讨论一次。

标签: fortran fortran95


【解决方案1】:

您的Suche_Wort 子例程至少存在三个问题:

  • 它从不检查z 变量的索引是否在界限内。

  • 它假定结束索引严格大于开始索引,因此不允许使用 1 个字符的单词。

  • 在它的每个循环中,它都会增加一个i 和另一个整数变量(第一个循环中的a,第二个循环中的e),有效地将 z 的索引增加每次迭代 2 个。

我建议对zeichen 程序进行两项更改,以消除尾随空格,方法是使用内部函数trim(删除尾随空格)和len_trim(计算修剪变量的长度) :

2 READ(39,"(A)", end=10) z
    a=1;
    DO WHILE(a<=len_trim(z))
     WRITE(*,*) z
     WRITE(*,*) a
     CALL Suche_Wort(trim(z),a,e)
!...

然后,可以将检查和更正添加到Suche_Wort 子例程(比我们不得不担心留在z(a:) 中的所有字符都是空格的可能性更容易):

SUBROUTINE Suche_Wort(z,a,e)
  CHARACTER(LEN=*), INTENT(in):: z ! Dummy argument has length of actual argument
  INTEGER, INTENT(inout):: a
  INTEGER, INTENT(out):: e
  CHARACTER(len=1):: temp
  temp=z(a:a)
  DO WHILE((temp == " ").and.(a<len(z)))    !Find start of next word
    temp=z(a+1:a+1)
    a=a+1
  END DO
  e=a                              ! Allows 1-character words
  DO WHILE((temp/= " ").and.(e<len(z)))      !find where the word ends by finding a space
    temp=z(e+1:e+1)
    e=e+1
  END DO
END SUBROUTINE Suche_Wort

【讨论】:

  • 在应用您的更改后,它几乎可以完美运行。唯一剩下的问题是输出在同一行
  • 对不起,这个问题只发生在记事本中,而不是记事本++中。
【解决方案2】:

为什么你需要考虑单词? 只需转换 A:Z 或 a:z。

   PROGRAM zeichen
     CHARACTER(LEN=132) :: z
     INTEGER :: iostat, Verschiebung = 1

     OPEN (UNIT=39, FILE="ziechen.f90", ACTION="READ", STATUS="OLD")
     OPEN (UNIT=40, FILE="outext.txt", STATUS="UNKNOWN")

      DO 
         READ (39,fmt="(A)", iostat=iostat) z
         if ( iostat /= 0 ) exit

         call convert_line ( z, Verschiebung )

         WRITE (40,fmt="(A)") trim (z)
         WRITE ( *,fmt="(A)") trim (z)
      END DO
   END PROGRAM zeichen

    Subroutine convert_line ( z, inc )
      character*(*) z
      integer   inc, i
      do i = 1, len_trim (z)
        call convert_character ( z(i:i), inc )
      end do
    end Subroutine convert_line

    Subroutine convert_character ( z, inc )
      character z
      integer   inc, ia, ic
!
      if      ( z >= 'A' .and. z <= 'Z' ) then
        ia = ichar ('A')
      else if ( z >= 'a' .and. z <= 'z' ) then
        ia = ichar ('a')
      else
        return
      end if
      ic = mod ( ichar (z) - ia + inc + 26, 26 )
      z  = char (ia + ic )
!
    end Subroutine convert_character

【讨论】:

  • 因为我是根据每个单词的长度而不是固定的数量来更改每个单词
  • 我的错误,我在阅读代码时将“l”取为 1。我对 convert_character 所做的更改可能有一些相关性,具体取决于可用于单词的字符集。
  • 无论如何我都很感激;任何写得更好的代码对我都有用。
  • 如果你有一个包含单词的CHARACTER数组z,你可以通过z = merge(achar(iachar(z)+modulo(iand(iachar(z),NOT(32))-65+size(z),26)- (iand(iachar(z),NOT(32))-65)),z,BLT(iand(iachar(z),NOT(32))-65,26))进行转换
  • @user5713492 我真的不明白为什么这么复杂的解决方案很有吸引力。我总是建议将问题分解成更容易理解的小块。
猜你喜欢
  • 2020-04-16
  • 2015-09-29
  • 2012-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-01
  • 2014-03-20
  • 2013-03-25
相关资源
最近更新 更多