【问题标题】:Text processing with two files两个文件的文本处理
【发布时间】:2012-05-14 15:54:17
【问题描述】:

我有两个格式如下的文本文件:

每一行都是这样的:

Key1:Value1

第二个是这样的:

Key2:Value2

有没有办法可以将file1 中的Value1 替换为Value2,这是通过将其用作file2 中的键获得的?

例如:

文件1:

foo:hello
bar:world

文件2:

hello:adam
bar:eve

我想得到:

foo:adam
bar:eve

每一行的两个文件之间不一定匹配。这可以在 awk 或其他东西中巧妙地完成,还是应该在 Python 中天真地完成?

【问题讨论】:

    标签: python text awk


    【解决方案1】:

    创建两个字典,每个文件一个。例如:

    file1 = {}
    for line in open('file1', 'r'):
        k, v = line.strip().split(':')
        file1[k] = v
    

    或者,如果您更喜欢单线:

    file1 = dict(l.strip().split(':') for l in open('file1', 'r'))
    

    然后你可以这样做:

    result = {}
    for key, value in file1.iteritems():
        if value in file2:
            result[key] = file2[value]
    

    另一种方法是您可以为 file1 反向生成键值对并使用集合。例如,如果您的 file1 包含 foo:bar,则您的 file1 dict 为 {bar: foo}

    for key in set(file1) & set(file2):
        result[file1[key]] = file2[key]
    

    基本上,您可以使用集合交集快速找到共同元素,因此这些元素保证在 file2 中,您不会浪费时间检查它们的存在。

    编辑:正如@pepr 所指出的,如果顺序对您很重要,您可以使用collections.OrderedDict 作为第一种方法。

    【讨论】:

    • collections.OrderedDict(Python 2.7+ 和 3.1+)可能是按原始顺序将值写回文件的选项(如果要写回)。 [我不喜欢字典的 fileX 名称。此外,打开的文件应始终在运行时之前关闭。]
    【解决方案2】:

    awk 解决方案:

    awk '
      BEGIN {FS = OFS = ":"}
      NR==FNR {val[$1] = $2; next}
      $1 in val {$2 = val[$1]}
      {print}
    }' file2 file1
    

    【讨论】:

      【解决方案3】:
      join -t : -1 2 -2 1 -o 0 2.2 -a 2 <(sort -k 2 -t : file1) <(sort file2)
      

      输入文件必须按它们所在的字段排序。

      选项:

      • -t : - 使用冒号作为分隔符
      • -1 2 - 加入文件 1 的字段 2
      • -2 1 - 加入文件 2 的字段 1
      • -o 0 2.2 - 输出连接字段,后跟来自 file2 的字段 2(由分隔符分隔)
      • -a 2 - 从 file2 输出未连接的行

      【讨论】:

        【解决方案4】:

        一旦你有:

        file1 = {'foo':'hello', 'bar':'world'}
        file2 = {'hello':'adam', 'bar':'eve'}
        

        你可以做一个丑陋的衬里:

        print dict([(i,file2[i]) if i in file2 else (i,file2[j]) if j in file2 else (i,j) for i,j in file1.items()])
        {'foo': 'adam', 'bar': 'eve'}
        

        在您的示例中,您在file2 中同时使用file1keysvalues 作为keys

        【讨论】:

          【解决方案5】:

          这可能对你有用(可能是 GNU sed):

          sed 's#\([^:]*\):\(.*\)#/\\(^\1:\\|:\1$\\)/s/:.*/:\2/#' file2 | sed -f - file1
          

          【讨论】:

            【解决方案6】:

            如果你不考虑使用基本的 Unix/Linux 命令作弊,那么这里有一个使用 paste 和 awk 的解决方案。

            paste file1.txt file2.txt | awk -F ":" '{ print $1":"$3 }'

            【讨论】:

            • 此解决方案假定file1 中的键控数据与引用发生的file2 中的行号位于该文件的同一行号上。可以合理地假设这是在给定的小样本数据中的巧合。
            【解决方案7】:

            TXR:

            @(next "file2")
            @(collect)
            @key:@value1
            @  (cases)
            @    (next "file1")
            @    (skip)
            @value2:@key
            @  (or)
            @    (bind value2 key)
            @  (end)
            @  (output)
            @value2:@value1
            @  (end)
            @(end)
            

            运行:

            $ txr subst.txr
            foo:adam
            bar:eve
            

            【讨论】:

              猜你喜欢
              • 2016-01-30
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2020-05-19
              相关资源
              最近更新 更多