Python+Excel+數據——一鍵通關的快樂ing(V2.0)

2020-08-10 17:20:05

一.人生苦短,學點Python

在上週五準備這周出差的時候,我突然意識到偏離了「一鍵通關」含義180°,那時候我的程式碼已經敲到最後數據導出了…無限崩潰_(:з」∠)_不回圈而且無理。

二.需求是第一生產動力

1.主線任務:一鍵通關:讀取《調研表》和《SAG數據總表》,導出系統測評表

2.賞金任務:自定義錯誤型別,字串各種切割,弄弄表情包

3.修仙任務:整理《SAG數據總表》

4.渡劫任務:模糊演算法+隨便找個測評表將內容替換進導出的測評表中

三.Just do it——幹就完了

1.回顧:

之前說pycharm沒有replace功能是我沒發現或者用得不是很多,所以給忽略了,其實只要右鍵變數或者函數名->重構->重新命名便可以一次性替換一個檔案裡所有的內容了,但跨檔案或者想替換特殊符號?前的字串應該是行不通的,所以自己寫給replace還是有必要的。還有就是if name == ‘main’: 可以用來進行偵錯或者測試當前檔案的功能程式碼,程式碼如下,可以自定義測試數據等:

# 當前檔案被呼叫的時候,if裡的語句不執行
if __name__ == '__main__':
    readInpath = '../assess_require/調查表.xlsx'
    writeOutpath = '../dataCool/asset/allAsset.py'
    # 執行主函數
    _, _, _ = questionaire(readInpath, writeOutpath)

2.任務:

①.主線:一鍵通關

程式碼如下:
檔名:Tool.py

# coding:utf-8

# 系統:匯入模組
import re, pprint, sys
from datetime import datetime

# 私有:匯入模組
from report_generate import *
from sag_and_assess import *

# 數據源的設定路徑包
questionaireDir = './assess_require/調查表.xlsx'
assetDir='./dataCool/asset/allAsset.py'
sagpathDir='./dataCool/base'
reportPathdir='./assess_report'

def Tool_main():
    systemName, sagLevel ,industry= questionaire(questionaireDir,assetDir)
    if out_temp_program(sagLevel):
        assess_report_export(sagpathDir,reportPathdir,systemName,sagLevel,industry)
    else:
        sys.exit('目前測試系統等級不包含5級,請修改\'調查表.xlsx\'內容!')

# func:臨時退出函數,判斷內容裡是否含有'5'
def out_temp_program(list):
    for str in list:
        if re.search('5',str) is not None:
            return False
        else:
            return True


if __name__ == '__main__':
    Tool_main()
    pass
②.主線:讀取《調研表》

程式碼如下有點多…
檔名:sag_and_assess.py

# coding:utf-8
# 抽選說明:依據'資產數量'和'重要程度'進行篩選,不要求用途名稱相同的資產按照數量進行命名和排序
# 抽選方式:相同類型至少抽20%,10台以內全部抽選
# 關於數量的例子:
# 實際調查表中
#      資產名稱             數量
#   應用系統伺服器            10

# 調查表上傳報告生成工具前應修改爲:
#      資產名稱             數量
#   應用系統伺服器01          1
#   應用系統伺服器02          1
#   應用系統伺服器03-20       10

# 程式碼抽選的數據檔案記憶體儲爲:
# [應用系統伺服器01,應用系統伺服器02]

# 匯入模組
import sys, os

sys.path.append(os.path.dirname(os.path.dirname(__file__)))
from input_aggregate import *
from file_action import *
from print_aggregate import *

# 檔案函數的功能介紹
funcName = '資產數據分析模組'

# 定義:資產列表和字典
安全物理環境 = {}
網路裝置 = {}
安全裝置 = {}
伺服器 = {}
終端 = {}
管理軟體 = {}
應用 = {}


# main:開啓'調查表.xlsx',循序篩選每一個sheet的數據。
# 若'調查表.xlsx'發生更新,後期再由維護人員?手動更新程式碼即可。
def questionaire(fileReadpath, fileWritepath):
    function_open_print(funcName)
    string = '# coding:utf-8\n\n'
    while True:
        try:
            wbData = file_read_auto(fileReadpath)
            systemName, sagLevel, industryString, industry = essential_information_function(wbData)
            string = engine_room_function(wbData,string)
            string = network_function(string)
            string = network_equipment_function(wbData,string)
            string = safety_equipment_function(wbData,string)
            string = server_function(wbData,string)
            string = terminal_function(wbData,string)
            string = center_function(string)
            string = management_software_function(wbData,string)
            string = application_system_function(wbData,string)
            string = management_function(string)
            file_write_auto(fileWritepath, write_string_combination(string,industryString))
            function_close_print(funcName)
            break
        except Exception as err:
            topString, middleString, _ = string_parentheses(pprint.pformat(err))
            if topString == 'InputError':
                print(middleString)
                pass
            elif topString == 'RequestExit':
                sys.exit(middleString)
            else:
                function_fail()
                sys.exit('一條野生異常需要處理......sag_and_assess_01')
                pass
    print(sagLevel)
    return systemName, sagLevel, industry


levelListchar = ['一', '二', '三', '四', '五']
levelListnum = ['1','2','3','4','5']
levelDict={'一':'1', '二':'2', '三':'3', '四':'4', '五':'5'}
levelSpecial=['5','五']
levelList=[]


# func:獲取基本資訊:系統名稱、sa等級、通用/擴充套件
def essential_information_function(wb):
    try:
        assetSh = wb['表1-系統基礎資訊表']
    except Exception as err:
        raise RequestExit('sheet名字不正確(表1-系統基礎資訊表)!')
    # C列'定級系統名稱'
    systemName = assetSh['C' + '1'].value
    # C列'安全保護等級'
    topString, middleString, _ = string_parentheses(assetSh['C' + '2'].value)
    # 判斷:全5級
    if middleString[1] == '5' and middleString[3] == '5':
        raise RequestExit('SA填寫錯誤,沒有全5級系統(表1-系統基礎資訊表)!')
    else:
        # 判斷:SXAX長度不爲4,不存在S,不存在A,X不爲數位字串
        if len(middleString) != 4 or middleString[0] != 'S' or \
                middleString[2] != 'A' or re.search(r'\D', middleString[1]) is not None or re.search(r'\D',
                                                                                                     middleString[
                                                                                                         3]) is not None:
            raise RequestExit('SA等級填寫錯誤(表1-系統基礎資訊表)!')
        else:
            # 判斷:GX中X不在leveListchar列表中
            if topString[1] not in levelListchar:
                # 判斷:GX中X不在leveListnum列表中
                if topString[1] not in levelListnum:
                    raise RequestExit('系統等級錯誤(表1-系統基礎資訊表)!')
                else:
                    # 判斷:G的X不與SA的X相同
                    if topString[1] != middleString[1] and topString[1] != middleString[3]:
                        raise RequestExit('系統等級和SA等級不符(表1-系統基礎資訊表)!')
                    else:
                        # 判斷:S的X大於A的X
                        if int(middleString[1]) > int(middleString[3]):
                            # 判斷:G的X不等於S的X
                            if topString[1] != middleString[1]:
                                raise RequestExit('系統等級是SA等級中最高階一項(表1-系統基礎資訊表)!')
                            else:
                                levelList.append(middleString[0:2])
                                levelList.append(middleString[2:4])
                                levelList.append(topString)
                        else:
                            # 判斷:G的X不等於A的X
                            if topString[1] != middleString[3]:
                                raise RequestExit('系統等級是SA等級中最高階一項(表1-系統基礎資訊表)!')
                            else:
                                levelList.append(middleString[0:2])
                                levelList.append(middleString[2:4])
                                levelList.append(topString)
            else:
                # 判斷:G的X不與SA的X相同
                if levelDict[topString[1]] != middleString[1] and levelDict[topString[1]] != middleString[3]:
                    raise RequestExit('系統等級和SA等級不符(表1-系統基礎資訊表)!')
                else:
                    # 判斷:S的X大於A的X
                    if int(middleString[1]) > int(middleString[3]):
                        # 判斷:G的X不等於S的X
                        if levelDict[topString[1]] != middleString[1]:
                            raise RequestExit('系統等級是SA等級中最高階一項(表1-系統基礎資訊表)!')
                        else:
                            levelList.append(middleString[0:2])
                            levelList.append(middleString[2:4])
                            levelList.append('G'+levelDict[topString[1]])
                    else:
                        # 判斷:G的X不等於A的X
                        if levelDict[topString[1]] != middleString[3]:
                            raise RequestExit('系統等級是SA等級中最高階一項(表1-系統基礎資訊表)!')
                        else:
                            levelList.append(middleString[0:2])
                            levelList.append(middleString[2:4])
                            levelList.append('G'+levelDict[topString[1]])
    # C列'系統形態'
    industry = string_industry(assetSh['C' + '5'].value)
    industryString = string_industry_allasset(industry)
    return systemName, levelList, industryString,industry


# func:處理物理機房數據,不?存在數量
def engine_room_function(wb,string):
    # 找到'表2-物理機房'
    try:
        assetSh = wb['表2-物理機房']
    except Exception as err:
        raise RequestExit('sheet名字不正確(表2-物理機房)!')
    for row in range(2, assetSh.max_row + 1):
        # B列'機房名稱'
        name = assetSh['B' + str(row)].value
        # D列'重要程度'
        importance = assetSh['D' + str(row)].value
        if name == None and name != importance:
            raise RequestExit('數據讀取異常,\'表2-物理機房\' \'的內容爲空。。。。。。')
        else:
            pass
        if importance == '非常重要' or importance == '重要':
            安全物理環境.setdefault(name, 'common')
        # or 過濾?空行數據
        elif importance == '一般' or name == importance:
            continue
        else:
            raise RequestExit('數據讀取異常,\'表2-物理機房\' \'重要程度\'的內容有誤。。。。。。')
    return write_string_combination(string, '安全物理環境' +'=' + pprint.pformat(安全物理環境) + '\n')


# func:通訊網路、區域邊界字串拼接
def network_function(string):
    return write_string_combination(string,'安全通訊網路'+'=' + '{\'安全通訊網路\':\'common\'}'+'\n'+'安全區域邊界'+'=' + '{\'安全區域邊界\':\'common\'}'+'\n')


# func:處理網路裝置數據
def network_equipment_function(wb,string):
    # 找到'表3-網路裝置'
    try:
        assetSh = wb['表3-網路裝置']
    except Exception as err:
        raise RequestExit('sheet名字不正確(表3-網路裝置)!')
    for row in range(2, assetSh.max_row + 1):
        # B列'裝置名稱'
        name = assetSh['B' + str(row)].value
        # G列'重要程度'
        importance = assetSh['G' + str(row)].value
        if name == None and name != importance:
            raise RequestExit('數據讀取異常,\'表3-網路裝置\' \'的內容爲空。。。。。。')
        else:
            pass
        # I列'數量'
        amount = assetSh['I' + str(row)].value
        if importance == '非常重要' or importance == '重要':
            # 處理非數位型別字元的異常
            try:
                # 如果資產數量10台以內
                if int(amount) < 10:
                    for i in range(1, int(amount) + 1):
                        網路裝置.setdefault(name + '0' + str(i), 'common')
                # 如果資產數量超過10
                elif int(amount) > 10:
                    i = 0
                    if int(amount) % 5 != 0:
                        i = int(amount) // 5 + 1
                    for j in range(1, i + 1):
                        # 呼叫:追加'裝置名稱',至少抽?20%
                        if i < 10:
                            網路裝置.setdefault(name + '0' + str(i), 'common')
                        else:
                            網路裝置.setdefault(name + str(i), 'common')
            except Exception as e:
                raise RequestExit('數據讀取異常,\'表3-網路裝置\' \'數量\'的內容有誤。。。。。。')
        # or 過濾?空行數據
        elif importance == '一般' or name == importance:
            continue
        else:
            raise RequestExit('數據讀取異常,\'表3-網路裝置\' \'數量\'的內容有誤。。。。。。')
    return write_string_combination(string, '網路裝置' +'=' + pprint.pformat(網路裝置) + '\n')


# func:處理安全裝置數據
def safety_equipment_function(wb,string):
    # 找到'表4-安全裝置'
    try:
        assetSh = wb['表4-安全裝置']
    except Exception as err:
        raise RequestExit('sheet名字不正確(表4-安全裝置)!')
    for row in range(2, assetSh.max_row + 1):
        # B列'裝置名稱'
        name = assetSh['B' + str(row)].value
        # G列'重要程度'
        importance = assetSh['G' + str(row)].value
        if name == None and name != importance:
            raise RequestExit('數據讀取異常,\'表4-安全裝置\' \'的內容爲空。。。。。。')
        else:
            pass
        # I列'數量'
        amount = assetSh['I' + str(row)].value
        if importance == '非常重要' or importance == '重要':
            # 處理非數位型別字元的異常
            try:
                # 如果資產數量10台以內
                if int(amount) < 10:
                    for i in range(1, int(amount) + 1):
                        安全裝置.setdefault(name + '0' + str(i), 'common')
                # 如果資產數量超過10
                elif int(amount) > 10:
                    i = 0
                    if int(amount) % 5 != 0:
                        i = int(amount) // 5 + 1
                    for j in range(1, i + 1):
                        # 呼叫:追加'裝置名稱',至少抽?20%
                        if i < 10:
                            安全裝置.setdefault(name + '0' + str(i), 'common')
                        else:
                            安全裝置.setdefault(name + str(i), 'common')
            except Exception as e:
                raise RequestExit('數據讀取異常,\'表4-安全裝置\' \'重要程度\'的內容有誤。。。。。。')
        # or 過濾?空行數據
        elif importance == '一般' or name == importance:
            continue
        else:
            raise RequestExit('數據讀取異常,\'表4-安全裝置\' \'重要程度\'的內容有誤。。。。。。')
    return write_string_combination(string,'安全裝置' +'=' + pprint.pformat(安全裝置) + '\n')


# func:處理伺服器或儲存裝置數據
def server_function(wb,string):
    # 找到'表6-伺服器或儲存裝置'
    try:
        assetSh = wb['表6-伺服器或儲存裝置']
    except Exception as err:
        raise RequestExit('sheet名字不正確(表6-伺服器或儲存裝置)!')
    for row in range(2, assetSh.max_row + 1):
        # B列'裝置名稱'
        name = assetSh['B' + str(row)].value
        # E列'操作系統'
        if re.search(r'windows', assetSh['E' + str(row)].value, flags=re.I):
            system = 'windows'
        elif re.search(r'linux', assetSh['E' + str(row)].value, flags=re.I):
            system = 'linux'
        elif re.search(r'centos', assetSh['E' + str(row)].value, flags=re.I):
            system = 'linux'
        elif re.search(r'redhat', assetSh['E' + str(row)].value, flags=re.I):
            system = 'linux'
        elif re.search(r'麒麟', assetSh['E' + str(row)].value, flags=re.I):
            system = 'linux'
        elif re.search(r'ubuntu', assetSh['E' + str(row)].value, flags=re.I):
            system = 'linux'
        elif re.search(r'suse', assetSh['E' + str(row)].value, flags=re.I):
            system = 'linux'
        elif re.search(r'debain', assetSh['E' + str(row)].value, flags=re.I):
            system = 'linux'
        elif re.search(r'aix', assetSh['E' + str(row)].value, flags=re.I):
            system = 'aix'
        else:
            system = 'common-system'
        # H列'重要程度'
        importance = assetSh['H' + str(row)].value
        if name == None and name != importance:
            raise RequestExit('數據讀取異常,\'表6-伺服器或儲存裝置\' \'的內容爲空。。。。。。')
        else:
            pass
        # I列'數量'
        amount = assetSh['I' + str(row)].value
        if importance == '非常重要' or importance == '重要':
            # 處理非數位型別字元的異常
            try:
                # 如果資產數量10台以內
                if int(amount) < 10:
                    for i in range(1, int(amount) + 1):
                        伺服器.setdefault(name + '0' + str(i), system)
                # 如果資產數量超過10
                elif int(amount) > 10:
                    i = 0
                    if int(amount) % 5 != 0:
                        i = int(amount) // 5 + 1
                    for j in range(1, i + 1):
                        # 呼叫:追加'裝置名稱',至少抽?20%
                        if i < 10:
                            伺服器.setdefault(name + '0' + str(i), system)
                        else:
                            伺服器.setdefault(name + str(i), system)
            except Exception as e:
                # 呼叫:退出程式,並列印錯誤資訊
                raise RequestExit('數據讀取異常,\'表6-伺服器或儲存裝置\' \'數量\'的內容有誤。。。。。。')
        # or 過濾?空行數據
        elif importance == '一般' or name == importance:
            continue
        else:
            raise RequestExit('數據讀取異常,\'表6-伺服器或儲存裝置\' \'數量\'的內容有誤。。。。。。')
    return write_string_combination(string,'伺服器' +'=' + pprint.pformat(伺服器) + '\n')


# func:處理終端或現場裝置數據
def terminal_function(wb,string):
    # 找到'表7-終端或現場裝置'
    try:
        assetSh = wb['表7-終端或現場裝置']
    except Exception as err:
        raise RequestExit('sheet名字不正確(表7-終端或現場裝置)!')
    for row in range(2, assetSh.max_row + 1):
        # B列'裝置名稱'
        name = assetSh['B' + str(row)].value
        # F列'重要程度'
        importance = assetSh['F' + str(row)].value
        if name == None and name != importance:
            raise RequestExit('數據讀取異常,\'表7-終端或現場裝置\' \'的內容爲空。。。。。。')
        else:
            pass
        # G列'數量'
        amount = assetSh['G' + str(row)].value
        if importance == '非常重要' or importance == '重要':
            # 處理非數位型別字元的異常
            try:
                # 如果資產數量10台以內
                if int(amount) < 10:
                    for i in range(1, int(amount) + 1):
                        終端.setdefault(name + '0' + str(i), 'common')
                # 如果資產數量超過10
                elif int(amount) > 10:
                    i = 0
                    if int(amount) % 5 != 0:
                        i = int(amount) // 5 + 1
                    for j in range(1, i + 1):
                        # 呼叫:追加'裝置名稱',至少抽?20%
                        if i < 10:
                            終端.setdefault(name + '0' + str(j), 'common')
                        else:
                            終端.setdefault(name + str(j), 'common')
            except Exception as e:
                # 呼叫:退出程式,並列印錯誤資訊
                raise RequestExit('數據讀取異常,\'表7-終端或現場裝置\' \'數量\'的內容有誤。。。。。。')
        # or 過濾?空行數據
        elif importance == '一般' or name == importance:
            continue
        else:
            raise RequestExit('數據讀取異常,\'表7-終端或現場裝置\' \'數量\'的內容有誤。。。。。。')
    return write_string_combination(string, '終端' +'=' + pprint.pformat(終端) + '\n')


# func:處理系統管理軟體或平臺數據
def management_software_function(wb,string):
    # 找到'表8-系統管理軟體或平臺'
    try:
        assetSh = wb['表8-系統管理軟體或平臺']
    except Exception as err:
        raise RequestExit('sheet名字不正確(表8-系統管理軟體或平臺)!')
    for row in range(2, assetSh.max_row + 1):
        # B列'機房名稱'
        name = assetSh['B' + str(row)].value
        # 軟件系統
        # 數據庫
        if re.search(r'mysql', name, flags=re.I):
            system = 'mysql'
        elif re.search(r'sqlserver', name, flags=re.I):
            system = 'SQL Server'
        elif re.search(r'sql server', name, flags=re.I):
            system = 'SQL server'
        elif re.search(r'oracle', name, flags=re.I):
            system = 'oracle'
        elif re.search(r'sqlite', name, flags=re.I):
            system = 'sqlite'
        elif re.search(r'postgresql', name, flags=re.I):
            system = 'postgresql'
        elif re.search(r'mariadb', name, flags=re.I):
            system = 'mariadb'
        elif re.search(r'mongodb', name, flags=re.I):
            system = 'mongodb'
        elif re.search(r'redis', name, flags=re.I):
            system = 'redis'
        # 中介軟體
        elif re.search(r'iis', name, flags=re.I):
            system = 'iis'
        elif re.search(r'tomcat', name, flags=re.I):
            system = 'tomcat'
        elif re.search(r'weblogic', name, flags=re.I):
            system = 'weblogic'
        elif re.search(r'jetty', name, flags=re.I):
            system = 'jetty'
        elif re.search(r'jboss', name, flags=re.I):
            system = 'jboss'
        elif re.search(r'webshphere', name, flags=re.I):
            system = 'websphere'
        elif re.search(r'mq', name, flags=re.I):
            system = 'mq'
        else:
            system = 'common-system'
        # F列'重要程度'
        importance = assetSh['F' + str(row)].value
        if name == None and name != importance:
            raise RequestExit('數據讀取異常,\'表8-系統管理軟體或平臺\' \'的內容爲空。。。。。。')
        else:
            pass
        if importance == '非常重要' or importance == '重要':
            管理軟體.setdefault(name, system)
        # or 過濾?空行數據
        elif importance == '一般' or name == importance:
            continue
        else:
            raise RequestExit('數據讀取異常,\'表8-系統管理軟體或平臺\' \'重要程度\'的內容有誤。。。。。。')
    return write_string_combination(string, '管理軟體' +'=' + pprint.pformat(管理軟體) + '\n')


# func:處理業務應用系統或平臺數據
def application_system_function(wb,string):
    # 找到'表9-業務應用系統或平臺'
    try:
        assetSh = wb['表9-業務應用系統或平臺']
    except Exception as err:
        raise RequestExit('sheet名字不正確(表9-業務應用系統或平臺)!')
    for row in range(2, assetSh.max_row + 1):
        # B列'機房名稱'
        name = assetSh['B' + str(row)].value
        # F列'重要程度'
        importance = assetSh['F' + str(row)].value
        if name == None and name != importance:
            raise RequestExit('數據讀取異常,\'表9-業務應用系統或平臺\' \'的內容爲空。。。。。。')
        else:
            pass
        if importance == '非常重要' or importance == '重要':
            應用.setdefault(name, 'common')
        # or 過濾?空行數據
        elif importance == '一般' or name == importance:
            continue
        else:
            raise RequestExit('數據讀取異常,\'表9-業務應用系統或平臺\' \'重要程度\'的內容有誤。。。。。。')
    return write_string_combination(string,'應用' +'=' + pprint.pformat(應用) + '\n')


# func:安全管理中心字串拼接
def center_function(string):
    return write_string_combination(string,'安全管理中心'+'=' + '{\'安全管理中心\':\'common\'}'+'\n')


# func:安全管理 字串拼接
def management_function(string):
    return write_string_combination(string,'安全管理制度'+'=' + '{\'安全管理制度\':\'common\'}'+'\n'+'安全管理機構'+'=' + '{\'安全管理機構\':\'common\'}'+'\n'+'安全管理人員'+'=' + '{\'安全管理人員\':\'common\'}'+'\n'+'\n'+'安全建設管理'+'=' + '{\'安全建設管理\':\'common\'}'+'\n'+'安全運維管理'+'=' + '{\'安全運維管理\':\'common\'}'+'\n')


# func:資產名稱和內容整合
def write_string_combination(string,addString):
    string += addString
    return string


# 當前檔案被呼叫的時候,if裡的語句不執行
if __name__ == '__main__':
    readInpath = '../assess_require/調查表.xlsx'
    writeOutpath = '../dataCool/asset/allAsset.py'
    # 執行主函數
    _, _, _ = questionaire(readInpath, writeOutpath)
③.主線:讀取《SAG數據總表》

程式碼如下:
檔名:report_generate.py

# coding:utf-8


# 匯入模組
import sys, os, openpyxl, pprint

from openpyxl.utils import get_column_letter

sys.path.append(os.path.dirname(os.path.dirname(__file__)))
from file_action import *
from dataCool.asset.allAsset import *
from configuration.questionaire_basic import *
from configuration.sagfile_title import *

funcName='·測評表導出模組'
# 字典:存放要建立的sheet的名稱和SAG數據總表(bate版).xlsx中對應的sheet的名稱
realDict={}


# function:主函數入口
def assess_report_export(sagpathdir,reportpathdir,systemname,saglist,industry):
    function_open_print(systemname+funcName)
    filePath = sagpathdir + '/' + 'SAG數據總表(bate版)' + '.xlsx'
    reportpath = reportpathdir + '/' + systemname + '測評總表' + '.xlsx'
    while True:
        try:
            wbData = workbook_read(filePath)
            sheetList = sheet_title_list(wbData)
            for str in industry:
                make_sheet(allAesset_industryList[str], realDict,sheetList)
            # print(realDict)
            write_report(reportpath,wbData,realDict,saglist)
            break
        except Exception as err:
            topString, middleString, _ = string_parentheses(pprint.pformat(err))
            if topString == 'InputError':
                print(middleString)
            elif topString == 'RequestExit':
                sys.exit(middleString)
            else:
                function_fail()
                sys.exit('一條野生異常需要處理......report_generate_01')
    function_close_print(systemname+funcName)


# func:獲取要建立的sheet的名稱和SAG數據總表(bate版).xlsx中對應的sheet的名稱
def make_sheet(sheetTerm,realDict,sheetList):
    for str in sheetTerm:
        for k,v in eval(str).items():
            realDict.setdefault(k,string_list_match(v,string_list_match(str,sheetList)))


def write_report(reportpath, wbdata,realdict, saglist):
    try:
        value=''
        wb = openpyxl.Workbook()
        # print(realdict)
        for k,v in realDict.items():
            for i in range(len(realdict),-1,-1):
                shReport = wb.create_sheet(index=i, title=k)
                # 返回標識屬性所在的座標,dataConfirm爲sagfile_title.py中的參數
                locationKeylist = cell_location(wbdata[v[0]], dataConfirm)
                # 返回建表所需的表頭座標,sagFiletitlecommon爲sagfile_title.py中的參數
                locationTitlelist = cell_location(wbdata[v[0]], sagFiletitlecommon)
                # locationKeylist[1]爲屬性標識
                colstr = get_column_letter(locationKeylist[1][1])
                # 確認標識屬性和sag真是等級對應的row橫座標
                rowNew = 1
                for row in range(1,wbdata[v[0]].max_row+1):
                    if rowNew == 1:
                        for col in range(1,len(sagFiletitlecommon)+1):
                            shReport.cell(row=rowNew, column=col, value=sagFiletitlecommon[int(col)-1])
                        rowNew += 1
                    else:
                        pass
                    colNew = 1
                    for sag in saglist:
                        sagNum=int(sag[1])+5
                        if sag in wbdata[v[0]][colstr+str(row)].value:
                            for list in locationTitlelist:
                                colString = get_column_letter(list[1])
                                if int(locationKeylist[0][1]) == int(list[1]):
                                    shReport.cell(row=rowNew, column=colNew,
                                                  value=str(sagNum)+'.'+wbdata[v[0]][colString+str(row)].value)
                                    colNew += 1
                                elif int(locationKeylist[1][1]) == int(list[1]):
                                    shReport.cell(row=rowNew, column=colNew,
                                                  value=sag)
                                    colNew += 1
                                elif int(locationKeylist[2][1]) == int(list[1]):
                                    if wbdata[v[0]][colString + str(row)].value != None:
                                        shReport.cell(row=rowNew, column=colNew,
                                                      value='高')
                                        colNew += 1
                                    else:
                                        pass
                                else:
                                    shReport.cell(row=rowNew, column=colNew,
                                                  value=wbdata[v[0]][colString + str(row)].value)
                                    colNew +=1
                            rowNew += 1
                        else:
                            pass
                # 中斷跳出:這裏將 i 作爲頁數,所以必須退出才能 纔能對應
                break
            # 中斷跳出:單個頁面偵錯
            # break
        wb.remove(wb['Sheet'])
        wb.save(reportpath)
    except Exception as err:
        raise RequestExit('write_report函數內部錯誤!')


# func:根據內容反求Excel的座標
def cell_location(sheet,list):
    tempList=[]
    valueList=[]
    for i in range(len(list)):
        for row in range(1, sheet.max_row + 1):
            for col in range(1, sheet.max_column + 1):
                colStr = get_column_letter(col)
                if sheet[colStr + str(row)].value == list[i]:
                    tempList.append(row)
                    tempList.append(col)
                    valueList.append(tempList)
                    tempList = []
                else:
                    pass
    if len(valueList)!=len(list):
        content_sag_print()
        raise RequestExit('傳參的數據或數據檔案的數據內容不匹配!')
    else:
        pass
    return valueList


#func:讀取Excel工作簿
def workbook_read(filepath):
    try:
        wbData = openpyxl.load_workbook(filepath)
        return wbData
    except Exception as err:
        function_fail()
        raise RequestExit('程式碼路徑有誤或檔案不存在!')


# func:獲取Excel的所有sheet名稱
def sheet_title_list(wbdata):
    shList=[]
    for sheet in wbdata:
        shList.append(sheet.title)
    return shList


# func:傳函數作爲參數
def func_recall(func):
    return func()


if __name__ == '__main__':
    sagpathDir = '../dataCool/base'
    reportpathdir = '../assess_report'
    sagList=['S2','A3','G3']
    assess_report_export(sagpathDir,reportpathdir,'使完feel倍兒爽系統',sagList,['傳統IT系統','移動互聯'])
④.主線:設定數據

程式碼如下:
檔名:questionaire_basic.py

# coding:utf-8

# 整合調查表:表1-系統基礎資訊表的內容
industryList = ['傳統IT系統','雲端計算','移動互聯','物聯網','工業控制系統','大數據','其他']
judgeIndustry = [' □傳',' □雲',' □移',' □物',' □工',' □大',' □其']
manageDict={'安全管理制度':'安全管理制度'+'=' + '{\'安全管理制度\':\'common\'}'+'\n','安全管理機構':'安全管理機構'+'=' + '{\'安全管理機構\':\'common\'}'+'\n','安全管理人員':'安全管理人員'+'=' + '{\'安全管理人員\':\'commom\'}'+'\n','安全建設管理':'安全建設管理'+'=' + '{\'安全建設管理\':\'common\'}'+'\n'+'安全運維管理'+'=' + '{\'安全運維管理\':\'common\'}'+'\n'}
industryDict={'雲端計算':'雲端計算'+'=' + '{\'雲端計算\':\'common\'}','移動互聯':'移動互聯'+'=' + '{\'移動互聯\':\'common\'}','物聯網':'物聯網'+'=' + '{\'物聯網\':\'common\'}','工業控制系統':'工業控制系統'+'=' + '{\'工業控制系統\':\'common\'}','大數據':'大數據'+'=' + '{\'大數據\':\'common\'}','其他':'其他'+'=' + '{\'其他\':\'common\'}'}
industryDictnull={'雲端計算':'雲端計算'+'=' + '{\'雲端計算\':\'null\'}','移動互聯':'移動互聯'+'=' + '{\'移動互聯\':\'null\'}','物聯網':'物聯網'+'=' + '{\'物聯網\':\'null\'}','工業控制系統':'工業控制系統'+'=' + '{\'工業控制系統\':\'null\'}','大數據':'大數據'+'=' + '{\'大數據\':\'null\'}','其他':'其他'+'=' + '{\'其他\':\'null\'}'}

# 整合:allAsset.py的數據和industryList:
allAesset_industryList={'傳統IT系統':['安全物理環境','安全通訊網路','安全區域邊界','網路裝置','安全裝置','伺服器','終端','管理軟體','應用','安全管理中心','安全管理制度','安全管理機構','安全管理人員','安全建設管理','安全運維管理'],'雲端計算':['雲端計算'],'移動互聯':['移動互聯'],'物聯網':['物聯網'],'工業控制系統':['工業控制系統'],'大數據':['大數據'],'其他':['其他']}

檔名:sagfile_title.py

# coding:utf-8

sagFiletitlebasic=['通用/擴充套件','技術/管理','安全層面','安全控制點','標準編號','屬性標識','測評指標','測評物件','測評實施內容','單元判定','測評方法','結果記錄','符合程度','高風險等級','高風險判定內容','高風險補償措施','整改建議']

sagFiletitlecommon=['安全層面','安全控制點','標準編號','屬性標識','測評指標','測評物件','測評方法','結果記錄','符合程度','高風險等級']

dataConfirm=['標準編號','屬性標識','高風險等級']
①.賞金:自定義錯誤型別字串各種切割,弄弄表情包

程式碼如下:
檔名:exception_class.py

# coding:utf-8


# 類:input輸入錯誤的錯誤型別
class InputError(Exception):
    def __init__(self, message):
        self.message = message

    def fail_information(self):
        print(self.message)


# 類:請求退出的錯誤型別
class RequestExit(Exception):
    def __init__(self, message):
        self.message = message

    def fail_information(self):
        print(self.message)


# 類:庫函數執行出錯的錯誤型別
class LibaryRuningError(Exception):
    def __init__(self, message):
        self.message = message

    def fail_information(self):
        print(self.message)
②.賞金:字串各種切割

程式碼如下:
檔名:string_processing.py

# coding:utf-8


import inspect,re,sys,os,math
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
from configuration.questionaire_basic import *
from pyclass.exception_class import *


# func:取出字串中最外層圓括號(英文括號)內的字串
# 例子:
# 傳入:  ssa,n//2h1e)()as.sad>f,,qwmcma()wkql(laksdkl))))aa
# 返回:  ssa,n//2h1e  ()as.sad>f,,qwmcma()wkql(laksdkl)))  aa
def string_parentheses(string):
    num = []
    startString = ''
    middleString = ''
    endingString = ''
    for i in range(len(string)):
        if string[i] == '(' or string[i] == ')' or string[i] == '(' or string[i] == ')':
            num.append(i)
    for i in range(0, num[0]):
        startString = startString + string[i]
    for i in range(num[0] + 1, num[len(num) - 1]):
        middleString = middleString + string[i]
    for i in range(num[len(num) - 1] + 1, len(string)):
        endingString = endingString + string[i]
    return startString, middleString, endingString


# func:判斷' □'和它後面的字元與是否在傳入的字串中,最終返回通用/擴充套件項
# 例子:
# 傳入:  √□傳統IT系統 □雲端計算 ■移動互聯 R物聯網 □工業控制系統 □大數據 □其他
# 返回:  傳統IT系統 行動網際網路 物聯網
def string_industry(string):
    counter = 0
    realList = []
    for str in judgeIndustry:
        if re.search(str, string, flags=re.I) is None:
            realList.append(industryList[counter])
        else:
            pass
        counter += 1
    if counter == 0 or re.search(' □傳', string, flags=re.I) is not None:
        raise RequestExit('檔案內容有誤,請覈實!')
    else:
        pass
    return realList


# func:擴充套件項字串組合,傳調configuration包中的questionaire_basic檔案中的數據industryDict
def string_industry_allasset(industrylist):
    industryString = ''
    for str in industrylist:
        if str == '傳統IT系統':
            pass
        else:
            industryString += industryDict[str]
            industryString += '\n'
    return industryString



# func:遍歷判斷字串中是否存在空格
# 返回:bool型別
def string_have_empty(string):
    for i in range(len(string)):
        if string[i-1] == ' ':
            return True
    return False


# func:字串模糊匹配
# 概述:字串模糊匹配的問題研究:單個字元在順序上的偏移或者不符。
# 舉例:如sql server 和 sqlserver ,空格匹配不到,而後續的字元整體向前偏移了1個精度。
# 總結:單個字元或者連續及散點的字元進行匹配的概率即爲匹配精度,而單個字元或者連續字元的規律性偏移程度爲偏移精度,兩者既可獨立,也可連續存在。
# 舉例:如sql seaver 和 sqlserver,空格不存在,se是偏移的,a所在及其後續的匹配中都不存在。
# 簡單演算法設計:採用反減的方式進行匹配,匹配字元長度至少是字串長度的一半,匹配成功之後根據字串取半的長度和匹配回圈計數器進行計算求出精度,精度符合要求則返回相應值
# 特殊匹配:散點匹配,即取sql seaver 中隨機的任意字元和sqlserver進行精度和偏移的匹配再求概率,或者取字串區間中任意字元進行匹配,對精度要求更高,這裏僅做參考。
# 傳入:匹配字串,庫源字串
# 輸出:匹配成功字元列表(列表巢狀),匹配精度(計算方法:)
def string_vague_match(subject,object):
    counter=0
    tempList = []
    matchList = []
    while True:
        if len(subject)>counter:
            coordinateList=section_subtraction(len(subject),counter)
            for i in range(len(coordinateList)):
                if re.search(subject[coordinateList[i][0]:coordinateList[i][1]],object,flags=re.I) is not None:
                    tempList.append(subject[coordinateList[i][0]:coordinateList[i][1]])
                else:
                    pass
            if len(tempList) != 0:
                matchList.append(tempList)
            else:
                pass
            tempList=[]
            counter += 1
        else:
            # raise InputError('調查表數據有誤'+'('+subject+')'+'請修改調查表儲存繼續或直接退出!')
            pass
            break
    accuracyCount=len(matchList)/len(subject)*100
    return matchList,accuracyCount


# func:在列表中匹配字串,相同返回列表中完整的字串列表
def string_list_match(string,list):
    realList=[]
    for i in range(len(list)):
        if re.search(string,list[i],flags=re.I) is not None:
            realList.append(list[i])
        else:
            pass
    if len(realList) == 0:
        raise RequestExit('請檢查\'調查表.xlsx\'中資產的型號是否和\'SAG數據總表(bate版).xlsx\'的sheet名稱對應上!')
    else:
        return realList


# func:求字串區間座標
# 例子:’subject‘,座標[2,3]的值爲'b',長度爲字串長,區間定長爲1
# 傳入:字串長度,區間定長
# 返回:符合區間的座標列表(列表巢狀的:[[0,1],[0,2]......])
def section_subtraction(length,fixedlength):
    combinationList=[]
    valueList=[]
    for x in range(int(length)+1):
        for y in range(int(length)+1):
            if int(fixedlength) == 0:
                combinationList.append(int(fixedlength))
                combinationList.append(int(length))
                valueList.append(combinationList)
                return valueList
            elif x<=y and abs(x-y) == int(fixedlength):
                combinationList.append(x)
                combinationList.append(y)
                valueList.append(combinationList)
                combinationList=[]
            else:
                pass
    return valueList


#func:變數名轉換成字串,tips:函數名在search函數中作爲字串,次函數的呼叫只能賦值一次,連續回撥只返回第一個變數名
def varname_to_string(p):
    for line in inspect.getframeinfo(inspect.currentframe().f_back)[3]:
        m = re.search(r'\bvarname_to_string\s*\(\s*([A-Za-z_][A-Za-z0-9_]*)\s*\)', line)
        if m:
            return m.group(1)

def test_code():
    if string_have_empty(' sss s'):
        print('have')
    else:
        print('no')


# print(string_parentheses('ssa,n//2h1e)()as.sad>f,,qwmcma()wkql(laksdkl))))aa'))
if __name__ == '__main__':
    subject = 'sql seaver'
    object = 'sqlserver'
    print(string_vague_match(subject,object))
    pass
③.賞金:弄弄表情包

程式碼如下:
檔名:print_aggregate.py

# coding:utf-8

import sys,os

sys.path.append(os.path.dirname(os.path.dirname(__file__)))
from pyclass.exception_class import *


# sug:將表情入庫並分類,最後亂數列印
# tips:如果表情符號非utf-8,則會報錯


def function_open_print(func):
    print('\n~ ̄▽ ̄~[-.-] ')
    print('***' + func + '功能啓動***')


def function_read_ok():
    print('\n<( ̄︶ ̄)↗[Go!]')
    print('***讀取成功***')


def function_write_ok():
    print('\n<( ̄︶ ̄)↗[Go!]')
    print('***寫入成功***')


def function_close_print(func):
    print('\n(°ー°〃)')
    print('***' + func + '功能結束***')

def function_fail():
    print('\n(〇o〇;)')
    # print('***失敗了***')


def questionaire_file_path_read():
    print('\n︿( ̄︶ ̄)︿')
    print('請輸入\'調查表\'檔案的相對路徑:             (exit退出)')


def questionaire_file_path_write():
    print('\n(ˉ▽ˉ;)')
    print('請輸入\'資產表\'檔案的相對路徑:             (exit退出)')


def sag_glevel_print():
    print('\no(# ̄▽ ̄)==G')
    print('請輸入系統安全(G)等級:             (exit退出)')


def sag_salevel_print():
    print('\no(# ̄▽ ̄)==SA')
    print('請輸入系統安全(SA)等級(連續數位):             (exit退出)')


def sheet_title_print():
    print('\n~o ̄▽ ̄~o')
    print('請輸入你要的*測評層面*,內容參考如上(支援關鍵字搜尋,以中文逗號分隔):             (exit退出)')


def sheet_header_print():
    print('\n~o ̄▽ ̄~o')
    print('請輸入你要的*製表內容*,內容參考如上(支援關鍵字搜尋,以中文逗號分隔):             (exit退出)')


def input_again_print():
    print('\n~o ̄▽ ̄~o')
    print('請重新*輸入內容*(支援關鍵字搜尋,以中文逗號分隔):             (exit退出)')


def content_filter_print():
    print('\n⊙_⊙')
    print('內容有誤,過濾後內容如上所示:')


def filt_state_open_print():
    print('\n⊙_⊙')
    print('儲存的檔案處於開啓狀態,請儲存關閉重新輸入:')


def content_sag_print():
    print('\n⊙_⊙')
    print('數據源表頭缺損,請儲存修改完數據原始檔後,按任意鍵重新輸入!')


def pass_or_exit_print():
    print('\n= ̄ω ̄=')
    print('繼續則輸出上述過濾內容:         (y)')
    print('或重新選擇測評層面:            (n)')
    print('退出:                      (exit)')


def report_out_print():
    print('\n (=^ω^=)')
    print('===製作完成===')


def count_2_control_list_print(list):
    flag=0
    if len(list)==0:
        raise InputError('選擇物件內容爲空,請重新選擇!02')
    else:
        pass
    for i in list:
        if flag < 2:
            flag+=1
            print(i,end='\t\t')
        else:
            flag=0
            print(i,end='\n')


def count_3_control_list_print(list):
    flag=0
    if len(list)==0:
        raise InputError('選擇物件內容爲空,請重新選擇!03')
    else:
        pass
    for i in list:
        if flag < 2:
            flag+=1
            print(i,end='\t\t')
        else:
            flag=0
            print(i,end='\n')


def count_4_control_list_print(list):
    flag=0
    if len(list)==0:
        raise InputError('選擇物件內容爲空,請重新選擇!04')
    else:
        pass
    for i in list:
        if flag < 4:
            flag+=1
            print(i,end='\t\t')
        else:
            flag=0
            print(i,end='\n')



if __name__ == '__main__':
    function_read_ok()
①.修仙:整理《SAG數據總表》

在这里插入图片描述
在这里插入图片描述
簡單分析:結構就是表頭+內容沒什麼,主要是後面對數據讀取的判斷因素,這裏將標準編號(1.1.1)、屬性標識(G1G2G3G4…)、高風險等級(G1G2…)(這裏有個瑕疵:前面屬性未A的我也標成G了,這裏要統一,因爲程式碼裡沒有演算法做判斷)作爲程式裡判斷數據是否應該抽取的邏輯依據,總表的內容可以增加,在數據組態檔中也可固定需要導出的內容項。

①.渡劫任務:模糊演算法和測評表數據的轉移

考慮到實際情況調研表的內容現場填寫如果出現筆誤,比如SQL Server 敲成了SQL sever、Windows敲成了windos怎麼辦,這裏我在程式碼裡固定了專屬名稱的格式,如果數據不符會則報錯,但更智慧的方法是可以設計出一種模糊演算法,將錯誤的內容標準化,這樣後面書面的品質也得到了提高。
至於測評表之間的數據遷移問題,當然是擱到下章啦︿( ̄︶ ̄)︿

3.細節截圖:

①.目前還沒有5級系統,所以下面 下麪增加5級的判斷:

在这里插入图片描述
在这里插入图片描述

②.S4A1G4等級的系統執行截圖:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

③.資產抽選說明(伺服器):

在这里插入图片描述
在这里插入图片描述

④.專案工程的目錄結構說明:

在这里插入图片描述

⑤.questionaire_basic.py介紹:

在这里插入图片描述
在这里插入图片描述

⑥.sag_and_assess.py介紹:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

⑦.小細節:

在这里插入图片描述

文章結語:小滿

在这里插入图片描述