【问题标题】:Replace text in the first line in a huge txt tab delimited file替换巨大的 txt 制表符分隔文件的第一行中的文本
【发布时间】:2013-01-08 15:39:54
【问题描述】:

我有一个巨大的文本文件(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. 从原始文件中删除第一行并用新的替换它

这是一个好方法还是有更好的方法?
哪种语言最适合实现这一目标?
我们有在 python、vbscipt 和 Perl 方面有经验的人。

【问题讨论】:

    标签: python perl file vbscript


    【解决方案1】:

    只要替换行的长度与原始行的长度相同,几乎任何语言(我确信 Python 和 Perl)都可以实现整个“替换”,或者如果可以通过用空格填充来制作相同(否则,您将不得不重写整个文件)。

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

    【讨论】:

    • 如果 "id1" => "rs004" 可能不起作用。所以可能是写新文件的唯一方法。
    • 谢谢。我现在正在运行一个 Python 代码来执行您的建议。 id 长度不同,需要重写文件。我在 Windows 环境中,可能需要几个小时才能运行。我希望它有效。
    【解决方案2】:

    我建议您使用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;
    

    【讨论】:

      【解决方案3】:

      这应该很容易。我会使用 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)
      

      【讨论】:

      • 非常感谢!我将把这段代码展示给我的程序员。谢谢
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-04
      • 1970-01-01
      • 1970-01-01
      • 2018-11-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多