最好的方法可能是使用自定义解析器和解析状态机样式:首先确定站点,然后执行特定于站点的路由:
patterns={
'github.com': r'/(?P<user>[^/]+)/(?P<project>[^/#]+)(?:[/#]|$)',
'sourceforge.net': r'/projects/(?P<project>)[^/]+/',
<etc etc etc>
}
import urllib.parse
pr = urllib.parse.urlparse(url)
site = pr.hostname
parts = re.match(patterns[site], pr.path).groupdict()
代替正则表达式,路径也可以用状态机解析,如果前面有进一步的分裂,那么它可能更易于管理。
(
they recommend a
enum
instead of magic strings for states
;我使用魔术字符串只是为了简化示例代码)
def parse_github(path):
r = argparse.Namespace()
pp = path.split('/')
p = pp.pop(0)
assert(p == '')
state='user'
for p in pp:
if state=='user':
r.user=p
state='project'
else if state=='project':
r.project==p
state='kind'
else if state=='kind':
if p in {'pull','commit','blob'}:
state=p
else: break
else if state=='pull':
r.pr=p
state='pr_tab'
<etc etc>
return r
原则上,这里没有递归结构,因此
可以
只使用正则表达式,但这很尴尬:
site_patterns = [
r"(github\.com/)[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+",
r"(bitbucket\.org/)[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+",
r"(gitlab\.com/)[a-zA-Z0-9_.-]+(?:/[a-zA-Z0-9_.-]+)+",
r"(sourceforge\.net/projects/)[a-zA-Z0-9_.-]+",
<etc etc etc>
]
r_all = re.compile("("+"|".join(site_patterns)+")")