Преобразование CSV в TSV

Есть много способов:

  1. Поместите гостевую машину C в ту же подсеть, что и на гостевых компьютерах A и B.

  2. Используйте мостовое соединение вместо NAT для гостевой машины C. Тогда у вас будет доступ к гостевой машине C от гостей A и B, но гостевой компьютер C не будет имеют доступ к гостям A и B.

  3. Разрешите пересылку на хост-сервере между интерфейсами virbr0 и virbr1. Выполните следующие команды:

    iptables -I FORWARD -i virbr0 -o virbr1 -s 192.168.122.0/24 -d 192.168. 100.0 / 24 -j ACCEPT

    iptables -I FORWARD -i virbr1 -o virbr0 -s 192.168.100.0/24 -d 192.168.122.0/24 -j ACCEPT

    /etc/init.d/iptables save

  4. Просто добавьте вторую виртуальную сетевую карту к машине C и подключите ее к virbr0.

27
19.04.2017, 13:22
14 ответов

Python

Добавьте в файл с именем csv2tab.sh и сделайте его исполняемым

#!/usr/bin/env python
import csv, sys
csv.writer(sys.stdout, dialect='excel-tab').writerows(csv.reader(sys.stdin))

Тестовые прогоны

$ echo 'A,,C,"D,E,F","G",I,"K,L,M",Z' | ./csv2tab.sh                         
A       C   D,E,F   G   I   K,L,M   Z

$ ./csv2tab.sh < data.csv > data.tsv && head data.tsv                                                   
1A      C   D,E,F   G   I   K,L,M   Z
2A      C   D,E,F   G   I   K,L,M   Z
3A      C   D,E,F   G   I   K,L,M   Z
50
27.01.2020, 19:39

Perl

perl -lne '
   my $re = qr/,(?=(?:[^"]*"[^"]*")*(?![^"]*"))/;
   print join "\t", map { s/(?<!\\)"//gr =~ s/\\"/"/gr } split $re;
'

Awk

awk -v Q=\" -v FPAT="([^,]*)|(\"[^\"]+\")" -v OFS="\t" '{
   for (i=1; i<=NF; ++i)
      if ( substr($i, 1, 1) == Q )
         $i = substr($i, 2, length($i) - 2)
   print $1, $2, $3, $4, $5, $6, $7, $8
}'

Результат:

A               C       D,E,F   G       I       K,L,M   Z
8
27.01.2020, 19:39

Одним из вариантов может быть модуль perl Text::CSV, например,

perl -MText::CSV -lne 'BEGIN { $csv = Text::CSV->new() }
  print join "\t", $csv->fields() if $csv->parse($_)
' somefile

для демонстрации

echo 'A,,C,"D,E,F","G",I,"K,L,M",Z' |
  perl -MText::CSV -lne 'BEGIN { $csv = Text::CSV->new() }
  print join "\t", $csv->fields() if $csv->parse($_)
'
A       C   D,E,F   G   I   K,L,M   Z
14
27.01.2020, 19:39

Для развлечения, sed

sed -E 's/("([^"]*)")?,/\2\t/g' file

Если ваш sed не поддерживает -E, попробуйте использовать -r. Если ваш sed не поддерживает \t для литеральной табуляции, попробуйте поставить литеральную табуляцию (во многих оболочках, ctrl-v tab) или в Bash используйте $'. ...' в стиле C (в этом случае обратный слеш в \2 нужно удвоить). Если вы хотите сохранить кавычки, используйте \1 вместо \2 (в этом случае внутренняя пара круглых скобок бесполезна и может быть удалена).

Здесь не делается попытка обработать двойные кавычки внутри двойных кавычек; некоторые диалекты CSV поддерживают это, удваивая цитируемую двойную кавычку (sic).

22
27.01.2020, 19:39

Использование csvkit утилиты (Python), например:

$ csvformat -T in.csv > out.txt

Выполняет потоковую передачу с правильным цитированием и экранированием CSV и TSV

Это в apt и других менеджерах пакетов

29
27.01.2020, 19:39

Решение для термоядерной мухобойки должно использовать libreoffice. Хотя https://ask.libreoffice.org/en/question/19042/is-is-possible-to-convert-comma-separated-value-csv-to-tab-separated-value-tsv-via-headless-mode/ предполагает, что это невозможно, но он ошибается (или просто устарел?) и следующая команда работает на моей 5.3. :

loffice "-env:UserInstallation=file:///tmp/LibO_Conversion" --convert-to csv: "Text - txt - csv (StarCalc)":9,34,UTF8 --headless --outdir some/path --infilter='csv:44,34,UTF8' *. csv

аргумент env можно пропустить, но так документы не появятся в вашем недавнем документе.

6
27.01.2020, 19:39

Vim

Ради интереса подстановки регулярных выражений можно выполнять в Vim. Вот потенциальное четырехстрочное решение, адаптированное из: https://stackoverflow.com/questions/33332871/remove-all-commas-between-quotes-with-a-vim-regex

  1. Запятые между кавычками стоят первыми изменено на подчеркивание (или другой отсутствующий символ),
  2. Все остальные запятые заменены табуляцией,
  3. Подчеркивание внутри кавычек заменено на запятую,
  4. Кавычки удалены.

     :%s/".\{-}"/\=substitute(submatch(0), ',', '_' , 'g')/g
    :%s/,/\t/g
    :%s/_/,/г
    :%s/"//г
     

Чтобы написать решение, четыре строки выше (без двоеточия в начале) можно сохранить в файл, например. to_tsv.vim. Откройте каждый CSV для редактирования с помощью Vim и source сценария to_tsv.vim в командной строке Vim (адаптировано из https ://stackoverflow.com/questions/3374179/run-vim-script-from-vim-commandline/8806874#8806874):

    :source /path/to/vim/filename/to_tsv.vim
2
27.01.2020, 19:39

Я создал конвертер CSV в TSV с открытым -исходным кодом, который обрабатывает описанные преобразования. Это довольно быстро, возможно, стоит взглянуть, если -понадобится конвертировать большие файлы CSV. Инструмент является частью набора утилит eBay TSV(документации csv2tsv здесь). Для описанного входа достаточно параметров по умолчанию:

$ csv2tsv file.csv > file.tsv

При преобразовании CSV в TSV следует учитывать обработку разделителей полей и записей (, запятой и новой строки )в данных. CSV использует escape-синтаксис. Если цель состоит в том, чтобы использовать выходные данные с инструментами Unix, такими как cut, awkи т. д., выходные данные должны быть свободны от escape-символов. Большинство перечисленных здесь решений создают escape-последовательности в стиле CSV, когда в данных присутствуют разделители. csv2tsvотличается от других решений тем, что производит TSV без побегов. Подробности смотрите в документации.

Чтобы увидеть, что делает конкретное решение, преобразуйте CSV-файл, содержащий запятые, символы табуляции, кавычки и символы новой строки в данных. Например:

$ echo $'Line,Field1,Field2\n1,"Comma: |,|","Quote: |""|"\n"2","TAB: |\t|","Newline: |\n|"' | <conversion-script-or-command>

Решения, генерирующие escape-последовательности, заключают в двойные кавычки поля, содержащие кавычки, символы новой строки или символы табуляции.

7
27.01.2020, 19:39

Нижеследующее является просто исправлением к ответу от @tripleeeтак что он удаляет любые кавычки из последнего поля так же, как и для всех других полей.

Чтобы показать, что исправлено, ниже приведен ответ tripee , а также небольшая модификация данных примера OP с добавлением кавычек вокруг последнего поля « Z ».

echo 'A,,C,"D,E,F","G",I,"K,L,M","Z"' |  sed -r -e 's/("([^"]*)")?,/\2\t/g'
A       C   D,E,F   G   I   K,L,M   "Z"

Вы можете видеть, что ' Z ' заключено в кавычки. Это отличается от того, как обрабатываются внутренние поля. Например, «G » не имеет кавычек.

Следующая команда использует вторую замену для очистки последнего столбца:

echo 'A,,C,"D,E,F","G",I,"K,L,M","Z"' |  sed -r -e 's/("([^"]*)")?,/\2\t/g' \
                                                -e 's/\t"([^"]*)"$/\t\1/'
A       C   D,E,F   G   I   K,L,M   Z
0
27.01.2020, 19:39

Использованиеmlrпочти лаконично, но для отключения заголовков требуются длинные параметры:

mlr --c2t --implicit-csv-header --headerless-csv-output cat file.csv 

Выход:

A       C   D,E,F   G   I   K,L,M   Z
5
27.01.2020, 19:39

С perl, при условии, что поля csv не имеют встроенных "или новых строк или вкладок:

perl -pe 's{"(.*?)"|,}{$1//"\t"}ge'
2
27.01.2020, 19:39

sedрешение (с требованиями ):Следует также обрабатывать буквальные двойные -кавычки, которые представлены парой двойных -кавычек в поле CSV.

Сначала измените все такие литералы двойных -кавычек на стенд -во флаге; затем удалите все разделители полей (одиночные двойные -кавычки )и преобразуйте разделители полей (запятые )в табуляции; затем измените позицию -во флагах на двойные -кавычки.

Здесь я использую\v(вертикальную вкладку )в качестве подставки -во флаге для встроенных двойных -кавычек:

sed -r 's/""/\v/g; s/("([^"]+)")?,/\2\t/g; s/\v/"/g\'

Это решение основано на ваших данных CSV , не содержащих вертикальных -символов табуляции , а также на пустых полях CSV , не в кавычках.

1
02.05.2020, 22:38

Послеgem install csv:

$ time </tmp/a ruby -rcsv -e'puts CSV.parse($<).map{|x|x*"\t"}'>/dev/null
0.307
$ time ruby -rcsv -e'CSV.foreach("/tmp/a"){|x|puts x*"\t"}'>/dev/null
0.367
$ time </tmp/a ruby -rcsv -ne'puts CSV.parse($_)*"\t"'>/dev/null
2.456
1
21.07.2020, 07:02

Разбор контекстно-зависимых форматов действительно постоянно раздражает, особенно. когда цитирование csv непоследовательно и даже нерегулярно. Вот простой awk, который каждый должен иметь возможность использовать/пересматривать. Он не такой умный, как краткий awk, но, возможно, хороший строительный блок, который легко настроить. Да, я знаю, что его можно было бы сократить, но мне нравится, чтобы многоразовый awk имел некоторую слабину.

{
  mark[++nmark] = 0
  thislength = length($0)
  for (i=1; i<=thislength; i++) {
    thisc = substr($0,i,1)
    if (thisc == "\\") { i++; continue } # skip \x for any x
    if (thisc == "\"") qflag = 1-qflag
    if (thisc == "," && !qflag) mark[++nmark] = i
  }
  mark[++nmark] = thislength+1
  for (i=1; i<nmark; i++) {
    thiso = outfield[++noutfield] = substr($0, mark[i]+1, mark[i+1]-mark[i]-1)
    if (thiso ~ /^".*"$/) {
      sub(/"$/,"",outfield[noutfield])
      sub(/^"/,"",outfield[noutfield])
    }
  }
  for (i=1; i<noutfield; i++) printf "%s", outfield[i]"\t"
  print outfield[noutfield]
}
0
29.09.2020, 04:16

Теги

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