このディレクトリの索引
# 入力ファイルを読み込み、顧客別売上明細書を出力する
# 
# ・支店が変われば、支店合計を印字し改ページをする
# ・顧客が変われば、顧客合計を印字し、1行空白を印字する
# ・入力ファイルはソートされているものとする
# ・入力ファイル、出力ファイルはコマンドライン引数で受け取る
# ・20行を超える場合は、改ページする
#  ただし、合計出力途中の場合は20行を超えていても出力する
# ・金額出力時のカンマ編集をする
# 
# ・例外処理は、コマンドライン引数が正しくない場合、入力・出力ファイルがオープンできない場合、入力ファイルにデータがない場合の4種類
# 
# ・突合せ処理(コントロールブレイク>)を使用する
# 
# ・入力ファイルの支店コードから売上金額までクラス分けをする
# 	(クラス分けがよく解りませんが、Cの構造体のようなものを使用せよと言われました)
# 	
# ・例外処理を書いたメインメソッド、突合せ処理メソッド、ヘッダメソッドの3つに分ける
# 
# 下記の処理をヘッダメソッドとする
# ここから
# 				帳票明細
# 001 東京 支店		出力日6月21日(出力した日)  P.1
# 			(空白行 1行)
# 	販売先				販売日		販売金額
# ---------------------------------------------------------------
# ここまで
# 
# 
# 
# ☆入力ファイル例
# ?支店コード ?支店名 ?販売日 ?販売先コード ?販売先名 ?売上金額
# 
# 
# 001 東京 20090601 0001 田中商店  1000
# 001 東京 20090602 0001 田中商店  5000
# 001 東京 20090603 0001 田中商店  10000
# 001 東京 20090601 0002 山田スーパー  3000
# 002 沖縄 20090604 0001 沖縄商店  7000
# ☆出力ファイル例
# 
# 				帳票明細
# 
# 001 東京 支店		出力日6月21日(出力した日)  P.1
# 			(空白行 1行)
# 	販売先				販売日		販売金額
# ---------------------------------------------------------------
# 0001	田中商店			6月1日		1,000
# 0001	田中商店			6月2日		5,000
# 0001	田中商店			6月3日		10,000
# ----------------------------------------------------------------
# 	販売合計		件数 3			16,000
# 			(空白行 1行)
# 0002	山田スーパー			6月1日		3,000
# ----------------------------------------------------------------
# 	販売合計		件数 1			3,000
# 			(空白行 1行)
#    **支店合計		件数 4			19,000
# 
# 
# 
# 
# 				帳票明細
# 002 沖縄 支店		出力日6月21日(出力した日)  P.2
# 			(空白行 1行)
# 	販売先				販売日		販売金額
# ----------------------------------------------------------------
# 0001	沖縄商店			6月4日		7,000
# ----------------------------------------------------------------
# 	販売合計		件数 1			7,000
# 			(空白行 1行)
#    **支店合計		件数 1			7,000
#    ***総合計			件数 5			26,000
# 
# 
#
# 入力ファイルを以下のように変更しましょう。

顧客別売上明細書を出力する :-
   入力ファイルを読み込む(F1,F2,F3,L1,L2,L3),
   コントロールブレイク(L1,L2,L3,0,0,0,0,0,0,0).
   

入力ファイルを読み込む(F1,F2,F3,L1,L2,L3) :-
    ファイルを全行読み取る(F1,L1),
    ファイルを全行読み取る(F2,L2),
    ファイルを全行読み取る(F3,L3).

コントロールブレイク([L1],[L2|R2],[L3|R3],_頁,_行,CX1,CX2,CX3,SX1,SX2,SX3) :-
    コントロールブレイクパターン(6,L1,[],L2,L3),
    合計加算(L1,SX,SX2,SX3,SX4,SX5,SX6),
    明細行表示(_頁,_頁1,_行,_行1,L1,L2,L3),
    write('---------------------------------------------------------------\n'),
    改頁制御(_頁1,_頁2,_行1,_行2,L2,L3),
    販売先合計表示(_行2,_行3,CX5,SX5),
    改頁制御(_頁2,_頁3,_行3,_行4),
    支店合計表示(_行4,_行5,CX4,SX4),
    改頁制御(_頁3,_頁4,_行5,_行6),
    総合計表示(_行3,_,CX3,SX3),!.
コントロールブレイク([L1,L12|R1],[L2|R2],[L3|R3],_頁,_行,CX1,CX2,CX3,SX1,SX2,SX3) :-
    コントロールブレイクパターン(1,L1,L12,L2,L3),
    合計加算(L1,SX1,SX2,SX3,SX4,SX5,SX6),
    明細行表示(_頁,_頁1,_行,_行1,[K|R11],L2,L3),
    コントロールブレイク([L12|R1],[L2|R2],[L3|R3],_頁1,_行1,CX4,CX5,CX6,SX4,SX5,SX6).
コントロールブレイク([L1,L12|R1],[L2|R2],[L3|R3],_頁,_行,CX1,CX2,CX3,SX1,SX2,SX3) :-
    コントロールブレイクパターン(2,L1,L12,L2,L3),
    合計加算(L1,SX,SX2,SX3,SX4,SX5,SX6),
    明細行表示(_頁,_頁1,_行,_行1,L1,L2,L3),
    販売先合計表示(_頁1,_頁2,_行1,_行2,CX5,SX5),
    コントロールブレイク([L12|R1],[L2|R2],[L3|R3],_頁2,_行2,CX,0,CX6,SX4,0,SX6).
コントロールブレイク([L1,L12|R1],[L2|R2],[L3|R3],_頁,_行,CX1,CX2,CX3,SX1,SX2,SX3) :-
    コントロールブレイクパターン(3,L1,L12,L2,L3),
    合計加算(L1,SX,SX2,SX3,SX4,SX5,SX6),
    明細印刷(_頁,_頁1,_行,_行1,L1,L2,L3),
    販売先合計表示(_頁1,_頁2,_行2,_行3,CX5,SX5),
    支店合計表示(_頁2,_頁3,_行4,_行5,CX4,SX4),
    コントロールブレイク([L12|R1],[L2|R2],[L3|R3],_頁3,0,0,0,CX3,0,0,SX3),!.
コントロールブレイク([L1|R1],[L2|R2],[L3|R3],_頁,_行,CX1,CX2,CX3,SX1,SX2,SX3) :-
    コントロールブレイクパターン(4,L1,_,L2,L3),
    コントロールブレイク([L1|R1],R2,[L3|R3],_頁,_行,CX1,CX2,CX3,SX1,SX2,SX3),!.
コントロールブレイク([L1|R1],[L2|R2],[L3|R3],_頁,_行,CX1,CX2,CX3,SX1,SX2,SX3) :-
    コントロールブレイクパターン(5,L1,_,L2,L3),
    コントロールブレイク([L1|R1],[L2|R2],R3,_頁,_行,CX1,CX2,CX3,SX1,SX2,SX3).


コントロールブレイクパターン(1,L1,L12,L2,L3) :-
    鍵項目(売上明細,L1,[KL1,KL11|_]),
    鍵項目(売上明細,L12,[KL1,KL11|_]),
    鍵項目(支店名,L2,[KL1|_]),
    鍵項目(販売先名,L3,[KL11|_]),!.
コントロールブレイクパターン(2,L1,L12,L2,L3) :-
    鍵項目(売上明細,L1,[KL1,KL11|_]),
    鍵項目(売上明細,L12,[KL1,KL12|_]),
    not(KL11=KL12),
    鍵項目(支店名L2,[KL1|_]),
    鍵項目(販売先名,L3,[KL11|_]),!.
コントロールブレイクパターン(3,L1,L12,_,_) :-
    鍵項目(売上明細,L1,[KL1,_|_]),
    鍵項目(売上明細,L12,[KL12,_|_]),
    not(KL1=KL12),!.
コントロールブレイクパターン(4,L1,_,L2,_) :-
    鍵項目(売上明細,L1,[KL1|_]),
    鍵項目(支店名,L2,[KL2|_]),
    KL1 @> KL2,!.
コントロールブレイクパターン(5,L1,_,_,L3) :-
    鍵項目(売上明細,L1,[_,KL11|_]),
    鍵項目(販売先名,L3,[KL3|_]),
    KL11 @> KL3,!.
コントロールブレイクパターン(6,L1,[],L2,L3) :-
    鍵項目(売上明細,L1,[KL1,KL11|_]),
    鍵項目(支店名,L2,[KL1|_]),
    鍵項目(販売先名,L3,[KL11|_]),!.

鍵項目(売上明細,[_支店コード,_,_販売先コード|_],[_支店コード,_販売先コード]).
鍵項目(支店名,[_支店コード|_],[_支店コード]).
鍵項目(販売先名,[_販売先コード|_],[_販売先コード]).

明細行表示(_頁,_次の頁,0,_次の行,L1,L2,L3) :-
    鍵項目(支店名,L2,[_支店コード,_支店名|_]),
    今日(_今日),
    sub_atom(_今日,4,2,_,_月),
    sub_atom(_今日,6,2,_,_日),
    支店名見出し(_支店コード,_支店名,_月,_日,_頁),
    明細行表示(_頁,_頁,0,6,L1,L2,L3),!.
明細行表示(_頁,_次の頁,_行,_次の行,
           [_支店コード,_支店名,_販売日,_販売先コード,_販売先名,_売上金額],
           L2,L3) :-
    _行 > 20,
    _頁1 is _頁 + 1,
    明細行表示(_頁1,_次の頁,1,_次の行,
               [_支店コード,_支店名,_販売日,_販売先コード,_販売先名,_売上金額],
               L2,L3),!.

明細行表示(_頁,_頁,_行,_次の行,
           [_支店コード,_支店名,_販売日,_販売先コード,_販売先名,_売上金額],
           L2,L3) :-
    _行 < 20,
    sub_atom(_販売日,4,2,_,_月),
    sub_atom(_販売日,6,2,_,_日),
    カンマの挿入(10,_売上金額,_カンマ付き売上金額),
    write_formatted('%4d %-30s%2d月%2d日        %t\n',[_販売先コード,_販売先名,_月,_日,_カンマ付き販売金額]),
    _次の行 is _行 + 1,!.
支店合計表示(_頁,_次の頁,_行,_次の行,_件数,_合計) :-
    _行 > 20,
    改頁,
    _頁1 is _頁 + 1,
    支店合計表示(_頁1,_次の頁,1,_次の行,_件数,_合計),!.
支店合計表示(_頁,_次の頁,_行,_次の行,_件数,_合計) :-
    _行 =< 20,
    _次の行 is _行 + 1,
    カンマの挿入(10,_合計金額,_カンマ付き合計金額),
    write('     **支店合計            件数 %2d               %t\n',[_件数,_カンマ付き合計金額]),!.


販売先合計表示(_頁,_次の頁,_行,_次の行,_件数,_合計) :-
    _行 > 20,
    改頁,
    _頁1 is _頁 + 1,
    販売先合計表示(_頁1,_次の頁,1,_次の行,_件数,_合計),!.
販売先合計表示(_頁,_頁,_行,_次の行,_件数,_合計) :-
    _行 =< 20,
    _次の行 is _行 + 1,
    カンマの挿入(10,_合計金額,_カンマ付き合計金額),
    write('     販売合計              件数 %2d               %t\n',[_件数,_カンマ付き合計金額]),!.

総合計表示(_頁,_次の頁,_行,_次の行,_件数,_合計) :-
    _行 > 20,
    改頁,
    _次の頁 is _頁 + 1,
    総合計表示(_頁,_次の頁,_行,_次の行,_件数,_合計),!.
総合計表示(_頁,_次の頁,_行,_次の行,_件数,_合計) :-
    _行 =< 20,
    _次の行 is _行 + 1,
    カンマの挿入(10,_合計,_カンマ付き合計),
    write_formatted('         総合計       %t\n',[_カンマ付き合計]).

帳票明細見出し :-
    write('\n                            帳票明細\n').

支店名見出し(_支店コード,_支店名,_月,_日,_頁) :-
    write_formatted('\n%t %t    出力日%2d月%2d日    P.2d\n\n',[_支店コード,_支店名_月,_日,_頁]),
    write('       販売先                            販売日              販売金額\n').
    write('---------------------------------------------------------------\n').

明細行項目(L1,_支店コード,_販売日,_販売先コード,_売上金額) :-
    sub_atom(L1,0,3,A1),atom_to_term(A1,_支店コード),
    sub_atom(L1,3,8,A2),A2 = _販売日,
    sub_atom(L1,11,6,A3),atom_to_term(A3,_販売先コード),
    sub_atom(L1,19,8,A4),atom_to_term(A4,_売上金額).

支店名項目(L2,_支店コード,_支店名) :-
    sub_atom(L2,0,3,A1),atom_to_term(A1,_支店コード),
    sub_atom(L2,3,10,_支店名).

販売先名項目(L3,_販売先コード,_販売先名) :-
    sub_atom(L3,0,6,A),atom_to_term(A3,_販売先コード),
    sub_atom(L3,6,30,_販売先名).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

カンマの挿入(_表示桁数,_数値,_表示文字列) :-
    number(_数値),
    number_codes(_数値,Codes),
    atom_codes(_数値文字列,Codes),
    カンマの挿入(_表示桁数,_数値文字列,_表示文字列),!.
カンマの挿入(_表示桁数,_数値文字列,_表示文字列) :-
    atom_chars(_数値文字列,_数値文字ならび),
    正数部の長さ(_数値文字ならび,_数値桁数),
    カンマの挿入の二(_数値桁数,_数値文字ならび,_空白のない数値ならび),
    length(_空白のない数値ならび,_空白のない数値ならびの桁数),
    _空白数 is _表示桁数 - _空白のない数値ならびの桁数,
    空白文字を連結する(_空白数,_空白のない数値ならび,_表示文字列),!.

カンマの挿入の二(0,X,X) :- ! .
カンマの挿入の二(1,X,X) :- ! .
カンマの挿入の二(N,[-|R],[-|R1]) :-
    M is N - 1,
    カンマの挿入の二(M,R,R1),! .
カンマの挿入の二(N,[ |R],[ |R1]) :-
    M is N - 1,
    カンマの挿入の二(M,R,R1),! .
カンマの挿入の二(N,[A|R],[A,,|R1]) :-
    M is N - 1,
    0 is M mod 3,
    カンマの挿入の二(M,R,R1),! .
カンマの挿入の二(N,[A|R],[A|R1]) :-
    M is N - 1,
    カンマの挿入の二(M,R,R1),! .

正数部の長さ([],0) :- !.
正数部の長さ([.|_],0) :- !.
正数部の長さ([_|R],N) :-
    正数部の長さ(R,M),
    N is M + 1,!.

空白文字を連結する(N,[_|R],_表示文字列) :-
    N < 0,
    M is N + 1,
    空白文字を連結する(M,R,_表示文字列),!.
空白文字を連結する(0,_表示文字ならび,_表示文字列) :-
    文字列の結合(_表示文字ならび,_表示文字列),!.
空白文字を連結する(N,_表示文字ならび,_表示文字列) :-
    M is N - 1,
    空白文字を連結する(M,[' '|_表示文字ならび],_表示文字列),!.

改頁 :-
    char_code(C,12),
    write_formatted('%c',[C]),!.

ファイルから全行読み取る(_ファイル,_全行) :-
open(_ファイル,read,_ストリーム),
ストリームから全行読み取る(_ストリーム,_全行),
close(_ストリーム).

ストリームから全行読み取る(_ストリーム,[]) :-
at_end_of_stream(_ストリーム),!.
ストリームから全行読み取る(_ストリーム,_全行) :-
ストリームから全行読み取って行く(_ストリーム,_全行).

ストリームから全行読み取って行く(_ストリーム,[_行|R]) :-
行入力(_ストリーム,_行),
ストリームから全行読み取る(_ストリーム,R).

行入力(_ストリーム,_行) :-
read_line_to_codes(_ストリーム,Codes),
atom_codes(_行,Codes).