2011-02-14 56 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()