# 本ソースコードは、あくまで、Pythonの学習用・練習材料として提供するものです。 # 一通りデバグしてありますが、住所録としての動作を保証するものではありません。 # デバグが完璧ではなく、データの破損などが起こりえますが、瑕疵責任は負いません。 # 著作権は(有)りるらるが保持しますが、自由に改造・改良などでお使いください。 from adglobal import N, P, A, T, M, j # global変数 import adclass import adsub import sys # プログラムの強制停止関数:sys.exit()を使うために、importしておく。 import pdb # デバグ開始関数:pdb.set_trace()を使うために、importしておく。 print("作業開始") # プログラムの始まりを表示 # 住所録の存在するディレクトリは、global.pyの中で設定 adsub.setdir() # 住所録の存在するディレクトリにカレントディレクトリを移す。 b = adclass.book("addressbook") # addressbookという名前で住所録クラスを作る。 cnt1 = b.readab() if cnt1 >= 0: # 住所録ファイルが壊れているときはcnt1<0 ct = [N[0], P[0], A[0], T[0], M[0]] # 逐次入力、修正モードのコマンドのリスト na, pa, aa, ta, ma = [], [], [], [], [] # 項目毎のリスト ba = [na, pa, aa, ta, ma] # 項目毎リストのリスト for p in b.a: # 項目毎リストを作成 adsub.eachappend(ba, p) ra = [] b.show(ra) # raが空のときは、住所録一覧表示 ctf1 = True # コマンド入力モードを継続させるためのフラグ(Trueのとき継続) cnf1 = True # コマンド入力を省略させるためのフラグ(Trueのとき、コマンド入力する) ra = [] # 修正リスト、いきなり修正モードに行くとエラーになるのでここで初期化しておく。 while ctf1: if cnf1: print("c:correct, d:dup-check, e:end, l:list, r:remove, ") # コマンド一覧を表示 print("s:sequential input, n,p,a,t,m:search") com = input("command:") if com == "": # 何も入力しないで[Enter]すると住所録プログラムを終了 ctf1 = False break c1 = com[0] match c1: case 'd': # 二重データ確認(入力されたコマンド先頭文字が'd'のとき) t, u = [], [] for i, p in enumerate(na): # 重複の確認は名前に対して行う。 if p in t: u.append(i) # pがtの中に存在すれば、リストuに項目番号を付加 else: t.append(p) # pがtの中に存在しないときにはリストtに付加 if len(u) > 0: # リストuの中には、重複したデータの項目番号が入っている。 print("duplicate data exist.") for i in u: ra.append(i) # 修正リストに入れる b.show(ra) else: print("no duplicate data") # リストuが空のときは、重複データは存在しない。 case "e": # 終了コマンド ctf1 = False break case "r": # 削除コマンド(先頭文字が'r'で続いて削除するデータの項目番号が来る) k = -1 if com[1:].isdecimal(): # 項目番号が数字かどうか確認する。 k = int(com[1:]) # 文字列になっている項目番号を数値化 if k >= 0 and k < len(b.a): # 項目番号は、住所録データの範囲内にあるはず b.a.pop(k) # 住所録から削除 cnt1 -= 1 # データ個数を1減らす。 else: print("input error") case "l": # 一覧表示コマンド(コマンド文字列の先頭が'l') ra = [] b.show(ra) # 一覧表示 case "s": # 逐次入力コマンド(コマンド文字列の先頭が's') ctf2 = True # ctf2=Falseになると逐次入力モードを終了する rcnt = 0 # データ個数をクリア while ctf2: d = {N: "", P: "", A: "", T: "", M: ""} # 各項目データの初期値 for i, e in enumerate(j): # eには、name, postcode, addressなどが入る。 data = input(e + ':') # データを入力 data = adsub.zhconv(data) # 郵便番号、電話番号が全角入力されてしまうことがあるので半角化する。 if data == "": # 何も入れずに[Enter]すると逐次モードを抜ける。 ctf2 = False break if adsub.check_func[i](data): # 各項目のデータが適正か確認(i:項目番号) d[e] = data # 辞書式にデータを保持 else: print("illegal " + e) # 入力データ・エラー ctf2 = False break if d[N] == "": # 全項目入力後、名前が入力されていない ctf2 = False break # 逐次入力モードの終了 else: s = adclass.person(list(d.values())) # 辞書式に保持されたデータをリスト化して、personのインスタンスを作る。 b.a.append(s) # 名前だけでも入力されていれば不完全でも登録する。 adsub.eachappend(ba, s) # 項目毎リストにも登録する。 rcnt += 1 cnt1 += 1 if rcnt == 0: # 逐次入力終了時何も入力されていないときは、コマンド入力に戻る。 continue else: k1 = len(b.a) - 1 # 末尾の項目番号(今入れたばかりのデータを指す) ra2 = [k1] s.show(ra2) # 何か入力されている場合は、最終入力内容を表示して修正モードへ。len(b.a)-1は項目番号。 if d[N] != "" and d[M] == "": # メールd[M]が入っているか?入っていれば修正モードに行かない。 ra = [k1] # メールが入っていなければ修正リストに入れる cnf1 = False # 逐次入力が途中終了なら修正モードへ com = "c" + str(k1) # 逐次入力が途中終了ならcomに修正コマンドを作り修正モードへ case "c": # 修正モード,ra[]に表示されている住所データの項目番号が入っている。 if len(com) > 1: # cコマンドでいきなり来る場合は、cに続いて修正する項目の番号が入っている。 k = -1 if com[1:].isdecimal(): no = int(com[1:]) # コマンド文字列から修正する項目の番号を取り出す。 if no >= 0 and no < len(b.a): # 修正する項目番号をチェック ra2 = [no] b.show(ra2) # 修正する項目内容を表示 else: print("input error") continue # コマンド入力に戻る。 else: print("input error") continue # コマンド入力に戻る。 else: if len(ra) > 1: # raの内容は既に画面にデータが表示されている com = input("which? enter no.:") # 複数のデータから1つを選択する if com.isdecimal(): # 入力された番号は数字か? no = int(com) # 入力された文字列を数値化 if no in ra: # 指定された番号がraの中のものか確認 ra = [no] else: print("illegal input") cnf1 = True continue # com[0]='c'のままなので、再度which?と表示される。 else: print("illegal input") cnf1 = True continue # com[0]='c'のままなので、再度which?と表示される。 if ra: b.show(ra) # 選ばれた番号を再度表示 else: cnf1 = True print("illegal no") continue else: if ra: no = ra[0] else: print("specify data no. following c") continue d = b.a[no].fetch() # 選択された番号のデータを辞書式に取り出す ctf2 = True while ctf2: # ctf2=Trueである限り修正モードを継続 com = input("modify mode command(n,p,a,t,m,e):") if com == "e" or com == "": # 修正がイヤになった場合は何もせずに[Enter]する ctf2 = False break if com[0] in ct: # 入力されたコマンド文字列の先頭文字com[0]がコマンド data = adsub.zhconv(com[1:]) # 2文字目以降com[1:]がデータ i = ct.index(com[0]) # コマンド文字から項目番号を取得 if adsub.check_func[i](data): # コマンドに引き続く文字列がデータ d[j[i]] = data # j[i]には、nameかpostcodeかaddressかtelnoかmailが入っている。これでは辞書式にする意味がない。 else: print("illegal input") continue else: print("command error") b.a[no].fix(d) # 住所録に修正を登録 ra2 = [no] b.show(ra2) # 修正内容を表示 cnf1 = True # コマンド入力へ ra = [] # 修正リストをクリア case _: # queryコマンド、n, p, a, t, mに応じて関連データを探し出す ra = [] # 修正リストをクリア if com[0] in ct: # com[0]がコマンドリストの中に一致するものがあるか? i = ct.index(com[0]) # com[0]は何番目(どの項目)か?i:項目番号 for k, da in enumerate(ba[i]): # 指定された番号の項目のリストからデータdaを取り出す。 if com[1:] in da: # daの中に指定文字列com[1:]が含まれていれば選択する ra.append(k) # 修正項目リストに付加する。 if len(ra) > 0: b.show(ra) # 選択された項目のデータを表示する。 cnf1 = False # コマンド入力には行かない。 com = "c" # ra[]に項目番号を入れて、このまま修正モードへ else: print("command error") # コマンドとしてあり得ないものを入れると、コマンド入力に戻る。 cnf1 = True continue if cnt1 > 0: # cnt1=0のときは書かない。データを全削除した場合でも元の住所録はそのまま。cnt1とするよりも、len(b.a)とすべきかも? b.writeab() adsub.restoredir() # カレントディレクトリを元に戻す。 print("作業終了") # プログラムの終了を表示