程序要求
-
文件存储时可以这样表示
id,name,age,phone,dept,enroll_date
-
可进行模糊查询,语法至少支持下面3种查询语法:
select name,age from staff_table where age > 22 select * from staff_table where dept = "IT" select * from staff_table where enroll_date like "2013"
-
可创建新员工纪录,以phone做唯一键(即不允许表里有手机号重复的情况),staff_id需自增语法:
add to staff_table values Alex Li,25,134435344,IT,2015-10-29
-
可删除指定员工信息纪录,输入员工id,即可删除语法:
del from staff_table where id = 3
-
可修改员工信息,语法如下:
update staff_table set dept = Market where dept = IT #把所有dept=IT的纪录的dept改成Market update staff_table set age = 25 where name = Alex Li #把name=Alex Li的纪录的年龄改成25
- 以上每条语名执行完毕后,要显示这条语句影响了多少条纪录。比如查询语句就显示查询出了多少条、修改语句就显示修改了多少条等。
注意:以上需求,要充分使用函数,请尽你的最大限度来减少重复代码!
编写思路
程序目录结构
homework_project
├── action
│ ├── database.py # 对数据库中的表文件进行操作
│ ├── __init__.py
├── config
│ ├── __init__.py
│ └── syntax.py # 配置文件。
├── core
│ ├── actions.py # 对不同的sql类型进行对应的操作
│ ├── help.py # 提供帮助
│ ├── __init__.py
│ ├── main.py # 主函数,提供用户输入界面。并执行语法解析与sql操作
│ ├── parsers.py # 语法解析函数。对用户输入的语法正确性镜像解析,并最终解析成字典格式
├── database
│ └── staff_table # 表
├── __init__.py
__init__.py
mysql_run.py # 执行程序
程序运行命令
python mysql_run.py
程序正文
mysql_run.py:执行脚本
from homework_project.core.main import main
if __name__ == '__main__':
main()
main.py:主入口程序
# -*- coding: utf-8 -*-
from . import parsers as p
from .actions import actions
import os
def main():
""" 主函数
获取用户输入,并对用户进行解析。如果获取解析值,并执行相应的sql操作。
"""
database_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + '/database/' # 获取数据库文件的路径
while True:
sql_str = input('请输入sql语句>').strip()
if sql_str:
sql_type = sql_str.split()[0].lower() # 获取输入的sql语句的类型。
if p.parses(sql_type): # 检查sql的类型是否符合规则
dict_sql = p.parses(sql_type)(sql_str, sql_type, database_dir) # 调用parsers模块的parses函数进行语法解析
if dict_sql: # 如果字典格式的sql语句返回
actions(sql_type)(dict_sql) # 则执行后面的sql操作
else:
print('sql语法错误,程序支持select,del,add,update语句。')
else:
continue
parsers.py:sql语法解析模块
# -*- coding: utf-8 -*-
import re
from .help import help
def parses(sql_type):
""" 语法解析函数
:param sql_type: 从main()函数导入的sql语句类型。
:return:
parsers_dict[sql_type]
相应的语法解析函数
"""
parsers_dict = {'select': select_parser,
'add': add_parser,
'del': del_parser,
'update': update_parser}
if sql_type in parsers_dict:
return parsers_dict[sql_type]
else:
return False
def select_parser(sql_str, sql_type, base_dir):
""" 搜索语句解析函数
:param sql_str: 用户输入的sql语句
:param sql_type: 用户输入的sql语句类型
:param base_dir: 主函数导入的数据库所在路径
:return:
"""
dict_sql = {} # 创建空字典
command_parse = re.search(r'select\s(.*?)\sfrom\s(.*?)\swhere\s(.*)', sql_str, re.I) # 使用正则表达式解析add语法,并且re.I忽略大小写
if command_parse:
dict_sql['select'] = command_parse.group(1)
dict_sql['from'] = base_dir + command_parse.group(2) # sql字典'from’键添加数据库表文件路径的值
dict_sql['where'] = command_parse.group(3).split(',') # sql字典‘where’键添加插入的值
if logic_cal(dict_sql['where']): # 使用logic_cal函数将where语句语法再次进行解析
dict_sql['where'] = logic_cal(dict_sql['where']) # 如解析有返回值,将返回值重新作为dict_sql['where']的值
return dict_sql
else:
print(help(sql_type)) # 当语法解析不正常答应帮助
else:
print(help(sql_type)) # 当语法解析不正常答应帮助
def add_parser(sql_str, sql_type, base_dir):
""" 添加语句解析函数
:param sql_str: 用户输入的sql语句
:param sql_type: 用户输入的sql语句类型
:param base_dir: 主函数导入的数据库所在路径
:return:
dict_sql
解析后的字典格式sql语句
"""
dict_sql = {}
command_parse = re.search(r'add\sto\s(.*?)\svalues\s(.*)', sql_str, re.I) # 使用正则表达式解析add语法,并且re.I忽略大小写
if command_parse:
dict_sql['to'] = base_dir + command_parse.group(1) # sql字典'to’键添加数据库表文件路径的值
dict_sql['values'] = command_parse.group(2).split(',') # sql字典‘values’键添加插入的值
return dict_sql
else:
print(help(sql_type)) # 当语法解析不正常答应帮助
def del_parser(sql_str, sql_type, base_dir):
""" 删除语句解析函数
:param sql_str: 用户输入的sql语句
:param sql_type: 用户输入的sql语句类型
:param base_dir: 主函数导入的数据库所在路径
:return:
dict_sql
解析后的字典格式sql语句
"""
dict_sql = {}
command_parse = re.search(r'del\sfrom\s(.*?)\swhere\s(.*)', sql_str, re.I)
if command_parse:
dict_sql['from'] = base_dir + command_parse.group(1) # sql字典'to’键添加数据库表文件路径的值
dict_sql['where'] = command_parse.group(2).split(',') # sql字典‘where’键添加插入的值
if logic_cal(dict_sql['where']): # 使用logic_cal函数将where语句语法再次进行解析
dict_sql['where'] = logic_cal(dict_sql['where']) # 如解析有返回值,将返回值重新作为dict_sql['where']的值
return dict_sql
else:
print(help(sql_type)) # 当语法解析不正常答应帮助
else:
print(help(sql_type)) # 当语法解析不正常答应帮助
def update_parser(sql_str, sql_type, base_dir):
""" 更新语句解析函数
:param sql_str: 用户输入的sql语句
:param sql_type: 用户输入的sql语句类型
:param base_dir: 主函数导入的数据库所在路径
:return:
dict_sql
解析后的字典格式sql语句
"""
dict_sql = {}
command_parse = re.search(r'update\s(.*?)\sset\s(.*?)=(.*?)\swhere\s(.*)', sql_str, re.I)
if command_parse:
dict_sql['update'] = base_dir + command_parse.group(1) # sql字典'to’键添加数据库表文件路径的值
dict_sql['set'] = [command_parse.group(2), '=', command_parse.group(3)] # sql字典‘where’键添加插入的值
dict_sql['where'] = command_parse.group(4).split(',')
if logic_cal(dict_sql['where']) and logic_cal(dict_sql['set']): # 如果where语句、set语句都符合logic_cal中定义的规范
dict_sql['where'] = logic_cal(dict_sql['where']) # 如解析有返回值,将返回值重新作为dict_sql['where']的值
dict_sql['set'] = logic_cal(dict_sql['set']) # 如解析有返回值,将返回值重新作为dict_sql['set']的值
return dict_sql
else:
print(help(sql_type)) # 当语法解析不正常答应帮助
else:
print(help(sql_type)) # 当语法解析不正常答应帮助
def logic_cal(logic_exp):
""" 逻辑函数
:param logic_exp: sql语句中和逻辑判断相关的语句,列表格式。如[‘age','>=',20] 或 [‘dept','like','HR']
:return:
logic_exp
经过语法解析后的逻辑判断语句。列表格式。如[‘age','==',20] 或 [‘dept','like','HR']
"""
# 表达式列表优化成三个元素,形如[‘age','>=',20] 或 [‘dept','like','HR']
logic_exp = re.search('(.+?)\s([=<>]{1,2}|like)\s(.+)', ''.join(logic_exp))
if logic_exp:
logic_exp = list(logic_exp. group(1, 2, 3)) # 取得re匹配的所有值,并作为一个列表
if logic_exp[1] == '=':
logic_exp[1] = '=='
# 判断逻辑运算的比较符号后的值是否字母,并且用户是否输入了双引号。如没有输入手工添加上双引号。
if not logic_exp[2].isdigit() and not re.search('"(.*?)"', logic_exp[2]):
logic_exp[2] = '"' + logic_exp[2] + '"'
return logic_exp
else:
return False
actions.py:sql操作模块
# -*- coding: utf-8 -*-
from homework_project.action.database import read_db, write_db, print_info
from homework_project.config.syntax import get_title
import re
def actions(sql_type):
""" sql操作主函数
:param sql_type: sql语句的类型
:return:
actions_dict[sql_type]
相应操作的函数
"""
actions_dict = {'select': select_action,
'add': add_action,
'del': del_action,
'update': update_action}
if sql_type in actions_dict: # 判断导入的sql类型是否在actions_dict字典中定义。
return actions_dict[sql_type]
def select_action(dict_sql):
info = dict_sql['select']
data = read_db(dict_sql['from']) # 获取原始数据库文件中的所有数据,data为列表格式
key = dict_sql['where'][0] # 获取sql语句中where语句的key值。如id = 1,获取id
count = 0
for values in data: # 读取data列表中的每一个元素,values是字典格式
if type(values[key]) is int:
value = str(values[key])
else:
value = '"' + str(values[key]) + '"'
dict_sql['where'][0] = value # 将values[key]的值取出并重新赋值为sql语句的key值。
if where_action(dict_sql['where']): # 将新的where语句,发送给where_action语句进行bool判断。
count += 1
print_info(info, **values)
print('已查找%s条记录' % count)
def add_action(dict_sql):
""" 插入动作
获取用户输入的values,并在表中插入
:param dict_sql: parsers函数处理后的字典格式的sql语句
"""
data = read_db(dict_sql['to']) # 获取原始数据库文件中的所有数据
value = dict_sql['values'] # 从dict_sql中获取values的列表
t_id = str(int(data[-1]['id']) + 1) # 获取原始数据库文件中id列最后一行的id数值,并每次自动+1。然后转换为字符串格式
value.insert(0, t_id) # 将添加的id插入到value变量中
if len(value) != len(get_title()): # 判断输入值得长度是否等于数据库文件中定义的列的长度
print('列数不正确')
else:
data.append(dict(zip(get_title(), value))) # 在获取的原始数据中插入行的数据
print('已添加记录')
write_db(dict_sql['to'], data) # 写入文件
def del_action(dict_sql):
""" 删除动作函数
:param dict_sql: parsers函数处理后的字典格式的sql语句
"""
temp_list = []
data = read_db(dict_sql['from']) # 获取原始数据库文件中的所有数据,data为列表格式
key = dict_sql['where'][0] # 获取sql语句中where语句的key值。如id = 1,获取id
for values in data: # 读取data列表中的每一个元素,values是字典格式
if type(values[key]) is int:
value = str(values[key])
else:
value = '"' + str(values[key]) + '"'
dict_sql['where'][0] = value # 将values[key]的值取出并重新赋值为sql语句的key值。
if where_action(dict_sql['where']): # 将新的where语句,发送给where_action语句进行bool判断。
temp_list.append(values) # 如果符合条件,就从data中移除对应的values
print('已删除%s条记录' % len(temp_list))
for i in temp_list:
data.remove(i)
write_db(dict_sql['from'], data) # 将新生成的data重新写入文件
def update_action(dict_sql):
""" 更新动作函数
:param dict_sql: parsers函数处理后的字典格式的sql语句
"""
data = read_db(dict_sql['update']) # 获取原始数据库文件中的所有数据,data为列表格式
key = dict_sql['where'][0] # 获取sql语句中where语句的key值。如id = 1,获取id
set_key = dict_sql['set'][0] # 获取set语句中用户输入的key
set_value = dict_sql['set'][3].strip("'").strip('"') # 获取set语句中用户输入的value
count = 0
for values in data: # 读取data列表中的每一个元素,values是字典格式
if type(values[key]) is int:
value = str(values[key])
else:
value = '"' + str(values[key]) + '"'
dict_sql['where'][0] = value # 将values[key]的值取出并重新赋值为sql语句的key值。
if where_action(dict_sql['where']): # 将新的where语句,发送给where_action语句进行bool判断。
count += 1
values[set_key] = set_value # 如果符合条件,使用将set_key的值修改为set_value
print('已更新%s条记录' % count)
write_db(dict_sql['update'], data) # 将新生成的data重新写入文件
def where_action(condition):
""" where语句操作函数
:param condition: 判断语句。就是字典中where的值
:return:
"""
if 'like' in condition: # 如果like在语句中
# 将where语句中的第二个参数和,第一个参数进行正则比较。如果执行正常就返回True
return re.search(condition[2].strip("'").strip('"'), condition[0]) and True
else:
return eval(' '.join(condition)) # 除此使用eval进行python的逻辑判断
help.py:帮助模块
# -*- coding: utf-8 -*-
def help(sql_type):
dict = {'select': select_help,
'add': add_help,
'del': del_help,
'update': update_help,
}
if sql_type in dict:
return dict[sql_type]()
def select_help():
strings = '''select语法错误。请查看案例:
select name,age from staff_table where age > 22
select * from staff_table where dept = "IT"
select * from staff_table where enroll_date like "2013"
'''
return strings
def add_help():
strings = '''add语法错误。请查看案例:
add to staff_table values Alex Li,25,134435344,IT,2015-10-29
'''
return strings
def del_help():
strings = '''del语法错误。请查看案例:
del from staff_table where id = 3
'''
return strings
def update_help():
strings = '''update语法错误。请查看案例:
UPDATE staff_table SET dept="Market" WHERE dept = "IT"
UPDATE staff_table SET age=25 WHERE name = "Alex Li"
'''
return strings
database.py:文件读写模块
# -*- coding: utf-8 -*-
from homework_project.config.syntax import get_title
def read_db(table):
""" 读取表文件函数。
:param table: 表文件参数
:return: 返回一个包含表文件内容的字典
"""
title = get_title()
try:
main_list = []
with open(table, 'r', encoding='utf-8') as rf:
for line in rf:
temp_list = []
if line.rstrip('\n').split(',') == title:
continue
else:
for values in line.strip('\n').split(','):
if values.isdigit():
temp_list.append(int(values))
else:
temp_list.append(values)
main_list.append(dict(zip(title, temp_list)))
return main_list
except FileNotFoundError as e:
print(e)
exit(1)
def write_db(table, data):
""" 写入表文件函数。
:param table: 表文件参数
:param data: 导入的数据。为字典格式
"""
value2 = ','.join(get_title()) + '\n'
for values in data:
temp_list = []
for value in values.values():
temp_list.append(str(value))
value2 += ','.join(temp_list) + '\n'
with open(file=table, mode='w', encoding='utf-8') as wf:
wf.write(value2)
def print_info(info, **kwargs):
""" 打印函数。
用于select语句打印显示
:param info: select语句中需要显示的类
:param kwargs: 字典,用于进行操作的原始数据
:return:
"""
temp_list = []
if info == '*':
for key in kwargs:
temp_list.append(str(kwargs[key]))
print(','.join(temp_list))
else:
info_list = info.split(',')
for i in info_list:
temp_list.append(str(kwargs[i]))
print(','.join(temp_list))
sytanx.py:配置文件模块
def get_title():
title_dict = ['id','name','age','phone','dept','enroll_date']
return title_dict
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。