当前位置: 首页 > 编程语言 > C#

如何进行平衡组捕获?分享

时间:2023-04-10 18:21:04 C#

如何做均衡的群抓取?假设我有这个文本输入。tes{}tR{R{abc}aD{mnoR{xyz}}}我想提取ff输出:R{abc}R{xyz}D{mnoR{xyz}}R{R{abc}aD{mnoR{xyz目前,我只能使用来自msdn的平衡组方法提取{}组内的内容。这是模式:^[^{}]*(((?'Open'{)[^{}]*)+((?'Target-Open'})[^{}]*)+)*(?(Open)(?!))$有人知道如何在输出中包含R{}和D{}吗?我认为这里需要一种不同的方法。一旦匹配到第一个较大的组R{R{abc}aD{mnoR{xyz}}}(请参阅我对可能的拼写错误的评论),您将无法获得内部子组,因为不允许捕获正则表达式单个R{...}组。所以必须有一些方法来捕获而不是消耗,显而易见的方法是使用积极的前瞻。从那里,你可以把你使用的表达式,虽然有一些变化以适应新的焦点变化,我想出了:(?=([A-Z](?:(?:(?'O'{)[^{}]*)+(?:(?'-O'})[^{}]*?)+)+(?(O)(?!))))[我也将'open'重命名为'O'并删除了闭括号的命名捕获,以使其更短并避免匹配中的噪音]在regexhero.net(我目前知道的唯一免费的.NET正则表达式测试程序)中,我得到了以下捕获组:1:R{R{abc}aD{mnoR{xyz}}}1:R{abc}1:D{mnoR{xyz}}1:R{xyz}正则表达式的分解:(?=#Openingpositivelookahead([AZ]#开头的捕获组和任何大写字母(以匹配R&D)(?:#第一个非捕获组开头(?:#第二个非捕获组开头(?'O'{)#获取命名的开头大括号[^{}]*#Anynon-brace)+#关闭第二个非捕获组并根据需要重复多次(?:#Thirdnon-capturegroupopening(?'-O'})#Removalofnamedopeningbrace当遇到[^{}]*?#任何其他非大括号字符,以防有更多嵌套大括号)+#关闭第三个非捕获组并根据需要重复多次)+#关闭第一个非捕获组分组并重复多次多个并排嵌套大括号是必需的(?(O)(?!))#Conditiontopreventunbalancedbraces)#Closecapturegroup)#Closepositivelookahead以下在C#中不起作用我实际上想尝试如何它应该在PCRE引擎上工作,因为可以选择使用递归正则表达式,我认为它更容易,因为我更熟悉它并且它产生更短的正则表达式:)(?=([A-Z]{(?:[^{}]|(?1))+}))regex101demo(?=#Openingpositivelookahead([AZ]#Openingcapturegroupandanyuppercaseletter(tomatchR&D){#Openingbrace(?:#Openingnon-捕获组[^{}]#匹配非大括号|#OR(?1)#递归第一个捕获组)+#关闭非捕获组并根据需要重复多次}#关闭大括号)#关闭捕获组)#关闭正前瞻我不确定单个正则表达式是否会做你想做的事情:这些嵌套的子字符串总是把它搞砸一种解决方法可能是以下算法(用Java编写,但我想对C#的翻译不会那么难):/***在输入字符串中查找正则表达式的所有匹配项(即包括子/嵌套匹配项)。**@paraminput*输入字符串。*@paramregex*正则表达式模式。它必须以嵌套最多的子字符串为目标。例如,给定以下输入字符串*A{01B{23}45C{67}89},如果要捕获每个X{*}子字符串(其中X是大写字母),*您必须使用[AZ][{][^{]+?[}]或[AZ][{][^{}]+[}]而不是[AZ][{].+?[}]。*@paramformat*格式必须跟matches=newLinkedHashMap();模式pattern=Pattern.compile(regex);匹配器匹配器=pattern.matcher(input);//如果找到子字符串while(matcher.find()){//使用计数器创建一个唯一的替换字符串Stringreplace=String.format(format,counter++);//将关系“替换字符串-->初始子字符串”存储在队列中matches.put(replace,matcher.group());Stringend=input.substring(matcher.end(),输入.length());Stringstart=input.substring(0,matcher.start());//用创建的唯一替换字符串替换找到的子字符串input=start+replace+end;//重复新的输入字符串(伪造原始的matcher.find()实现)matcher=pattern.matcher(input);}List>entries=newLinkedList>(matches.entrySet());//对于队列的每个关系“替换字符串-->初始子字符串”for(inti=0;icurrent=entries.get(i);//对于可能在当前关系之前找到的每个关系(即更多嵌套)for(intj=0;jprevious=entries.get(j);//如果当前初始子字符串包含前一个替换字符串if(current.getValue().contains(previous.getKey())){//用当前初始子串中的前一个初始子串替换之前的替换字符串current.setValue(current.getValue().replace(previous.getKey(),previous.getValue()));}}}returnnewLinkedList(匹配.values());所以在你的情况下:Stringinput="tes{}tR{R{abc}aD{mnoR{xyz}}}";字符串正则表达式="[AZ][{][^{}]+[}]";findAllMatches(输入,正则表达式,空);返回:R{abc}R{xyz}D{mnoR{xyz}}R{R{abc}aD{mnoR{xyz}}}.Net正则表达式中的平衡组让您可以准确控制捕获的内容,.Net正则表达式引擎保留一个组的所有捕获的完整历史记录(而不是只捕获大多数其他类型的每个组的最后一次出现)不同的MSDN示例有点过于复杂。一个更简单的匹配嵌套结构的方法是:(?>(?)p{Lu}{#PushtotheOstack,andmatchanupper-caseletterand{|#OR}(?)#Match}andpopfromthestack|#ORp{Ll}#匹配小写字母)+(?(O)(?!))#确保堆栈为空或在一行中:(?>(?)p{Lu}{|}(?)|p{Ll})+(?(O)(?!))RegexStorm上的工作示例在您的示例中,它还匹配字符串开头的“tes”,但别担心,我们没做完。通过一个小的修复,我们还可以捕获R{...}对之间的事件:(?>(?)p{Lu}{|}(?)|p{Ll})+(?(O)(?!))每场比赛都会有一个名为“目标”的组,并且每个这样的组在每次出现时都会有一个捕获-你只关心这些捕获。RegexStorm工作示例——点击Table选项卡,勾选${Target}的4个capture以上为C#学习教程:Howtodobalancedgroupcapture?分享的所有内容,如果对你有用,需要了解更多C#学习教程,希望大家多多关注——你也可以看看:本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: