【问题标题】:Antlr4: How to parse only one part of the fileAntlr4:如何只解析文件的一部分
【发布时间】:2018-12-20 10:27:45
【问题描述】:

是否可以只用 antlr4 解析文件的前半部分? 我正在解析大文件,我正在使用 UnbufferedCharStream 和 UnbufferedTokenStream。

我没有构建解析树,而是使用解析操作而不是访问者/侦听器模式。有了这些,我能够节省大量 RAM 并提高解析速度。

但是解析整个文件仍然需要大约 15 秒。解析后的文件分为两部分。文件的前半部分有元数据,后半部分是实际数据。大部分时间都花在数据部分,因为有超过 3m。要解析的行。元数据部分只有大约 20,000 行。是否可以只解析前半部分,从而显着提高解析速度?是否可以在元数据部分之后手动注入 EOF?

把文件分成两份怎么样?

【问题讨论】:

    标签: c# parsing antlr4


    【解决方案1】:

    您如何以编程方式仅提取要解析的部分并创建一个新的 tmp.extension 文件以供解析?它可能看起来像这样:

    System.IO.File.WriteAllText(@"C:\Users\Path\tmp.extension", text);
    

    解析后可以删除tmp文件,原样保留。

    System.IO.File.Delete(@"C:\Users\Path\tmp.extension");
    

    【讨论】:

    • 我正在使用解析器来验证 Web 应用程序中上传的文件。所以在磁盘上创建额外的文件并不是一个很好的选择。我想找到一个更好的,例如以修改输入流的方式。谢谢。
    • 您可以尝试仅提取您想要的部分并将其转换为流,请参阅Convert String to System.IO.Stream。这是一个非常大的字符串,但如果您可以通过编程方式仅提取您想要的部分,它可能会起作用
    • 是的,我可以,但是由于文件非常大,因此 Stream 会占用大量内存。这就是我使用 UnbufferedCharStream 和 UnbufferedTokenStream 的原因。
    【解决方案2】:

    ANTLR4 创建递归体面的解析器,解析函数可以直接调用。假设你有这样的语法:

    grammar t;
    
    start: meta data EOF;
    meta: x y z;
    
    data: a b c+;
    

    您的自然入口点将是 start 规则(在您的情况下,这将是整个文件的规则)。但也可以只调用规则meta,在您的情况下,它可能是文件的标题部分。如果你不以 EOF 结束这条规则,你的解析器将只消耗足够的输入来解析整个文件的这个特定部分。

    【讨论】:

    • 这是我已经尝试过的第一个替代方案。但问题是如果你不以 EOF 结束文件,那么 ANTLR4 不能保证它会消耗足够的令牌。存在未报告元数据部分低端错误的情况。
    • 好吧,我猜这就是您必须付出的代价,除非您以某种方式手动拆分文件并且只将第一部分提供给解析器。那么你当然也可以添加EOF。
    【解决方案3】:

    所以,我能够找到解决方案。我从生成的词法分析器中覆盖了 Emit 方法 因此它找到了第二部分的开头并手动注入 EOF 令牌, 像这样:

    public override IToken Emit()
    {
        string tokenText = base.Text;
        if (this.metaDataOnly && tokenText == "DATA")
            return base.EmitEOF();
        return base.Emit();
    }
    

    【讨论】:

      猜你喜欢
      • 2021-12-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-19
      • 2016-05-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多