Io 用Fortran语言读写表格

Io 用Fortran语言读写表格,io,fortran,Io,Fortran,我有一个日历表,上面有上升和设定时间,格式为 Jan Feb .... Dec rise set rise set .... rise set 0643 1754 0433 1305 .... 1256 0219 1057 2230 1038 9999 .... 1502 0151 0912 9999 1026 0139 .... 1559 0103 1147 0149 .... 1739 0130 (不必担心9999,我以后再

我有一个日历表,上面有上升和设定时间,格式为

   Jan       Feb     ....    Dec
rise set  rise set   .... rise set
0643 1754 0433 1305  .... 1256 0219
1057 2230 1038 9999  .... 1502 0151
0912 9999 1026 0139  .... 1559 0103
1147 0149            .... 1739 0130
(不必担心9999,我以后再处理。二月底的空白指示当天不存在)

显然,我希望一次处理两列数据,而不是将整年加载到一个数组中(在任何给定的时间组中计算DOY时,这将是一场噩梦)。我尝试使用如下格式的变量编写脚本:

26     format(<iskip>X,I2,3X,I2)
       idoy=001
       iskip=4
       irise1=00
4      read(1,26,end=6,err=4)irise2,iset2
       if (irise2.eq.iset2) go to 6    !if both blank, move to next column
7      irise1=irise2
       iset1=iset2
       irise2=99
       iset2=99
       idoy++
       go to 4

6      iskip=iskip+11
       irise1=irise2
       iset1=iset2
       irise2=99
       iset2=99
       idoy++
       if (iskip.lt.128) go to 4
26格式(X,I2,3X,I2)
idoy=001
iskip=4
虹膜1=00
4读(1,26,end=6,err=4)虹膜2,iset2
如果(irise2.eq.iset2)转到6!如果两者都为空,则移动到下一列
7虹膜1=虹膜2
iset1=iset2
虹膜2=99
iset2=99
艾迪++
去4号
6 iskip=iskip+11
虹膜1=虹膜2
iset1=iset2
虹膜2=99
iset2=99
艾迪++
如果(iskip.lt.128)转到4
基本上,程序一次读取两列,存储数据并跟踪一年中的哪一天

为了试验在格式中使用变量的想法,我创建了一个测试程序,该程序打印出一个10x24的值矩阵,这些值应该看起来像DOYHH逐列:

    integer idoy,ihour,iskip

    idoy=1
    ihour=0
    iskip=0

    do while (idoy.le.10)
            do while (ihour.lt.24)
 2                  format(<iskip>X,I3,I2)
                    write(2,2)idoy,ihour
            end do
            iskip=iskip+6
    end do
    end
整数idoy、ihour、iskip
idoy=1
ihour=0
iskip=0
请便(我的第10章)
请稍等片刻(ihour.lt.24)
2格式(X、I3、I2)
写(2,2)我自己,我自己
结束
iskip=iskip+6
结束
结束
但是f77和f95的编译器似乎对此非常不满意。关于如何让测试程序运行有什么建议吗?我可能可以从那里推断出技术。同样,测试程序写入矩阵的底部,然后在顶部重新启动,这一点非常重要

来自F77的错误消息:

test.f: In program `MAIN__':
test.f:9:
    2                  format(<iskip>X,I3,I2)
                                     ^
Variable-expression FORMAT specifier at (^) -- unsupported
test.f:在程序'MAIN____;'中:
测试f:9:
2格式(X、I3、I2)
^
位于(^)的变量表达式格式说明符--不支持
来自F95的错误消息:

test.f:9.16:
 2  format(<iskip>X,I3,I2)
           1
Error: Unexpected element '<' in format string at (1)
test.f:10.17:

    write(2,2)idoy,ihour
            1
Error: FORMAT label 2 at (1) not defined
test.f:9.16:
2格式(X、I3、I2)
1.

错误:意外元素“有几种可能的方法,下面我将介绍三种模式


[1st approach]按照问题中的建议,一次读两列。给定一个每年4天3个月的样本输入,每次都以
”(I5)
格式编写

   Jan       Feb    June
 rise set  rise set  rise set
 0643 1754 0433 1305 1256 0219
 1057 2230 1038 9999 1502 0151
 0912 9999           1559 0103
 1147 0149
我们可以把它们理解为

integer, parameter :: Nday = 4, Nmon = 3   !! for actual data, Nday = 31 and Nmon = 12
integer, dimension( Nday, Nmon ) :: rise, set
integer :: d, m
character(200) :: lineskip

open( 10, file="time_blank.dat", status="old" )

do m = 1, Nmon
    rewind( 10 )
    read( 10, * ); read( 10, * )  !! skip the two header lines

    do d = 1, Nday
        read( 10, "(a, 2i5)" ) &
                lineskip( 1 : 10 * (m-1) ), rise( d, m ), set( d, m )
    enddo
enddo
close( 10 )
在这里,我们使用
lineskip
(一个伪字符串)跳过已经处理过的数据。请注意,空字段的
rise
set
被设置为
0
,这可能不符合实际情况


[第二种方法]将每一行读入一个字符串,然后对其进行解析以获得整数数据。比如说,

integer :: offset
character(1000) :: line
character(5) :: str1, str2

rise(:,:) = -1 ; set(:,:) = -1   !! first, initialize all data with dummy values
...
do d = 1, Nday
    read( 10, "(a)" ) line

    do m = 1, Nmon
        offset = 10 * (m-1)
        str1 = line( offset + 1 : offset + 5  )
        str2 = line( offset + 6 : offset + 10 )
        if ( str1 /= "" ) read( str1, * ) rise( d, m )
        if ( str2 /= "" ) read( str2, * ) set ( d, m )
    enddo
enddo
其中,每行被读入
,划分为字段,然后提取整数值(如果有)。此处,空数据的
rise
set
设置为用户定义的伪值(此处,
-1
)。类似的方法也可用于改进第一种方法


[第三种方法]有时,使用自由格式的输入文件更方便。为此,让我们用虚拟值填充空数据,例如-1:

Jan           Feb         June
rise  set     rise  set      rise set
0643  1754    0433  1305   1256 0219
1057  2230    1038  9999    1502 0151
0912  9999    -1    -1     1559 0103
1147  0149    -1    -1        -1   -1   <--- free format
在我看来,这是最简单和最灵活的方法,只要我们可以修改输入文件


[序列化数据]可以将
上升
设置
序列化为DOY as的函数

idoy = 0
do m = 1, Nmon
do d = 1, Nday
    if ( rise( d, m ) >= 0 ) then    !! assuming the dummy value = -1
        idoy = idoy + 1
        print *, idoy, rise( d, m ), set( d, m )
    endif
enddo
enddo
或使用
pack
功能:

integer, allocatable :: rise_doy(:), set_doy(:)

rise_doy = pack( rise, rise >= 0 )  !! assuming the dummy value = -1
set_doy  = pack( set,  set  >= 0 )

(请注意,对于英特尔fortran,我们需要
-假设realloc_lhs
选项)。

他们以什么方式“真正不高兴”?有错误消息吗?[注意,代码不是标准Fortran.]什么是“f77和f95看起来都很不开心”的意思?您得到的错误是什么?添加了f95和f77的编译器输出。很抱歉。可能是重复的嗯。。。非常接近,但我不确定如何实现他们的答案。我不确定空白字段(在第一种方法中)的“上升”和“设置”是否总是由任何编译器设置为0。。。(尽管格弗特兰和伊弗特似乎是这样做的)。我尝试附加iostat,但这不适用于空白字段。对于数字输入,根据Fortran标准,完全由空白组成的字段被视为零。谢谢,我不知道这种行为。。。我记下笔记,又加了一个方法:)当事情在午夜升起或落下时会发生什么?在决定字段是否为null/empty/zero之前,我将读取一个字符变量,然后进行测试。
integer, allocatable :: rise_doy(:), set_doy(:)

rise_doy = pack( rise, rise >= 0 )  !! assuming the dummy value = -1
set_doy  = pack( set,  set  >= 0 )