Substitua apenas aspas duplas no arquivo de dados

0

Nós extraímos os dados de um banco de dados para um arquivo simples, usamos um canal para delimitador de coluna e aspas duplas para o delimitador de texto.

O arquivo de dados parece com algo assim:

"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"

Que comando / script pode encontrar todos os casos em que os dados (sem incluir o delimitador de texto) podem ser escapados com uma segunda aspa dupla?

O resultado final deve ser assim:

"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"
    
por Ora Clesismo 04.04.2018 / 03:54

4 respostas

0

Isso é um pouco complicado apenas com expressões regulares, mas isso pode ser feito em várias etapas. Aqui está o script perl que eu usei para isso (sed não pode ser usado porque eu usei lookaheads):

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

(use perl -pi -e se você quiser editar o arquivo de entrada)

O script executa as seguintes etapas:

  1. Procure por tudo o que estiver dentro de | "{...}" |, (início da linha) "{...}" | ou | "{...}" (fim da linha), ignorando espaços fora do texto. Substitua os bits externos por ~~ (usei algo que não é conhecido dentro do texto)
  2. Substitua todas as aspas restantes por outras duplicadas
  3. Substitua todas as seqüências ~~{...}~~ internas por ~~"{...}"~~
  4. Substitua todas as seqüências de ~~~~ (que serão todas internas) para |
  5. Remove todas as sequências ~~ restantes (que estarão no início e no final das linhas)

Execução de cada etapa, de acordo com o seguinte texto de teste:

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

Recebemos a seguinte saída após cada etapa:

$ perl -pe 's/(?:(?:\||^)[ ]*"(.*?)\"[ ]*(?=\||$))/~~~~/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/(?:(?:\||^)[ ]*"(.*?)\"[ ]*(?=\||$))/~~~~/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/(?:(?:\||^)[ ]*"(.*?)\"[ ]*(?=\||$))/~~~~/gm;s/"/""/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/(?:(?:\||^)[ ]*"(.*?)\"[ ]*(?=\||$))/~~~~/gm;s/"/""/g;s/~~(.*?)~~/~~""~~/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/(?:(?:\||^)[ ]*"(.*?)\"[ ]*(?=\||$))/~~~~/gm;s/"/""/g;s/~~(.*?)~~/~~""~~/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"""
    
por 04.04.2018 / 08:49
0

Suas aspas duplas não são aspas duplas reais ("vs").
Com aspas duplas reais ", Você pode tentar este sed (assumir que não há @ em seus dados)

sed 's/" | "/@/g;s/"/""/g;s/^"//;s/"$//;s/@/" | "/g' infile
    
por 04.04.2018 / 17:49
0

Bahrat deste fórum postou uma resposta que estava muito perto de resolver o problema, de alguma forma, foi removido deste post (código abaixo). O único problema é que não pode lidar com um tubo | dentro de uma string (ou seja, "25" | "para concatenar dados a | deve ser usado" | "addendum 1" | 20 | "last entry") Ele deveria postar hoje, mas o segmento foi excluído ??

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

Entrada -

 "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" 

CMD:

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

Saída -

 "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" 
    
por 04.04.2018 / 09:49