Python: вопрос о регулярных выражениях / разбор CSV / вложенные массивы Psycopg - PullRequest
2 голосов
/ 14 февраля 2011

У меня проблемы с анализом вложенных массивов, возвращаемых Psycopg2.БД, над которой я работаю, возвращает записи, которые могут иметь вложенный массив в качестве значения.Psycopg анализирует только внешний массив таких значений.

Моим первым подходом было разбиение строки на запятые, но потом я столкнулся с проблемой, что иногда строка в результате также содержит запятые, что делает весь подход непригодным,Моей следующей попыткой было использование регулярного выражения для поиска «компонентов» в строке, но потом я заметил, что не смог обнаружить числа (поскольку числа также могут встречаться в строках).

В настоящее время это мой код:

import re
text = '{2f5e5fef-1e8c-43a2-9a11-3a39b2cbb45e,"Marc, Dirk en Koen",398547,85.5,-9.2, 62fe6393-00f7-418d-b0b3-7116f6d5cf10}'
r = re.compile('\".*?\"|[\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12}|^\d*[0-9](|.\d*[0-9]|,\d*[0-9])?$')
result = r.search(text)
if result:
    result = result.groups()

Результат должен быть следующим:

['2f5e5fef-1e8c-43a2-9a11-3a39b2cbb45e', 'Marc, Dirk en Koen', 398547, 85.5, -9.2, '62fe6393-00f7-418d-b0b3-7116f6d5cf10']

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

Использую ли я неправильный подход?Или кто-нибудь может указать мне правильное направление?

Заранее спасибо!

Ответы [ 5 ]

3 голосов
/ 14 февраля 2011

Собственная библиотека Python должна хорошо работать. Вы уже пробовали это?

http://docs.python.org/library/csv.html

0 голосов
/ 16 января 2016

Улучшено после ответа Дирка. Это лучше обрабатывает escape-символы, а также регистр пустого массива. Также на один стриптиз:

def restore_str_array(val):
    """
    Converts a postgres formatted string array (as a string) to python

    :param val: postgres string array
    :return: python array with values as strings
    """
    val = val.strip("{}")
    if not val:
        return []
    reader = csv.reader(StringIO(val), delimiter=',', quotechar='"', escapechar='\\')
    return reader.next()
0 голосов
/ 15 февраля 2011

Казалось, что CSV-подход проще всего реализовать:

def parsePsycopgSQLArray(input):
    import csv
    import cStringIO

    input = input.strip("{")
    input = input.strip("}")

    buffer = cStringIO.StringIO(input)
    reader = csv.reader(buffer, delimiter=',', quotechar='"')   

    return reader.next() #There can only be one row 

if __name__ == "__main__":
    text = '{2f5e5fef-1e8c-43a2-9a11-3a39b2cbb45e,"Marc, Dirk en Koen",398547,85.5,-9.2, 62fe6393-00f7-418d-b0b3-7116f6d5cf10}' 
    result = parsePsycopgSQLArray(text)
    print result

Спасибо за ответы, они были самыми полезными!

0 голосов
/ 14 февраля 2011

Если вы можете выполнять ВЕРСИЯ, это приведет вас на правильный путь.

Эта проблема слишком обширна, чтобы ее можно было выполнить в одном регулярном выражении.Вы пытаетесь одновременно выполнить проверку и анализ в глобальном совпадении.Но ваш ожидаемый результат требует дополнительной обработки после матча.По этой причине лучше написать более простой глобальный синтаксический анализатор, а затем перебрать результаты проверки и исправления (да, в вашем примере предусмотрены исправления).

Вот два основных регулярных выражения:

  1. тоже разделяет кавычки, и только $ 2 содержит данные, используется в цикле while, глобальный контекст
    /(?!}$)(?:^{?|,)\s*("|)(.*?)\1\s*(?=,|}$)/

  2. мой предпочтительный,не удаляет кавычки, только захватывает $ 1, может использовать для захвата в массиве или в цикле while, глобальный контекст
    /(?!}$)(?:^{?|,)\s*(".*?"|.*?)\s*(?=,|}$)/

Это пример постобработки (в Perl) с задокументированным регулярным выражением: ( edit: исправить добавление в конце, )

use strict; use warnings;

my $str = '{2f5e5fef-1e8c-43a2-9a11-3a39b2cbb45e,"Marc, Dirk en Koen",398547,85.5,-9.2, 62fe6393-00f7-418d-b0b3-7116f6d5cf10}';

my $rx = qr/ (?!}$) (?:^{?|,) \s* ( ".*?" | .*?) \s* (?=,|}$) /x;

my $rxExpanded = qr/
         (?!}$)           # ASSERT ahead:  NOT a } plus end
         (?:^{?|,)        # Boundry: Start of string plus { OR comma
         \s*              # 0 or more whitespace
         ( ".*?" | .*?)   # Capture "Quoted" or non quoted data
         \s*              # 0 or more whitespace
         (?=,|}$)         # Boundry ASSERT ahead:  Comma OR } plus end
  /x;

my ($newstring, $sucess) = ('[', 0);

for my $field ($str =~ /$rx/g)
{
   my $tmp = $field;
   $sucess = 1;

   if (  $tmp =~ s/^"|"$//g || $tmp =~ /(?:[a-f0-9]+-){3,}/ ) {
      $tmp = "'$tmp'";
   }
   $newstring .= "$tmp,";
}
if ( $sucess ) {
    $newstring =~ s/,$//;
    $newstring .= ']';
    print $newstring,"\n";
}
else {
    print "Invalid string!\n";
}

Вывод:
['2f5e5fef-1e8c-43a2-9a11-3a39b2cbb45e','Marc, Dirk en Koen',398547,85.5,-9.2,'6 2fe6393-00f7-418d-b0b3-7116f6d5cf10']

0 голосов
/ 14 февраля 2011

Из вашего примера это выглядит как ^{(?:(?:([^},"']+|"[^"]+"|'[^']+')(?:,|}))+(?<=})|})$ для меня. Это не идеально, так как допускается "{foo, bar} baz}", но это можно исправить, если это важно для вас.

...