Замена запятых в текстовом файле вертикальной чертой, кроме кавычек

Кажется, это работает:

#!/bin/bash

a=$(parallel --shellquote ::: "$@")
echo "$timeStamp" -  Executing command: sudo /home/editini.sh $a

Протестировано с:

mylog '"I  want  a  2"x4"", said the 3 * captain"' to his friend

Он не будет заключен в кавычки, потому что (, как видно из теста )", может быть частью входных данных. Вместо этого используется \. Функция цитирования оболочки в GNU Parallel тщательно тестируется, поэтому я буду удивлен, если вы сможете дать ей входные данные, которые будут указаны неправильно.

2
08.03.2020, 02:36
7 ответов

Расширение идеи @RudiC:

awk -v RS='"' -v ORS= '{if(NR % 2){gsub(",","|"); print} else print RS $0 RS}' file

 | "Hi, I am Tom"||"16"
"I3"| "Hi, I am Jerry"|"Mouse"|"17"

Это должно работать, когда "цитируется путем удвоения, как в"""Hi, I am Tom"", said the DOG"(так, как это делается в стандартном CSV ), а не когда экранируется обратная косая черта -. За исключением чередующегося текста без кавычек и кавычек, это не зависит от формата файла; это не обязательно должен быть действительный CSV.

С GNU gawk(gawk)это можно упростить до

gawk -v RS='"' -v ORS= 'NR % 2 {gsub(",","|")} {print $0 RT}' file

То же самое сperl:

perl -pe 'BEGIN{$/=q/"/} s/,/|/ if $. % 2' file
2
28.04.2021, 23:21

Если исправить пробелы вокруг запятых, как прокомментировал Эд, то

$ cat text.csv
,"Hi, I am Tom",,"16"
"I3","Hi, I am Jerry","Mouse","17"

$ csvformat -D '|' text.csv
|Hi, I am Tom||16
I3|Hi, I am Jerry|Mouse|17

csvformatявляется частью csvkit :https://csvkit.readthedocs.io/en/1.0.2/scripts/csvformat.html


другие языки, которые вы, возможно, уже установили, поставляются с модулями CSV, такими как ruby ​​:

$ ruby -rcsv -e 'CSV.foreach(ARGV.shift) {|row| puts CSV.generate_line(row, col_sep: "|")}' text.csv
|Hi, I am Tom||16
I3|Hi, I am Jerry|Mouse|17
4
28.04.2021, 23:21

С perl, предполагая, что части в кавычках не содержат новых строк или экранированных кавычек:

perl -pe 's{(".*?")|,}{$1//"|"}ge' < your-file
1
28.04.2021, 23:21

Мы можем подойти к PBM упрощенно. способ построения с нуля регулярных выражений того, как выглядят поля:

Q=\"                    # the quote char 
NQ="[^${Q}]"      # a non-quote char 
nqF="[^${Q},]*"   # a non quoted field
qF="${Q}${NQ}*${Q}"   # a quoted fieldwith no nested quotes 
qFwq= "\(\(${qF}\)\{2\}\)*" # a quoted field with nested quotes 

Позикс-сед:

$ sed -e " 
     H;s/.*//;x;     # to place a marker at the beginning of pattern space 
     :a
        s/\(\n\)\(${qFwq}\),/\2|\1/
        s/\(\n\)\(${qF}\),/\2|\1/
        s/\(\n\)\(${nqF}\),/\2|\1/
     ta
     s/\n//
" file.csv

Использование Perl:

 $ perl -F\" -lane 'local $|;
      $|-- or tr/,/|/ for @F;
      print join q["], @F;
  ' file.csv

Предполагается, что записи csv не переходят на следующую строку.

0
28.04.2021, 23:21

Еще один способ справиться с этим :используя Perl, мы читаем в записи (новую строку, разделенную )и разделяем ее запятой.

Не просто запятая, а "особая" запятая, когда мы стоим и видим четное количество двойных кавычек до конца записи.

Затем установите разделитель элементов массива в вертикальной черте "|":

$ perl \
  -F',(?=(?:(?:[^"]*"){2})*[^"]*$)' \
  -pale '$"=q[|]; $_ = "@F"' file.csv
0
28.04.2021, 23:21

Это распространенная проблема с CSV, см. что такое -самый -самый -надежный -способ -для -эффективного -разбора -csv -с использованием -авк .

Только для ввода, такого как вы показали нам, и использования GNU awk для FPAT после избавления от пробелов вокруг вашего поля -разделительные запятые и установки RS на \r\n, поскольку ваш входной файл имеет окончания строк DOS:

$ cat -v file
,"Hi, I am Tom",,"16"^M
"I3","Hi, I am Jerry","Mouse","17"^M

$ awk -v RS='\r\n' -v FPAT='[^,]*|"[^"]+"' -v OFS='|' '{NF; $1=$1} 1' file
|"Hi, I am Tom"||"16"
"I3"|"Hi, I am Jerry"|"Mouse"|"17"

NF;предназначен для обхода текущей ошибки в gawk 5.0.1:https://lists.gnu.org/archive/html/bug-gawk/2019-11/msg00003.html

Конечно, теперь вы должны спросить себя -, что мне делать, если поле в кавычках содержит |s, экранированные двойные кавычки(""или\")или символы новой строки?

2
28.04.2021, 23:21

Один из подходов состоит в том, чтобы заменить запятые в двойных кавычках на неиспользуемые в тексте символы, заменить все остальные запятые на целевые символы, а затем заменить токены обратно на запятые:

$ awk -F'"' '
        {for (i=2; i<=NF; i+=2) gsub (/,/, "\001", $i)
         gsub (/,/, "|")
         gsub (/\001/, ",")
        }
1
' OFS='"' file
 | "Hi, I am Tom"||"16"
"I3"| "Hi, I am Jerry"|"Mouse"|"17"

Кажется, вы также удалили пробелы в своем образце вывода?

0
28.04.2021, 23:21

Теги

Похожие вопросы