问题点1
遍历list,使用del删除空时,连续4个空,只能删除两个,因为删除时原list索引变化。
使用range(len-1,-1,-1)从后面往前删,保证了未删除的元素索引不变化。
问题点2:
解决select name , age from staff_table where age > 22
Name,age之前空格问题
Sql三个关键词,位置对应0,2,4,但是以空格为分割符,name和age之问有空格,就不能判断2的位置是from的位置,所以需要把from到select之间的元素合成一个。
方法二:
search 三个关键字,字符串切片,这种方法简单。:),不高大上。其实我想做一个同时解析出update和select语句的牛X代码,,,,,,
问题3:
格式化后的字段和条件字符串位置不一样,
['select', 'age,name', 'from', 'staff_table', 'where', '22>age']
原字符串拼接语句:field = field + sql_list[i]
修改成:field = sql_list[i] +field
问题4:
Sql语句查询条件解析,需要判断各个运算符号。
使用eval()可以直接返回运算结果,使用 try判断不是条件或者条件格式错误,提示错误,返回False。
问题5:
当出现错误时,在不同功能里,需要重复打印相同错误
把所有错误统一处理,写在一个函数,当处理错误非学多的时候,代码块特别长。后来,每个错误都做成单独函数,返回错误值,使用装饰器捕捉错误,打印提示。代码块小,管理方便。
但是,使用此方式会报变量未定义错误,所以需要初始化变量值。
问题6:
解析sql语句的select和update时,使用每句的关键字进行判断,要把select和update都做一遍。
做成函数,关键字动态以后,同一段代码可以解析两条不同关键字语句。
问题点7:
Eval()和exec()作为两个运行字符串的神奇的函数,给我留下了超级大坑。所以必须重点写一下。
背景:制作update和select语句时,总想把语句做的智能化一些,代码也尽可能的短,所以想到了eval()和exec().
过程:在处理select的查询条件时,eval()确实十分有用,给对应变量赋值就可以判断。
但是处理update的赋值时,使用exec()遇到了莫名妙的问题,在s=’dept=”IT”’, 执行exec(s)时,dept始终是初始值,没有变化。查资料发现原来是限于全局变量,如果在函数内用处理起来十分麻烦,但是可能在类里面能够正常,没学到类,以后补充。
问题10
程序终于做完了,测试时候功能也实现了,但是,fuck了,文件存的数据有空行,打印出来的信息也是没有规律的空行!!!!
越改格式出现的问题越多,后来回了一个写入文件函数,所有写入数据库的都需要格式化一下,然后数据格式就好了。
def strip_and_enter(string):
ds_enter = string.strip()+'\n'
return ds_enter
问题9
装饰器,终极版。
其实就是外面再套一层函数。套的多了自然就迷糊了,迷糊了就是高大上~~
附上很烂的程序原代码
#!-*- coding:utf-8 -*-
# __author__ = 'david'
"""
员工信息管理系统
1.使用select语句查找
2.条件格式支持symbol_list里面的所有符号
3.select支持自定义显示字段。
4.update也可以使用条件格式,支持symbol_list里面的所有符号
5.每个功能使用一次后返回主菜单,所以有些显示信息可能被冲掉
6.登陆信息时不能中途退出
7.子菜单第一个输入界面可以使用q返回
8.删除功能,可以自定义字段
--------
待改进:
1.search模块功能繁琐
2.删除功能,模糊查找
3.条件格式不支持not and or
4.装饰器,可以捕捉更多错误
5.文件目录没有设计
"""
# def sql_delete_blank(sql) 删除sql语句多余空格
# def format_sql() 按关键字组合成列表 格式:
# format_sql(key_0, key_2, key_4, sql_list=sql_delete_blank(input_sql))
# def try_eval(string) 检测eval合法性
# def try_int(num): 检测数字类型的合法性
# def str_check(string, length_min=4, length_max=20) 检测字符字段的值合法性
# def num_check(string, length_min=4, length_max=20) 检测数字字段的值合法性
# def sql_delete_blank(sql) 用空格分割成列表,并删除列表里的所有空格
# def format_sql(key_0, key_2, key_4, sql_list): 以sql语句格式化sql_delete_blank处理过的列表
# def check_field(field_str, em_info_filed=original_filed) select字段显示控制,可以支持自定义字段
# def show_info(field, line_list) 查询显示函数,可以和更新、删除做在一起,后续优化
# def copy_file(source_file, target_file) 复制文件
# def search() 根据条件查询函数,本来做个通用的,发现太大,花费了许许多多时间
# def search(sql, func_choice, source_file=main_file, target_file=temp_file)
# def check_exist(index, value, source_file=main_file) 检测文件里是不是存在数据,比上面功能单一,可以合并成一个
# def append_user() 追加用户函数,返回追加的信息
# def append_user(filed_list, check_num_filed, check_str_filed, append_file_name=main_file)
# def del_user(del_index, del_value, source_file, target_file) 删除用户函数,显示删除的用户信息
# def show_error(func) 装鉓器,获取错误,打印提示
# sql_list = []
# sql_list_temp = []
# index = 0
# em_info_filed
import os
# #############初始化值################ #
main_file = 'em_info.txt'
temp_file = 'em_info_temp.txt'
original_filed = ['staff_id', 'name', 'age', 'phone', 'dept', 'enroll_date']
original_filed_dict = {'staff_id': None, 'name': None, 'age': None,
'phone': None, 'dept': None, 'enroll_date': None}
# 限制字段值的一些条件
num_filed = {'staff_id': (1, 99999999999, 88), 'age': (10, 99, 23), 'phone': (11111111111, 99999999999, 13899998888)}
str_filed = {'name': (1, 30, 'Edmond'), 'dept': (1, 99, 'IT'), 'enroll_date': (6, 20, '2018-08-08')}
menu_list = ['非常牛X的员工信息操作面板', '1.模糊查询', '2.模糊修改', '3.新建员工', '4.删除员工', '5.退出程序']
select_sql = """select name,age from staff_table where age > 22"""
update_sql = """UPDATE staff_table SET dept ="Market" where dept = "IT" """
symbol_list = [' in ', '>=', '<=', '=', '>', '<']
main_key = 'phone'
em_info = """1,Alex Li,22,13651054608,IT,2013-04-01
2,Da Peng,65,13265234552,SH,2013-04-01
3,Event,24,18652434308,IT,2013-04-01
4,Pan Da,44,15523422223,HR,2013-04-01
"""
# 创建原始文件:
if os.path.exists('main_file'):
pass
else:
with open(main_file, 'w', encoding='utf-8') as file:
file.write(em_info)
def menu(m_list):
for i in m_list:
print(i)
def strip_and_enter(string):
ds_enter = string.strip()+'\n'
return ds_enter
def show_error(func): # 装饰器,捕捉try_eval,try_int错误信息。
def print_prompt(*args, **kwargs):
prompt = func(*args, **kwargs)
if prompt == 'EvalError':
print('输入条件格式错误,请正确输入!')
return False
if prompt == 'IntError':
print('输入数字格式错误,请正确输入!')
return False
else:
return True
return print_prompt
@show_error
def try_eval(string,staff_id=0, name='', age=0, phone='', dept='', enroll_date='', *args, **kwargs):
print(dept)
try:
eval(string)
except:
return 'EvalError'
@show_error
def try_int(num):
try:
int(num)
except:
return 'IntError'
def str_check(string, length_min=4, length_max=20):
string = string.replace('"', '')
if length_min < len(string) < length_max:
str_list = string.strip().split(' ')
for i in range(len(str_list)):
if str_list[i].isalnum():
pass
else:
print('含有非法字符!')
return False
else:
return True
else:
print('长度不符合要求,需要在%d和%d之间'.strip() % (length_min, length_max))
return False
def num_check(number, num_min=11111111111, num_max=99999999999):
if number.isdigit():
if num_min < int(number) < num_max:
return True
else:
print(strip_and_enter('值不符合要求,需要在%d和%d之间,'.strip() % (num_min, num_max)))
return False
else:
print('只能是数字!')
return False
def sql_delete_blank(sql):
sql_list = sql.strip().split(" ")
index = len(sql_list)-1
for i in range(index, -1, -1):
temp = sql_list[i].lower()
if temp == '': # 去除语句中多余的空格
del sql_list[i]
return sql_list
def format_sql(key_0, key_2, key_4, sql_list):
field = ''
condition = ''
condition_str = ''
index = k0 = k2 = k4 = len(sql_list)-1
for i in range(index, -1, -1):
temp = sql_list[i]
if temp.lower() == key_4: # 用于截取条件语句的阀值w=1截取结束
k4 = 1
elif temp.lower() == key_2:
k2 = 1
elif temp.lower() == key_0:
k0 = 1
if k4 != 1: # 用于组合位置5
if temp.lower() == 'like':
temp = ' in ' # 把like换成in 放便使用eval
elif temp.lower() == '=': # 把=好换成==,用于eval
temp = '=='
condition_str = temp + condition_str
del sql_list[i]
elif k4 == 1 and k2 != 1 and temp.lower() != key_4: # 用于组合位置3
condition = temp + condition
del sql_list[i]
elif k2 == 1 and k0 != 1 and temp.lower() != key_2: # 用户于组合位置1
field = temp.lower() + field
del sql_list[i]
if ' in ' in condition_str:
re_split = condition_str.strip().split(' ')
condition_str = re_split[-1] + ' ' + re_split[1] + ' ' + re_split[0]
sql_list.insert(1, field)
sql_list.insert(-1, condition)
sql_list.append(condition_str)
if sql_list[0].lower() != key_0 or sql_list[2].lower() != key_2 or sql_list[4].lower() != key_4 :
sql_list = [0, 0, 0, 0, 0, 0]
return sql_list
def check_field(field_str, em_info_filed=original_filed):
# 判断字段是否存在,存在,反回所有字段列表,不存在返回空,提示错误!
if field_str == '*': # *是全字段,不需要进一步解析
return em_info_filed
field_show = []
field_list = field_str.split(',')
for fi in field_list:
if fi in em_info_filed:
field_show.append(fi)
else:
field_show.clear()
return field_show # 如果输入字段没在原始字段里,返回空列表=False
return field_show # 如果全在原始字段里,返回list
def show_info(field, line_list):
field_input = check_field(field)
if field_input:
f3 = line_list
field_dict = dict(zip(original_filed, f3))
for show in field_input:
print(field_dict[show].ljust(20, ' '), end='')
def copy_file(source_file, target_file):
with open(target_file, 'w', encoding='utf-8') as target_file_write,\
open(source_file, 'r', encoding='utf-8') as file_read:
file_read_line = file_read.readline()
while file_read_line:
target_file_write.write(file_read_line)
file_read_line = file_read.readline()
def search(sql, func_choice, source_file=main_file, target_file=temp_file):
count = 0
field_str = ''
update_value = ''
condition = sql[-1].lower()
if func_choice == 1:
field_str = sql[1]
if func_choice == 2:
update_value = sql[3]
with open(source_file, 'r') as file_search,\
open(target_file, 'w') as file_temp:
fs = file_search.readline()
while fs:
temp_list = fs.strip().split(',')
staff_id = int(temp_list[0])
name = temp_list[1].lower()
age = int(temp_list[2])
phone = temp_list[3]
dept = temp_list[4].lower()
enroll_date = temp_list[5]
if eval(condition):
if func_choice == 1:
show_info(field_str, temp_list)
count += 1
if func_choice == 2:
tem = update_value.split('=')
tem[0] = tem[0].strip().lower()
tem[1] = tem[1].strip(' ').strip('"')
if tem[0] == 'name':
temp_list[1] = tem[1]
if tem[0] == 'age':
temp_list[2] = tem[1]
if tem[0] == 'phone':
temp_list[3] = tem[1]
if tem[0] == 'dept':
temp_list[4] = tem[1]
if tem[0] == 'enroll_date':
temp_list[5] = tem[1]
fs = '%s,%s,%s,%s,%s,%s' % (str(temp_list[0]), str(temp_list[1]), str(temp_list[2]),
str(temp_list[3]), str(temp_list[4]), str(temp_list[5]))
print(strip_and_enter(fs), end='')
count += 1
if func_choice == 3:
pass
file_temp.write(strip_and_enter(fs))
fs = file_search.readline()
return count
def check_exist(index, value, source_file=main_file):
id_field = ''
temp_list = []
with open(source_file, 'r', encoding='utf-8') as check_main_key:
f = check_main_key.readline()
while f:
temp_list = f.strip().split(',')
if temp_list[index] == value:
print(temp_list)
id_field = ''
return id_field
else:
id_field = temp_list[0]
f = check_main_key.readline()
return id_field
def append_user(filed_list, check_num_filed, check_str_filed, append_file_name=main_file):
f = ''
check = ''
value = ''
value_type = ''
fs = ''
value_example = ''
temp_list = []
for f in filed_list:
if f in check_num_filed:
value_type = '数字'
value_example = str(check_num_filed[f][2])
else:
value_type = '字符'
value_example = str(check_str_filed[f][2])
while True:
if filed_list.index(f) == 0:
temp_list.append('0')
break
value = input("请输入[%s],%s类型,示例[%s]:" % (f, value_type, value_example)).strip()
if f in check_num_filed:
check = num_check(value, check_num_filed[f][0], check_num_filed[f][1])
else:
check = str_check(value.replace('-', ' '), check_str_filed[f][0], check_str_filed[f][1])
if f.strip() == main_key:
if check_exist(filed_list.index(main_key), value):
temp_list[0] = int(check_exist(filed_list.index(main_key), value))+1
else:
print('[%s]必须唯一,请重新输入' % f)
continue
if check:
temp_list.append(value.strip('"').strip("'"))
break
else:
print("请重新输入")
continue
else:
fs = '%s,%s,%s,%s,%s,%s' % (str(temp_list[0]), str(temp_list[1]), str(temp_list[2]),
str(temp_list[3]), str(temp_list[4]), str(temp_list[5]))
with open(append_file_name, 'a', encoding='utf-8') as append:
append.write(strip_and_enter(fs))
return fs
def del_user(del_index, del_value, source_file, target_file):
s_list = []
count = 0
with open(source_file, 'r', encoding='utf-8') as s_file,\
open(target_file, 'w', encoding='utf-8') as t_file:
s_line = s_file.readline()
while s_line:
s_list = s_line.strip().split(',')
if s_list[del_index].strip().lower() == del_value.lower():
print("{0:10}{1:10}{2:10}{3:10}{4:10}{5:10}".format(*s_list))
count += 1
s_line = s_file.readline()
continue
t_file.write(strip_and_enter(s_line))
s_line = s_file.readline()
else:
return count
while True:
menu(menu_list)
choice = input('请选择对应数字:').strip()
if choice == '1': # 查询
while True:
c1 = input("您已选择[%s],请输入查询语句:\n[例如:%s]" % (menu_list[int(choice)], select_sql)).strip()
if c1.lower() == 'q': # q返回列表
print('您已返回列表。')
break
a1 = sql_delete_blank(c1) # 删除中间多余的空格
a = format_sql('select', 'from', 'where', a1) # 判断select语句格式
if try_eval(a[-1]): # 条件语句合法性检查
a2 = search(a, 1) # a2查询数量
if a2:
print("本次共查询到[%d]条记录。" % a2)
else:
print("对不起,没有查到符合条件的记录。")
break
else:
pass
elif choice == '2': # 更新
while True:
c2 = input("您已选择[%s],请输入修改语句:\n[例如:%s]" % (menu_list[int(choice)], update_sql)).strip()
if c2.lower() == 'q': # q返回列表
print('您已返回列表。')
break
c2 = c2.replace(' WHERE ', ' where ').replace('UPDATE ', 'update ').replace(' SET ', ' set ')
# 关键字不影响值,所以替换小写方便使用
c2_a = c2.strip().split(' where ') # c2_a[1]是条件
c2_b = c2_a[0].strip().split(' set ') # c2_b[1]是赋值
if len(c2_a) == 2 and len(c2_b) == 2:
s = []
s2_0 = sql_delete_blank(c2_b[0]) # set前面的语句列表,删除所有空格
s2_1 = sql_delete_blank(c2_a[1]) # where 后面的语句列表,删除所有空格
s.extend(s2_0)
s.extend(['set'])
s.extend([c2_b[1].strip()]) # 姓名有空格,所以赋值语句不能使用sql_delete_blan删除空格
s.extend(['where'])
s.extend(s2_1) # 以上主要是空格处理,完成后按原来格式组合
s = format_sql('update', 'set', 'where', s)
if s and try_eval(s[-1]): # 条件表达式格式通过
s3_list=s[3].strip().split('=') # 开始判断赋值语句
s3_list[0] = s3_list[0].strip()
s3_list[1] = s3_list[1].strip()
if s3_list[0].lower() in num_filed: # 判断字段合法,并且是数字字段
# 判断数字值的有效性
if num_check(s3_list[1], num_filed[s3_list[0]][0], num_filed[s3_list[0]][1]):
pass
else:
continue
elif s3_list[0].lower() in str_filed: # 判断字段合法,并且是数字字段
# 判断字符值的有效性
if str_check(s3_list[1], str_filed[s3_list[0]][0], str_filed[s3_list[0]][1]):
pass
else:
continue
else:
print('更新字段错误,请重试!')
continue
get_flag = search(s, 2) # get_flag返回值,判断是否找到记录
if get_flag:
print("本次共更新了[%d]条记录。" % get_flag)
copy_file(temp_file, main_file)
os.remove(temp_file)
break
else:
print("对不起,没有符合条件的记录,返回主菜单....")
break
elif choice == '3': # 追加
while True:
cq = input('[q]返回,任意键添加用户...')
if cq.lower() == 'q': # q返回列表
print('您已返回列表。')
break
c3 = append_user(original_filed, num_filed, str_filed) # 直接调用追加函数,c3返回的是用户信息。
if c3:
print('添加成功!您的信息是:\n', c3)
break
else:
print('未知错误:已被你玩坏!')
elif choice == '4': # 删除,可以自定义用来检索的字段,所以比较长,较长,长,长。。。
while True:
delete_str = 'staff_id'.strip() # 如果变成input可以实现自定义条件字段
# delete_str = input('试一次会咋样,字段名'),strip() 如果解除input可以实现自定义
if delete_str.lower() == 'q': # q返回列表
print('您已返回列表。')
break
if check_field(delete_str): # 判断字段有效性
break
else:
print('找不到[%s]字段,可选择字段有:\n' % delete_str, original_filed)
if delete_str.lower() == 'q': # q返回列表
continue
while True: # 读取字段属性,并检测输入值有效性
value_4 = input('已经选择[%s]字段,请输入值:' % delete_str).strip()
if delete_str in num_filed:
if num_check(value_4, num_filed[delete_str][0], num_filed[delete_str][1]):
break
elif delete_str in str_filed:
if str_check(value_4, str_filed[delete_str][0], str_filed[delete_str][0]):
break
else:
print('值[%s]不符合要求!请重新输入....' % value_4)
index_4 = original_filed.index(delete_str) # 获取些字段的位置
if not check_exist(index_4, value_4): # 查找值在文件中存在,开始调用
del_count4 = del_user(index_4, value_4, main_file, temp_file) # 删除用户,新表存放在temp_file
copy_file(temp_file, main_file) # 数据复制回主文件
os.remove(temp_file)
print("一共删除了[%s]条记录。" % del_count4)
elif choice.lower() == 'q' or choice== '5': # 退出
print('谢谢使用,再见!')
break
else:
print('输入无效,请重试')
# 因为select form where是关键字,所以判断这三个位置是不是0,2,4
# if sql_list[0].lower() == 'select' and sql_list[2].lower() == 'form' and sql_list[4].lower() == 'where':