シート読み取りから解答欄へ

概要

Eコマンドで得られるデータにあるようにマークリーダから送られるデータは欄ごとで、下図の様に横長に使ったときには縦一列を読んだデータを列ごとに読み出すことになります。これを解答欄ごとのデータに変換しなければなりません。

特に入試では通し番号の汎用解答シートを使うのを避け、大問1の問1とか(1)などで解答位置を指定していますから、教科により年度によりレイアウトが異なります。

これをどのようにプログラムに伝えるか。これを解説します。

レイアウト

2011年の理科の解答用紙です。この年はまだSR-505で、0.3インチピッチでしたから24行までで行のマークもA-Wでしめされていましたが、無理やり0.25インチピッチのつもりで0-9,:;<=>?@,A-Gまでの24行として考えてみます。(ほんとうはGまでではなくPまでの33行)

シート 読み取り範囲 対応する解答

[読み取り範囲]をクリックすると読み取る位置とその位置を表すコードが見えます。

[対応する解答]をクリックするとそのコードに対応する解答が見えます。これを以下の様なテキストファイルで指示します。

NNNN IIIIIIIII IIIIIIIII IIIIIIIII
                                  
1111                              
2222           123456789          
3333           123456789          
4444 123456789 123456789 123456789
5555 123456789 123456789 123456789
6666 123456789 123456789 123456789
7777 123456789 123456789 123456789
8888 123456789           123456789
9999 123456789           123456789
0000 123456789                    
               123456789 123456789
     123456789 123456789 123456789
               123456789 123456789
                                  
               123456789          
     123456789                    
     123456789           123456789
                         123456789
                                  
                                  
               123456789          
     123456789 123456789          
     123456789 123456789          

NNNN IIIII は欄をグループ分けする仕組みです。スペースがグループの区切り、Nのついた欄は受験番号のフィールド、Iのついた欄はは解答のフィールドを表しています。最下行のタイミングマークに対応します。ただしマークリーダーはタイミングマークの間が余計に間が空いていることは関知しません。そこで4欄と5欄の間に区切りがあることをNNNN IIII... のスペースで知らせるわけです。

その次の行からはそこにマークを感知したとき何を選んだことになるかの記号を書きます。たとえば

1,2,3,4欄の F にマークがあった場合は、それぞれ 1111
5,6,7,8,9,10,11,12,13欄の C にマークがあった場合は、それぞれ 123456789

とマークがあったとするということです。文字がなくスペースの所はマークがあっても無視するところになります。

マークシートを正値したときのレイアウトを、そのままテキストファイルにすればよいようにしています。

欄のグループ指示を読むプログラム

上記のファイルを文字変数の配列DS$(i)に読みます。まず1行目の"NNNN IIIII...."がDS$(0)に読み込まれたとしてそれを切り分けます。

DEFINT A-Z
TRUE=(1=1):FALSE=NOT TRUE
DS$(0)="NNNN III IIIII IIIIIIII IIIIIIII"
' == *SETCODE の一部 ==
DIM CMBG(80),CMW(20),PTR(80)
CMON=FALSE:CMMX=0:CM=0:TMCT=0:WCT=0
FOR I=1 TO LEN(DS$(0))
    I$=MID$(DS$(0),I,1)
    IF I$<>" " THEN
        TMCT=TMCT+1:PTR(TMCT)=I
        IF CMON=FALSE THEN 
            CM=CM+1:CMBG(CM)=TMCT:WCT=1
            CMON=TRUE
            IF I$="N" THEN CMJUB=CM
        ELSE
            WCT=WCT+1
        ENDIF
    ELSE
        IF CMON=TRUE THEN CMW(CM)=WCT:CMON=FALSE
    ENDIF
NEXT
CMW(CM)=WCT:CMON=FALSE:CMMX=CM:IDCM=CMW(CMJUB)

このプログラムで次のようなデータが用意されます。このBASICでも配列の添字は0からですが、ここでは1から使用しています。

CMMX=5 TMCT=28 CMJUB=1
CMBG(1)= 1 CMW(1)=4  
CMBG(2)= 5 CMW(2)=3
CMBG(3)= 8 CMW(3)=5
CMBG(4)=13 CMW(4)=8  
CMBG(5)=21 CMW(5)=8
PTR(i)=0,1,2,3,4,6,7,8,10,11,12,13,14,16,17,18,19,20,21,22,23,25,26,27,28,29,30,31,32
DS$(0)="NNNN IIIIIIIII II..."
DS$(g)="3333 123456789 12..."

各変数の説明です。

PTR(i) :DS$(0)のうちスペースでない文字の位置を表す
      "NNNN IIII III" なら 1,2,3,4,6,7,8,9,11,12,13
CMBG(i):i番目のコラム(Tマークの群)が始まるTマークの番号を表す
      "NNNN IIII III" なら 1,5,9
      (Tマークには隙間はないのでNNNNIIIIIIIと読んでいる)
CMW(i) :i番目のコラム(Tマークの群)の幅(Tマーク数)を表す
      "NNNN IIII III" なら 4,4,3
CMMX   :コラム数
CMJUB  :受験番号になるコラム番号(先頭がNであることで判断)

グループ指示に従って解答欄ごとに切り出す

マークリーダの都合で行単位で読みだしたものを、解答欄ごとに再構成するプログラム。

WHILE と DOITを組み合わせている部分は、N88BASICが IF〜ENDIF(多行IF文) が使えなかったのでその代用の構文。受験番号(CMJUB)以外のグループだけ処理するのに使用している。02とあるのは2002年に国語の受験番号のグループを縦書きに合わせて右に移動したにの対応させたもの。

解答欄ごとに再構成したマークは一旦KA$(i)に収められ、その後使わない解答欄を省いて最終的にSE$(i)に格納する。

*TOMMS 'i(DEK$(),SKA$(),MM()),o(KA$(M)),w(CM,J,I,OTH,MBG,U,SK$,S$)
 ERASE KA$:DIM KA$(MLIM) :CMCT=0:DOIT=FALSE
 FOR CM=1 TO CMMX 'CM1
   IF CM<>CMJUB THEN DOIT=TRUE    '<<02
   WHILE DOIT
     CMCT=CMCT+1
     FOR J=1 TO CMW(CM)
       AX$=AX$(CMBG(CM)+J-1)
       FOR I=1 TO LEN(AX$)
         S$=MID$(AX$,I,1)
         if S$=" " then continue
         U$=MID$(DS$(GYOMX-ASC(S$)+&H30),PTR(CMBG(CM)+J-1),1)
         IF U$<>" " THEN M=CMCT*GYOMX-ASC(S$)+&H30:KA$(M)=KA$(M)+U$ 'CM1
       NEXT
     NEXT
     DOIT=FALSE
   WEND
 NEXT
 MMAX=0
 FOR M=1 TO CMMX*GYOMX
    IF KA$(M)<>"" THEN MMAX=MMAX+1:MM(MMAX)=M:SE$(MMAX)=KA$(M)
    'PRINT M;"(";KA$(M);")";"-";
 NEXT  :PRINT
RETURN

各変数の説明です。

AX$(i) :マークリーダーが行ごとに読んだデータ。
        マークのあった欄に対応するアスキー文字が入っている。
        可変長データ。
KA$(i):NNNNでないグルーブの数×マークリーダの欄数からなる解答欄ごとのデータ。
        欄のグループ指示に対応する文字のないところは空文字列となる。
SE$(i) :KA$(i)から空文字列でないものを取り出して、通し番号をつけたもの。
MM(i)  :SE$()がKA$()の何番目に当たるかの数値。SE$(i)=KA$(MM(i))

架空ミニサイズシートでの具体的な例

A-Jの10欄からなる架空のマークリーダーとシートを実例に説明してみましょう。

マーク例シートはこんな感じで、すでに例としてマークをしてある。レイアウトを指定するテキストファイルは次のようになります。

NN IIII III
11         
22      123
33      123
44 1234 123
55 1234    
66 1234    
77 1234 123
88 1234 123
99 1234 123
00 1234    

これを読んだ後の変数の値は次のようになっています。

CMMX=3 TMCT=9 CMJUB=1
CMBG(1)= 1 CMW(1)=2  
CMBG(2)= 3 CMW(2)=4
CMBG(3)= 7 CMW(3)=3
PTR(i)=0,1,2,4,5,6,7,9,10,11 (iは0〜10)
DS$(0)="NN IIII III"
DS$(1)="11         "
DS$(2)="22      123"
DS$(3)="33      123"
DS$(4)="44 1234 123"
DS$(5)="55 1234    "
DS$(6)="66 1234    "
DS$(7)="77 1234 123"
DS$(8)="88 1234 123"
DS$(9)="99 1234 123"
DS$(10)="00 1234    "

リーダーで読み取りマークリーダのEコマンドで読み取ったデータは次のようになります。

AX$(1)="J"
AX$(2)="I"
AX$(3)="BE"
AX$(4)="ACG"
AX$(5)=" "
AX$(6)="ADF"
AX$(7)="BG"
AX$(8)="CDH"
AX$(9)="I"

AX$(0)はあえて使っていません。図の下部の青い数字が行番号でAX$()の添字になります。図はAX$(4)が"ACG"であることを示しています。マークリーダの仕様でマークのない行はスペース1個が出力されます(AX$(5))。

また、記述の解答欄への記入や黒い字で印刷された部分も読む場合があります。たとえばAX$(9)では「欄」という字をマークとみなしてAX$(9)="EIJ"となるかもしれません。しかし、レイアウトを指定するテキストではスペースですから次のKA$(M)に影響しません。

解答欄ごとに切り出すAX$(i)を解答欄ごとに切り出し、さらにA-Jを対応する解答に置き換えます。ます。*TOMMSのサブルーチンで、KA$(M)は次のように変換されます。

KA$(1)=""
KA$(2)=""
KA$(3)=""
KA$(4)="2"
KA$(5)="4"
KA$(6)="1"
KA$(7)="4"
KA$(8)="2"
KA$(9)="1"
KA$(10)="24"
KA$(11)=""
KA$(12)="3"
KA$(13)="2"
KA$(14)="1"
KA$(15)=""
KA$(16)=""
KA$(17)="2"
KA$(18)="2"
KA$(19)="1"
KA$(20)=""

使用する解答欄だけさらに*TOMMSのサブルーチンの最後で、使用する解答欄SE$(N)だけを取り出します。

SE$(1)="2"   :MM(1)=4
SE$(2)="4"   :MM(2)=5
SE$(3)="1"   :MM(3)=6
SE$(4)="4"   :MM(4)=7
SE$(5)="2"   :MM(5)=8
SE$(6)="1"   :MM(6)=9
SE$(7)="24"  :MM(7)=10
SE$(8)="3"   :MM(8)=12
SE$(9)="2"   :MM(9)=13
SE$(10)="1"  :MM(10)=14
SE$(11)="2"  :MM(11)=17
SE$(12)="2"  :MM(12)=18
SE$(13)="1"  :MM(13)=19

変数名がSEになっていますが、これは正解のマークとして読み取らせた場合を想定しています。

MM()について追加。KA$()の値をもとにSE$()に正解の設定をするのがここ*TOMMSですが、正解以外のシートではMM()の値に従いKA$()の値を詰めてKA$()をそのまま使います。そのためにMM()の理解が必要です。


Jan.2012
安達順一
http://www.seiai.ed.jp/