假设我有这样的SMTP / IMAP / POP3登录网址:
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()
不幸的是,这个正则表达式有几个问题,包括:
smtp://
冒号匹配)。我尝试了(?<=\w+://\w+:)
,但外观需要自定义长度。也许我可以使用这些URL部分并替换为\1*****\2)
或类似的东西?@
和/或:
的密码将无法识别,我甚至不确定它们是如何转义的(这就是我不使用非贪婪标志的原因) 请注意,我不能使用Python3(urlparse
模块) - 除非严格需要,否则我不想使用第三方库。
提前感谢我指出了正确的方向。
答案 0 :(得分:3)
您可以使用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'
答案 1 :(得分:2)
使用此正则表达式:
(?<=:)([^@:]+)(?=@[^@]+$)
我将:
添加到[^@]
。因此,此正则表达式将匹配:
和@
之间的字符串,而中间没有任何:
或@
。
print( re.sub("(?<=:)([^@:]+)(?=@[^@]+$)", "*****",
"smtp://foobar:abc@smtp.example.com:25") )
smtp://foobar:*****@smtp.example.com:25