【问题标题】:Regex matching mixed string segments containing operator, string designator, and curly-brace group正则表达式匹配包含运算符、字符串指示符和花括号组的混合字符串段
【发布时间】:2022-10-04 17:24:43
【问题描述】:

我正在寻找一个 C# 正则表达式解决方案来匹配/捕获一些小而复杂的数据块。我的数据库中有数千个非结构化数据块(来自第三方数据存储),看起来类似于:

not BATTCOMPAR{275} and FORKCARRIA{ForkSpreader} and SIDESHIFT{WithSSPassAttachCenterLine} and TILTANGLE{4up_2down} and not AUTOMATSS{true} and not FORKLASGUI{true} and not FORKCAMSYS{true} and OKED{true}

我希望能够将其拆分为离散的部分(正则表达式匹配/捕获),如下所示:

not BATTCOMPAR{275} 
and FORKCARRIA{ForkSpreader} 
and SIDESHIFT{WithSSPassAttachCenterLine} 
and TILTANGLE{4up_2down} 
and not AUTOMATSS{true} 
and not FORKLASGUI{true} 
and not FORKCAMSYS{true} 
and OKED{true}
CONTAINER{Container}

数据将始终符合以下规则:

  • 在每个数据块的末尾会有一个用大括号括起来的字符串,如下所示:{275}
  • “花括号分组”总是出现在以notandand not 开头的字符串的末尾,或者什么都没有。 "nothing" 与and 相同,并且仅在它是字符串中的第一个块时才会出现。例如,如果我的and OKED{true} 出现在字符串的开头,则and 将被省略,OKED{true} 将不加前缀(空字符串)。但它与and 相同。
  • 在运算符(andnotand not 或什么都没有)之后总会有一个字符串指示符,它在花括号分组之前结束。示例:BATTCOMPAR
  • 出现字符串指示符将始终触及花括号分组,中间没有空格,但我不是 100% 确定。正则表达式应适应字符串指示符和左花括号之间可能出现空格的情况。
  • 以上几点总结#1:每个块将有3个不同的子组:运算符(如and not)、字符串指示符(如BATTCOMPAR)和花括号分组(如{ForkSpreader}) .
  • 上述要点的总结 #2:每个块将以列出的 3 个运算符之一开始,或者不以任何字符开头,并以右花括号结束。保证整个段中只有 1 个左花括号和 1 个右花括号,并且它们总是在段的末尾分组在一起。不用担心在该段的其他部分遇到额外的/杂散的花括号。

我尝试了几种不同的正则表达式结构:

匹配花括号分组:

Regex regex = new Regex(@"{(.*?)}");
return regex.Matches(str);

以上几乎可以工作,但只得到花括号分组,而不是随之而来的运算符和字符串指示符。

根据字符串前缀捕获块,尝试匹配运算符字符串:

var capturedWords = new List<string>();
string regex = $@"(?<!\w){prefix}\w+";

foreach ( Match match in Regex.Matches(haystack, regex) ) {
    capturedWords.Add(match.Value);
}

return capturedWords;

以上部分有效,但仅获得运算符,而不是我需要的整个块:(运算符 + 字符串指示符 + 花括号分组)

提前感谢您的帮助。

【问题讨论】:

标签: c# regex regex-group


【解决方案1】:

最简单的解决方案似乎是使用这个正则表达式和split

new Regex(@"[ ](?=and)");

它只是在and 后面的空格上拆分:

Regex regex = new Regex(@"[ ](?=and)");
return regex.Split(str);

编辑(每条评论):

如果您使用替换(|),您可以look ahead 用于您想要拆分的任何单词,如下所示:

new Regex(@"s(?=and|CONTAINER)");

如果您愿意,可以添加其他单词。

我假设CONTAINER 前面有一个space。否则很难让它“安全”。

在这里更新了结果:NetRegexBuilder

【讨论】:

  • 谢谢波尔。我相信这会很好,但我接受了 Ryan 的回答,因为它使用了更具体的匹配,如果我的数据发生变化并且“基于和”的方法失效,这可能会在未来有所帮助。再次感谢。
  • 如何修改正则表达式以找到CONTAINER{Container}(之前没有运算符)?
  • 对不起,我不清楚。前面没有空格,需要匹配 XXX{YYY} - 换句话说 - 任何包含大括号的“单词”。之前、之后或内部可能没有空格。但之前和/或之后也可能有空格。
  • 请编辑有问题的输入字符串。
  • 波尔,我已经这样做了。唯一的绝对值是封闭的花括号。字符串的所有其他部分都应被视为“示例”——它可以是任何东西。
【解决方案2】:

这对我有用:/([ands|ors|nots]+)?.*?({.*?})/mg on Regex Tester

DotNet Fiddle 上,这对我有用:

() - 捕获组

[and\s|or\s|not\s]+? - 以单个 and、or、not 或组合开头,后跟一个空格

.*? 任意字符组合或无字符,例如。电池比较

\{.*?\} 用花括号括起来的最后一部分,包含任意字符组合或不包含任何字符

string test = "not BATTCOMPAR{275} and FORKCARRIA{ForkSpreader} and SIDESHIFT{WithSSPassAttachCenterLine} and TILTANGLE{4up_2down} and not AUTOMATSS{true} and not FORKLASGUI{true} and not FORKCAMSYS{true} and OKED{true}";
Regex r = new Regex("([and\s|or\s|not\s]+?.*?\{.*?\})", RegexOptions.Multiline);

//or if you need to account for matches where there is no
//prepending words ie. and, not and
//Regex r = new Regex("([and\s|or\s|not\s|]+?.*?\{.*?\}|.*?\{.*?\})", RegexOptions.Multiline);

MatchCollection matches = r.Matches(test);
        
foreach(Match m in matches)
{
    Console.WriteLine(m.Value); 
}

印刷:

//not BATTCOMPAR{275}
//and FORKCARRIA{ForkSpreader}
//and SIDESHIFT{WithSSPassAttachCenterLine}
//and TILTANGLE{4up_2down}
//and not AUTOMATSS{true}
//and not FORKLASGUI{true}
//and not FORKCAMSYS{true}
//and OKED{true}

【讨论】:

  • [charclasses](只提)
  • @bobblebubble 是的。我记得当我的邻居朋友在 1980 年把它放在 NES 上时……记忆有点模糊。一定是 1986 年 - Bubble_Bobble
  • @bobblebubble 我完全搞砸了,当我写这篇文章时,它仍然有效。是的,我累了,我在想w 是空格,而s 是空格。现在我明白你为什么要放你放的东西了。我将我的答案固定为我想要的。
  • 不用担心,它仍然可以工作:) PS:看看[ands|ors|nots]+ 匹配什么。
  • 我认为您要使用的是group,而不是character-class,类似于(?:ands|ors|nots)+.*?{.*?},但是如果缺少and|or|not 部分并且巧合使用w 使其起作用,则此模式将不起作用,所以像(?:w.*?)?{.*?} 这样的一些正则表达式最终证明就足够了,但这只是我的猜测。现在我祝你美梦,感谢你的谈话:)
【解决方案3】:

你需要使用

((?:and|or)(?:s+not)?|not)?s*(w+){([^{}]*)}

请参阅regex demo细节

  • - 单词边界
  • ((?:and|or)(?:s+not)?|not)? - 可选组 1:
  • s* - 零个或多个空格(* 表示零个或多个)
  • (w+) - 第 2 组:一个或多个单词字符
  • { - 一个 { 字符
  • ([^{}]*) - 第 3 组:除 {} 之外的任何零个或多个字符
  • } - } 字符。

【讨论】:

    猜你喜欢
    • 2019-01-05
    • 2016-04-21
    • 2018-03-15
    • 2015-07-31
    • 2021-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多