Удалить кавычки вокруг целых чисел в CSV-файле

В большом (> 1 ГБ) файле CSV у меня есть что-то вроде

"34432", "name", "0", "very long description"

, но вместо этого я хотел бы иметь

34432, "name", 0, "very long description".

, на который я смотрел sed но эта задача выходит за рамки моей компетенции.

Какой-нибудь совет, как этого добиться?

4
задан 12 March 2015 в 22:44

4 ответа

Используя жемчуг:

perl -ne 's/"(\d+)"/$1/g; print' file.csv > new_file.txt

Вся работа сделана s/"(\d+)"/$1/g, где

  • s/patternA/patternB/ используется для замены patternA patternB
  • тогда, жемчуг ищет одну или несколько цифр \d+ окруженный двойными кавычками.
  • круглая скобка [приблизительно 1 113] ( \d+ ) используются, чтобы получить цифру (цифры) и снова использовать их как заменяющий шаблон со специальной переменной жемчуга $1.
0
ответ дан 12 March 2015 в 22:44

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]

0
ответ дан 12 March 2015 в 22:44

Ваше описание проблемы не очень конкретно. Я предполагаю, что Вы хотите удалить двойные кавычки вокруг 1-х и 3-х полей только. Если так, любой из них должен работать:

  1. 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-е.

  2. Perl

    perl -pe 's/^"([^"]+)"(\s*,\s*[^,]+)\s*,\s*"([^"]+)"/$1$2, $3/; ' file.csv
    

    Объяснение

    -p средства печатают каждую строку после применения сценария, мимо которого проходят -e. Сам сценарий является в основном тем же regex как в sed выше. Только здесь, полученные шаблоны $1.

  3. awk

    awk -F, -v OFS="," '{gsub("\"","",$1)0gsub("\"","",$3);}1;' file.csv 
    

    Объяснение

    -F устанавливает разделителя полей на ,. OFS выходной разделитель полей, который также установлен на , так, чтобы строки были распечатаны правильно. gsub делает замену, заменяя все " ни с чем, так как мы выполняем его на 1-м ($1) и 3-и поля ($3) это только удалит кавычки из тех полей. 1; справедливо awk сокращение от "печати строка".

5
ответ дан 12 March 2015 в 22:44

Решение Python

Маленький сценарий ниже параметра командной строки файла взятий, выполняет итерации по каждой строке в том файле и разделяет каждую строку на список использования объектов , как разделитель. Каждая запись затем закрывается кавычки и проверена на то, что она была числовой строкой; если строка является числовой, это оставляют неупомянутым.

#!/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))
1
ответ дан 12 March 2015 в 22:44
  • 1
    Спасибо. Но I' m перепутанный. Я думаю for i in "$1"/* циклы согласно значению IFS, и значение по умолчанию IFS содержит пробел, поэтому если имя файла будет содержать пробел, [то 113] будет разделен на несколько частей. Например, если "$PWD" test folder, $i должен быть test и folder. Но на самом деле, дело обстоит не так. сценарий работает очень хорошо. Почему? Я пропускал что-нибудь? – Searene 28 September 2015 в 02:17

Другие вопросы по тегам:

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