【问题标题】:Python flow control with Flag?带有标志的Python流控制?
【发布时间】:2013-11-16 21:27:33
【问题描述】:

以这种形式匹配一个文件。它总是以 InvNo 开头,~EOR~ 是记录结束。

InvNo: 123
Tag1: rat cake
Media: d234
Tag2: rat pudding
~EOR~
InvNo: 5433
Tag1: strawberry tart
Tag5: 's got some rat in it 
~EOR~
InvNo: 345
Tag2: 5
Media: d234
Tag5: rather a lot really
~EOR~

应该变成

IN 123
UR blabla
**
IN 345
UR blibli
**

其中 UR 是一个 URL。我想将 InvNo 作为第一个标签。 ** 现在是记录结束标记。这有效:

impfile = filename[:4]
media = open(filename + '_earmark.dat', 'w')

with open(impfile, 'r') as f: 
    HASMEDIA = False
    recordbuf = ''

    for line in f:
        if 'InvNo: ' in line:
            InvNo = line[line.find('InvNo: ')+7:len(line)]  
            recordbuf = 'IN {}'.format(InvNo)

        if 'Media: ' in line:
            HASMEDIA = True
            mediaref = line[7:len(line)-1]

            URL = getURL(mediaref) # there's more to it, but that's not important now  
            recordbuf += 'UR {}\n'.format(URL))

        if '~EOR~' in line:
            if HASMEDIA:
                recordbuf += '**\n'
                media.write(recordbuf)
                HASMEDIA = False

            recordbuf = ''

media.close()

有没有更好、更 Pythonic 的方式?使用 recordbuffer 和 HASMEDIA 标志似乎是老生常谈了。有什么好的或更好的做法的例子或提示吗?

(另外,我愿意为这篇文章提供更中肯的标题)

【问题讨论】:

    标签: python flags flow-control


    【解决方案1】:

    您可以将InvNoURL 初始设置为None,并且仅在InvNoURL 都不是Falsish 时打印一条记录:

    impfile = filename[:4]
    with open(filename + '_earmark.dat', 'w') as media, open(impfile, 'r') as f:
        InvNo = URL = None
        for line in f:
            if line.startswith('InvNo: '):
                InvNo = line[line.find('InvNo: ')+7:len(line)]  
    
            if line.startswith('Media: '):
                mediaref = line[7:len(line)-1]
                URL = getURL(mediaref) 
    
            if line.startswith('~EOR~'):
                if InvNo and URL:
                    recordbuf = 'IN {}\nUR {}\n**\n'.format(InvNo, URL)
                    media.write(recordbuf)
                InvNo = URL = None
    

    注意:我将'InvNo: ' in line 更改为line.startswith('InvNo: ') 基于假设 InvNo 总是出现在行首。在您的示例中似乎是正确的,但您使用 line.find('InvNo: ') 的事实表明 'InvNo:' 可能出现在该行的任何位置。

    如果InvNo: 仅出现在行首,则使用line.startswith(...) 并删除line.find('InvNo: ')(因为它等于0)。

    否则,您将不得不保留 'InvNo:' in lineline.find(当然,Media~EOR~ 也是如此)。 使用像'Media' in line 这样的代码的问题是,如果Tags 可以包含任何内容,它可能包含字符串'Media' 而不是真正的字段标题。

    【讨论】:

    • 谢谢!关于你的笔记:我使用'find'是因为输入文件以字节顺序标记开头,所以'startswith'会错过第一个InvNo。与'Media: ' 匹配的字段内容也很好。
    • 要处理 BOM 并避免使用find 的陷阱,请使用codecs.open 打开文件,并指定编码。如果是 UTF-8 编码文件,则指定编码为'utf-8_sig'。然后 BOM 将被正确解释,而不会与文本数据混在一起。
    【解决方案2】:

    如果您不想切片并且需要再次写入相同的输出文件,这里有一个版本,您可能不需要,您可以将 'w' 更改为 'a'。

    with open('input_file', 'r') as f, open('output.dat', 'a') as media:
        write_to_file = False
        lines = f.readlines()
        for line in lines:
            if line.startswith('InvNo:'):
                first_line = 'IN ' + line.split()[1] + '\n'
            if line.startswith('Media:'):
                write_to_file = True
            if line.startswith('~EOR~') and write_to_file:
                url = 'blabla' #Put getUrl() here
                media.write(first_line + url + '\n' + '**\n')
                write_to_file = False
                first_line = ''
    

    【讨论】:

      猜你喜欢
      • 2013-09-25
      • 1970-01-01
      • 1970-01-01
      • 2011-12-08
      • 2018-05-31
      • 2021-06-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多