匹配 SSH url 部分的正则表达式

Regex to match SSH url parts

给定以下 SSH 网址:

git@github.com:james/example
git@github.com:007/example
git@github.com:22/james/example
git@github.com:22/007/example

如何拉取以下内容:

{user}@{host}:{optional port}{path (user/repo)}

如您在示例中所见,其中一个用户名是数字而不是端口。我不知道如何解决这个问题。端口也不总是在 URL 中。

我当前的正则表达式是:

^(?P<user>[^@]+)@(?P<host>[^:\s]+)?:(?:(?P<port>\d{1,5})\/)?(?P<path>[^\].*)$

不确定还能尝试什么。

惰性量词来拯救!

这似乎运行良好并满足可选端口:

^
(?P<user>.*?)@
(?P<host>.*?):
(?:(?P<port>.*?)/)?
(?P<path>.*?/.*?)
$

换行符不是正则表达式的一部分,因为启用了 /x 修饰符。如果您不使用 /x.

,请删除所有换行符

https://regex101.com/r/wdE30O/5


谢谢@Jan for the

如果您使用 Python,您可以编写自己的解析器:

from parsimonious.grammar import Grammar
from parsimonious.nodes import NodeVisitor

data = """git@github.com:james/example
git@github.com:007/example
git@github.com:22/james/example
git@github.com:22/007/example"""

class GitVisitor(NodeVisitor):
    grammar = Grammar(
        r"""
        expr        = user at domain colon rest

        user        = word+
        domain      = ~"[^:]+"
        rest        = (port path) / path

        path        = word slash word
        port        = digits slash

        slash       = "/"
        colon       = ":"
        at          = "@"
        digits      = ~"\d+"
        word        = ~"\w+"

        """)

    def generic_visit(self, node, visited_children):
        return visited_children or node

    def visit_user(self, node, visited_children):
        return {"user": node.text}

    def visit_domain(self, node, visited_children):
        return {"domain": node.text}

    def visit_rest(self, node, visited_children):
        child = visited_children[0]
        if isinstance(child, list):
            # first branch, port and path
            return {"port": child[0], "path": child[1]}
        else:
            return {"path": child}

    def visit_path(self, node, visited_children):
        return node.text

    def visit_port(self, node, visited_children):
        digits, _ = visited_children
        return digits.text

    def visit_expr(self, node, visited_children):
        out = {}
        _ = [out.update(child) for child in visited_children if isinstance(child, dict)]
        return out

gv = GitVisitor()
for line in data.split("\n"):
    result = gv.parse(line)
    print(result)

哪个会产生

{'user': 'git', 'domain': 'github.com', 'path': 'james/example'}
{'user': 'git', 'domain': 'github.com', 'path': '007/example'}
{'user': 'git', 'domain': 'github.com', 'port': '22', 'path': 'james/example'}
{'user': 'git', 'domain': 'github.com', 'port': '22', 'path': '007/example'}

解析器允许您在此处显然存在的一些歧义。