【问题标题】:Need pattern for a complex Regex Split复杂正则表达式拆分的需要模式
【发布时间】:2013-09-07 01:24:42
【问题描述】:

我想拆分以下字符串

// Comments
KeyA : SomeType { SubKey : SubValue } KeyB:'This\'s a string'
KeyC : [ 1 2 3 ] // array value

进入

KeyA
:
SomeType
{ SubKey : SubValue }
KeyB
:
This's a string
KeyC
:
[ 1 2 3 ]

(: 和空格是分隔符,尽管 : 保留在结果中;cmets 被忽略;{}、[] 或 '' 之间没有分隔符)

我可以使用 Regex Split 或 Match 来实现吗?如果是这样,正确的模式是什么?对模式字符串的评论将不胜感激。

此外,如果输入字符串无效,也希望抛出异常或返回错误消息(请参阅下面的注释)。

谢谢。

【问题讨论】:

  • 输入"A{B[C}D]" 会发生什么?给"A'B{C'"?给"A{B{C}D}E"?
  • 对于第一个,它应该返回一个错误(最好带有一些用于调试的上下文)。对于第二个,它应该返回 A , {B{C}D} , E
  • 您是否有理由将其强制为正则表达式?这将更容易(非常!)编写为递归下降解析器。
  • 我最初认为可以通过不那么复杂的正则表达式模式来实现。但是,我已经按照您的建议实现了自定义 Lexer。

标签: c# .net regex tokenize lexer


【解决方案1】:

你可以使用这个模式...

string pattern = @"(\w+)\s*:\s*((?>[^\w\s\"'{[:]+|\w+\b(?!\s*:)|\s(?!\w+\s*:|$)|\[[^]]*]|{[^}]*}|\"(?>[^\"\\]|\\.)*\"|'(?>[^'\\]|\\.)*')+)\s*";

...有两种方式:

  1. 使用 Match 方法,该方法将使用组 1 中的键和组 2 中的值为您提供所需的内容
  2. 使用拆分方法,但必须删除所有空结果。

如何构建模式的第二部分(: 之后)?

首先要避免有问题的字符:[^\w\s\"'{[:]+ 然后,您允许这些字符中的每一个,但在特定情况下:

  • \w+\b(?!\s*:)一个不是关键的词
  • \s(?!\w+\s*:|$) 不在值末尾的空格(修剪它们)
  • \[[^]]*] 方括号括起来的内容
  • {[^}]*} 与大括号相同
  • "(?>[^"\\]|\\\\|\\.)*" 双引号之间的内容(允许转义双引号)
  • '(?>[^'\\]|\\\\|\\.)*' 单引号也一样

请注意,括号或引号内的冒号问题是可以避免的。

【讨论】:

    【解决方案2】:

    当您访问 KeyC 时,我不太确定您在寻找什么。您如何知道 KeyB 的字符串值何时结束而 KeyC 的字符串何时开始? 'this\'s is a string' 或换行符后是否有冒号?下面是一个让您入门的示例:

    [TestMethod]
    public void SplitString()
    {
        string splitMe = "KeyA : SubComponent { SubKey : SubValue } KeyB:This's is a string";
        string pattern = "^(.*):(.*)({.*})(.*):(.*)";
    
        Match match = Regex.Match(splitMe, pattern);
    
        Assert.IsTrue(match.Success);
        Assert.AreEqual(6, match.Groups.Count); // 1st group is the entire match
        Assert.AreEqual("KeyA", match.Groups[1].Value.Trim());
        Assert.AreEqual("SubComponent", match.Groups[2].Value.Trim());
        Assert.AreEqual("{ SubKey : SubValue }", match.Groups[3].Value.Trim());
        Assert.AreEqual("KeyB", match.Groups[4].Value.Trim());
        Assert.AreEqual("This's is a string", match.Groups[5].Value.Trim());
    }
    

    【讨论】:

    • ^ 字符表示行首,括号定义组。
    • 感谢您的提问。 ':' 和空格都是分隔符。我会更正这个问题。
    【解决方案3】:

    这个正则表达式模式应该适合你

    \s*:\s*(?![^\[]*\])(?![^{]*})(?=(([^"]*"[^"]*){2})*$|[^"]+$)
    

    当替换为

    \n$0\n
    

    Demo

    【讨论】:

      猜你喜欢
      • 2013-12-26
      • 2018-05-13
      • 2023-02-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-03
      • 2020-07-06
      相关资源
      最近更新 更多