例題9 文字処理

 次のような書式のデータファイルが2つある(例題8のデータファイルと同じ書式)。このデータはアメダスで1時間ごとに観測された気温(1ヶ月分)で、観測年月と観測所はファイルの先頭に記述されている。気温データの書式仕様は(i2,24f4.1)でファイル名はt199601.dm199601.dである(前後の目盛りの行は除く)。

ファイル t199601.d の内容
----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----
                                                          ←  1レコード目は空の行
     観測所番号:44131  東京                          ↓  5レコード目からデータ
          1996年01月   気温(0.1°C)
日   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24時
 1  36  43  54  59  72  40  28  40  74  81  92 100 100  98  89  82  68  58  52  49  47  45  44  41
 2  39  37  35  35  32  31  26  22  38  58  65  78  81  87  90  89  83  77  71  65  65  62  64  58
 3  49  41  39  36  32  31  27  27  39  64  69  92 110 123 142 122 137 130 126 125 124 121 119  76
                                             :
                                             :
31   9   7   8   4  11   6   8  14  25  38  45  55  54  65  61  57  58  53  51  45  43  33  27  25
----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----

ファイル m199601.d の内容
----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----
                                                          ←  1レコード目は空の行
     観測所番号:17112  紋別                          ↓  5レコード目からデータ
          1996年01月   気温(0.1°C)
日   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24時
 1 -16 -16 -27 -36 -44 -48 -53 -56 -44 -40 -38 -43 -43 -49 -55 -62 -69 -72 -71 -71 -68 -64 -55 -46
 2 -40 -32 -30 -37 -34 -31 -27 -20 -13  -7  -5   3   6   4   4 -12 -32 -38 -40 -40 -38 -46 -40 -34
 3 -11 -20 -22 -21 -27 -16 -16 -17   3  15  11  15  30  28  25  15  11  10  23  38  38  15  12  46
                                             :
                                             :
31-134-135-138-140-140-140-140-140-133-130-125-128-124-133-136-140-142-144-149-149-150-153-148-147
----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----

 このデータを読み込んで、2地点(ここでは東京と紋別)の、
観測時刻毎(1時,2時,・・・,24時)の1ヶ月の平均気温と2地点の平均気温の差を求めて出力するプログラムを作成する。

 まず31日分のデータを読み込んで観測時刻毎の1ヶ月の平均気温を求め、配列に格納します。 これを2回繰り返します。1回目はファイル t199601.d を2回目はファイル m199601.d を読み込みます。

 例題9のフローチャートとプログラムの例を示します。

概要

プログラム
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
c Example 9     文字処理
c  機械工学科 1年  xxxxxxx  my name
c         Filename = reidai09.f
      integer hour, day
      parameter (hour=24, day=31)
      real a(hour,day),av(hour,2)
      character filen(2)*9,data1(2)*40,data2(2)*40
      character*8 toshi1,toshi2
      data m/hour/
      filen(1)='t199601.d'
      filen(2)='m199601.d'
      do 10010 k=1,2
c   気温データを読む
      open(11,file=filen(k),status='old')
      read(11,100) 
      read(11,100) data1(k)
      read(11,100) data2(k)
      read(11,100) 
 1001 continue
      read(11,101,end=2001) n,(a(i,n),i=1,m)
      go to 1001
 2001 continue
      close(11)
c   各時の平均気温を求める
      do 2010 i=1,m
        asum=0.0
        do 2020 j=1,n
          asum=asum+a(i,j)
 2020   continue
        av(i,k)=asum/real(n)
 2010 continue
10010 continue 
c   出力
      toshi1=data1(1)(24:31)
      toshi2=data1(2)(24:31)
      write(*,601) data2(1)(11:27),toshi1,toshi2
      write(*,602) toshi1,toshi2,toshi1,toshi2
      do 3010 i=1,m/2
        i1=2*i-1
        i2=i1+1
        write(*,603) i1, av(i1,1), av(i1,2), av(i1,1)-av(i1,2)
     *              ,i2, av(i2,1), av(i2,2), av(i2,1)-av(i2,2)
 3010 continue
      stop
  100 format(a40)
  101 format(i2,24f4.1)
  601 format( 3x,a17,'の差',4x,a8,'と',2x,a8)
  602 format(/ 2(8x,' 時',5x,a8,1x,a8,3x,'差'))
  603 format(2(8x,i3,3f9.1))
      end


 例題9のプログラム例について説明します。

 4行目から9行目は宣言文です。

4行目         integer hour, day
5行目         parameter (hour=24, day=31)
6行目         real a(hour,day),av(hour,2)
7行目         character filen(2)*9,data1(2)*40,data2(2)*40
8行目         character*8 toshi1,toshi2
9行目         data m/hour/

 5行目のparameter文については例題8を参照してください。
 6行目の型宣言文では、1から hour と1から day の寸法をもつ2次元配列 a, 1から hour と 1 から 2 の寸法をもつ2次元配列 av を実数型と宣言しています。a は気温データ 24時分×31日分 を格納しておくため、av は1日の観測時刻(24)分の平均気温を2地点について格納しておくために用意したものです。
 9行目のdata文では、m に初期値として定数 hour を設定しています。
 7行目と8行目の型宣言文は、character文で文字型(character)の変数を定義しています。7行目では、変数 filen を1から 2 の寸法をもつ文字型の1次元配列で文字の長さは9文字、変数 data1 と data2 を1から 2 の寸法をもつ文字型の1次元配列で文字の長さは40文字と宣言しています。8行目は、character*8によりこの文の並びの変数 toshi1 と toshi2 を文字型で長さが8文字と宣言しています。この例に示すように文字型変数の長さの指定方法に2種類あります。長さの指定を省略すると長さは 1 になります。

 10行目から11行目は、配列要素 filen(1) に1回目に読み込むデータファイルのファイル名 't199601.d' を、配列要素 filen(2) に2回目に読み込むデータファイルのファイル名 'm199601.d' を格納しています。

10行目       filen(1)='t199601.d'
11行目       filen(2)='m199601.d'

 12行目から32行目は、1地点の気温データファイルを読み込んで、各観測時刻の平均気温を求める部分でこれをdo文で2回繰り返しています。

12行目       do 10010 k=1,2
   :
32行目 10010 continue 

この部分について詳しくみていきましょう。

 14行目から18行目はファイルをオープンして、先頭の4行のデータを読み込む部分です。

14行目       open(11,file=filen(k),status='old')
15行目       read(11,100) 
16行目       read(11,100) data1(k)
17行目       read(11,100) data2(k)
18行目       read(11,100) 
   :
45行目   100 format(a40)

14行目のopen文でデータファイル(ファイル名は文字型の配列要素 filen(k) の値)を装置番号11の装置につなげて開きます。1回目(k=1)はファイル名 't199601.d' のファイルがオープンされ、2回目(k=2)はファイル名 'm199601.d' のファイルがオープンされます。15行目のread文で、先頭の1レコードを読み飛ばします。16行目と17行目のread文で、次の2レコードの先頭から40文字を data1(k) と data2(k) に読み込みます。この read文の書式は45行目の文番号 100 の format文で (a40) です。data1(k) には観測地点名が含まれている文字列(k=1の時)

     観測所番号:44131  東京        
が、data2(k) には観測年月が含まれている文字列(k=1の時)
          1996年01月   気温(0.1°C)     
が読み込まれることになります。18行目のread文では次のレコード(4レコード目)を読み飛ばしています。

 19行目から23行目はファイルから1ヶ月分のデータを読み込み、最後にファイルを閉じる部分です。データの書式仕様は46行目の文番号101のformat文です。

19行目  1001 continue
20行目       read(11,101,end=2001) n,(a(i,n),i=1,m)
21行目       go to 1001
22行目  2001 continue
23行目       close(11)
   :
46行目   101 format(i2,24f4.1)

20行目のread文で1日分のデータを読み込んだら、次行の go to 文で、次の日のデータを読むために文番号 1001 の continue文に無条件に戻します。データが終わりになったらファイル終了指定子により文番号 2001 の continue文に制御を移します。1月のデータは31日分ありますが、他の月のデータは31日分あるとは限りませんので、ファイル終了指定子を用いてデータ数の違いに対応できるようにしています。
 この read文では、書式仕様(i2,24f4.1)にしたがって、まず日にちを変数 n に i2(2桁の整数)で読み込み、次に do 並び(配列要素 a(i,n) の i について1から m(ここでは24)まで)を f4.1(4桁の幅で小数点以下1桁)で読み込みます。
 23行目の close文で装置番号11のファイルを閉じます。

25行目から31行目は平均気温を求める部分です。「観測時刻ごとの1ヶ月の平均気温を求める」ことを観測時刻分繰り返しますので、次に示すように do のループが2重の入れ子になっています。内側のループ(27行目から29行目)が1ヶ月( j について1から n )、外側のループ(25行目から31行目)が1日分(24時)( i について1から m )です。

25行目       do 2010 i=1,m
26行目         asum=0.0
27行目         do 2020 j=1,n
28行目           asum=asum+a(i,j)
29行目  2020   continue
30行目         av(i,k)=asum/real(n)
31行目  2010 continue

 外側の doループの中(26行目〜30行目)は、i のある値について平均気温を求める部分です。まず、合計を求める変数 asum を 0.0 にしてから内側の doループで j について1〜n の合計を求め、30行目では平均気温を求めています。平均気温は2回目の地点の計算中に値が失われてはならないので、配列要素 av(i,k) に格納しています。すなわち、k=1のときには av(i,1)に、k=2のときには av(i,2)にそれぞれ格納しています。

 34行目と35行目は、文字型変数 toshi1 と toshi2 に文字型の配列要素 deta1(1) と deta1(2) の内容から観測地点名を抜き出しています(文字処理参照)。

34行目       toshi1=data1(1)(24:31)
35行目       toshi2=data1(2)(24:31)

data1(1)の内容はここでは

     観測所番号:44131  東京        
になっています。部分文字列 data1(1)(24:31) は配列要素 data1(1) の24文字目から31文字目までの8文字を抽出していますので、文字型変数 toshi1 には東京  が代入されています。文字型変数 toshi2 には、同様に紋別  が代入されます。観測地点名には漢字で4文字分を想定しています。

 36行目から43行目は計算結果を出力する部分です。書式仕様には47行目から49行目のformat文を使用しています。

36行目       write(*,601) data2(1)(11:27),toshi1,toshi2
37行目       write(*,602) toshi1,toshi2,toshi1,toshi2
38行目       do 3010 i=1,m/2
39行目         i1=2*i-1
40行目         i2=i1+1
41行目         write(*,603) i1, av(i1,1), av(i1,2), av(i1,1)-av(i1,2)
42行目      *              ,i2, av(i2,1), av(i2,2), av(i2,1)-av(i2,2)
43行目  3010 continue
   :
47行目   601 format( 3x,a17,'の差',4x,a8,'と',2x,a8)
48行目   602 format(/ 2(8x,' 時',5x,a8,1x,a8,3x,'差'))
49行目   603 format(2(8x,i3,3f9.1))

36行目と37行目のwrite文で見出しを出力します。
36行目のwrite文では、文字変数 data2(1)(11:27),toshi1,toshi2 を文番号 601 の format文の書式にしたがって出力します。まず、3桁移動してから、文字型配列要素 data2(1) の内容

          1996年01月  気温(0.1°C)     
の11文字目から27文字目までの部分文字列1996年01月  気温を書式仕式(a17)で、次に文字列の差、4桁移動して、文字型変数 toshi1 の内容東京  を書式仕様(a8)で、2桁移動して、文字型変数 toshi2 の内容紋別  を書式仕様(a8)で出力します。このwrite文では
   1996年01月   気温の差    東京  と  紋別  
と出力されます。

37行目のwrite文では、文字変数 toshi1,toshi2,toshi1,toshi2 を文番号 602 の format文の書式にしたがって出力します。まず、区切り記号 / により改行してから( )内を2回繰り返します。( )内は、まず8桁移動してから、文字列を、次に5桁移動して、 文字型変数 toshi1 の内容東京  を書式仕様(a8)で、1桁移動して、文字型変数 toshi2 の内容紋別  を書式仕様(a8)で、3桁移動して、文字列を出力します。このwrite文では
         時     東京   紋別     差         時     東京   紋別     差
と出力されます。

36行目と37行目のwrite文で出力した見出しの下に各観測時刻の1ヶ月の平均気温を、東京の平均気温、紋別の平均気温、その差という順番に2列に並べて出力します。そのため39行目から43行目の do文の範囲は変数 m の半分の回数だけ繰り返せばいいことになります。
39行目と40行目では変数 do の制御変数 i と出力する配列の要素の番号との関係を変数 i1 と i2 に 計算しています。i=1のときには i1=1,i2=2、i=2のときには i1=3,i2=4、・・・となっています。
41、42行目のwrite文では、出力並び i1, av(i1,1), av(i1,2), av(i1,1)-av(i1,2)を文番号 603 の format文の書式にしたがって出力します。 まず8桁移動してから、変数 i1 を書式仕様(i3)で、続けてav(i1,1), av(i1,2), av(i1,1)-av(i1,2)を書式仕様(3f9.1)で出力し、出力並び i2, av(i2,1), av(i2,2), av(i2,1)-av(i2,2)を書式の繰り返しにしたがって同様に出力します。i=1のとき、このwrite文では
          1      5.3     -5.8     11.1          2      5.0     -6.0     11.0
と出力されます。


 例題9の出力結果は次のようになります。


   1996年01月   気温の差    東京  と  紋別  

         時     東京   紋別     差         時     東京   紋別     差
          1      5.3     -5.8     11.1          2      5.0     -6.0     11.0
          3      4.7     -6.2     10.9          4      4.3     -6.3     10.6
          5      4.0     -6.5     10.5          6      3.8     -6.6     10.5
          7      3.8     -6.7     10.5          8      4.5     -6.2     10.6
          9      5.6     -5.2     10.8         10      6.9     -4.2     11.1
         11      7.9     -3.5     11.4         12      8.8     -3.4     12.2
         13      9.2     -3.3     12.6         14      9.6     -3.6     13.3
         15      9.6     -3.9     13.5         16      9.0     -4.4     13.4
         17      8.5     -4.8     13.3         18      7.9     -5.2     13.1
         19      7.5     -5.4     13.0         20      7.1     -5.8     12.8
         21      6.8     -5.9     12.7         22      6.4     -6.0     12.4
         23      6.0     -6.1     12.1         24      5.7     -6.0     11.7


Fortranの文法参照