2011-02-14 51 views
2

我无法解析Psycopg2返回的嵌套数组。我正在处理的数据库返回可以嵌套数组作为值的记录。 Psycopg只解析这些值的外部数组。Python:正则表达式问题/ CSV解析/ 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,(带符号)整数和(带符号)小数。

我用错了吗?或者任何人都可以将我指向正确的方向?

提前致谢!

+0

能琴弦也含有“或”,或许逃过那些 – 2011-02-14 16:13:19

回答

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 

谢谢f或答复,他们是最有帮助的!

0

从您的示例中,它看起来像^{(?:(?:([^},"']+|"[^"]+"|'[^']+')(?:,|}))+(?<=})|})$给我。这不是完美的,因为它会允许“{foo,bar} baz}”,但如果这对你来说可能是固定的。

0

如果你能做到断言,这将让你在正确的轨道上。

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

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

  1. 带分隔符报价也只有2 $包含的数据,while循环使用,全球范围内
    /(?!}$)(?:^{?|,)\s*("|)(.*?)\1\s*(?=,|}$)/

  2. 我的首选之一,不不带条形引号,仅捕获$ 1,可用于捕获数组或全局上下文
    /(?!}$)(?:^{?|,)\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']

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()