仅替换数据文件中的某些双引号

仅替换数据文件中的某些双引号

我们将数据从数据库提取到平面文件,使用管道作为列分隔符,使用双引号作为文本分隔符。

数据文件看起来像这样:

"164829" | "collection 1" | "wood plank 2" x 4" long" | "23.5" 
"2017"|"S"|"221318"|"WE"|"20170118"|"Someones name"|"20170215"|"1785"|"009"|"20170215"|"182339"|"99536"|"00090"|"LOCAL00"|"930N"|"2017"|"6100"|"0000880"|1.000|0.000|"EA"|" "|" "|" "|" "|"005"|"00000000"|" "|" "|"1785"|"50228"|"R"|"2017"|"NMT CAUTION| 5" X 3" NAT ON BLK"|" "|" "|"USD"|"7444"|" "|"000"|"COIN"|"04"|35.00|"00"

什么命令/脚本可以找到数据(不包括文本分隔符)可以用第二个双引号转义的每种情况?

最终结果应该是这样的:

"164829" | "collection 1" | "wood plank 2"" x 4"" long" | "23.5"
"2017"|"S"|"221318"|"WE"|"20170118"|"Someones name"|"20170215"|"1785"|"009"|"20170215"|"182339"|"99536"|"00090"|"LOCAL00"|"930N"|"2017"|"6100"|"0000880"|1.000|0.000|"EA"|" "|" "|" "|" "|"005"|"00000000"|" "|" "|"1785"|"50228"|"R"|"2017"|"NMT CAUTION| 5"" X 3"" NAT ON BLK"|" "|" "|"USD"|"7444"|" "|"000"|"COIN"|"04"|35.00|"00"

答案1

仅使用正则表达式这有点棘手,但可以通过几个步骤完成。这是我为此使用的 perl 脚本(无法使用 sed,因为我使用了前瞻):

perl -pe 's/(?:(?:\||^)[ ]*"(.*?)\"[ ]*(?=\||$))/~~\1~~/gm;s/"/""/g;s/~~(.*?)~~/~~"\1"~~/g;s/~~~~/|/g;s/~~//g' inputfile.txt

perl -pi -e如果您想编辑输入文件,请使用)

该脚本执行以下步骤:

  1. 查找 |"{...}"|、(行首)"{...}"| 或 |"{...}"(行尾)内的所有内容,忽略外部的空格的文本。将外部位替换为~~(我使用了已知不在文本内部的内容)
  2. 将所有剩余的引号替换为双引号
  3. 将所有内部~~{...}~~序列替换为~~"{...}"~~
  4. 将所有~~~~序列(全部是内部序列)替换为|
  5. 删除所有剩余的~~序列(位于行的开头和结尾)

运行每个步骤并给出以下测试文本:

"164829" | "collection 1" | "wood plank 2" x 4" long" | "23.5"
"939485"|"collect "name""|"more items with | " and ""|"294.5""

每一步之后我们都会得到以下输出:

$ perl -pe 's/(?:(?:\||^)[ ]*"(.*?)\"[ ]*(?=\||$))/~~\1~~/gm;' testinput.txt                       
~~164829~~~~collection 1~~~~wood plank 2" x 4" long~~~~23.5~~
~~939485~~~~collect "name"~~~~more items with | " and "~~~~294.5"~~

$ perl -pe 's/(?:(?:\||^)[ ]*"(.*?)\"[ ]*(?=\||$))/~~\1~~/gm;s/"/""/g;' testinput.txt
~~164829~~~~collection 1~~~~wood plank 2"" x 4"" long~~~~23.5~~
~~939485~~~~collect ""name""~~~~more items with | "" and ""~~~~294.5""~~

$ perl -pe 's/(?:(?:\||^)[ ]*"(.*?)\"[ ]*(?=\||$))/~~\1~~/gm;s/"/""/g;s/~~(.*?)~~/~~"\1"~~/g;' testinput.txt
~~"164829"~~~~"collection 1"~~~~"wood plank 2"" x 4"" long"~~~~"23.5"~~
~~"939485"~~~~"collect ""name"""~~~~"more items with | "" and """~~~~"294.5"""~~

$ perl -pe 's/(?:(?:\||^)[ ]*"(.*?)\"[ ]*(?=\||$))/~~\1~~/gm;s/"/""/g;s/~~(.*?)~~/~~"\1"~~/g;s/~~~~/|/g;' testinput.txt
~~"164829"|"collection 1"|"wood plank 2"" x 4"" long"|"23.5"~~
~~"939485"|"collect ""name"""|"more items with | "" and """|"294.5"""~~

$ perl -pe 's/(?:(?:\||^)[ ]*"(.*?)\"[ ]*(?=\||$))/~~\1~~/gm;s/"/""/g;s/~~(.*?)~~/~~"\1"~~/g;s/~~~~/|/g;s/~~//g' testpipe.txt
"164829"|"collection 1"|"wood plank 2"" x 4"" long"|"23.5"
"939485"|"collect ""name"""|"more items with | "" and """|"294.5"""

答案2

你的双引号不是真正的双引号(“ vs ")。
使用真正的双引号 " ,你可以尝试这个 sed (假设你的数据中没有@)

sed 's/" | "/@/g;s/"/""/g;s/^"//;s/"$//;s/@/" | "/g' infile

答案3

这个论坛的 Bahrat 发布了一个非常接近解决问题的答案,但不知何故它被从这篇文章中删除了(代码如下)。唯一的问题是它无法处理管道 |在一个字符串中(即“25”|“必须使用一个|连接数据”|“附录1”|20|“最后一个条目”)他本来应该今天发帖,但该线程被删除了?

awk -v FS='|' -v OFS='|' '{for(i=1;i<=NF;i++){gsub(/"/,"\"\"",$i);sub(/"/,"",$i);sub(/"[^"]*$/,"",$i)}print}' myfile > myfile3

答案4

输入 -

“2017”|“S”|“221318”|“我们”|“20170118”|“某人的名字”|“20170215”|“1785”|“009”|“20170215”|“182339”|“99536”|“ 00090"|"本地00"|"930N"|"2017"|"6100"|"0000880"|1.000|0.000|"EA"|""|""|""|""|"005"|"00000000" |" "|" "|"1785"|"50228"|"R"|"2017"|"NMT 注意| 5" X 3" NAT ON BLK"|" "|" "|"USD"|"7444" |" "|"000"|"硬币"|"04"|35.00|"00"

命令:

  awk -v RS='[[:blank:]]*[[:blank:]]*[|][[:blank:]]*|[[:blank:]]*[\n][[:blank:]]*' '{ if ($0 !~ /(^"([^"]|"")*"$)/) { gsub(/\"/,"\"\"");sub(/^"/,"");sub(/"$/,"") } printf "%s%s", $0, RT}' file.txt

输出 -

“2017”|“S”|“221318”|“我们”|“20170118”|“某人的名字”|“20170215”|“1785”|“009”|“20170215”|“182339”|“99536”|“ 00090"|"本地00"|"930N"|"2017"|"6100"|"0000880"|1.000|0.000|"EA"|""|""|""|""|"005"|"00000000" |" "|" "|"1785"|"50228"|"R"|"2017"|"NMT 注意| 5"" X 3"" NAT ON BLK"|" "|" "|"USD"|" 7444"|""|"000"|"硬币"|"04"|35.00|"00"

相关内容