Как мне написать собственный читатель CSV в python без использования CSV импорта? - PullRequest
0 голосов
/ 04 мая 2020

Я пытаюсь решить проблему с сайта pyschools, который просит написать скрипт, который читает файл CSV с запятыми "," в качестве разделителя и возвращает список записей. Когда мой скрипт запускается на их веб-сайте, он возвращается как неправильный, используя тестовый пример: csvReader ('books.csv') [0], таким образом возвращая:

['"Pete,Zelle","Intro to HTML, CSS",2011']

, когда ожидаемый результат:

['Pete,Zelle', 'Intro to HTML, CSS', '2011']

Я заметил, что проблема связана с кавычками "&", но все еще не нашел правильный ответ, используя замену ('"', '') для строковой переменной, чтобы удалить двойные кавычки не исправляют это, поскольку возвращаются как:

['Pete,Zelle,Intro to HTML, CSS,2011']

, где удаляет последнюю кавычку из некоторых слов, например, Zelle вместо Zelle ',.

Ниже недопустимо предоставить ссылка на упражнение, проблема и мой текущий сценарий. Любое объяснение или помощь приветствуются.

ссылка: http://www.pyschools.com/quiz/view_question/s13-q8

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

script:

def csvReader(filename):
    records = []
    for line in open(filename):
        line = line.rstrip()  # strip '\n'
        if line=='","':
           continue           # ignore empty line

        records.append([line.replace('"','')])


    return records

Ответы [ 2 ]

0 голосов
/ 04 мая 2020

Батареи включены, как обычно, с python. Здесь используется стандартный модуль lib csv:

import csv
with open(path, "r") as f:
    csv_reader = csv.reader(f, delimiter=",")
    for row_number, row in enumerate(csv_reader):
        print(f"{row_number} => {row}")

Если stdlib не доступен по какой-то странной причине ... вам нужно будет токенизировать каждую строку с разделителями, разделителями и ячейкой ценности'. Опять же, это было бы тривиально с stdlib (import re). Давайте представим, что у вас совсем нет батарей, просто plain python.

Вам нужно будет понять, что то, как вы относитесь к каждому символу каждой строки, зависит от «контекста» и что этот контекст создается всеми предыдущие персонажи. Использование стека рекомендуется здесь. Вы вытягиваете sh и извлекаете состояния (или контексты) из стека в зависимости от текущего контекста (вершины стека) и текущего персонажа, с которым вы работаете. Теперь, учитывая контекст, вы можете обрабатывать каждый символ по-разному в зависимости от этого контекста:

class State: 
    IN_NON_DELIMITED_CELL = 1 
    IN_DELIMITED_CELL = 2 

def get_cell_values(line, quotechar='"', separator=','): 
    stack = [] 
    stack.append(State.IN_NON_DELIMITED_CELL) 
    cell_values = [""] 
    for character in line: 
        current_state = stack[-1] 
        if current_state == State.IN_NON_DELIMITED_CELL: 
            if character == quotechar: 
                stack.append(State.IN_DELIMITED_CELL) 
            elif character == separator: 
                cell_values.append("") 
            else: 
                cell_values[-1] += character 

        if current_state == State.IN_DELIMITED_CELL: 
            if character == quotechar: 
                stack.pop() 
            else: 
                cell_values[-1] += character 
    return cell_values 

with open(path, "r") as f:
    for line in f:
        cell_values = tokenize(line, quotechar='"', delimiter=',')
        print(cell_values)

Это хорошая отправная точка:

print(get_cell_values('"this","is",an,example,of,"doing things, the hard way?"'))
# prints:
['this', 'is', 'an', 'example', 'of', 'doing things, the hard way?']

Для дальнейшего развития этого (НАМНОГО), посмотрите на эти темы: токенизация строк, парсеры LL + LR, рекурсивный спуск, парсеры уменьшения смещения.

0 голосов
/ 04 мая 2020

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

В этом случае я бы порекомендовал библиотеку CSV и установил символ кавычки.

import csv
record = '"Pete,Zelle","Intro to HTML, CSS",2011'
newStr = [ '"{}"'.format(x) for x in list(csv.reader([record], delimiter=',', quotechar='"'))[0] ]
print(newStr)

Будет return ['"Pete, Zelle"', '"Intro to HTML, CSS"', '"2011"']

В вашей функции вы можете включить это, как показано ниже

import csv
def csvReader(filename):
    records = []
    for line in open(filename):
        line = line.rstrip()  # strip '\n'
        if line=='","':
           continue           # ignore empty line
        newLine = [ '"{}"'.format(x) for x in list(csv.reader([line], delimiter=',', quotechar='"'))[0] ]
        records.append(newLine)

    return records
...