【问题标题】:Remove multiple EOL in file删除文件中的多个 EOL
【发布时间】:2013-07-06 16:43:21
【问题描述】:

我有一个带有 \n EOL 字符的制表符分隔文件,看起来像这样:

User Name\tCode\tTrack\tColor\tNote\n\nUser Name2\tCode2\tTrack2\tColor2\tNote2\n

我正在获取此输入文件并使用split('\t') 将其重新格式化为嵌套列表。该列表应如下所示:

[['User Name','Code','Track','Color','Note'],
 ['User Name2','Code2','Track2','Color2','Note2']]

生成文件的软件允许用户在填写“备注”字段时按“输入”键任意次数。它还允许用户按“回车”创建任意数量的换行符,而无需在“注释”字段中输入任何可见文本。

最后,用户可以在“Note”中间按“enter”任意次,创建多个段落,但从操作的角度来看,这种情况非常罕见,我愿意不考虑这种可能性如果它使代码复杂得多。这种可能性真的非常低优先级。

从上面的示例中可以看出,这些操作可能会导致一系列“\n\n...”代码在“注释”字段之前、后面或替换为任意长度。或者这样说,在将文件对象放入列表之前,需要进行以下替换:

\t\n\n... preceding "Note" must become \t
\n\n... trailing "note" must become \n
\n\n... in place of "note" must become \n
\n\n... in the middle of the text note must become a single whitespace, if easy to do

我曾尝试使用 strip() 和 replace() 方法但没有成功。在使用 replace() 方法之前,文件对象是否需要先复制到其他地方?

我有使用 Awk 的经验,但我希望不需要正则表达式,因为我对 Python 还很陌生。这是我需要改进以解决多个换行符的代码:

marker = [i.strip() for i in open('SomeFile.txt', 'r')]

marker_array = []
for i in marker:
    marker_array.append(i.split('\t'))

for i in marker_array:
    print i

【问题讨论】:

  • 可以修改生成SomeFile.txt的软件吗?如果是这样,它是用 Python 编写的吗?
  • 用户也可以在备注字段中输入标签吗?
  • 如果您使用csv 模块来写入此数据并正确引用注释字段,将会有所帮助。
  • 生成文本文件的软件不是Python写的。修改它不是一种选择。

标签: python eol


【解决方案1】:

计算标签;如果您假设注释字段的一行中从来没有 4 个选项卡,您可以收集注释,直到找到 确实 有 4 个选项卡的行:

def collapse_newlines(s):
    # Collapse multiple consecutive newlines into one; removes trailing newlines
    return '\n'.join(filter(None, s.split('\n')))

def read_tabbed_file(filename):
    with open(filename) as f:
        row = None
        for line in f:
            if line.count('\t') < 4:   # Note continuation
                row[-1] += line
                continue

            if row is not None:
                row[-1] = collapse_newlines(row[-1])
                yield row

            row = line.split('\t')

        if row is not None:
            row[-1] = collapse_newlines(row[-1])
            yield row

在确定下一行没有音符继续之前,上述生成器函数不会产生一行,有效地向前看。

现在使用read_tabbed_file() 函数作为生成器并循环遍历结果:

for row in read_tabbed_file(yourfilename):
    # row is a list of elements

演示:

>>> open('/tmp/test.csv', 'w').write('User Name\tCode\tTrack\tColor\tNote\n\nUser Name2\tCode2\tTrack2\tColor2\tNote2\n')
>>> for row in read_tabbed_file('/tmp/test.csv'):
...     print row
... 
['User Name', 'Code', 'Track', 'Color', 'Note']
['User Name2', 'Code2', 'Track2', 'Color2', 'Note2']

【讨论】:

  • 在这种情况下,我可能会将整个文件作为字符串读取并使用 splitlines() 来避免在生成器停止之前保持文件句柄打开。
  • @llb:如果文件短了一百万行怎么办?打开的文件句柄很便宜。在内存中保存所有数据不是。
【解决方案2】:

您遇到的第一个问题是in - 它试图提供帮助并一次从文件中读取一行文本。

>>> [i for i in open('SomeFile.txt', 'r') ]
['User Name\tCode\tTrack\tColor\tNote\n', '\n', 'User Name2\tCode2\tTrack2\tColor2\tNote2\n', '\n']

添加对.strip() 的调用确实会从每一行中去除空格,但这会留下空行 - 它不会将那些空元素从列表中删除。

>>> [i.strip() for i in open('SomeFile.txt', 'r') ]
['User Name\tCode\tTrack\tColor\tNote', '', 'User Name2\tCode2\tTrack2\tColor2\tNote2', '']

但是,您可以在 if 子句中向列表推导提供以使其删除只有换行符的行:

>>> [i.strip() for i in open('SomeFile.txt', 'r') if len(i) >1 ]
['User Name\tCode\tTrack\tColor\tNote', 'User Name2\tCode2\tTrack2\tColor2\tNote2']
>>>

【讨论】:

  • 请注意,OP 的 Note 字段可能包含嵌入的换行符以及以换行符开头或结尾的内容。在换行符上拆分(或在流上迭代)不会有效地处理这种情况。
  • 正确,但请注意,OP 还表示他们现在不关心处理该皱纹(或者至少,这是一个低优先级)。
  • 感谢这个非常简单的答案。它几乎可以工作,但我决定使用上面基于生成器的解决方案。
  • 生成器解决方案简单而优雅,我更喜欢它比“几乎可以工作”的解决方案。
【解决方案3】:

我想,那个 csv 模块会对你有所帮助。

例如看看这个:Parsing CSV / tab-delimited txt file with Python

【讨论】:

  • csv 不会帮助 OP,因为文件可以包含多个换行符。
猜你喜欢
  • 1970-01-01
  • 2012-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多