Python:正则表达式问题 / CSV解析 / Psycopg嵌套数组

2 投票
5 回答
702 浏览
提问于 2025-04-16 11:48

我在处理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 个回答

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

3

Python自带的库应该能很好地完成这个任务。你试过了吗?

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

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

谢谢大家的回复,真的很有帮助!

撰写回答