正则表达式匹配 SSH url 部分

Posted

技术标签:

【中文标题】正则表达式匹配 SSH url 部分【英文标题】:Regex to match SSH url parts 【发布时间】:2020-01-02 00:48:10 【问题描述】:

鉴于以下 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 portpath (user/repo)

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

我目前的正则表达式是:

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

不知道还能尝试什么。

【问题讨论】:

一个小的解析器? @Jan 你的意思是不使用正则表达式来做到这一点? 看我的答案bewlo(但选择另一个较短的)。 【参考方案1】:

懒惰的量词来拯救!

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

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

换行符不是正则表达式的一部分,因为/x 修饰符已启用。如果您不使用/x,请删除所有换行符。

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


感谢@Janoptimizations。

【讨论】:

@ThatGuy343 正确,007 出现在冒号 : 之后 @ThatGuy343 如果007 不是端口,那么哪个捕获组应该包含它?是否应该完全忽略该条目,因为它是“无效的”?我的目标是创建一个简单的解析器,而不是验证器 007 是用户名,也是路径的一部分。路径组是这样的:username/repo @MonkeyZeus +1 我认为你很接近,但是如果 git@github.com:22/james ...它将匹配路径为 22/james,我相信什么时候应该只是 james。 .. @MonkeyZeus: +1 但有一些优化:a)使用详细模式,b)你现在使用的非捕获是多余的,c)去掉正斜杠港口。总之看regex101.com/r/wdE30O/5【参考方案2】:

如果您使用的是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'

解析器允许一些歧义,你显然在这里。

【讨论】:

你知道,我在两个多月前开始参加正则表达式标签以提高我的技能,我觉得我取得了很好的进步;不确定我是否是专家,但至少正则表达式不再显得过于神秘(我大部分归功于使用正则表达式可视化工具)。我从来没有想过我会进入解析器,但你的帖子是如此冷漠“嗯,试试这个解析器”,这可能是我的下一次冒险,哈哈 @MonkeyZeus:很高兴这里有另一个旅行者。一个很好的起点是tomassetti.me/guide-parsing-algorithms-terminology 用于一般概述,github.com/erikrose/parsimonious 用于Python 中的 PEG 解析器。它确实拓宽了可能性。 @MonkeyZeus:无耻的自我宣传:你可以很好地将正则表达式和解析器结合起来,两全其美,见***.com/a/57749422/1231450

以上是关于正则表达式匹配 SSH url 部分的主要内容,如果未能解决你的问题,请参考以下文章

无法使用 Java 正则表达式匹配字符串的最后部分 [重复]

Nginx Location 正则表达式

可选文件扩展名的正则表达式匹配

使用正则表达式重新字符串匹配提取 URL 链接 - Python

正则表达式匹配特定的 URL 片段而不是所有其他 URL 可能性

正则表达式匹配URL