程序要求

  1. 文件存储时可以这样表示

    id,name,age,phone,dept,enroll_date
    
  2. 可进行模糊查询,语法至少支持下面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"
  3. 可创建新员工纪录,以phone做唯一键(即不允许表里有手机号重复的情况),staff_id需自增语法:

    add to staff_table values Alex Li,25,134435344,IT,2015-10-29
  4. 可删除指定员工信息纪录,输入员工id,即可删除语法:

    del from staff_table where id = 3
  5. 可修改员工信息,语法如下:

    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
  6. 以上每条语名执行完毕后,要显示这条语句影响了多少条纪录。比如查询语句就显示查询出了多少条、修改语句就显示修改了多少条等。

注意:以上需求,要充分使用函数,请尽你的最大限度来减少重复代码!

编写思路

图片描述

程序目录结构

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 # 执行程序

github链接

程序运行命令

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

README

README.md

学习笔记

文件处理笔记
函数基础笔记
函数高阶笔记
模块笔记(待修改)


henryyuan
25 声望13 粉丝