天天看点

python docx 一种文档缩略语提取方案

问题描述

提取word文档中的缩略语,并将文档内的缩略语替换为全称

python docx 一种文档缩略语提取方案

解决方案

首先观察数据,缩小问题范围

发现文档内缩略语基本都以表格方式呈现,一般是两列,有时也有四列,所以只考虑解决缩略语为表格且为2、4列的情况,其他特殊情况(段落等非表格形式,列数不为2、4)不考虑

缩略语判断逻辑主要就是单元格内文本是大写字符串的比例

代码里我写了两种逻辑,V1是判断大写单元格占总的单元格比例,V2是,奇数列大写与偶数列非大写的比例

判断缩略语提取缩略语
def extract_abbreviation(file, cfd=0.1, judgement='V1'):
    start_time = time.time()
    all_abrvt = []
    for table in file.tables:
        try:
            width, length = len(table.columns), len(table.rows)
            if not (width == 2 or width ==4):
                continue
            if judgement == 'V1':   # 判断英文大写占单元格文本比例
                cell_text = [cell.text for row in table.rows for cell in row.cells if cell.text]
                cell_upper = [i for i in cell_text if i.isupper()]
                if 0.4 < (len(cell_upper)+1) / (len(cell_text)+1) < 0.6:
                    is_abrvt = True
                else:
                    is_abrvt = False
            elif judgement == 'V2':   # 判断每列单元格文本类型比例
                column_odd_text = [cell.text for i in range(0, width, 2) for cell in table.columns[i].cells if cell.text]
                column_even_text = [cell.text for i in range(1, width, 2) for cell in table.columns[i].cells if cell.text]
                column_odd_upper = [i for i in column_odd_text if i.isupper()]
                column_even_upper = [i for i in column_even_text if not i.isupper()]
                if 0.8 < (len(column_odd_upper)+1) / (len(column_even_upper)+1) < 1.2:
                    is_abrvt = True
                else:
                    is_abrvt = False
            if  is_abrvt:
                abrvt, cfd_num, confidence= [], 0, 0
                for i in range(length):
                    for j in range(0, width, 2):
                        cell_1, cell_2 = table.rows[i].cells[j].text, table.rows[i].cells[j+1].text
                        if cell_1.isupper() and len(cell_1)>1 and len(cell_2)>2:
                            abrvt.append([cell_1, cell_2])
                            c_word = cell_2.split(' ')
                            c_head = ''.join([k[0] for k in c_word if k])
                            if c_head.lower() == cell_1.lower():
                                cfd_num += 1
                if length == 2:
                    confidence = cfd_num / length
                else:
                    confidence = cfd_num / (length * 2)
                if confidence > cfd:
                    logging.info('***** 发现缩略语表,%s, confidence: %s' % (abrvt, confidence))
                    all_abrvt.extend(abrvt)
            else:
                continue
        except Exception as e:
            logging.error('Error: ' + str(e), exc_info=True)
            print(e)
    print(all_abrvt)
    print('time: ', time.time()-start_time)
    return all_abrvt
           

提取出来的缩略语事例:

python docx 一种文档缩略语提取方案

文档内缩略语的替换

这里函数的输入是文本段落内容和抓取到的缩略语列表,

def abrvt_replace(file_text_total, abrvt):
    try:
        file_text = file_text_total.copy()
        for i in range(len(file_text)):
            abr_text = word_tokenize(file_text[i])
            for j in abrvt:
                if (file_text[i] != j[0]) and (j[0] in abr_text)  and \
                        (j[1].lower() not in file_text[i].lower()):
                    for k in range(len(abr_text)):
                        if abr_text[k] == j[0]:
                            abr_text[k] = j[1] + "(" + j[0] + ")"
                            break
                    file_text[i] = ' '.join(abr_text)
        return file_text
    except Exception as e:
        logging.info("***** 缩略语替换出错")
        logging.error('Error: ' + str(e), exc_info=True)
        return file_text_total
           

以上抓取和替换都不是很严谨,总能构造出反例,但实际效果以足够解决90%以上但问题了

继续阅读