2

我无法解析 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、(有符号)整数和(有符号)小数。

我使用了错误的方法吗?或者谁能​​指出我正确的方向?

提前致谢!

4

5 回答 5

3

Python 的原生库应该做得很好。你已经试过了吗?

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

于 2011-02-14T16:22:07.393 回答
0

从你的样本来看,它看起来像^{(?:(?:([^},"']+|"[^"]+"|'[^']+')(?:,|}))+(?<=})|})$我。这并不完美,因为它允许“{foo,bar}baz}”,但如果这对你很重要,它可以被修复。

于 2011-02-14T16:18:08.870 回答
0

如果你能做断言,这将使你走上正确的轨道。

这个问题太广泛了,无法在单个正则表达式中完成。您正在尝试在全局匹配中同时验证和解析。但是您的预期结果需要在比赛后进行子处理。出于这个原因,最好编写一个更简单的全局解析器,然后迭代结果以进行验证和修复(是的,您的示例中规定了修复)。

两个主要的解析正则表达式是:

  1. 也去掉分隔符引用,只有 $2 包含数据,在 while 循环中使用,全局上下文
    /(?!}$)(?:^{?|,)\s*("|)(.*?)\1\s*(?=,|}$)/

  2. 我的首选,不去除引号,仅捕获 $1,可用于在数组或 while 循环中捕获全局上下文
    /(?!}$)(?:^{?|,)\s*(".*?"|.*?)\s*(?=,|}$)/

这是一个使用记录的正则表达式进行后处理(在 Perl 中)的示例:(编辑:修复附加尾随,

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']

于 2011-02-14T18:52:00.403 回答
0

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

感谢您的回复,他们最有帮助!

于 2011-02-15T09:16:23.900 回答
0

改进了德克的回答。这可以更好地处理转义字符以及空数组的情况。也少了一次脱衣舞:

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()
于 2016-01-15T21:46:15.300 回答