Python筆記之re.search()

最近有學習到 正則表達式,有一點收穫,分享一下;

re.search()

在這裏插入圖片描述

情景A

某需求中 銀行流水的description字段值是我們財務同事來填寫的,我想給這條流水來匹配某些關鍵字,咋搞?

我最初的思路就是 description字段值.find(關鍵字);
管你三七二十一,find()的結果 非-1,就代表能找到;

加深一點,如果某些關鍵字 如下圖

在這裏插入圖片描述
onnqor&SYAFTRACO 這個關鍵字, & 不是內容,是and ; 整個關鍵字 實際理解爲 【onnqor 某些內容 SYAFTRACO】;
故不能用find();

    def find_str(self, description, keyword):
        """
        非標匹配
        :param description:
        :param keyword:
        :return:
        """

        # 會先進行普通規則匹配【匹配時 不改變description】,匹配失敗纔會進行正則匹配
        desc = description.replace(' ', '')
        # 實際非標匹配是有 & 和 ...
        k_str = keyword.replace('&', '.*').replace('...', '.*')

        if (re.search(k_str, desc)) is not None:
            Log.info('當前元素 {},正則匹配成功 {}'.format(description, keyword))

情景B

假設 某銀行流水的details字段的 ref_no 是我們財務同事來填寫的,要來匹配某些規則(前綴爲某關鍵字 + 結尾爲12位數字【年月日 8位數字+4位編號】),流水的details字段值 如下圖 【爲了不泄密,就是這樣的啦】

在這裏插入圖片描述

    def check_json(self, j):
        try:
            json.loads(j)
            return True
        except BaseException:
            return False

    def find_str_2(self, data_list):
        zz_1 = re.compile('^{"')
        zz_2 = re.compile('\d{12}$')
        for data in data_list:
            detail = data[-1]
            if detail is not None and zz_1.search(detail) is not None and self.check_json(
                    detail) is True and ('ref_no' in json.loads(detail).keys()) is True:

                reference = json.loads(detail)['ref_no']
                # Log.info(reference)

                yuanzu = ('探親', '出差', '薪資(CN)', 'zyooooxie', 'csdn')

                if reference is not None and reference.startswith(yuanzu) is True and zz_2.search(reference.strip()) is not None:
                    Log.info('將進行匹配')

變量yuanzu 代表了 所有的前綴關鍵字;
而結尾的12位數字,應該要再優化下【思路是 寫死 年月日的取值範圍,從20200101開始】

    def end_search(self, reference):
        """
        編號的日期 是 20200101開始,後四位爲 全數字
        :return:
        """
        zz_2 = re.compile(r'\d{12}$')
        print(zz_2.search(reference), '優化前')
        test_str = '(20[2-9]\d|[3-9]\d{3}|2[1-9]\d{2})(0[1-9]|1[1-2])(0[1-9]|[1-2]\d|3[0-1])\d{4}$'           # 年份大於等於2020,小於等於9999
        zz_2_new = re.compile(test_str)
        print(zz_2_new.search(reference), '優化後')

好像不錯呦;

但 我傳 20200431(4月沒有31號),用上面的正則 是校驗不出來的;
在這裏插入圖片描述

說起來 每月的天數 30or31or29or28,校驗是很複雜的 (如2月29 -> 閏年的’四年一閏,百年不閏,四百年再閏’ ),我只能 再寫個校驗日期的方法 = = (實際原因:正則表達式,我實在是太菜,搞不定)

    def check_date(self, reference, zz_2_new):
        # test_str = '(20[2-9]\d|[3-9]\d{3}|2[1-9]\d{2})(0[1-9]|1[1-2])(0[1-9]|[1-2]\d|3[0-1])\d{4}$'           # 年份大於等於2020,小於等於9999
        # zz_2_new = re.compile(test_str)
        if zz_2_new.search(reference) is None:
            return False
        else:
            result = zz_2_new.search(reference).group()
            check_date = result[0:8]
            check_month = result[0:6]
            f_l = self.month_first_last('-'.join([check_month[0:4], check_month[4:]]))

            check_date = '-'.join([check_date[0:4], check_date[4:6], check_date[6:]])

            try:
                assert check_date in self.date_list(f_l[0], f_l[1])
                return True
            except AssertionError:
                return False

定義yuanzu變量後 代碼改爲:

	# 前面的zz_2
	test_str = '(20[2-9]\d|[3-9]\d{3}|2[1-9]\d{2})(0[1-9]|1[1-2])(0[1-9]|[1-2]\d|3[0-1])\d{4}$'  # 年份大於等於2020,小於等於9999
	zz_2 = re.compile(test_str)
	
	yuanzu = ('探親', '出差', '薪資(CN)', 'zyooooxie', 'csdn')

	if reference is not None and reference.startswith(yuanzu) is True and self.check_date(reference.strip(), zz_2) is True:
		pass			# 以下省略

實際的困境

以上 是我寫的匹配過程,但我們後臺的思路更粗暴:直接把reference的字段值 扔到某個庫表去匹配all結果,匹配上,就ok;匹配不上,匹配結束;

實際很不符合需求!

產品小姐姐 定的需求是 匹配前先檢查reference是否符合這一類規則,符合就走這一類匹配,不然就走 情景A說的關鍵字匹配;只是 季度末趕時間交付,產品大佬 又改需求,so 我也得改成這樣粗暴匹配;

來到這兒,就得考慮實際庫表的記錄數量,之前分享過:Python的dict來處理大數據量對賬 ,故 把 庫表all值 某個字段做成dict

    def oa_table_llbh_dict(self):
        new_data = self.OA_VALUE()
        # Log.info(new_data)
        
        new = [i[0] for i in new_data]
        
        new_dict = dict.fromkeys(new, True)
        # Log.info(new_dict)
        return new_dict

這樣的情景下,代碼變成:

	yuanzu = ('探親', '出差', '薪資(CN)', 'zyooooxie', 'csdn')
    if (reference.strip() if reference is not None else reference) in self.oa_table_llbh_dict().keys():
	    pass			# 以下省略

情景C

情景:某文件夾內,有很多Excel、CSV文件,其中CSV都是相關Excel轉換來的【假設名稱完全一樣,除了格式不同】;我想知道某個Excel有沒有轉換成CSV文件,咋整?

思路好像就是: 列出整個文件夾的內容,進行查找,若找到就return,找不到就拉倒;

    def find_excel_csv(self, file):
        import os
        import re
        os.chdir(os.path.dirname(file))
        # Log.info(file)
        # Log.info(os.getcwd())

        all_file = os.listdir('.')
        Log.info(all_file)
        
        file_csv = '^{}.*.csv$'.format(os.path.basename(file)[:-5])
        Log.info(file_csv)

        for a in all_file:
            if re.search(file_csv, a) is not None:
                Log.info('找到了')
                Log.info(a)
                return a

上面的 for某循環 if某條件,可以直接寫成 列表生成式 【或是 列表推導式,列表解析式】 之前有說到 :Python 筆記【一】列表生成式

    def find_csv(self, file):
        import os
        os.chdir(os.path.dirname(file))

        all_file = os.listdir('.')
        file_csv = '^{}.*.csv$'.format(os.path.basename(file)[:-5])
        Log.info(file_csv)

        ele = [a for a in all_file if re.search(file_csv, a) is not None]
        if len(ele) != 0:
            Log.info('找到了')
            new_file = ele[0]
            Log.info(new_file)

        else:
            Log.info('整個文件夾沒有相關的CSV文件')

交流技術 歡迎+QQ 153132336 zy
個人博客 https://blog.csdn.net/zyooooxie

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章