爱气象,爱气象家园! 

气象家园

 找回密码
 立即注册

QQ登录

只需一步,快速开始

新浪微博登陆

只需一步, 快速开始

搜索
查看: 15006|回复: 9

[经验总结] 文件中有空行的fortran处理方法

[复制链接]

新浪微博达人勋

0
早起挑战累计收入
发表于 2011-7-27 21:15:28 | 显示全部楼层 |阅读模式

登录后查看更多精彩内容~

您需要 登录 才可以下载或查看,没有帐号?立即注册 新浪微博登陆

x
今天1群有朋友问了这么个问题:
    现有一个数据文件,文件的列数固定,但是不知道会在哪一行出现空行,默认情况下,fortran读取到空行(该朋友的文件中空行中是有空格的)会自动跳过直到读取到数据为止,这样的话如果使用的是固定循环数量的话,就会出现实际循环数小于指定循环数的情况,最终就是 -end of file encountered

这个是他的示例数据:
53694 1960 1 1 -24 79 -89
53694 1960 1 2 15 97 -56
53694 1960 1 3 0 79 -41
53694 1960 1 4 40 101 -29
53694 1960 1 5 -13 15 -44
53694 1960 1 6 -41 37 -107
                                                   
0        0     0       0        0       1         2

他的要求是:空出的行跳过去,该行的数组赋值为0,如果用fortran默认的方法读取,也就是下面这个他给我的程序:
      program yy12
      integer i,titol,station,year(8),month(8),day(8)
     &,htmin(8),htmax(8),a(8)
open(222,FILE='test.txt',FORM='FORMATTED')
do i=1,8
      read(222,*) station,year(i),month(i),day(i),htmin(i),htmax(i),a(i)
print*
      print*,i
      print*,station,year(i),month(i),day(i),htmin(i),htmax(i),a(i)
enddo
700   format(i5,3x,i5,x,i4,4x,i2,3x,i2,3x,i5)
      close(222)
      end
结果将会是这样:
1.jpg

原因就是上面说的fortran默认读取的问题,因此要解决就需要先判断该行是否为空行,我的方法也不是很完美,只是根据第一列进行了判断,程序如下:
      program yy12
      integer i,titol,year(8),month(8),day(8)
     &,htmin(8),htmax(8),a(8)
character*5 station
open(222,FILE='test.txt')
i=1
do while(1)
read(222,'(a)',end=100,advance='no')station
if(trim(station)=="")then
  read(222,*)
  year(i)=0
  month(i)=0
  day(i)=0
  htmin(i)=0
  htmax(i)=0
  a(i)=0
  i=i+1
  cycle
endif
      read(222,*)year(i),month(i),day(i),htmin(i),htmax(i),a(i)
      !print*,station,year(i),month(i),day(i),htmin(i),htmax(i),a(i)
i=i+1
enddo
      100 close(222)
      end
我把整型的站号修改为字符型,然后来判断是不是为空,这样算是解决了他的数据格式问题,但是还有很多毛病:
1、如果空行什么数据都没有,只有一个回车,那么将会认为文件到空行就结束了;
2、如果正常情况下站号之前就存在空格,那么将会不读取任何数据
有没有朋友有更好的算法呢?


评分

参与人数 2金钱 +16 贡献 +4 收起 理由
传说中的谁 + 8 + 2
topmad + 8 + 2 辛苦帖 我也在考虑算法

查看全部评分

密码修改失败请联系微信:mofangbao

新浪微博达人勋

发表于 2011-7-27 22:48:42 | 显示全部楼层
fortran我不懂,我以前用VB读的时候,跳过空行的一个思路是取得改行的字符长度,如果为0就可以判定是空的。
密码修改失败请联系微信:mofangbao

新浪微博达人勋

0
早起挑战累计收入
 楼主| 发表于 2011-7-28 08:03:52 | 显示全部楼层

fortran对字符串处理能力不足,很纠结啊
密码修改失败请联系微信:mofangbao

新浪微博达人勋

发表于 2011-7-31 22:48:35 | 显示全部楼层
本帖最后由 godenflame135 于 2011-8-1 00:16 编辑

请看看我的方法可以不:
设计思想:先整体读入一行(79个字符),循环判断非空格就判定为有数据,并接着将该行分散读取到年月日等变量。
下面是我修改的程序,请参考,实际情况相应修改。
!############################################
前提:空行中有空格。
注意:1.在有可能读入数据为负数时,读取方式要稍加修改。
           2.如果单个文件的行数特别多,建议将所有数据一次性读入字符型数组中,再分行判断,这样运行速度可在一定程度
              上提升。
!#############################################

如有不当,请回帖讨论交流。

!-------------------------------------------------------------------------------------------------------------------------------------------
  program yy12
      implicit none
      integer i,titol,station,year(8),month(8),day(8)
     &,htmin(8),htmax(8),a(8)
    character*79      :: c_line    !for read one row
    integer               :: i,j,k      !for loop if need
    logical                 :: L_have_number
open(222,FILE='test.txt',FORM='FORMATTED',err=998)
j=0      !index of  station,year...

! begin loop to read------------------------------------------------
do while()     !----------exit by going to 999 when read-----
799   read(222,'(a79)',err=999)c_line
          L_have_number=    .false.
!   ---loop to judge have number or not--------------------------
    do i=1,79
          if(ichar(c_line(i:i))  /= 32      )  then     !   any one which is not space
               L_have_number  =  .true.
                go to 800
          end if
     end do
!   ----end judge have number--------------------------------------
!judge to write data to station(j),year(j)....
       j=j+1
800  if(L_have_number)then   
              write(c_line(1:5),*)      station (j)
              write(c_line(7:10),*)    year    (j)
              write(c_line(12:12),*)  month(j)
              write(c_line(13:13),*)  day     (j)
             if(ichar(15)  ==  45   )then                      !   '-' sign   ,htmin(j)<100,means have only 2 digitals.
                 write(c_line(15:17),*)htmin(j)
                 k=17
              else                                                        ! no '-'  sign,htmin(j)<100,means have only 2 digitals                 
                  write(c_line(15:16),*)htmin(j)   
                  k=16      
              end if
             if (ichar( c_line(k+4))  /=32    )     then    !htmax(j) >100,means have only 3 digitals.
                 write(c_line(k+1:k+4),*)htmax(j)  
                 k=k+4
            else                                                         !htmax(j)<100,means have only 2 digitals.   
                 write(c_line(k+1:k+3),*)htmax(j)     
                 k=K+3
             end if
          if(ichar(k+4) /= 32 )then                           !  all of a(j) have  '-' sign ,-999<a(j)<-100.
                   write(c_line(k+1:k+4),*)a(j)
                   k=k+4
          else                                                           ! all of a(j) have '-' sign ,-100<a(j)<-10.
                   write(c_line(k+1:k+3),*)a(j)
                    k=K+3
           end if
          ! -----end of write a line------------------------

           print*,station(j),year(j),month(j),day(j),htmin(j),htmax(j),a(j)

         !----end of print each number-----------------
             go to 799        !continue to read next row

    else                                                            ! have no number,no write and read next row.
          station(j)  =  0
          year(j)      =  0
          month(j)   =  0
          day(j)        =  0
          htmin(j)     =   0
          htmax(j)    =   0
          a(j)            =   0
            
             print*,station(j),year(j),month(j),day(j),htmin(j),htmax(j),a(j)

            !----end of print each number-----------------

          go to 799     !continue to read next row

        end if    !------end of judge to write  number or not-----------------
end do   !----------exit by going to 999 when read-----
go to 1000     ! ----------go to the end

!  error process--------------------------------------------------
999 print *,'read error, or EOF'
      go to 1000
998 print *,'open error  ,  or file not exist.'
1000 continue

close(222)

      end

!----------------------------------------------------------------------------------------------------------------------------------------







评分

参与人数 1金钱 +5 收起 理由
mofangbao + 5 先给分,中午再测试,哈哈

查看全部评分

密码修改失败请联系微信:mofangbao

新浪微博达人勋

0
早起挑战累计收入
 楼主| 发表于 2011-8-1 13:00:25 | 显示全部楼层
godenflame135 发表于 2011-7-31 22:48
请看看我的方法可以不:
设计思想:先整体读入一行(79个字符),循环判断非空格就判定为有数据,并接着将 ...

调试中发现一点问题,
1、重复定义了i变量,station不知道你是不是定义为数组的,上下有一些不一致
2、程序第38行附近出现编译错误,大概是操作的参数有问题,不知道是不是应该把:
if (ichar( c_line(k+4))  /=32    ) 改为:if (ichar( k+4)  /=32    )
3、由于没有调试成功,还没发进一步测试
呵呵 不错你的想法挺不错的 不知道你用的哪个fortran版本,出结果了没?
密码修改失败请联系微信:mofangbao

新浪微博达人勋

发表于 2015-5-19 22:27:22 | 显示全部楼层
还好可以用
密码修改失败请联系微信:mofangbao

新浪微博达人勋

发表于 2015-8-10 14:55:03 | 显示全部楼层
最近也遇到个文件中有几行不需要的情况。不知上面那位的方法能用不
密码修改失败请联系微信:mofangbao

新浪微博达人勋

发表于 2015-9-16 20:53:51 | 显示全部楼层
{:eb502:}{:eb502:}{:eb502:}
密码修改失败请联系微信:mofangbao
回复

使用道具 举报

新浪微博达人勋

发表于 2016-9-1 09:45:57 | 显示全部楼层
如果我的数据是这样的
12,12,12,12,12, ,12,12
11,11,11,11, ,11,11,11
这样用fortran怎么读取呢?
密码修改失败请联系微信:mofangbao

新浪微博达人勋

发表于 2016-9-1 10:08:03 | 显示全部楼层
cycle用的不错
密码修改失败请联系微信:mofangbao
您需要登录后才可以回帖 登录 | 立即注册 新浪微博登陆

本版积分规则

Copyright ©2011-2014 bbs.06climate.com All Rights Reserved.  Powered by Discuz! (京ICP-10201084)

本站信息均由会员发表,不代表气象家园立场,禁止在本站发表与国家法律相抵触言论

快速回复 返回顶部 返回列表