【问题标题】:merge 2 files - column alternatively from file1 and file2合并 2 个文件 - 列从 file1 和 file2
【发布时间】:2014-11-15 08:48:26
【问题描述】:

f1.txt

A, 77, 1, 2.0,  !P ,  F, - ,     
B,   77 , 4, 5, P,  P, - ,     
C, 88, 6,  7,   F,   P, -,

f2.txt

A, 77, 1, 2, P, F,  P,    
B, 77, 4, 5, F, P,  P,    
C, 88, 6, 7, F, P,  P,    
D, 99, 8, 9, P, P,  F, 

想要的输出

A, 77, 1, 2, P, not P(*), F, F, P, -,    
B, 77, 4, 5, F, P(*), P, P, P, -,    
C, 88, 6, 7, F, F, P, P, F, -,    
D, 99, 8, 9, P, -, P, -, P, -,

基本上,匹配两个文件中的 4 列,然后合并每个文件中的替代列:匹配 4 列,然后是 f2_column5,然后是 f1_column5,如果不同,则添加 (*)(如果不可用,则 "-"

  1. 列数> 1000,f1.txt 的# 列和f2.txt 的# 列不一样
  2. f1.txtf2.txt 中的行数可以> 1000 并且不相同
  3. (如果可能的话,代码是否可以扩展为超过2个文件输入(f1,f2);例如,f3.txt是

f3.txt : B, 77 , 4, 5, P, P, - , 和所需的输出(对于 3 个输入文件 - f1.txt、f2.txt、f3.txt)

想要的输出

A, 77, 1, 2, P, not P(*), -, -, F, F, P, -, -,    
B, 77, 4, 5, F, P(*),  P(*), P, P, P, P, -, -,    
C, 88, 6, 7, F, F, -,        P, P, -, F, -, -,   
D, 99, 8, 9, P, -, -,        P, -, -, P, -, -,

             |               |        |
            f2.5th          f2.6th   f2.7th

================================================ =========================================

如果列数小于10,我可以使用下面的

awk 'FNR==NR {a[NR]=$1;
b[NR]=$2;
c[NR]=$3;
d[NR]=$4;
e[NR]=$5;
f[NR]=$6;
g[NR]=$7;
next}
{print $1,$2,$3,$4,$5,
( e[FNR]!="" ? e[FNR] : "-" ),
$6,
( f[FNR]!="" ? f[FNR] : "-" ),
$7,
( g[FNR]!="" ? g[FNR] : "-" ) }' f1.txt f2.txt

但这我假设f1.txtf2.txt 的4 列,不是我想要的;我想看看它是否匹配。我不知道如何处理大量列以及检查是否有 (*)。

【问题讨论】:

  • 如果字符之间有两个空格,是否算作一列不可用?每列之间是否正好有一个空格?
  • 空格的个数不固定,空格可以是字段分隔符或者文件可以有“,”作为字段分隔符(不过还是有空格的,即前导空格也要去掉as) ...另外,有多个文件(如 f1.txt),代码可以用于多个文件吗?我想问的另一件事是数字是否是浮点数,例如 8.2 那么如何将字符串“8.2”转换为数字“8.2”(我知道使用 int 将字符串转换为整数,但我没有看到任何字符串浮点数,反之亦然)。谢谢。
  • 如果您有其他详细信息要添加到您的问题中,您应该对其进行编辑,以尽可能清楚地说明您想要做什么。
  • 我确实详细更新了问题(输入文件和所需的输出)。谢谢。

标签: awk sed excel-2007


【解决方案1】:

我认为您的问题可能过于宽泛,但希望这是一个起点。目前,输出并不完全正确,但调整代码以满足您的需求应该不会太难。

对于这么长的脚本,我觉得还是写个awk脚本比较好。代码可以保存到文件并使用awk -f script.awk f1 f2运行:

BEGIN { FS = "[[:space:]]*,[[:space:]]*" }
NR == FNR {
    k = $1 SUBSEP int($2) SUBSEP int($3) SUBSEP int($4)
    seen[k]=NF
    for (i=5; i<=NF; ++i) { 
        a[k,i] = $i 
    }
    next
}
{
    k = $1 SUBSEP int($2) SUBSEP int($3) SUBSEP int($4)
    seen[k]=seen[k]>NF?seen[k]:NF
    for (i=5; i<=NF; ++i) { 
        b[k,i] = $i
    }
}
END {
    for (i in seen) {
        n = split(i, c, SUBSEP)
        for (j=1; j<=n; ++j)
            printf "%s, ", c[j]
        for (k=5; k<seen[i]; ++k)
            printf "%s, %s,%s", b[i,k], a[i,k], (k<seen[i]-1?OFS:ORS)            
    }
}

解释:

  • 将字段分隔符设置为逗号,由任意数量的空白字符包围
  • NR==FNR(在第一个文件中)时:
    • 将数组键k 设置为由特殊变量SUBSEP 分隔的前四个字段组成的字符串。使用int() 将数字转换为整数值
    • 数组seen 跟踪到目前为止的键。数组中的值设置为字段数,后面循环使用
    • 循环遍历从 5 开始的所有字段,并设置数组 a 中字段的值
    • 跳至next 记录,忽略其余说明
  • 在第二个文件中:
    • 以同样的方式再次设置密钥k
    • 如果第二个文件包含更多的字段,请更新seen 中的值(我不确定文件中的每一行是否具有相同数量的键?)
    • 将文件中的每个字段保存到数组b
  • 处理完所有记录后:
    • 循环遍历seen 中的键
    • 在我们之前使用的分隔符 SUBSEP 上拆分键
    • split 返回数组中的元素个数 c
    • 循环遍历每个元素并打印值
    • 从 5 循环到最大字段数,打印来自 ab 的备用值

需要做的事情:

  • 检查b[i,k]a[i,k]是否不同,可以添加(*)
  • ! 替换为not 这两件事都只是向END 块添加额外逻辑的情况。

【讨论】:

  • 谢谢。请解释一下好吗?
  • 当然,希望对您有所帮助。
  • 它解决了你的问题吗,@maria ?由于您是新来的,如果您的问题已经解决,请不要忘记将答案标记为已接受。您可以单击答案旁边的复选标记将其从空心切换为绿色。如有任何疑问,请参阅Help Center > Asking
  • 感谢您的解释。我今天会尝试并更新并标记答案。
  • 谢谢。但是,我不知道如何做接下来的事情(添加 (*) if b[i,k] 和 a[i,k] 并替换!
猜你喜欢
  • 2020-06-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-01
  • 2016-02-09
  • 2021-02-20
  • 1970-01-01
  • 2016-02-20
  • 2021-08-17
相关资源
最近更新 更多