我们将数据从数据库提取到平面文件,使用管道作为列分隔符,使用双引号作为文本分隔符。
数据文件看起来像这样:
"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
如果您想编辑输入文件,请使用)
该脚本执行以下步骤:
- 查找 |"{...}"|、(行首)"{...}"| 或 |"{...}"(行尾)内的所有内容,忽略外部的空格的文本。将外部位替换为
~~
(我使用了已知不在文本内部的内容) - 将所有剩余的引号替换为双引号
- 将所有内部
~~{...}~~
序列替换为~~"{...}"~~
- 将所有
~~~~
序列(全部是内部序列)替换为|
- 删除所有剩余的
~~
序列(位于行的开头和结尾)
运行每个步骤并给出以下测试文本:
"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"