使用Regex清理数据

时间:2016-07-17 10:10:48

标签: python regex awk sed data-cleaning

我有非常多的非常大的文件。

每个文件都包含这样的行:

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

使用:

\1\t\2\n\1\t

但它很慢,显然需要重复申请。

是否有更快的编程方式在所有文件中执行此操作?

工具箱中可用的工具:unix工具(sed,awk等),python,可能是perl。

不寻求宗教战争,只是务实的做法。

其他信息

这是我使用的完整脚本,基于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

3 个答案:

答案 0 :(得分:2)

您可以使用awk脚本:

<强> script.awk:

BEGIN { FS="[\t\v]" }
      { for(i=2 ; i <= NF; i++ ) printf("%s\t%s\n",$1,$i) }

像这样:awk -f script.awk yourfile

(我没有尝试使用大型数据集,我真的很感兴趣它与其他解决方案相比如何。)

答案 1 :(得分:1)

这是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')

答案 2 :(得分:1)

这是一个awk脚本,也会检查uuid。

它会忽略没有有效uuid的行。

BEGIN { FS="\v"; OFS="\t" }
{
  split($1,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

说实话,我希望一旦你测试了不同的解决方案,就可以与我们分享这样一个巨大文件的处理速度/速度越来越快。