首页 > 解决方案 > REGEX - 如何递归地捕获一个组?

问题描述

{"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

标签: regexcapture

解决方案


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

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

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

.*?{"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 将字符串转换为对象列表可能会有所帮助。与依赖您自己的正则表达式相比,使用起来更容易,更易于维护和健壮得多。


推荐阅读