假设我有一个像这样的 SMTP/IMAP/POP3 登录 URL:
smtp://foobar@example.com:abc@smtp.example.com:465
我想用固定数量的星号(例如 abc)替换密码(在本例中为 *****),以便对用户隐藏。
到目前为止,我尝试过大量使用环视:
def starPassword(route):
"""
>>> starPassword("smtp://foobar@example.com:abc@smtp.example.com:465")
'smtp://foobar@example.com:*****@smtp.example.com:465'
>>> starPassword("smtp://foobar:abc@smtp.example.com:25")
'smtp://foobar:*****@smtp.example.com:465'
"""
# Regex explanation:
# (?<=\w+://\w+:) matches the colon before the password without consuming
# ([^@]+) matches the password (TODO use a better match, passwords might contain @! Check escaping)
# (?=@[^@]+$) matches the @ after the server, plus the rest of the URL
return re.sub("(?<=:)([^@]+)(?=@[^@]+$)", "*****", route)
if __name__ == "__main__":
import doctest
doctest.testmod()
不幸的是,这个正则表达式有几个问题,包括:
- 第一个单元测试成功,但第二个单元测试失败,因为协议(protocol)(
smtp://冒号匹配)。我试过(?<=\w+://\w+:),但后视需要自定义长度。也许我可以使用这些 URL 部分并替换为类似\1*****\2)的内容或类似的? - 包含
@的密码和/或:不会被识别,我什至不确定它们是如何转义的(这就是我不使用非贪婪标志的原因)
请注意,我不能使用 Python3(urlparse 模块)——我也不想使用第三方库,除非绝对必要。
预先感谢您为我指明正确的方向。
请您参考如下方法:
您可以使用 urlparse.urlsplit() function (在 Python 2 中也可用); .netloc 参数将包含用户名和密码(两者都将被转义为不包含纯 : 或 @ 字符,请参阅 RFC 3986 Section 3.2.1 ):
import urlparse
def starPassword(route):
parsed = urlparse.urlsplit(route)
if '@' not in parsed.netloc:
return route
userinfo, _, location = parsed.netloc.partition('@')
username, _, password = userinfo.partition(':')
if not password:
return route
userinfo = ':'.join([username, '*****'])
netloc = '@'.join([userinfo, location])
parsed = parsed._replace(netloc=netloc)
return urlparse.urlunsplit(parsed)
演示:
>>> starPassword('smtp://foobar%40example.com:abc@smtp.example.com:465')
'smtp://foobar%40example.com:*****@smtp.example.com:465'
>>> starPassword('smtp://foobar:abc@smtp.example.com:25')
'smtp://foobar:*****@smtp.example.com:25'
>>> starPassword('smtp://smtp.example.com:1234')
'smtp://smtp.example.com:1234'
>>> starPassword('smtp://foo@smtp.example.com:42')
'smtp://foo@smtp.example.com:42'
