我需要使用Python解析一个字符串并提取由:
(冒号)分隔的2个标记,这些标记可以用单引号,双引号或无引号括起来。
工作案例:
# <input string> -> <tuple that should return>
1) abc:def -> (abc, def)
2) abc:"def" -> (abc, def)
3) "abc":def -> (abc, def)
4) "abc":"def" -> (abc, def)
5) "a:bc":abc -> (a:bc, abc)
示例案例不起作用:
# <input string> -> <tuple that should return>
6) abc:"a:bc" -> (abc, a:bc)
7) "abcdef" -> (abcdef,)
使用的正则表达式是:
>>> import re
>>> rex = re.compile(r"(?P<fquote>[\'\"]?)"
r"(?P<user>.+)"
r"(?P=fquote)"
r"(?:\:"
r"(?P<squote>[\'\"]?)"
r"(?P<pass>.+)"
r"(?P=squote))")
我有2个问题,首先是样本案例6)和7)不起作用,第二个问题rex.match
后我希望所有组都匹配但不是fquote
和squote
个。我的意思是现在rex.match("'abc':'def').groups()
返回("'", "abc", "'", "def")
,我只想要("abc", "def")
。
有什么想法吗?
由于
答案 0 :(得分:1)
您可以在此使用csv
模块而不是正则表达式:
inputs = [
'abc:def', 'abc:"def"', '"abc":def', '"abc":"def"', '"a:bc":abc', #working
'abc:"a:bc"', 'abcdef' # not working
]
import csv
for idx, el in enumerate(inputs, start=1):
print idx, tuple(next(csv.reader([el], delimiter=':')))
这给了你:
1 ('abc', 'def')
2 ('abc', 'def')
3 ('abc', 'def')
4 ('abc', 'def')
5 ('a:bc', 'abc')
6 ('abc', 'a:bc')
7 ('abcdef',)
答案 1 :(得分:1)
def foo(string):
rex = re.compile(r"(?P<fquote>[\'\"]?)"
r"(?P<user>.+?)"
r"(?:(?P=fquote))"
r"(?:\:"
r"(?P<squote>[\'\"]?)"
r"(?P<pass>.+)"
r"(?P=squote))"
r"|(?P<sfquote>[\'\"]?)"
r"(?P<suser>.+)"
r"(?:(?P=sfquote))")
match = rex.match(string)
suser_match = match.group("suser")
return (suser_match,) if suser_match else (match.group("user"), match.group("pass"))
这可以胜任,但我强烈反对。正则表达式应尽可能简单,因为这种解决方案难以理解,因此难以维护。您可能需要一个无上下文的语法,在我看来,这更适合您作为示例提供的模式类型(特别适用于"abcdef"
字符串,这需要一个单独的组。)
您的第二个问题是,即使您将其置于(?:...)
内,也会捕获符号组。这就是为什么我认为检索它们更容易,然后用匹配的符号组创建元组。
答案 2 :(得分:1)
为什么要检索所有组?只需拿走你感兴趣的那些而忽略其余部分。这是一个例子:
rex = re.compile(
r"""^(?:
(?P<fquote>['"])
(?P<user1>(?:(?!(?P=fquote)).)+)
(?P=fquote)
|
(?P<user2>[^:"'\s]+)
)
(?:
:
(?:
(?P<squote>['"])
(?P<pass1>(?:(?!(?P=squote)).)+)
(?P=squote)
|
(?P<pass2>[^:"'\s]+)
)
)?
$""",
re.VERBOSE)
result = rex.sub(r"\g<user1>\g<user2> : \g<pass1>\g<pass2>", subject)
附加说明:
拆分它以分别处理引用和未引用的字段使得工作变得更加容易。你知道每对组中的一组总是空的,所以连接它们是安全的。
(?:(?!(?P=fquote)).)+
一次消耗一个字符,但只有在确认该字符与开头引号不同之后才会消耗。您不必担心它会超出收尾报价,就像.+
那样。 (你真的应该在那里使用一个不情愿的.+?
,但这样做会更好。)