2012-02-06 15 views
1

У меня есть регулярное выражение Python, который принимает строку (соединение с базой данных URI) и расщепляет его, используя именованные группы в имя пользователя, пароль и т.д.Python Regex - Спасаясь

uri = 'username:[email protected]/database' 
m = re.compile('^(?P<user>[^:@]+)(\:(?P<password>[^@]*))[email protected](?P<host>[^\:@/]+)(\:(?P<port>[0-9]+))?/(?P<db>[^\?]+)?$').match(uri) 
print m.groupdict() 
{'host': 'host', 'password': 'password', 'db': 'database', 'user': 'username', 'port': None} 

Это прекрасно работает. Проблема в том, что uri имеет в нем символ @, так как это используется для разделения пароля и хоста. Например,

uri = 'username:[email protected]@host/database' 

не будет соответствовать, что ожидается. Тем не менее, я хотел бы уйти от особого характера, например:

uri = 'username:p\@[email protected]/database' 

и иметь это соответствие. Мой опыт регулярных выражений довольно ограничен - я думаю, что я хотел бы сделать, это изменить группу

(?P<password>[^@]*) 

так, что он будет соответствовать любому символу, который не является @, если это не предшествует символ \. Конечно, некоторые (большинство) строк соединения не будут содержать \ @ вообще.

Любая помощь очень ценится.

+2

Почему это не URL-кодирование в первую очередь? –

+0

Не уверен, это не мой код изначально. Это от web2py. Во всяком случае, не будет ли у меня такая же проблема, если бы она была закодирована в URL, т. Е. @ Были заменены на% 40? Им все равно нужно ускользнуть. – Caligari

+0

Нет, поскольку механизм регулярных выражений не преобразует URL-адреса. –

ответ

0

Мое мнение вы хотите жадные соответствия, то есть пароль до последнего @ и имя хоста между последним @ и первый/

с помощью простого путь может быть таким:

In [68]: re.match('((?P<user>.*):)((?P<pass>.*)@)((?P<host>.*)/)((?P<db>.*))', "username:[email protected]@host/data").groupdict() 
Out[68]: {'db': 'data', 'host': 'host', 'pass': '[email protected]', 'user': 'username'} 

Возможно, вы захотите добавить дополнительные варианты, то есть (материал) +, если, например, имя пользователя и пароль могут быть опущены.

+0

Спасибо за это. Хорошие ответы вокруг, но это именно то, чем я был. Благодарю. – Caligari

0

Вы можете сделать:

(?P<password>([^\\@]|\\.)*) 

Это сканирует через строку и соответствует либо: а не- \ или не- @, или обратную косую черту в этом случае она соответствует то, что следует тоже. Единственный способ, которым «@» может быть сопоставлен этим регулярным выражением, заключается в том, что он прокрадывается через регулярное выражение \\., то есть он экранирован.

В качестве ссылки, чтобы написать регулярное выражение в python, используйте r "insert_regex_here".

В противном случае для регулярного выражения \\., вы должны написать его в python как "\\\\.". Чтобы избежать этого, вы можете сделать r"\\.".

0

Я бы порекомендовал вам использовать re.split:

>>> print re.split(r"(?<!\\)@|/|:", r"username:[email protected]/database") 
['username', 'password', 'host', 'database'] 
>>> print re.split(r"(?<!\\)@|/|:", r"username:p\@[email protected]/database") 
['username', 'p\\@ssword', 'host', 'database']