在两个文件中查找公共行,并将第一个文件的下一行替换为另一个文件的下一行

时间:2014-02-05 01:47:33

标签: perl bash sed awk grep

我想在两个文件中找到公共行,并用第二个文件的下一行替换第一个文件的下一行。 Sed,awk,Perl,Bash,欢迎任何解决方案。

比较不区分大小写,并且可能会多次出现同一行。

文件1:

         hgacdavd
sndm,ACNMSDC
msgid "Rome"
msgstr ""
kgcksdcgfkdsb
msgid ""
hsdvchgsdvc
msgstr ""
dhshfjksdfhmd
msgid "Vidya"
msgstr ""
sdjhcbnd
dcndnv
cfnkdndvrknvkf
dfkvrnkdfnk
snfvrkng
msgid "Rome"
msgstr ""
wdbhkjbcfj
#dmcdmf
f,nvdf,

fvnfnvk
vfmf,mv
vfn

msgid "vid"
msgstr ""
dmcbdmbcvmfbvmkhsdk

文件2:

  dfhkvgjbfrvkf  
msgid "Rome"
msgstr "new bie"
sdbsjbcdcbwoido
fjcdcvnm
msgid "vidya"
msgstr "expert"
dvnjfkdvhnkfvnknsbdjh


msgid "vid"
msgstr "newton"
dfenfjdbrfjbvlfnvl
dcnkncvkdfvknfv
fcndkbvknfkv
vfdnkvnfknbvkfn

稍后,文件1应为:

          hgacdavd
sndm,ACNMSDC
msgid "Rome"
msgstr "new bie"
kgcksdcgfkdsb
msgid ""
hsdvchgsdvc
msgstr ""
dhshfjksdfhmd
msgid "Vidya"
msgstr "expert"
sdjhcbnd
dcndnv
cfnkdndvrknvkf
dfkvrnkdfnk
snfvrkng
msgid "Rome"
msgstr "new bie"
wdbhkjbcfj
#dmcdmf
f,nvdf,

fvnfnvk
vfmf,mv
vfn

msgid "vid"
msgstr "newton"
dmcbdmbcvmfbvmkhsdk

3 个答案:

答案 0 :(得分:1)

问题的第1版:

在此版本的问题中,msgid和msgstr的行成对出现,并与其他行分隔为空行。对于这种情况,这是一个(长)行解决方案:

$ awk -F'"' 'BEGIN{RS="\n\n";OFS=""} NR==FNR {c[tolower($2)]=$4; next} {print $1,"\"",$2,"\"",$3,"\"",c[tolower($2)],"\"\n"}' file2 file1
msgid "Rome"
msgstr "new bie"

msgid "Vidya"
msgstr "expert"

msgid "Rome"
msgstr "new bie"

msgid "vid"
msgstr "newton"

更多信息:以下版本使用新信息更新file1:

$ awk -F'"' 'BEGIN{RS="\n\n";OFS=""} NR==FNR {c[tolower($2)]=$4; next} {print $1,"\"",$2,"\"",$3,"\"",c[tolower($2)],"\"\n"}' file2 file1 >tmp && mv tmp file1

工作原理:让我们把它分解成几部分。第一部分是设置:

$ awk -F'"' 'BEGIN{RS="\n\n";OFS=""}

要理解上述内容,需要知道awk将文件分解为“记录”,然后将记录分解为“字段”。上面说过,每当出现一个空白行(连续两个换行符)时,请将后面的内容视为新的“记录”。换句话说,记录分隔符是两个换行符:RS="\n\n"。它还说应该根据双引号的外观将记录分解为字段:-F'"'。最后,它说,在打印我们的输出时,不要在我们拥有的东西上添加任何额外的空间。换句话说,输出字段分隔符是空字符串:OFS=""

下一部分是:

... NR==FNR {c[tolower($2)]=$4; next} ...

这表示,在读取给定的第一个文件名(file2)时,创建一个名为c的关联数组(如字典)。数组的键是msgid。值是msgstr。因此,c[rome]=new bie。我们将tolower应用于msgid,以便所有密钥始终为小写。 next命令意味着。

上面的NR==FNR部分可能看起来很模糊。要理解它,需要知道awk计算它看到的记录数并将该值分配给NR。它还会计算它从当前正在读取的文件中看到的记录数,并将其分配给FNR。因此,当我们读取第一个文件时,两者是相等的:NR==FNR。当awk开始阅读第二个文件时,NR>FNR将跳过代码块。

最后一部分是:

... {print $1,"\"",$2,"\"",$3,"\"",c[tolower($2)],"\"\n"}' file2 file1

当我们开始阅读第二个文件(file1)并且只包含一个print语句时,将执行此部分。它打印msgid行,包括msgid:$1,"\"",$2,"\""周围的引号。并且,它还打印出msgstr,在我们的关联数组c中查找msgstr的值并在其周围加上引号,并在结尾添加换行符:"\"",$3,"\"",c[tolower($2)],"\"\n"

问题的第2版:

在此版本中,msgid和msgstr行不一定相邻。因此,每次遇到msgid行时,我们都会将其值保存到变量id。在浏览file2时,我们查找msgstr行并将其值存储在关联数组c中。然后,在处理file1时,我们在msgstr行中替换c[id]

awk  -F'"' 'NR==FNR && $1=="msgid " {id=tolower($2)} NR==FNR && $1=="msgstr " {c[id]=$2} NR==FNR {next} $1=="msgid " {id=tolower($2)} {if ($1=="msgstr ") print "msgstr \"" c[id] "\""; else print $0}' file2 file1 >tmp && mv tmp file1

答案 1 :(得分:0)

这可能适合你(GNU sed):

sed -r '/msgid/{$!N;s|(.*)\n(.*)|/\1/I{n;s/.*/\2/}|}' file2 | sed -rf - file1

file2转换为针对file1运行的sed脚本。

该脚本将以msgid开头的行和以下行转换为与msgid匹配的命令,然后打印该行并用脚本文件中的第二行内容替换下一行。

答案 2 :(得分:0)

  1. 你可以使用我用php写的这个应用程序。它解决了同样的问题。
  2. 输入:需要2个文件:
    • 文件1:喜欢第二个文件的字典
    • 文件2:喜欢获取对的目的地" msgid / msgstr"来自文件1,如果它存在。
  3. 输出:以及您提到的
  4. 在这里查看我的源代码! http://localhost/merge_two_po_files/web 通过以下链接连接到主页:... / merge_two_po_files / web(例如:JSFiddle Example