Python vs Modula-2

(1A) Reading data file

(1)に戻る   Workbench Python に戻る

<Task>

(1) より複雑になりますが実用的なプログラムです。 csv形式のテキストファイルの1行目に数値情報(iで始まれば2行目以降は整数、さもなくば実数)が書かれいます。その行の項目数は1行あたりの変数の数と同じです。 例えばdatasheet1.csv (内容はここ) には3つの実数データ time,conc,err が各行に入っています。 datasheet2.csv (内容はここ) には整数と実数のデータ i_number,weight が各行に入っています。 これらのデータを読み取り、表示してください。

<Python (Object Oriented Programming)>

[Module] fileRead.py

import numpy as np 

class readtest:
    
    def __init__(self,fname): 
        xa = []
        ya = []
        za = []
        maxitem = 3
        isf = np.arange(maxitem)
		
        def findTypes(res, n):
            for i in range(n):
                s = res[i].upper()
                isf[i] = (s[0] != 'I')
                if isf[i]==True:
                    print('float, ', end="")
                else:
                    print('integer, ', end="")
            print()
            return isf  # maybe redundant
  		
        file = open(fname, 'r') 
        line = file.readline()
        self.header = line

        l = len(line)
        line = line[:l-1]
        result = line.split(',')

        for x in reversed(result):  # remove ""
            if len(x)>0:
                break
            else:
                result.remove(x)
            
        n_item = len(result)
        isf = findTypes(result, n_item) 

        i = 0
        while (True):
            line = file.readline()
            l = len(line)
            line = line[:l-1]
            if len(line)==0: 
                print('Null line: end of file')
                break
            print(line)
            if ('END' in line.upper()):
                print('END found')
                break 

            result = line.split(',')
            if isf[0]:
                xa.append(float(result[0]))
            else:
                xa.append(int(result[0]))
            if n_item > 1:
                if isf[1]:
                    ya.append(float(result[1]))
                else:
                    ya.append(int(result[1]))
            if n_item > 2:
                if isf[2]:
                    za.append(float(result[2]))
                else:
                    za.append(int(result[2]))
               
            i += 1               
        file.close()

        self.fname = fname
        self.ndata = i
        self.nitem = n_item
		self.isfloat = isf
        self.xa = xa
        self.ya = ya
        self.za = za

    def datatypes(self):
        print('Data types: ', end="")
        for i in range(self.nitem):
            if self.isfloat[i]:
                print('float ',end="")
            else:
                print('integer ',end="")
        print()      
[Main] mytest.py
#f = readtest('datasheet1.csv')
f = readtest('datasheet2.csv')
nitem = f.nitem
print('x:',f.xa)
if nitem>1:
    print('y:',f.ya)
    if nitem>2:
        print('z:',f.za)
print('ndata:', f.ndata)
<Modula-2 (Structured Programming)>

IMPLEMENTATION MODULE fileRead.MOD

IMPORT FIO, Str;
FROM IO IMPORT WrStr, WrLn;

PROCEDURE readtest(fname: ARRAY OF CHAR;
	VAR ndata, nitem: INTEGER;
		 VAR isf: ARRAY OF BOOLEAN;
	       VAR x,y,z: ARRAY OF LONGREAL;
	    VAR ix,iy,iz: ARRAY OF INTEGER);

  PROCEDURE findTypes(s: ARRAY OF CHAR);
    VAR
      a: ARRAY[0..15] OF CHAR;
      i: INTEGER;
    BEGIN
      WrStr('findTypes'); WrLn;
      i:= 0;
      LOOP
        Str.Item(a, s, Str.CHARSET{','}, i);
	    IF Str.Length(a)=0 THEN EXIT END;
	    Str.Caps(a);
	    isf[i]:= (a[0]<>'I');
	    INC(i);
      END;	
      nitem:= i;
    END findTypes;

  VAR
    f : FIO.File;
    line, s: ARRAY[0..79] OF CHAR;
    nline,i: INTEGER;
    OK : BOOLEAN;
  BEGIN
    IF NOT FIO.Exists(fname) THEN 
	  WrStr('File not exist'); WrLn; RETURN END;
    f := FIO.Open(fname);
    nline := 0; ndata := 0;
    LOOP
      FIO.RdStr(f,line);
      WrStr(line); WrLn;
      IF Str.Length(line)=0 THEN 
	    WrStr('Null line found'); WrLn; EXIT END;
      INC(nline);
      IF nline=1 THEN
        Str.Copy(header,line);
        findTypes(header);
      ELSE
        Str.Caps(line);
        IF Str.Pos(line,'END')<Str.Length(line) THEN
          WrStr("'END' reached"); WrLn; EXIT;
     	END;
        FOR i:= 0 TO nitem-1 DO
          Str.Item(s, line, Str.CHARSET{','}, i);
          CASE i OF
       |0: IF isf[i] THEN x[ndata]:= Str.StrToReal(s,OK);
	       ELSE ix[ndata]:= Str.StrToInt(s,10,OK);
	       END;
       |1: IF isf[i] THEN y[ndata]:= Str.StrToReal(s,OK);
	       ELSE iy[ndata]:= Str.StrToInt(s,10,OK);
	       END;
       |2: IF isf[i] THEN z[ndata]:= Str.StrToReal(s,OK);
	       ELSE iz[ndata]:= Str.StrToInt(s,10,OK);
	       END;
          END;
        END;	
        INC(ndata);
      END;
    END;
    FIO.Close(f);
  END readtest;
  
PROCEDURE datatypes(isf: ARRAY OF BOOLEAN; n: INTEGER);
  VAR
    i: INTEGER;
  BEGIN
    WrStr('Data types: ');
	FOR i:= 0 TO n-1 DO
	  IF isf[i] THEN WrStr('float '); 
	  ELSE WrStr('integer '); END;
	END;
    WrLn;
  END datatypes;	

[Main] mytest.MOD

IMPORT fileRead;
FROM IO IMPORT WrStr, WrLn, WrLngReal, WrInt;
  
CONST
  N_item = 3;
  N_data = 1000;

VAR
  header: ARRAY [0..79] OF CHAR;
  isf: ARRAY [0..N_item-1] OF BOOLEAN;
  ndata, nitem: INTEGER;
  x,y,z: ARRAY[0..N_data-1] OF LONGREAL;
  ix,iy,iz: ARRAY[0..N_data-1] OF INTEGER;

BEGIN  
  fileRead.readtest('datasheet1.csv',
    ndata, nitem, isf, x,y,z, ix,iy,iz);
  WrStr('nitem='); WrInt(nitem,1); WrLn;
  WrStr('ndata='); WrInt(ndata,1); WrLn;
  FOR i:=0 TO ndata-1 DO
    j:=0;
    IF isf[j] THEN WrLngReal(x[i],5,10);
    ELSE WrInt(ix[i],2);
    END;
    WrStr(', ');
    IF nitem>1 THEN
      j:=1;
      IF isf[j] THEN WrLngReal(y[i],5,10);
      ELSE WrInt(iy[i],2);
      END;
      WrStr(', ');
      IF nitem>2 THEN
        j:=2;
        IF isf[j] THEN WrLngReal(z[i],5,10);
        ELSE WrInt(iz[i],2);
        END;
      END;
    END;
    WrLn;
  END;

コメント
初心者がいうのもなんですが・・・
  • [Main] が簡潔に書ける(xa が実数でも整数でも構わない) のは便利なことこの上ない。しかし f.datatypes() で確認しておくのが無難では。
  • csvファイルの空白セル "" も数えてしまうので削除しておいた。
  • type を別の流儀(string も含むとか)で判定したければ findTypes を書き換えればよい。

  • 実数か整数かはファイルを読んでみなければ分からないというのはModula-2にとって不利。 X〜y,ix〜iz の6個の配列を準備しておくのはメモリーの無駄遣いになる。
  • データ数の最大値や項目数の最大値が絞り込められれば CONST の内容を修正する。
  • findTypes を別にしたのは左と同じ。ARRAY OF BOOLEAN を ARRAY OF mytype の形にできるのは Modula-2 の利点。

11-11-2022, S. Hayashi