2013-12-16 3 views
0

Вот код у меня есть:Python: csv.DictWriter возвращаются пустые строки, если значение является буквенно-цифровым

import csv 
import os 

for root, subFolders, files in os.walk('/path/to/folder/'): 
    if 'routes.csv' in files: 
     with open(os.path.join(root, "R.csv"), "r") as inf, \ 
       open(os.path.join(root, "B.csv"), "a") as output: 
      reader = csv.DictReader(inf, quotechar='"') 
      headers = ["R_id"] 
      writer_B_routes = csv.DictWriter(output, headers, 
              extrasaction='ignore') 
      writer_B_routes.writeheader() 
      for row in reader: 
       if int(row["R_type"]) == 3: 
        writer_B_routes.writerow(row) 

Когда я бегу это на моих папках CSV, если значение R_id только числовой, то выводя на B.csv штраф (то есть 1234). Однако, если значение R_id является буквенно-цифровым (то есть A123), то выход, который я получаю в B.csv, равен "".

Я попытался изменить int(row["R_type"]) == 3 на str(), думая, что была проблема с тем, как строился Dialect, но это не сработало. Я не знаю, где эти данные передаются только целое число.

Update: Ссылка на выборку данных + скрипт: Here

Update 2: Я проверил с несколькими другими образцами - дело, кажется, быть уникальным, но я не могу определить, почему. У меня есть еще один образец данных, содержащий R_id от 005M1, и он работает нормально. Данные, дающие мне вопрос, имеют R_idE2 и аналогичные. Но теперь я знаю, что это не для всех буквенно-цифровых идентификаторов.

+0

Вы пробовали 'if "3" в str (строка ["R_type")'? – Jodgod

+0

Являются ли эти буквенно-цифровые значения R_id в файлах CSV (и, точнее, в словаре 'row')? Что произойдет, если вместо 'extrasaction = 'ignore'' вы используете' extrasaction =' raise'' в DictWriter? –

+0

@Jodgod Просто попробовал один, тот же вопрос. Предполагается, что 'writer_B_routes.writerow (строка) записывает значение' R_id' - где-то вдоль строки, по-видимому, отклоняет их, если они являются буквенно-цифровыми. Я также попробовал добавить 'quotechar = '' '' в 'DictWriter', но не повезло. –

ответ

3

Обратите внимание на следующее относится к коду в RemoveBAIO.pyне код, приведенный в вашем вопросе.

Проблема заключается в том, что routes.csv файл, который вы пытаетесь прочитать текстовый файл Unicode с UTF-8 Byte-Order-Mark (или BOM) в начале, что будучи снимаемого со стороны csv модуля - который может 't обрабатывает вход Unicode в Python 2, который отмечен в documentation - как имя первого поля, поэтому вместо "route_id" это "\xef\xbb\xbfroute_id".

Вот немного измененная версия вашего кода с указанием правильного способа обработки файлов, которые может иметь исходную спецификацию. Он делает это, используя codecs.open() в сочетании с кодировкой 'utf-8-sig'. Эта кодировка описана в разделе Encodings and Unicode документации для модуля codecs. При декодировании это пропустит любую имеющуюся спецификацию и при кодировании сначала будет записывать 3-байтную последовательность BOM. В приведенном ниже коде он намеренно используется только для чтения входного файла (я объясню, почему дальше вниз).Эффект заключается в том, что первое имя поля во входном файле не перепутано.

отметить Также я извлекал преобразование в int в "route_type" проверки, так что не будет поднимать ValueError исключение, если сталкиваются друг с нечисловых символов в нем.

bus_route_ids.csv будет не имеют ведущую спецификацию на нем. Добавление одного из них будет сложным, потому что возможно, что к нему будут добавлены данные, поэтому добавление спецификации должно быть обусловлено тем, существует ли файл уже или нет. FWIW, я также заметил, что routes.csv не является правильной UTF-8, поскольку она имеет \xa0 характер внедренный в последней строке, которая имеет порядковое значение больше 128.

import codecs 
import csv 
import os 

path_to_folder = '/insert/path/' 

with open('hasfares.txt', 'w') as hf: 
    for root, subFolders, files in os.walk(path_to_folder): 
     if 'fare_rules.csv' in files: 
      hf.write('%s\n' % root) 

     if 'routes.csv' in files: 
      routes_path = os.path.join(root, 'routes.csv') 
      bus_route_ids_path = os.path.join(root, 'bus_route_ids.csv') 
      appending_to_existing_file = os.path.exists(bus_route_ids_path) 
      with codecs.open(routes_path, 'r', 'utf-8-sig') as inf, \ 
        open(os.path.join(root, "bus_route_ids.csv"), "a") as output: 
       reader = csv.DictReader(inf, quotechar='"') 
       headers = ['route_id'] 
       writer_bus_routes = csv.DictWriter(output, headers, 
                extrasaction='ignore') 
       if not appending_to_existing_file: 
        writer_bus_routes.writeheader() 
       for row in reader: 
        if row['route_type'] == '3': 
         writer_bus_routes.writerow(row) 

Результирующая bus_route_ids.csv файл (если он не сделал уже существуют):

route_id 
E1 
E2 
N 
N1 
N2 
N3 
170 
S1 
S2 
S3 
S4 
W1 
W2 
W3 
W4 
C 
+0

+1 Ты получил мой голос. Хорошая работа. –

+0

@ T.Mount: Это не отвечает на ваш вопрос? – martineau

+0

Отлично, спасибо! Я прошу прощения за то, что не ответил раньше. –

0

Попробуйте

row["R_type"] == "3" 

Если R_type является буквенно-цифровым, то это тип строка. В то время как 3 является int.

Python не подразумевает синтаксический анализ значения int 3 в строке, и сравнение == между строкой и int всегда будет возвращать false. Чтобы исправить это, вы должны либо использовать строчную версию «3», либо добавить 3 в строку str (3).

Если R_type может быть проанализирован из CSV как int или string, вы также должны добавить явное приведение, чтобы всегда принудительно вводить строку, чтобы вы не получали никаких ложных негативов.

Например:

str(row["R_type"]) == "3" 
+0

Я попытался оба экземпляра этого, все еще возвращающ '' '' как R_id –

+0

Невозможно увидеть, что разрушает его без образца данных. –

+0

Загрузка в Dropbox - выведет ссылку в основной вопрос. –

Смежные вопросы