Skip to main content
 首页 » 编程设计

python之邮件 URL 中的正则表达式匹配密码

2025年05月04日23pengyingh

假设我有一个像这样的 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'