【问题标题】:Implementing parser for escape sequences为转义序列实现解析器
【发布时间】:2008-12-19 17:20:17
【问题描述】:

我想解析一个保持对象图状态的自定义字符串格式。这是 ASP.NET 场景,我希望在客户端 (JavaScript) 和服务器 (C#) 上易于使用。

我有类似的格式

{Name1|Value1|Value2|...|ValueN}{Name2|Value1|...}{...}{NameN|...}

在这种格式中,我有 3 个分隔符,{}|。此外,因为这些字符在名称/值中是可以想象的,所以我使用非常常见的\ 定义了一个转义序列,这样\{\}\| 都被解释为它们自己的正常版本,当然\\ 是一个反斜杠。都很标准。

最初我尝试使用正则表达式来尝试解析出具有类似(?<!\\)\{(.*?)(?<!\\)\} 的对象的字符串表示。请记住\{} 都保留在正则表达式中。这当然能够正确解析出{category|foo\}|bar\{} 之类的内容。但是我意识到它会失败,比如{category|foo|bar\\}

我只花了一分钟左右的时间就尝试了这个(?<!(?<!\\)\\)\{(.*?)(?<!(?<!\\)\\)\},并意识到这种方法是不可能的,因为您需要无限数量的负面回溯来处理潜在的无限数量的转义序列。当然,我不可能拥有超过一两个级别,因此我可能可以对其进行硬编码。但是,我觉得这是一个足够普遍的问题,应该有一个明确的解决方案。

我的下一个方法是尝试编写一个已定义的解析器,在该解析器中我实际扫描输入缓冲区并以只进的方法使用每个字符。我实际上还没有完成这个,但它似乎过于复杂,我觉得我一定错过了一些明显的东西。我的意思是,只要我们有计算机语言,我们就有解析器。

所以我的问题是用可能的转义序列解码这样的输入缓冲区的最简单、有效和优雅的方法是什么?

【问题讨论】:

  • 我不确定我是否完全理解您的问题。您的意思是您希望前面的反斜杠从 {、| 和 } 中删除特殊含义吗?也就是说,“{foo|ba\}r|baz}”应该只匹配“{foo|ba\}”还是完整的字符串?
  • 它应该匹配完整的字符串 {foo|ba\}r|bas} 并且捕获应该是 foo|ba\}r|bas

标签: regex parsing escaping


【解决方案1】:
(?<!\\)(?:\\\\)*\{(.*?(?<!\\)(?:\\\\)*)\}

(?&lt;!\\) 将阻止在此之前的任何\

(?:\\\\)* 将允许任意数量的转义\

\{ 匹配左大括号。

( 开始一个捕获组。

.*? 匹配内容,包括任何|

(?&lt;!\\) 将阻止在此之前的任何\

(?:\\\\)* 将允许任意数量的转义\

) 结束捕获组。

\} 匹配右大括号。

【讨论】:

  • 太棒了。没有意识到你可以有顺序反向引用,所以我尝试的实现在“非固定长度反向引用”问题上失败了。
  • @Brodie,您所说的是lookbehinds,而不是反向引用。 OP 在问题中犯了同样的错误,但我修复了它。
【解决方案2】:

这种解析器很容易用最少的状态跟踪来完成。下面花了我几分钟,相当难看,甚至做了一点点错误检查。 :)

可以说,它比复杂的正则表达式更具可读性,尽管前者更简洁一些。

struct RECORD
{
    public string[] Entries;
}
struct FILE
{
    public RECORD[] Records;
}

static FILE parseFile(string input)
{
    List<RECORD> records = new List<RECORD>();
    List<string> entries = new List<string>();
    bool escaped = false;
    bool inRecord = false;
    StringBuilder sb = new StringBuilder();
    foreach (char c in input)
    {
        switch (c)
        {
            case '|':
                if (escaped)
                {
                    sb.Append('|');
                    escaped = false;
                }
                else if (inRecord)
                {
                    entries.Add(sb.ToString());
                    sb = new StringBuilder();
                }
                else
                    throw new Exception("Invalid sequence");
                break;
            case '{':
                if (escaped)
                {
                    sb.Append('{');
                    escaped = false;
                }
                else if (inRecord)
                    throw new Exception("Invalid sequence");
                else
                {
                    inRecord = true;
                    sb = new StringBuilder();
                }
                break;
            case '}':
                if (escaped)
                {
                    sb.Append('}');
                    escaped = false;
                }
                else if (inRecord)
                {
                    inRecord = false;
                    entries.Add(sb.ToString());
                    sb = new StringBuilder();
                    records.Add(new RECORD(){Entries = entries.ToArray()});
                    entries.Clear();
                }
                else
                    throw new Exception("Invalid sequence");
                break;
            case '\\':
                if (escaped)
                {
                    sb.Append('\\');
                    escaped = false;
                }
                else if (!inRecord)
                    throw new Exception("Invalid sequence");
                else
                    escaped = true;
                break;
            default:
                if (escaped)
                    throw new Exception("Unrecognized escape sequence");
                else
                    sb.Append(c);
                break;
        }
    }
    if (inRecord)
        throw new Exception("Invalid sequence");
    return new FILE() { Records = records.ToArray() };
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-04
    • 1970-01-01
    • 2014-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-13
    相关资源
    最近更新 更多