Python:正则表达式问题 / CSV解析 / Psycopg嵌套数组
我在处理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 个回答
如果你能使用断言,这会让你走上正轨。
这个问题太复杂,不能用一个正则表达式来解决。你试图同时验证和解析数据,但你的目标结果需要在匹配后进行进一步处理。因此,最好先写一个简单的全局解析器,然后对结果进行验证和修正(是的,你的例子中提到了修正)。
主要的两个解析正则表达式是:
这个会去掉分隔符的引号,只有 $2 包含数据,可以在 while 循环中使用,适用于全局匹配
/(?!}$)(?:^{?|,)\s*("|)(.*?)\1\s*(?=,|}$)/
我更喜欢这个,不去掉引号,只捕获 $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']
Python自带的库应该能很好地完成这个任务。你试过了吗?
看起来用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
谢谢大家的回复,真的很有帮助!