使用正则表达式清理数据
Data Cleanup with Regex
我有很多非常大的文件。
每个文件包含这样的行:
uuid1 (tab) data1 (vtab) data2 ... dataN
uuid2 (tab) data1' (vtab) data2' (vtab) data3' (vtab) ... dataN'
....
其中每一行的 N 都不相同。结果需要如下所示:
uuid1 (tab) data1
uuid1 (tab) data2
....
uuid1 (tab) dataN
uuid2 (tab) data1'
uuid2 (tab) data2'
uuid2 (tab) data3'
...
uuid2 (tab) dataN'
....
我有一个正则表达式可以完成这项工作,替换:
^([abcdef0123456789]{8}-[abcdef0123456789]{4}-[abcdef0123456789]{4}-[abcdef0123456789]{4}-[abcdef0123456789]{12})\t(.+?)\x0B
与:
\t\n\t
但是很慢,显然需要重复申请。
是否有更快的编程方式来跨所有文件执行此操作?
工具箱中可用的工具:unix 工具(sed、awk 等),python,可能是 perl。
不寻求宗教war,只寻求务实的方法。
附加信息
这是我使用的完整脚本,基于 Kristof 的脚本,用于处理外循环:
#!/usr/bin/python
import os
import uuid
def processFile( in_filename ):
out_filename = os.path.splitext(in_filename)[0] + '.result.txt'
with open(in_filename) as f_in:
with open(out_filename, 'w') as f_out:
for line in f_in:
try:
# Retrieve the line and split into UUID and data
line_uuid, data = line.split('\t')
# Validate UUID
uuid.UUID(line_uuid)
except ValueError:
# Ignore this line
continue
# Write each individual piece of data to a separate line
for data_part in data.rstrip().split('\x0b'):
f_out.write(line_uuid + '\t' + data_part + '\n')
for i in os.listdir(os.getcwd()):
if i.endswith(".txt"):
print i
processFile( i )
continue
else:
continue
这是 Python 中的实现(在 3.5 中测试)。我还没有在大型数据集上尝试过这个,我会留给你试试。
import uuid
in_filename = 'test.txt'
out_filename = 'parsed.txt'
with open(in_filename) as f_in:
with open(out_filename, 'w') as f_out:
for line in f_in:
try:
# Retrieve the line and split into UUID and data
line_uuid, data = line.split('\t', maxsplit=1)
# Validate UUID
uuid.UUID(line_uuid)
except ValueError:
# Ignore this line
continue
# Write each individual piece of data to a separate line
for data_part in data.rstrip().split('\x0b'):
f_out.write(line_uuid + '\t' + data_part + '\n')
您可以使用 awk 脚本:
script.awk:
BEGIN { FS="[\t\v]" }
{ for(i=2 ; i <= NF; i++ ) printf("%s\t%s\n",,$i) }
像这样:awk -f script.awk yourfile
(我还没有在大型数据集上尝试过,我真的很感兴趣它与其他解决方案相比的表现如何。)
这是一个 awk 脚本,它也将检查 uuid。
它忽略没有有效 uuid 的行。
BEGIN { FS="\v"; OFS="\t" }
{
split(,a,/\s+/);
if (match(a[1], /^[a-f0-9]{8}(-[a-f0-9]{4}){3}-[a-f0-9]{12}$/, m))
{
print a[1],a[2];
for (i=2;i<=NF;i++) print a[1],$i;
}
}
在以下格式的小文件上进行测试:
uuid (普通标签) data1 (垂直标签) data2 ... (垂直标签) dataN
如果您确定 uuid 已经有效,那么删除 if
自然会加快它的速度,因为正则表达式匹配需要一点时间。但是您的文件系统的速度可能会成为更大的瓶颈。
$ awk -f unpivot_data.awk input.txt > result.txt
$ cat result.txt
abcd1234-ab12-ab12-ab12-abcdef123456 data1
abcd1234-ab12-ab12-ab12-abcdef123456 data2
老实说,我希望在您测试了不同的解决方案后,您可以与我们分享 faster/slower 如此大的文件的处理量是多少。
我有很多非常大的文件。
每个文件包含这样的行:
uuid1 (tab) data1 (vtab) data2 ... dataN
uuid2 (tab) data1' (vtab) data2' (vtab) data3' (vtab) ... dataN'
....
其中每一行的 N 都不相同。结果需要如下所示:
uuid1 (tab) data1
uuid1 (tab) data2
....
uuid1 (tab) dataN
uuid2 (tab) data1'
uuid2 (tab) data2'
uuid2 (tab) data3'
...
uuid2 (tab) dataN'
....
我有一个正则表达式可以完成这项工作,替换:
^([abcdef0123456789]{8}-[abcdef0123456789]{4}-[abcdef0123456789]{4}-[abcdef0123456789]{4}-[abcdef0123456789]{12})\t(.+?)\x0B
与:
\t\n\t
但是很慢,显然需要重复申请。
是否有更快的编程方式来跨所有文件执行此操作?
工具箱中可用的工具:unix 工具(sed、awk 等),python,可能是 perl。
不寻求宗教war,只寻求务实的方法。
附加信息
这是我使用的完整脚本,基于 Kristof 的脚本,用于处理外循环:
#!/usr/bin/python
import os
import uuid
def processFile( in_filename ):
out_filename = os.path.splitext(in_filename)[0] + '.result.txt'
with open(in_filename) as f_in:
with open(out_filename, 'w') as f_out:
for line in f_in:
try:
# Retrieve the line and split into UUID and data
line_uuid, data = line.split('\t')
# Validate UUID
uuid.UUID(line_uuid)
except ValueError:
# Ignore this line
continue
# Write each individual piece of data to a separate line
for data_part in data.rstrip().split('\x0b'):
f_out.write(line_uuid + '\t' + data_part + '\n')
for i in os.listdir(os.getcwd()):
if i.endswith(".txt"):
print i
processFile( i )
continue
else:
continue
这是 Python 中的实现(在 3.5 中测试)。我还没有在大型数据集上尝试过这个,我会留给你试试。
import uuid
in_filename = 'test.txt'
out_filename = 'parsed.txt'
with open(in_filename) as f_in:
with open(out_filename, 'w') as f_out:
for line in f_in:
try:
# Retrieve the line and split into UUID and data
line_uuid, data = line.split('\t', maxsplit=1)
# Validate UUID
uuid.UUID(line_uuid)
except ValueError:
# Ignore this line
continue
# Write each individual piece of data to a separate line
for data_part in data.rstrip().split('\x0b'):
f_out.write(line_uuid + '\t' + data_part + '\n')
您可以使用 awk 脚本:
script.awk:
BEGIN { FS="[\t\v]" }
{ for(i=2 ; i <= NF; i++ ) printf("%s\t%s\n",,$i) }
像这样:awk -f script.awk yourfile
(我还没有在大型数据集上尝试过,我真的很感兴趣它与其他解决方案相比的表现如何。)
这是一个 awk 脚本,它也将检查 uuid。
它忽略没有有效 uuid 的行。
BEGIN { FS="\v"; OFS="\t" }
{
split(,a,/\s+/);
if (match(a[1], /^[a-f0-9]{8}(-[a-f0-9]{4}){3}-[a-f0-9]{12}$/, m))
{
print a[1],a[2];
for (i=2;i<=NF;i++) print a[1],$i;
}
}
在以下格式的小文件上进行测试:
uuid (普通标签) data1 (垂直标签) data2 ... (垂直标签) dataN
如果您确定 uuid 已经有效,那么删除 if
自然会加快它的速度,因为正则表达式匹配需要一点时间。但是您的文件系统的速度可能会成为更大的瓶颈。
$ awk -f unpivot_data.awk input.txt > result.txt
$ cat result.txt
abcd1234-ab12-ab12-ab12-abcdef123456 data1
abcd1234-ab12-ab12-ab12-abcdef123456 data2
老实说,我希望在您测试了不同的解决方案后,您可以与我们分享 faster/slower 如此大的文件的处理量是多少。