發(fā)票結(jié)構(gòu)化識別

最近一段時間,老板給我的任務(wù)是發(fā)票的結(jié)構(gòu)化識別焊虏。目前市面上成熟的結(jié)構(gòu)化文本識別已經(jīng)很多了港令,關(guān)于如何才能夠?qū)ψR別結(jié)果進行結(jié)構(gòu)化分析這個問題啥容,困擾了我已經(jīng)有段時間了锈颗。像百度OCR應(yīng)該是知名度數(shù)一數(shù)二的,它能提供幾乎所有的結(jié)構(gòu)化文本識別服務(wù)咪惠,而我很長時間只停留在識別圖片中的文字击吱,而不能對它進行結(jié)構(gòu)化分析,這種感覺也太難受了遥昧。直到昨天晚上覆醇,說來也奇怪,無緣無故失眠了炭臭,我就想:既然睡不著永脓,那就不如想想明天要干些什么,想到老板最近派的任務(wù)鞋仍,又想到這兩天看過的正則表達式常摧。那這正則表達式不就正是為了處理識別結(jié)果這種字符串的嘛。正好威创,現(xiàn)學(xué)現(xiàn)賣虽界,敲一波,供日后復(fù)習(xí)用嵌赠。

關(guān)鍵字段

1.發(fā)票代碼
2.發(fā)票號碼
3.開票日期
4.校驗碼
5.購買方信息
6.銷售方信息
7.價稅合計

對應(yīng)的正則表達式

1.發(fā)票代碼

(?:(?<!\d)\d{12}(?!\d))

2.發(fā)票號碼

(?:(?<!\d)\d{8}(?!\d))

3.開票日期

[0-9]{1,4}年[0-9]{1,2}月[0-9]{1,2}

4.校驗碼

(?:校驗碼:|校驗碼:)[0-9]{1,20}

5.購買方信息

名稱         (?:稱:|稱:)[\u4e00-\u9fa5]+
納稅人識別號  (?:納稅人識別號:|納稅人識別號:)\w+
地址叫榕、電話    (?:地址、電話:|地址详炬、電話:)[\-0-9\u4e00-\u9fa5]+
開戶行及賬號  (?:開戶行及賬號:|開戶行及賬號:)[0-9\u4e00-\u9fa5]+

6.銷售方信息

名稱         (?:稱:|稱:)[\u4e00-\u9fa5]+
納稅人識別號  (?:納稅人識別號:|納稅人識別號:)\w+
地址盐类、電話    (?:地址、電話:|地址呛谜、電話:)[\-0-9\u4e00-\u9fa5]+
開戶行及賬號  (?:開戶行及賬號:|開戶行及賬號:)[0-9\u4e00-\u9fa5]+

7.價稅合計

[零壹貳叁肆伍陸柒捌玖圓整角]+

完整代碼

import re
class invoice_m:
    """
    增值稅機打發(fā)票結(jié)構(gòu)化識別
    """
    def __init__(self, result):
        self.FLAG_NAME = True
        self.FLAG_NO = True
        self.FLAG_ADD_TEL = True
        self.FLAG_BANK_NO = True
        self.result = result
        self.N = len(self.result)
        self.res = {}
        self.code()  # 發(fā)票代碼
        self.number()  # 發(fā)票號碼
        self.date()  # 開票日期
        self.check_code()  # 校驗碼
        self.total_price()  # 價稅合計(小寫)
        self.purchaser()  # 購買方
        self.seller()  # 銷售方

    def code(self):
        """
        發(fā)票代碼識別
        """
        No = {}
        for i in range(self.N):
            txt = self.result[i].replace(' ', '')
            txt = txt.replace(' ', '')
            res1 = re.findall('(?:(?<!\d)\d{10}(?!\d))', txt)
            res1 += re.findall('(?:(?<!\d)\d{12}(?!\d))', txt)
            if len(res1) > 0:
                No['發(fā)票代碼'] = res1[0]
                self.res.update(No)
                break

    def number(self):
        """
        識別發(fā)票號碼
        """
        nu = {}
        for i in range(self.N):
            txt = self.result[i].replace(' ', '')
            txt = txt.replace(' ', '')
            res1 = re.findall('(?:(?<!\d)\d{8}(?!\d))', txt)
            if len(res1) > 0:
                nu["發(fā)票號碼"] = res1[0]
                self.res.update(nu)
                break

    def date(self):
        """
        識別開票日期
        """
        da = {}
        for i in range(self.N):
            txt = self.result[i].replace(' ', '')
            txt = txt.replace(' ', '')
            res1 = re.findall('[0-9]{1,4}年[0-9]{1,2}月[0-9]{1,2}', txt)
            if len(res1) > 0:
                da["開票日期"] = res1[0] + '日'
                self.res.update(da)
                break

    def check_code(self):
        """
        校驗碼識別
        """
        check = {}
        for i in range(self.N):
            txt = self.result[i].replace(' ', '')
            txt = txt.replace(' ', '')
            res = re.findall('校驗碼[0-9]{1,20}', txt)
            res += re.findall('碼[0-9]{1,20}', txt)
            res += re.findall('(?:校驗碼:|校驗碼:)[0-9]{1,20}', txt)
            if len(res) > 0:
                check['校驗碼'] = res[0].replace('校驗碼', '').replace(':', '').replace('碼', '').replace(':', '')
                self.res.update(check)
                break

    def total_price(self):
        """
        識別價稅合計(小寫)
        """
        total_pri = {}
        switcher = {
            "零": '0',
            "壹": '1',
            "貳": '2',
            "叁": '3',
            "肆": '4',
            "伍": '5',
            "陸": '6',
            "柒": '7',
            "捌": '8',
            "玖": '9',
            "圓": '.',
            "整": '00',
            "角": ''
        }
        for i in range(self.N):
            txt = self.result[i].replace(' ', '')
            txt = txt.replace(' ', '')
            res1 = re.findall('[零壹貳叁肆伍陸柒捌玖圓整角]+', txt)
            res2 = ''
            if len(res1) > 0:
                for j in range(len(res1)):
                    if len(res1[j]) > 1:
                        for k in range(len(res1[j])):
                            res2 += switcher[res1[j][k]]
                        if res1[j][-1] == "角":
                            res2 += '0'
                    else:
                        res2 += switcher[res1[j]]
                        if res1[-1] == "角":
                            res2 += '0'
                total_pri["價稅合計"] = '¥' + res2
                self.res.update(total_pri)
                break

    def purchaser(self):
        """
        購買方信息識別
        """
        purchaser_info = {}
        self.res.setdefault('購買方')
        for i in range(self.N):
            txt = self.result[i].replace(' ', '')
            txt = txt.replace(' ', '')
            name = re.findall('(?:稱:|稱:)[\u4e00-\u9fa5]+', txt)
            no = re.findall('(?:納稅人識別號:|納稅人識別號:)\w+', txt)
            add_tel = re.findall('(?:地址在跳、電話:|地址、電話:)[\-0-9\u4e00-\u9fa5]+', txt)
            bank_no = re.findall('(?:開戶行及賬號:|開戶行及賬號:)[0-9\u4e00-\u9fa5]+', txt)
            if len(name) > 0 and self.FLAG_NAME:
                self.FLAG_NAME = False
                purchaser_info['名稱'] = name[0].replace(':', '').replace(':', '').replace('稱', '')
            if len(no) > 0 and self.FLAG_NO:
                self.FLAG_NO = False
                purchaser_info['納稅人識別號'] = no[0].replace(':', '').replace(':', '').replace('納稅人識別號', '')
            if len(add_tel) > 0 and self.FLAG_ADD_TEL:
                self.FLAG_ADD_TEL = False
                purchaser_info['地址隐岛、電話'] = add_tel[0].replace(':', '').replace(':', '').replace('地址猫妙、電話', '')
            if len(bank_no) > 0 and self.FLAG_BANK_NO:
                self.FLAG_BANK_NO = False
                purchaser_info['開戶行及賬號'] = bank_no[0].replace(':', '').replace(':', '').replace('開戶行及賬號', '')
        self.res['購買方'] = purchaser_info

    def seller(self):
        """
        銷售方信息識別
        """
        seller_info = {}
        self.res.setdefault('銷售方')
        for i in range(self.N):
            txt = self.result[i].replace(' ', '')
            txt = txt.replace(' ', '')
            name = re.findall('(?:稱:|稱:)[\u4e00-\u9fa5]+', txt)
            no = re.findall('(?:納稅人識別號:|納稅人識別號:)\w+', txt)
            add_tel = re.findall('(?:地址、電話:|地址聚凹、電話:)[\-0-9\u4e00-\u9fa5]+', txt)
            bank_no = re.findall('(?:開戶行及賬號:|開戶行及賬號:)[0-9\u4e00-\u9fa5]+', txt)
            if len(name) > 0 and not self.FLAG_NAME:
                seller_info['名稱'] = name[0].replace(':', '').replace(':', '').replace('稱', '')
            if len(no) > 0 and not self.FLAG_NO:
                seller_info['納稅人識別號'] = no[0].replace(':', '').replace(':', '').replace('納稅人識別號', '')
            if len(add_tel) > 0 and not self.FLAG_ADD_TEL:
                seller_info['地址割坠、電話'] = add_tel[0].replace(':', '').replace(':', '').replace('地址、電話', '')
            if len(bank_no) > 0 and not self.FLAG_BANK_NO:
                seller_info['開戶行及賬號'] = bank_no[0].replace(':', '').replace(':', '').replace('開戶行及賬號', '')
        self.res['銷售方'] = seller_info
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末妒牙,一起剝皮案震驚了整個濱河市彼哼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌湘今,老刑警劉巖敢朱,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡拴签,警方通過查閱死者的電腦和手機孝常,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蚓哩,“玉大人构灸,你說我怎么就攤上這事≌燃簦” “怎么了冻押?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長盛嘿。 經(jīng)常有香客問我洛巢,道長,這世上最難降的妖魔是什么次兆? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任稿茉,我火速辦了婚禮,結(jié)果婚禮上芥炭,老公的妹妹穿的比我還像新娘漓库。我一直安慰自己,他們只是感情好园蝠,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布渺蒿。 她就那樣靜靜地躺著,像睡著了一般彪薛。 火紅的嫁衣襯著肌膚如雪茂装。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天善延,我揣著相機與錄音少态,去河邊找鬼。 笑死易遣,一個胖子當著我的面吹牛彼妻,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播豆茫,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼侨歉,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了澜薄?” 一聲冷哼從身側(cè)響起为肮,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎肤京,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡忘分,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年棋枕,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片妒峦。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡重斑,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出肯骇,到底是詐尸還是另有隱情窥浪,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布笛丙,位于F島的核電站漾脂,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏胚鸯。R本人自食惡果不足惜骨稿,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望姜钳。 院中可真熱鬧坦冠,春花似錦、人聲如沸哥桥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拟糕。三九已至判呕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間已卸,已是汗流浹背佛玄。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留累澡,地道東北人梦抢。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像愧哟,于是被迫代替她去往敵國和親奥吩。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348