将列表更改为txt文件中的列和行

时间:2018-12-15 14:37:13

标签: python text-files

a sample file here 我有一个非常重的文本文件,其中包含4GB的此类信息。如何使用python快速更改以下格式

编辑: 问题在于文本文件中有相同格式的不同数据,我不希望更改其格式并将其移至新文件(只是想跳过它们)

注意:该文件是大文件数据的样本,在原始文件中,它们很多。

domain:         x.x.x.x.in-addr.arpa
descr:          IP xxx SA
admin-c:        DUMY-RIPE
tech-c:         DUMY-RIPE

domain,descr,admin-c,tech-c
x.x.x.in-addr.arpa,IP xxx SA,DUMY-RIPE,DUMY-RIPE

3 个答案:

答案 0 :(得分:0)

import re

string = """
domain:         x.x.x.x.in-addr.arpa
descr:          IP xxx SA
admin-c:        DUMY-RIPE
tech-c:         DUMY-RIPE
"""

vals = re.findall("(.*): *(.*)", string)
k = [i[0] for i in vals]
v = [i[1] for i in vals]

out = ",".join(k) + '\n' + ",".join(v)
print(out)

输出:

domain,descr,admin-c,tech-c
x.x.x.x.in-addr.arpa,IP xxx SA,DUMY-RIPE,DUMY-RIPE

说明:

  1. 正则表达式对字符串进行排序以在字符串中找到适当的键/值对。
  2. 我们将调查结果分成两个单独的列表,一个包含第一列的值,另一个包含第二列的值。
  3. 我们使用一些join魔术来将输出放入您喜欢的格式(如果您想进一步研究,它实际上称为CSV),然后打印结果。

如果您最终希望对此进行解析,请查看Python csv模块中的一些方便工具。


编辑1

因为我喜欢压缩代码;),因此,上述代码的一些较小版本:

import re

string = """
domain:         x.x.x.x.in-addr.arpa
descr:          IP xxx SA
admin-c:        DUMY-RIPE
tech-c:         DUMY-RIPE
"""

vals = re.findall("(.*): *(.*)", string)
out = ",".join([i[0] for i in vals]) + '\n' + ",".join([i[1] for i in vals]
)
print(out)

甚至是单线(不计算printstring的定义):

import re

string = """
domain:         x.x.x.x.in-addr.arpa
descr:          IP xxx SA
admin-c:        DUMY-RIPE
tech-c:         DUMY-RIPE
"""

out = ",".join([i[0] for i in re.findall("(.*): *(.*)", string)]) + '\n' + ",".join([i[1] for i in re.findall("(.*): *(.*)", string)]
)
print(out)

注意:单线虽然花哨且紧凑,但由于它两次使用re.findall可能会影响速度。为了获得最快的性能,我建议使用第二种解决方案。

答案 1 :(得分:0)

这可以通过Shell管道而不是Python来完成。

我假设所有记录都具有相同的四行格式,并且它们之间没有换行符。对于其他情况,也可以修改此解决方案。

我使用了这个输入文件“ test.txt”:

domain:         x.x.x.x.in-addr.arpa
descr:          IP xxx SA
admin-c:        DUMY-RIPE
tech-c:         DUMY-RIPE
domain:         x.x.x.x.in-addr.arpa
descr:          IP xxx SA
admin-c:        DUMY-RIPE
tech-c:         DUMY-RIPE

以及以下命令:

cut -f2 -d : test.txt | sed -e 's/^ *//' -e 's/$/,/' | gxargs -d '\n' -n 4 | sed -s 's/, /,/g' -e 's/,$//' > out.txt

对于此输出“ out.txt”:

x.x.x.x.in-addr.arpa,IP xxx SA,DUMY-RIPE,DUMY-RIPE
x.x.x.x.in-addr.arpa,IP xxx SA,DUMY-RIPE,DUMY-RIPE

有点麻烦,但应该可以完成工作。

  • cut-f2选择第二个字段,-d :用冒号分隔
  • 第一个sed:第一个-e s从行的开头(^)开始,后面紧跟所有空格(*),没有任何空格(最后两个斜杠(//之间缺少内容;这消除了cut留下的前导空白。第二个-e s取代了结尾({{1} }}行中加上$,为下一步做准备
  • ,(必须使用GNU xargs,因此在我的Mac上为xargs前缀):g以换行符(-d分隔)收集每组4行('\n'),并将它们放在一行上。这对-n 4有点奇怪,但这在这里很完美
  • 第二个xargsseds(逗号后跟空格)和,(不带空格),,用大括号表示(每行多次)线)。然后,g将多余的逗号s替换为{,$),以将其删除
  • //将最后一条命令的输出保存到> out.txt中。 (警告:如果存在,out.txt将会覆盖)

您可以手动添加标题行,也可以将其与out.txt结合使用以获得所需的最终格式。

如果您只需要执行一次或几次,这应该足够快。

答案 2 :(得分:0)

这是您可能在Python解决方案中有用的功能。

给出一个可重复的行(就像一个打开的文件会给你一样),此生成器将产生由空白隔开的每组线的列表。例如,此输入:

abc
def

aaa
bbb
ccc

您将获得列表['abc', 'def']['aaa', 'bbb', 'ccc']。该功能应对多个换行符和其他空格具有鲁棒性。

def group_by_newlines(lines):
    out = []
    for line in lines:
        cleaned = line.strip()
        if cleaned:  # true if there was non-whitespace on the line
            out.append(cleaned)
        else:
            if out:  # something has been added to out already
                yield out
                out = []  # prepare for the next set of output
            else:  # we're in a group of newlines, so move on to the next line
                continue  # not strictly necessary, you could just fall off the `if` branch

    if out:
        yield out  # yield the final set of lines

一旦有了行组列表,就可以执行所需的任何逻辑来查找要处理的数据,并结合使用split(':')strip()和相等性测试来解析数据放入所需的逗号分隔行中。

通常最好在字符串方法可以胜任时避免使用正则表达式!这样您会发现速度更快。

使用这样的生成器方法可以帮助您避免将整个文件读入内存。打开输入和输出,并在创建数据时将其写出。

编辑:修复了我的函数中的几个错误

编辑2:我忘记了itertools.groupby的灵活性。这是group_by_newlines的更新版本,它的使用要短得多(可能会减少错误)。

from itertools import groupby

def group_by_newlines(lines):
    for key, group in groupby(lines, key=lambda line: bool(line.strip())):
        if key:  # True if the line isn't only whitespace
            yield list(group)  # the `group` is a generator yielding each of the lines