使用正则表达式清理数据

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 如此大的文件的处理量是多少。