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
答案 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
说明:
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)
甚至是单线(不计算print
或string
的定义):
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
有点奇怪,但这在这里很完美xargs
:sed
将s
(逗号后跟空格)和,
(不带空格),,
用大括号表示(每行多次)线)。然后,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