【问题标题】:Regex - Extract Words within brackets and quotes if it starts with a keyword only正则表达式 - 如果仅以关键字开头,则提取括号和引号中的单词
【发布时间】:2017-08-08 23:20:39
【问题描述】:

我有以下字符串:

[The quick] brown fox [mykey*="is a super-fast9"] animal [mykey^="that"] can run "very rapid" and [otherkey="effortlessly"].

我需要提取双引号内的单词(以空格分隔),同时在以特定关键字(mykey)开头的括号内。

到目前为止我有:

快速

mykey*="是

一个

超快9"

mykey^="那个"

otherkey="毫不费力"

但我想要:

一个

超快9

那个

示例链接:https://regex101.com/r/zmNse1/2

【问题讨论】:

  • 这并不能回答您的问题,但是如果您经常在应用程序中执行此操作并且这不是一次性的,您可能需要考虑编写解析器而不是使用正则表达式。你可以使用像 ANTLR 这样的解析器生成器,所以你不需要从头开始。
  • 让我仔细检查一下:您需要[key="...."] 子字符串中双引号内的空格分隔值吗?并希望它们作为一个平面列表?
  • @WiktorStribiżew 是的,正确...并且仅当括号以特定键开头时... [mykey ....

标签: c# .net regex


【解决方案1】:

Wiktor 提供的解决方案是最合乎逻辑的解决方案,但对于 RegEx 挑战,请参阅此 Pattern \[(?!mykey)[^\[]+|([^\s\[=\"]+)(?=[^\"]*\"\]),检查组 #1 Demo

\[                  # "["
(?!                 # Negative Look-Ahead
  mykey             # "mykey"
)                   # End of Negative Look-Ahead
[^\[]               # Character not in [\[] Character Class
+                   # (one or more)(greedy)
|                   # OR
(                   # Capturing Group (1)
  [^\s\[=\"]        # Character not in [\s\[=\"] Character Class
  +                 # (one or more)(greedy)
)                   # End of Capturing Group (1)
(?=                 # Look-Ahead
  [^\"]             # Character not in [\"] Character Class
  *                 # (zero or more)(greedy)
  \"                # """
  \]                # "]"
)                   # End of Look-Ahead

【讨论】:

  • 太棒了。非常感谢。
  • 是的,我已经接受了你和 Wiktor 作为答案,因为在大文本中运行你的正则表达式真的很慢,所以在这种情况下,我可能最终会使用 Wiktor,如果文本更短,我会用过你的。非常感谢
  • @GabrielRodriguez 如果你最终使用了一个更有效的解决方案,为什么不接受它来告诉别人呢?
  • 嗨@WiktorStribiżew 我实际上最终在你的答案和AlphaBravo之间使用了某种混合体。为了简单起见,也为了让这个问题对未来的读者有用,我将 AlphaBravo 标记为官方答案,因为它更接近我提出的确切问题。但同样,两者都很好,感谢您的回复。
【解决方案2】:

您可以使用相对简单的正则表达式匹配所需的子字符串并捕获引号之间的部分,然后使用 1 个或多个空格模式拆分捕获:

var pattern = "\\[mykey[^][=]+=\"([^\"]*)\"]";
var s = "[The quick] brown fox [mykey*=\"is a  super-fast9\"] animal [mykey^=\"that\"] can run \"very rapid\".";
var result = Regex.Matches(s, pattern)
    .Cast<Match>()
    .SelectMany(v => v.Groups[1].Value.Trim().Split(new[] {" "}, StringSplitOptions.RemoveEmptyEntries))
    .ToList();
Console.WriteLine(string.Join("\n", result));

the C# demo

模式是

\[mykey[^][=]+="([^"]*)"]

请参阅regex demo

模式详情

  • \[ - 文字 [
  • mykey - 文字子串
  • [^][=]+ - 除了[]= 之外的 1 个或多个字符
  • = - 等号
  • " - 双引号
  • ([^"]*) - 第 1 组:除 " 之外的任何 0+ 个字符
  • "] - 文字 "] 子字符串。

请注意,捕获的值首先从前导/尾随空格中修剪(使用.Trim())以避免结果中出现空值。 @"\s+" 匹配 1 个或多个空格字符。 .Split(new[] {" "}, StringSplitOptions.RemoveEmptyEntries) 用空格分割 Group 1 值。

【讨论】:

  • 如果可以有mykey="111 222",则需要在正则表达式中将+替换为*\[mykey[^][=]*="([^"]*)"]
【解决方案3】:

这个正则表达式应该做你想做的事:
(?&lt;=\[mykey.?="[^]]*)[\w-]+(?=[^]]*"\])

演示here

我认为不能有嵌套的括号。另外我不知道如何处理mykey= 之间的^*,所以我允许使用可选的通配符。
您可能需要转义代码中的反斜杠。

【讨论】:

    【解决方案4】:

    对于它的价值:由于其他人提到了字符串解析,我想我会在这里给出一个实现。字符串解析选项总是冗长的,但比正则表达式快几个数量级。作为一个经常使用 Regex 的人,我仍然可以说我更喜欢字符串函数。这个答案的唯一复杂之处是您必须知道您的赋值运算符是什么,并且您的字符串值中不能有转义双引号。我写的相当冗长,不过如果你想要更少的代码字节,你可以删掉一些条件或缩短一些行。

    List<string> GetValuesByKeyword(string keyword, string input)
    {
        var vals = new List<string>();
        int startIndex = input.IndexOf("[");
        while (startIndex >= 0)
        {
            var newValue = "";
            if (startIndex >= 0 && startIndex < input.Length - 1)
            {
                var squareKey = input.Substring(startIndex + 1).Trim();
                if (squareKey.StartsWith(keyword))
                {
                    var squareAssign = squareKey.Substring(keyword.Length).Trim();
                    var assignOp = StartsWithWhich(squareAssign, "=", "+=", "-=", "*=", "/=", "^=", "%=");
                    if (!string.IsNullOrWhiteSpace(assignOp))
                    {
                        var quotedVal = squareAssign.Substring(assignOp.Length).Trim();
                        if (quotedVal.StartsWith("\""))
                        {
                            var endQuoteIndex = quotedVal.IndexOf('"', 1);
                            if (endQuoteIndex > 0)
                            {
                                newValue = quotedVal.Substring(1, endQuoteIndex - 1);
                            }
                        }
                    }
                }
            }
            if (!string.IsNullOrWhiteSpace(newValue))
            {
                vals.Add(newValue);
                startIndex = input.IndexOf("[", input.IndexOf(newValue, startIndex) + newValue.Length);
            }
            else startIndex = input.IndexOf("[", startIndex + 1);
        }
        return string.Join(" ", vals).Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList();
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-22
      • 1970-01-01
      • 1970-01-01
      • 2022-10-18
      相关资源
      最近更新 更多