В большом (> 1 ГБ) файле CSV у меня есть что-то вроде
"34432", "name", "0", "very long description"
, но вместо этого я хотел бы иметь
34432, "name", 0, "very long description".
, на который я смотрел sed
но эта задача выходит за рамки моей компетенции.
Какой-нибудь совет, как этого добиться?
Используя жемчуг:
perl -ne 's/"(\d+)"/$1/g; print' file.csv > new_file.txt
Вся работа сделана s/"(\d+)"/$1/g
, где
s/patternA/patternB/
используется для замены patternA
patternB
\d+
окруженный двойными кавычками. \d+
) используются, чтобы получить цифру (цифры) и снова использовать их как заменяющий шаблон со специальной переменной жемчуга $1
. GNU sed regex, который должен работать на этот случай,
sed -r 's/"([0-9]+)"/\1/g'
Для чистого sed, необходимо выйти из группирующихся круглых скобок и +
модификатор
sed 's/"\([0-9]\+\)"/\1/g'
, можно выполнить замену, оперативную с некоторыми версиями sed, например,
sed -ri 's/"([0-9]+)"/\1/g' file.csv
Вы могли также использовать класс [[:digit:]]
POSIX вместо диапазона символов [0-9]
Ваше описание проблемы не очень конкретно. Я предполагаю, что Вы хотите удалить двойные кавычки вокруг 1-х и 3-х полей только. Если так, любой из них должен работать:
sed
sed -r 's/^"([^"]+)"(\s*,\s*[^,]+)\s*,\s*"([^"]+)"/\1\2, \3/' file.csv
-r
включает расширенные регулярные выражения, позволяя нам использовать круглые скобки для получения шаблонов, не будучи должен выйти из них. Так, мы соответствуем кавычке в начале строки (^"
), сопровождаемый одним или несколькими несимволами кавычки ([^"]+
), затем заключительная кавычка, сопровождаемая 0 или больше пробелами, запятой, затем 0 или больше пробелов снова (\s*,\s*
), затем фрагмент незапятых до следующей запятой (это определяет 2-е поле). Наконец, мы ищем 0 или больше пробелов, запятую и замену это с 1-м полученным шаблоном (\1
), затем 2-е (\2
), запятая, пространство и 3-е.
Perl
perl -pe 's/^"([^"]+)"(\s*,\s*[^,]+)\s*,\s*"([^"]+)"/$1$2, $3/; ' file.csv
-p
средства печатают каждую строку после применения сценария, мимо которого проходят -e
. Сам сценарий является в основном тем же regex как в sed
выше. Только здесь, полученные шаблоны $1
.
awk
awk -F, -v OFS="," '{gsub("\"","",$1)0gsub("\"","",$3);}1;' file.csv
-F
устанавливает разделителя полей на ,
. OFS
выходной разделитель полей, который также установлен на ,
так, чтобы строки были распечатаны правильно. gsub
делает замену, заменяя все "
ни с чем, так как мы выполняем его на 1-м ($1
) и 3-и поля ($3
) это только удалит кавычки из тех полей. 1;
справедливо awk
сокращение от "печати строка".
Маленький сценарий ниже параметра командной строки файла взятий, выполняет итерации по каждой строке в том файле и разделяет каждую строку на список использования объектов ,
как разделитель. Каждая запись затем закрывается кавычки и проверена на то, что она была числовой строкой; если строка является числовой, это оставляют неупомянутым.
#!/usr/bin/env python
import sys
with open(sys.argv[1]) as fp:
for line in fp:
new_vals = []
vals = line.strip().split(',')
for val in vals:
val = val.strip().rstrip().replace('"','')
if not val.isdigit():
val = '"' + val + '"'
new_vals.append(val)
print(",".join(new_vals))
Тестовый прогон:
$ cat input.txt
"34432", "name", "0", "very long description"
"1234", "othe name" , "42", "another description"
$ ./unquote_integers.py input.txt
34432,"name",0,"very long description"
1234,"othe name",42,"another description"
Дополнительные примечания:
Попросили в комментариях, почему сценарий удаляет двойные кавычки вокруг каждого объекта прежде, чем оценить, если объект является числовой строкой или нет. Главная причина для этого состоит в том, потому что включение двойных кавычек сделает объект как "123"
оцените к False
, т.е. не числовой. Эффективно, мы должны оценить то, что в двойных кавычках так или иначе. Теперь, существует альтернативный способ приблизиться к этому через взятие части списка каждого значения. Однако это не немного лучше, чем использование .replace()
с начала. Это действительно делает код короче, но по крайней мере в этой краткости случая сценария не важно - наша цель состоит в том, чтобы заставить код работать, не гольф кода это.
Вот альтернативное решение с частями списка:
#!/usr/bin/env python
import sys
with open(sys.argv[1]) as fp:
for line in fp:
new_vals = []
vals = line.strip().split(',')
for val in vals:
val = val.strip().rstrip() #remove extra spaces
val = val.replace('"','') if val[1:-1].isdigit() else val
new_vals.append(val)
print(",".join(new_vals))
for i in "$1"/*
циклы согласно значению IFS
, и значение по умолчанию IFS
содержит пробел, поэтому если имя файла будет содержать пробел, [то 113] будет разделен на несколько частей. Например, если "$PWD"
test folder
, $i
должен быть test
и folder
. Но на самом деле, дело обстоит не так. сценарий работает очень хорошо. Почему? Я пропускал что-нибудь?
– Searene
28 September 2015 в 02:17