【问题标题】:REGEX - How to capture a group recursively?REGEX - 如何递归地捕获一个组?
【发布时间】:2021-11-29 08:09:24
【问题描述】:

{"dir":"false", "bytes":158481, "parent_folder":"/Annie/FROM OLD DVDS", "name":"1.jpg"}, {"dir":"false" , "bytes":382661, "parent_folder":"/Annie/FROM OLD DVDS", "name":"2.jpg"}, {"dir":"false", "bytes":1455205, "parent_folder": "/Annie/FROM OLD DVDS", "name":"3.jpg"}

这是我当前的 REGEX 字符串,它只捕获第一个匹配项:

(false.+\"name\"\:\")(.+\.(jpg|jpeg|png))(\")

我想捕捉每个名字,而不仅仅是第一个。目前它只解析最后一个 3.jpg。

想要的结果:

1.jpg、2.jpg、3.jpg

【问题讨论】:

  • 你为什么要使用正则表达式?这是(编辑:几乎)JSON。您是否缺少一些方括号?你用什么语言工作?
  • 是的。输出为 JSON。但我的问题是,有时它会捕获一个文件夹,这使得 dir 值 - true。我希望有更好的选择。我的知识仅限于 JSON/JToken 解析。语言是 C#。如果可能,我想只使用 JSON/XPath/Regex 进行解析。
  • 问题是,你有一个对象数组。每个对象都有一个dirbytesparent_foldername 属性。您只需要每个的 name 属性。查找您想与 C# 一起使用的任何 JSON 库。也许this page.
  • 如果可能的话,我只是在寻找关于正则表达式的快速解决方案。
  • 给出示例时的基本规则是显示所需的返回值。

标签: regex capture


【解决方案1】:

首先...除非您知道name 属性将出现的确切次数,否则您将无法使用正则表达式捕获所有名称。例如,如果您知道字符串将包含 3 个 name 属性,那么您可以编写一个看起来像 .*"name":"(.*?)".*"name":"(.*?)".*"name":"(.*?)".* 的正则表达式,它将捕获 3 组名称。

您的正则表达式没有捕获名字,它实际上捕获了姓氏。这是因为您使用了一个贪婪的量词和一个通配符.*。您必须考虑到 {} 标记表示一个新对象。所以你需要使用[^{}]*? 来确保你一次只看一个对象。 *? 量词是一个惰性匹配,因此它只会匹配所需数量的字符,而 +* 将匹配尽可能多的字符。

您还可以利用非捕获组 (?:) 匹配扩展而不捕获它们。这里的想法是确保我们捕获的唯一内容是名称的值。与您当前的正则表达式不同,它捕获多个组。最终的正则表达式如下所示:

.*?{"dir":"false"[^{}]*?"name":"([^{}]*?(?:jpg|jpeg|png))"}.*?

在 C# 中,导入 System.Text.RegularExpressions 以满足您的所有正则表达式需求。您可以使用Regex.Matches 查找正则表达式的所有匹配项。遍历生成的 MatchCollection 并从匹配中提取所有匹配和捕获。在您的情况下,您的代码可能看起来像

    string text = @"{""dir"":""false"", ""bytes"":158481, ""parent_folder"":""/Annie/FROM OLD DVDS"", ""name"":""1.jpg""}, {""dir"":""false"", ""bytes"":382661, ""parent_folder"":""/Annie/FROM OLD DVDS"", ""name"":""2.jpg""}, {""dir"":""false"", ""bytes"":1455205, ""parent_folder"":""/Annie/FROM OLD DVDS"", ""name"":""3.jpg""}";
    string search = ".*?{\"dir\":\"false\"[^{}]*?\"name\":\"([^{}]*?(?:jpg|jpeg|png))\"}.*?";
    MatchCollection matches = Regex.Matches(text, search);
    foreach(Match match in matches){
        GroupCollection groups = match.Groups;
        Console.WriteLine(groups[1].Value);
    }

根据您的用例(正如@adam 建议的那样),隔离每个对象并使用 Json Deserializer 将字符串转换为对象列表可能会有所帮助。与依赖您自己的正则表达式相比,使用起来更容易,更易于维护和健壮。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-10
    • 1970-01-01
    • 1970-01-01
    • 2013-01-02
    • 2019-10-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多