Python regex для чтения подобных CSV строк

Я хочу проанализировать входящие подобные CSV строки данных. Значения разделяются с запятыми (и там мог вести и запаздывать пробелы вокруг запятых), и может быть заключен в кавычки или с 'или с ". Например - это - допустимая строка:

    data1, data2  ,"data3'''",  'data4""',,,data5,

но этот уродлив:

    data1, data2, da"ta3", 'data4',

- кавычки могут только предварительно ожидаться или запоздали пробелами.

Такие уродливые строки должны быть распознаны - лучше всего должен был бы так или иначе отметить уродливое значение в строке, но если regex не соответствует целой строке затем, это также приемлемо.

Я пытаюсь записать regex способный проанализировать это, с помощью любого соответствия () findall (), но каждый regex, с которым я иду, имеет некоторые проблемы с пограничными случаями.

Так, возможно, кто-то с опытом в парсинге чего-то подобного мог помочь мне на этом? (Или возможно это слишком сложно для regex, и я должен просто записать функцию),

EDIT1:

csv модуль не является большой частью использования здесь:

    >>> list(csv.reader(StringIO('''2, "dat,a1", 'dat,a2',''')))
    [['2', ' "dat', 'a1"', " 'dat", "a2'", '']]

    >>> list(csv.reader(StringIO('''2,"dat,a1",'dat,a2',''')))
    [['2', 'dat,a1', "'dat", "a2'", '']]

- если это не может быть настроено?

EDIT2: Несколько редактирований языка - я надеюсь, что это - больше допустимого английского языка теперь

EDIT3: Спасибо за все ответы, я теперь вполне уверен, который регулярное выражение не то, что хорошая идея здесь как (1) покрытие всех пограничных случаев может быть хитро (2), вывод устройства записи не является регулярным. Пишущий, что, я решил проверить упомянутый pyparsing и или использовать его или записать пользовательский подобный FSM синтаксический анализатор.

14
задан Tomasz Zieliński 7 February 2010 в 14:12
поделиться

6 ответов

Хотя, вероятно, это было бы возможно при определенной комбинации предварительной обработки, использования модуля csv, постобработки и использования регулярных выражений, заявленные вами требования не очень хорошо сочетаются с конструкцией модуля csv и, возможно, с регулярными выражениями (в зависимости от сложности вложенных кавычек, которые вам, возможно, придется обрабатывать).

В сложных случаях парсинга, pyparsing всегда является хорошим пакетом, на который можно положиться. Если это не одноразовая ситуация, то она, скорее всего, даст наиболее простой и поддающийся обработке результат, за счет, возможно, небольших дополнительных усилий вперёд. Считайте, однако, что инвестиции должны быть быстро возвращены, так как вы экономите дополнительные усилия по отладке регексных решений для работы с угловыми корпусами....

Скорее всего, вы можете легко найти примеры парсинга CSV на основе pyparsing, задав этот вопрос , может быть, достаточно, чтобы начать работу.

7
ответ дан 1 December 2019 в 10:18
поделиться

Хотя модуль csv здесь является правильным ответом, регулярное выражение, которое могло бы сделать это, вполне выполнимо:

import re

r = re.compile(r'''
    \s*                # Any whitespace.
    (                  # Start capturing here.
      [^,"']+?         # Either a series of non-comma non-quote characters.
      |                # OR
      "(?:             # A double-quote followed by a string of characters...
          [^"\\]|\\.   # That are either non-quotes or escaped...
       )*              # ...repeated any number of times.
      "                # Followed by a closing double-quote.
      |                # OR
      '(?:[^'\\]|\\.)*'# Same as above, for single quotes.
    )                  # Done capturing.
    \s*                # Allow arbitrary space before the comma.
    (?:,|$)            # Followed by a comma or the end of a string.
    ''', re.VERBOSE)

line = r"""data1, data2  ,"data3'''",  'data4""',,,data5,"""

print r.findall(line)

# That prints: ['data1', 'data2', '"data3\'\'\'"', '\'data4""\'', 'data5']

РЕДАКТИРОВАТЬ: Для проверки строк вы можете повторно использовать регулярное выражение выше с небольшими дополнениями :

import re

r_validation = re.compile(r'''
    ^(?:    # Capture from the start.
      # Below is the same regex as above, but condensed.
      # One tiny modification is that it allows empty values
      # The first plus is replaced by an asterisk.
      \s*([^,"']*?|"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')\s*(?:,|$)
    )*$    # And don't stop until the end.
    ''', re.VERBOSE)

line1 = r"""data1, data2  ,"data3'''",  'data4""',,,data5,"""
line2 = r"""data1, data2, da"ta3", 'data4',"""

if r_validation.match(line1):
    print 'Line 1 is valid.'
else:
    print 'Line 1 is INvalid.'

if r_validation.match(line2):
    print 'Line 2 is valid.'
else:
    print 'Line 2 is INvalid.'

# Prints:
#    Line 1 is valid.
#    Line 2 is INvalid.
12
ответ дан 1 December 2019 в 10:18
поделиться

Python имеет стандартный библиотечный модуль для чтения файлов csv:

import csv

reader = csv.reader(open('file.csv'))

for line in reader:
    print line

Для вашего примера ввода это печатает

['data1', ' data2 ', "data3'''", ' \'data4""\'', '', '', 'data5', '']

EDIT:

вам нужно добавить skipinitalspace = True, чтобы разрешить пробелы перед двойными кавычками для дополнительных примеров, которые вы при условии. Пока не уверен в одинарных кавычках.

>>> list(csv.reader(StringIO('''2, "dat,a1", 'dat,a2','''), skipinitialspace=True))
[['2', 'dat,a1', "'dat", "a2'", '']]

>>> list(csv.reader(StringIO('''2,"dat,a1",'dat,a2','''), skipinitialspace=True))
[['2', 'dat,a1', "'dat", "a2'", '']]
4
ответ дан 1 December 2019 в 10:18
поделиться

Невозможно дать вам ответ, потому что вы не полностью указали протокол, который используется писателем.

Очевидно, он содержит такие правила, как:

Если поле содержит запятые или одинарные кавычки, заключите его в двойные кавычки.
В противном случае, если поле содержит двойные кавычки, заключите его в одинарные кавычки.
Примечание: результат все еще действителен, если вы поменяете местами двойное и одинарное в двух приведенных выше пунктах.
Иначе не цитируйте.
В результирующем поле могут быть добавлены или добавлены пробелы (или другие пробелы?).
Расширенные таким образом поля собираются в строку, разделяются запятыми и заканчиваются новой строкой платформы (LF или CRLF).

Что не упоминается, так это то, что делает писатель в этих случаях:
(0) поле содержит ОБЕ одинарные кавычки и двойные кавычки
(1) поле содержит начальные не -newline whitespace
(2) поле содержит завершающие пробелы без новой строки
(3) поле содержит любые символы новой строки.
Если автор игнорирует любой из этих случаев, укажите, каких результатов вы хотите.

Вы также упоминаете, что "кавычки могут быть добавлены или завершены пробелами" - конечно, вы имеете в виду, что также разрешены запятые, иначе ваш пример 'data4 ""' ,,, data5, не будет первая запятая.

Как кодируются ваши данные?

2
ответ дан 1 December 2019 в 10:18
поделиться

Это, наверное, звучит слишком просто, но на самом деле, судя по тому, что вы ищете строку, содержащую либо [a-zA-Z0-9]["']+[a-zA-Z0-9], я имею в виду, что без глубокой проверки данных, на самом деле, то, что вы ищете - это кавычки или двойные кавычки (или любая комбинация) между буквами (туда же вы можете добавлять числа).

Исходя из того, что вы спрашивали, на самом деле не имеет значения, что это CSV, важно то, что у вас есть данные, которые не соответствуют. Что я считаю просто поиском буквы, затем любой комбинации одной или нескольких " или " и другой буквы.

Теперь ты ищешь "количество" или просто распечатку строки, в которой она содержится, чтобы ты знал, какие из них вернуться и исправить?

Извини, что я не знаю, что такое "python regex", но на perl это выглядело бы примерно так:

# Look for one or more letter/number at least one ' or " or more and at least one    
#  or more letter/number
if ($line =~ m/[a-zA-Z0-9]+['"]+[a-zA-Z0-9]+/ig)
{
    # Prints the line if the above regex is found
    print $line;

}

Просто конвертируй это для того, чтобы, глядя на строку.

Простите, если я неправильно понял вопрос

Надеюсь, это поможет!

1
ответ дан 1 December 2019 в 10:18
поделиться

Если ваша цель - преобразовать данные в XML (или JSON, или YAML), посмотрите этот пример для синтаксиса Gelatin , который дает следующий результат:

<xml>
  <line>
    <column>data1</column>
    <column>data2  </column>
    <column>data3'''</column>
    <column>data4""</column>
    <column/>
    <column/>
    <column>data5</column>
    <column/>
  </line>
</xml>

Обратите внимание, что у Gelatin также есть API Python:

from Gelatin.util import compile, generate_to_file
syntax = compile('syntax.gel')
generate_to_file(syntax, 'input.csv', 'output.xml', 'xml')
0
ответ дан 1 December 2019 в 10:18
поделиться
Другие вопросы по тегам:

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