首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将纯文本字典数据拆分为多个文件,第2轮

将纯文本字典数据拆分为多个文件,第2轮
EN

Code Review用户
提问于 2014-08-12 19:11:02
回答 1查看 150关注 0票数 7

这是我先前的问题的延续。

我有一个带有字典(韦伯斯特“无删节词典”)内容的纯文本文件,格式如下:

A A(在英语中命名为A,最常见的是用其他语言命名)。Defn:英语和许多其他字母的第一个字母。中欧和西欧字母的大写A,以及小写字母(a),除了意大利语、黑色字母等的形式外,都是从古拉丁文A中继承而来的,后者是从希腊语阿尔法借来的,具有同样的形式;这是由第一个字母(Aleph )和它本身来自埃及血统的字母组成的。阿列弗是一个辅音字母,带有一种不属于希腊发音的喉音音;希腊人把它用发音表示他们的元音阿尔法,腓尼基字母没有元音符号。这个字母,在英语中,用于几个不同的元音。见发音指南,第43-74节。常规的长a,如在命运等方面,是一个相对现代的声音,并且已经取代了直到17世纪早期的那种质量(远)的声音。2. (毛里求斯)Defn:模型大音阶( C)中第六声调的名称,或小音阶的第一声调,以它的名字命名为A小调的音阶。小提琴的第二根弦是调到A的高音杆。-A sharp (A#)是介于A和B之间的音乐音调的名称。-A平面(A)是介于A和G之间的音调中间的名称A本身是Etym:(L本身),一个突出;一个nonesuch。大胸。 O公平的克雷赛德,花和特洛伊和希腊的本身。乔叟。A,准备。缩写形式的a(如.)上)。看上面。 1. In;on;at;by.大胸。“上帝的名字”“撕碎了一块”“踮起脚尖。”“一个星期天”沙克“现在男人有一天了。”乔叟。“给他们安排一个工作。”罗布森(更多的乌托邦) 2.在过程中;在动作中;进入;到;--与-ing中以辅音开头的动词实体连用。这是介词an的缩写形式(在元音之前使用);如在狩猎、建筑、乞讨中。“雅各布,当他是一个垂死的”哈伯。xi。21.“我们一起来一只鸟”“那是在做一件事”沙克。“他突然大笑起来。”麦考利。连字符可用于将a与口头实体(as、a-狩猎、a-building)连接起来,也可将单词单独书写。这种表达形式在很大程度上已经过时,a被省略,口头实体被当作分词来处理。马来人,马来人:马来半岛和印度群岛西部岛屿上的一种棕色或铜色人种。马来人;马来人- n. Defn:马来语马来苹果(Bot.),一种常见于印度的含羞草树(Eugenia Malaccensis);也是其苹果状果实。马来语“la*ya”lam,n. Defn:与泰米尔语密切相关的一种栽培的德拉威语的名称。尤勒。F. Defn:西非乔木猴(Cercopithecus cynosurus)。

我想把这个文件转换成一种不同的格式,以便更容易和更有效地在其中进行搜索。这就是我的想法:

  1. 将文件拆分为条目的集合
  2. 将每个条目保存在自己的文件中:
    • 并非所有目录(100k+文件)都被拆分为多个子目录

  3. 创建索引文件
    • 每项一行,格式为:FILENAME:WORD

我在@jcollado's优秀的先前的回答中实现了这些建议,并做了一些其他改进:

  • 重构函数,使用parse_content生成器返回term, content
  • 添加了对多次出现的术语的计数,形式为-1-2-3、附加(稍后由GUI应用程序以下标形式显示)
  • 更改了目录拆分逻辑,因为大多数输出目录中仍然有数百个文件。例如,现在单词greeting将改为g/gr/gre/greeting-NUM.txt而不是gr/greeting-NUM.txt
  • OptionParser替换为ArgumentParser
  • 使用--dry-run--max-count选项使调试变得更容易
  • 修正了一些小错误

这就是我现在使用的脚本:

代码语言:javascript
复制
#!/usr/bin/env python

import re
import os
import logging

from argparse import ArgumentParser

DATA_DIR = 'data'
INDEX_PATH = os.path.join(DATA_DIR, 'index.dat')

re_entry_start = re.compile(r'[A-Z][A-Z0-9 ;\'-.,]*它创建如下所示的索引文件:A/a/a_-1.txt:a/a_/a_-2.txt:a/a_/a_/a_-3.txt:a/a_/a_-4.txt:a/a_/a_-5.txt:a/a/a_-6.txt:a/a_/a_-7.txt:a- a/a__/a_-8 rod :a a/aa/aam/aam-9 rod:aam a/aa/aar/aard_vark-10.txt:aard-vark a/aa/aar/aard_wolf-11.txt:aard-wolf a/aa/aar/aaronic 12.txt:aaronic a/aa/aar/aar/aar-13.txt:标准a/aa/aar/aaron_S_棍棒-14.txt:aaron a aaron a/aa/aaron_14.txt_r棒/ab/ab/ab_-15.txt:ab-a/ab/ab/ab_-16.txt:ab a/ab/aba/abaca-17.txt:abaca /ab/aba/abaca 18.txt:aba a/ab/aba/算盘-19.txt:算盘a/ab/aba/算盘-20.txt:算盘A/ab/aba/abacist-21.txt:算盘师虽然我比以前的版本更喜欢它,但是由于我已经做了重大的修改,我想知道:我又犯了什么新错误?还有什么我还能做得更好的吗?完整的输入文件(清理的数据)是这里 (下载10 MB,解压缩27 MB )。开源项目是在GitHub上进行的。)
re_nonalpha = re.compile(r'[^a-z]')


def write_entry_file(dirname, filename, content):
    basedir = os.path.join(DATA_DIR, dirname)
    if not os.path.isdir(basedir):
        os.makedirs(basedir)

    path = os.path.join(basedir, filename)
    with open(path, 'w') as fh:
        fh.write('\n'.join(content) + '\n')


def is_new_term(line, prev_line_blank):
    return re_entry_start.match(line) and prev_line_blank and '  ' not in line


def parse_content(arg):
    prev_line_blank = True
    term = None
    term_count = 0
    content = []
    with open(arg) as fh:
        for line0 in fh:
            line = line0.strip()
            if is_new_term(line, prev_line_blank):
                if term:
                    for term in term.split('; '):
                        yield term, content
                prev_term = term
                term = line.lower()
                if term == prev_term:
                    term_count += 1
                    subscript = '-' + str(term_count)
                else:
                    term_count = 1
                    subscript = ''
                content = [term + subscript]
            else:
                content.append(line)
            prev_line_blank = not line


def get_split_path(term, count):
    slug = re_nonalpha.sub('_', term.lower()).ljust(3, '_')
    dirname = os.path.join(slug[0], slug[:2], slug[:3])
    filename = '{}-{}.txt'.format(slug, count)
    return dirname, filename


def parse_file(arg, dry_run=False, max_count=0):
    def rebuild_index():
        count = 0
        for term, content in parse_content(arg):
            count += 1
            if max_count and count > max_count:
                break
            dirname, filename = get_split_path(term, count)
            entry = '{}/{}:{}'.format(dirname, filename, term)
            logging.info(entry)
            if not dry_run:
                fh.write(entry + '\n')
                write_entry_file(dirname, filename, content)

    if dry_run:
        rebuild_index()
    else:
        if not os.path.isdir(DATA_DIR):
            os.makedirs(DATA_DIR)
        with open(INDEX_PATH, 'w') as fh:
            rebuild_index()


def main():
    parser = ArgumentParser(description='Generate index and entry files '
                                        'from cleaned plain text file')
    parser.add_argument('--dry-run', '-d', '-n', action='store_true',
                        help="Dry run, don't write to files")
    parser.add_argument('--max-count', '-c', type=int,
                        help="Exit after processing N records")
    parser.add_argument('files', help="File(s) to parse", nargs='+')
    args = parser.parse_args()

    logging.basicConfig(level=logging.INFO,
                        format='%(levelname)s: %(message)s')

    for arg in args.files:
        parse_file(arg, dry_run=args.dry_run, max_count=args.max_count)


if __name__ == '__main__':
    main()

它创建如下所示的索引文件:

J156

A/a/a_-1.txt:a/a_/a_-2.txt:a/a_/a_/a_-3.txt:a/a_/a_-4.txt:a/a_/a_-5.txt:a/a/a_-6.txt:a/a_/a_-7.txt:a- a/a__/a_-8 rod :a a/aa/aam/aam-9 rod:aam a/aa/aar/aard_vark-10.txt:aard-vark a/aa/aar/aard_wolf-11.txt:aard-wolf a/aa/aar/aaronic 12.txt:aaronic a/aa/aar/aar/aar-13.txt:标准a/aa/aar/aaron_S_棍棒-14.txt:aaron a aaron a/aa/aaron_14.txt_r棒/ab/ab/ab_-15.txt:ab-a/ab/ab/ab_-16.txt:ab a/ab/aba/abaca-17.txt:abaca /ab/aba/abaca 18.txt:aba a/ab/aba/算盘-19.txt:算盘a/ab/aba/算盘-20.txt:算盘A/ab/aba/abacist-21.txt:算盘师

J257

虽然我比以前的版本更喜欢它,但是由于我已经做了重大的修改,我想知道:

F158H159

我又犯了什么新错误?

H260H161

还有什么我还能做得更好的吗?

H262F263

完整的输入文件(清理的数据)是这里 (下载10 MB,解压缩27 MB )。

开源项目是在GitHub上进行的。

EN

回答 1

Code Review用户

回答已采纳

发布于 2014-08-13 09:10:11

代码看起来很好,并且在多个方面得到了改进( and解析,只打开一次索引文件,试运行标志而不是调试标志,.)。因此,这次检讨的重点是一些较小的细节:

  • 请添加文档字符串来记录代码。这将使代码更具可读性,并使github中的潜在协作者更容易加入该项目。
  • 试着按字母顺序订购进口商品。并不是真的需要,但这是个不错的选择。
  • 为了更好地分离关注点,write_entry_file不应该考虑加入content。在parse_file中,这种情况应该会更早发生。
  • count变量在rebuild_index中似乎是enumerate的一个很好的候选变量:对于枚举中的计数、(术语、内容)(parse_content(Arg)):
  • dry_run检查位于parse_file中的几个地方,一开始可能会让人感到困惑。比如: def parse_file(arg,dry_run=False,max_count=0):def rebuild_index():max_count=0=0,parse_content(Arg)中的内容:计数+= 1(如果max_count和count > max_count: break,filename = get_split_path(term,count)条目= '{}/{}:{}'.format(dirname ),Logging.info(条目)生成条目、大号、文件名、内容if dry_run: for _index_data in rebuild_index():pass :如果不是os.path.isdir(DATA_DIR):os.makedirs(DATA_DIR)和open(INDEX_PATH,'w')作为fh:对于条目,Rebuild_index()中的内容:fh.write(条目+ '\n') write_entry_file(目录名、文件名、内容)
  • 参数解析代码应该在一个单独的函数中,main应该使用参数。这样,如果您将来想编写测试用例,main是可测试的: if __name__ == '__main__':args = parse_arguments() main(args)
票数 6
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/59833

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档