【问题标题】:If the first column of file1 matches any string in file2, then replace it with the second column of file1如果 file1 的第一列与 file2 中的任何字符串匹配,则将其替换为 file1 的第二列
【发布时间】:2015-04-16 13:21:51
【问题描述】:

我有这个问题,我还没有解决...我想操作这些文件...如果 file1 的第一列与 file2 中的任何字符串匹配,则将其替换为 file1 的第二列...然后折叠它(我的意思是,我只需要 output_file 的第二列中的每个字段或“单元格”的唯一值)..
哪种语言解决这个问题并不重要(awk、perl、python)...文件包含 100000 行或更多...我一直在尝试单行 awk 脚本,但没有...

任何帮助表示赞赏。
问候

file1.txt

ID100000360640  ITEM1;ITEM2  
ID100000360638  ITEM1;ITEM3  
ID100000360644  ITEM1;ITEM4  
ID100000363115  ITEM5;ITEM2;ITEM3  
ID100000363116  ITEM1;ITEM7  
ID100000382126  ITEM8;ITEM1  
ID100000002165  ITEM1;ITEM2;ITEM3;ITEM9  
ID100000002596  ITEM1;ITEM10  
ID100000003084  ITEM1  

file2.txt

ID200000000419  ID100000360638;ID100000360640;ID100000360644;ID100000394921
ID200000000938 ID100000363115;ID100000363116;ID100000363117;ID100000382126  
ID200000001036  ID100000002165;ID100000398119 

output_expected.txt

ID200000000419  ITEM1;ITEM3;ITEM1;ITEM2;ITEM1;ITEM4;ID100000394921  
ID200000000938  ITEM5;ITEM2;ITEM3;ITEM1;ITEM7;ID100000363117;ITEM8;ITEM1;  
ID200000001036  ITEM1;ITEM2;ITEM3;ITEM9;ID100000398119  

processed_output.txt

ID200000000419  ITEM1;ITEM2;ITEM3;ITEM4;ID100000394921  
ID200000000938  ITEM1;ITEM2;ITEM3;ITEM5;ITEM7;ITEM8;ID100000363117;  
ID200000001036  ITEM1;ITEM2;ITEM3;ITEM9;ID100000398119 

谢谢

【问题讨论】:

  • 欢迎来到 Stack Overflow!看起来您希望我们为您编写一些代码。虽然许多用户愿意为陷入困境的程序员编写代码,但他们通常只会在发布者已经尝试自己解决问题时提供帮助。展示这项工作的一个好方法是包含您迄今为止编写的代码、示例输入(如果有的话)、预期输出和您实际获得的输出(控制台输出、堆栈跟踪、编译器错误 - 不管是什么适用的)。您提供的详细信息越多,您可能收到的答案就越多。
  • 嗨,欢迎来到 Stack Overflow。我们不会为您编写代码,但如果您向我们展示您的 awk 脚本,我们可以帮助您弄清楚如何使它们工作。
  • 当然......我尝试了 awk 但我不能(我想要那样)......然后我尝试了这个......同时阅读 col1 col2;做猫文件2.txt | sed -i s/$col1/$col2/g file2.txt ; done
  • 将上述评论添加到您的问题中。

标签: python bash perl awk sed


【解决方案1】:

通过python3。

#!/usr/bin/python3
with open('file1.txt') as f, open('file2.txt') as r:
    d = {}
    m = f.read()
    for line in m.split('\n'):
        try:
            d.update(dict([tuple(line.split())]))
        except:
            pass
    j = r.read()
    for k in d:
        j = j.replace(k, d[k])
    print(j)    

输出:

ID200000000419  ITEM1;ITEM3;ITEM1;ITEM2;ITEM1;ITEM4;ID100000394921
ID200000000938 ITEM5;ITEM2;ITEM3;ITEM1;ITEM7;ID100000363117;ITEM8;ITEM1  
ID200000001036  ITEM1;ITEM2;ITEM3;ITEM9;ID100000398119 

【讨论】:

  • 感谢 Avinash Raj...那么,我如何“折叠”每一行以获得唯一的项目...例如像这样... ID200000000419 ITEM1;ITEM2;ITEM3;ITEM4;ID100000394921
  • 最好把这个作为一个新问题来问,因为我已经回答了你问的问题。
  • 因为你是StackOverflow的新手,建议你阅读this
【解决方案2】:

这会产生折叠的输出:

$ awk 'FNR==NR{a[$1]=$2;next} {c="";delete d;delete e;split($2, b, /;/);for (i in b)c=c";"(a[b[i]]?a[b[i]]:b[i]);split(substr(c,2),d,/;/); for(i in d)e[d[i]]=1; c=""; for (i in e){c=c";"i}; print $1,substr(c,2)}' file1.txt file2.txt
ID200000000419 ID100000394921;ITEM1;ITEM2;ITEM3;ITEM4
ID200000000938 ITEM1;ITEM2;ITEM3;ID100000363117;ITEM5;ITEM7;ITEM8
ID200000001036 ITEM1;ITEM2;ITEM3;ID100000398119;ITEM9

工作原理

  • FNR==NR{a[$1]=$2;next}

    当我们读取第一个文件时,这会创建一个关联数组a,它将第一个字段作为键,将第二个字段作为值。因此,a[ID100000360640] 的值为ITEM1;ITEM2。这是为file1.txt 的所有行完成的。 next 语句会导致所有剩余的命令被跳过并跳转到下一行。

  • c="";delete d;delete e

    如果我们已经到达这里,这意味着我们正在处理第二个文件,file2.txt。这三个命令为新行初始化变量c 和数组de

  • split($2, b, /;/)

    这会将第二个字段拆分为分号并将结果分配给数组b

  • for (i in b)c=c";"(a[b[i]]?a[b[i]]:b[i])

    这将创建未压缩的输出。

  • split(substr(c,2),d,/;/); for(i in d)e[d[i]]=1

    这将创建一个关联数组e,其键是未压缩输出中的每个字段。

  • c=""

    这会在我们添加压缩输出之前再次将c 初始化为一个空行。

  • for (i in e)c=c";"i

    对于数组e 中的每个键,我们将键添加到字符串c。这将创建压缩输出。

  • print $1,substr(c,2)

    这会打印完整的压缩行。

【讨论】:

  • 对于初始未压缩的,使用 gsub awk 'FNR==NR{a[$1]=$2;next}{for(i in a)gsub(i,a[i])... 会更容易
【解决方案3】:

相当短的awk方式

awk 'FNR==NR{a[$1]=$2;next}
     {for(i in a)gsub(i,a[i])
      x=split($2,b,";")
      for(i=1;i<=x;i++)y!~b[i]";"&&y=y?y";"b[i]:b[i];$2=y;y=""}1' file file2

输出

ID200000000419 ITEM1;ITEM3;ITEM2;ITEM4;ID100000394921
ID200000000938 ITEM5;ITEM2;ITEM3;ITEM1;ITEM7;ID100000363117;ITEM8
ID200000001036 ITEM1;ITEM2;ITEM3;ITEM9;ID100000398119

工作原理

FNR==NR{a[$1]=$2;next}

当文件记录号与总记录号匹配时(实际上意味着在读取第一个文件时)将第二个字段分配给使用第一个字段作为键的数组。Next 表示跳过所有进一步的指令并转到下一条记录.

for(i in a)gsub(i,a[i])

现在我们在第二个文件中作为 FNR!=NR 了。
对于数组中的每个元素,gsub 将与键匹配的所有内容与数组中包含的内容进行交换。

x=split($2,b,";")

将第二个字段拆分为由;分隔的数组b。
将数组的大小分配给 x。

for(i=1;i<=x;i++)

从数组的大小循环。

y!~b[i]";"&&  

如果变量 y 已经包含 b 中的拆分值,则不要继续。

y=y?y";"b[i]:b[i] 

如果 y 存在,则将 b[i] 中的值添加到末尾,否则只需将 y 设置为 b[i]。

$2=y;y=""

将第二个字段设置为 y(我们的新字符串)中的值并将 y 重置为空。


资源

https://www.gnu.org/software/gawk/manual/html_node/String-Functions.html

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-01
    • 2022-01-11
    • 2019-12-09
    • 1970-01-01
    • 1970-01-01
    • 2016-01-02
    相关资源
    最近更新 更多