替换巨大的txt制表符分隔文件中第一行中的文本

时间:2013-01-24 19:08:16

标签: python perl file vbscript

我有一个巨大的文本文件(大小为19GB);它是一个带有变量和观察结果的遗传数据文件 第一行包含变量名称,结构如下:

id1.var1 id1.var2 id1.var3 id2.var1 id2.var2 id2.var3 

我需要交换id1,id2等。使用另一个文本文件中的相应值(此文件大约有7k行)ID没有任何特定顺序,其结构如下:

oldId newIds
id1 rs004
id2 rs135

我做了一些谷歌搜索,但实际上找不到允许执行以下操作的语言:

  1. 阅读第一行
  2. 用新ID替换ID
  3. 从原始文件中删除第一行并将其替换为新文件
  4. 这是一个好方法还是有更好的方法?
    哪个是最好的语言来实现这个目标?
    我们的人员有python,vbscipt和Perl的经验。

3 个答案:

答案 0 :(得分:4)

只要替换行的长度与原始相同,整个“替换”的东西几乎可以在任何语言中使用(我确定Python和Perl),或者如果它可以通过用空格填充 make 相同(否则,你将不得不重写整个文件)。

打开文件进行读写(w+模式),读取第一行,准备新行,seek将0放在文件中,写入新行,关闭文件。

答案 1 :(得分:3)

我建议你使用Tie::File模块,它将文本文件中的行映射到Perl数组,并且在标题之后重写行是简单的工作。

该程序演示。它首先将所有旧/新ID读入哈希,然后使用Tie::File映射数据文件。使用替换修改文件的第一行(在$file[0]中),然后解开该数组以重写并关闭该文件。

您需要更改我使用过的文件名。还要注意我假设ID总是“单词”字符(字母数字加下划线)后跟一个点,并且没有空格。当然,您需要在修改文件之前备份文件,并且应该在更新实际内容之前在较小的文件上测试程序。

use strict;
use warnings;

use Tie::File;

my %ids;
open my $fh, '<', 'newids.txt' or die $!;
while (<$fh>) {
  my ($old, $new) = split;
  $ids{$old} = $new;
}

tie my @file, 'Tie::File', 'datafile.txt' or die $!;
$file[0] =~ s<(\w+)(?=\.)><$ids{$1} // $1>eg;
untie @file;

答案 2 :(得分:1)

这应该很简单。我会使用Python,因为我是Python粉丝。概要:

  • 读取映射文件,并保存映射(在Python中,使用字典)。

  • 一次读取一行数据文件,重新映射变量名称,然后输出已编辑的行。

你真的无法就地编辑文件...嗯,我猜你可以,如果每个新的变量名称总是与旧名称完全相同。但为了便于编程和运行时的安全性,最好始终编写新的输出文件,然后删除原始文件。这意味着在运行之前您将需要至少20 GB的可用磁盘空间,但这应该不是问题。

这是一个Python程序,展示了如何做到这一点。我使用您的示例数据来制作测试文件,这似乎有效。

#!/usr/bin/python

import re
import sys

try:
    fname_idmap, fname_in, fname_out = sys.argv[1:]
except ValueError:
    print("Usage: remap_ids <id_map_file> <input_file> <output_file>")
    sys.exit(1)

# pattern to match an ID, only as a complete word (do not match inside another id)
# match start of line or whitespace, then match non-period until a period is seen
pat_id = re.compile("(^|\s)([^.]+).")

idmap = {}

def remap_id(m):
    before_word = m.group(1)
    word = m.group(2)
    if word in idmap:
        return before_word + idmap[word] + "."
    else:
        return m.group(0)  # return full matched string unchanged

def replace_ids(line, idmap):
    return re.sub(pat_id, remap_id, line)

with open(fname_idmap, "r") as f:
    next(f)  # discard first line with column header: "oldId newIds"
    for line in f:
        key, value = line.split()
        idmap[key] = value

with open(fname_in, "r") as f_in, open(fname_out, "w") as f_out:
    for line in f_in:
        line = replace_ids(line, idmap)
        f_out.write(line)