2013-09-25 85 views
2

我在scala中使用本地解析器组合器库,我想用它来解析一些大文件。我有我的combinators设置,但我试图解析的文件太大,一次不能读入内存。我希望能够通过解析器从输入文件进行流式处理,并将其读回到磁盘,以便我不需要立即将其全部存储在内存中。我的当前系统看起来像这样:斯卡拉解析器组合器:解析流

val f = Source.fromFile("myfile") 
parser.parse(parser.document.+, f.reader).get.map{_.writeToFile} 
f.close 

这将读取整个文件,因为它解析,我想避免。

回答

5

有没有简单的或内置的方式来完成这项使用Scala的解析器组合,这为实现parsing expression grammars设施。

诸如|||(最长匹配)等运算符在很大程度上与流解析模型不兼容,因为它们需要大量的回溯功能。为了完成你想要做的事情,你需要重新制定你的语法,以便不需要回溯,有史以来。这通常比听起来要困难得多。

正如其他人所提到的,您最好的选择就是查看初步阶段(例如按行),以便您可以一次处理一部分流。

+0

这很有道理。有什么办法可以利用我的顶级组合器只是一个重复的事实吗?也就是说,我可以按照单个“文档”大小的块读入流中吗? –

+0

只要你能想出办法(手动)分割文件,是的。然后你将每个文件分别转交给你的语法。大多数PEG运营商(包括重复)实际上都依赖于回溯,因为PEG的表现力是基于能够说“试试这个,如果不行的话我们会尝试其他的”。 –

0

这样做是从Source对象抢Iterator然后通过线路像这样走的一个简单的方法:

val source = Source.fromFile("myFile") 
val lines = source.getLines 
for (line <- lines) { 
    // Do magic with the line-value 
} 
source.close // Close the file 

但你需要能够通过一个在使用该行一个当然你的解析器。

来源:https://groups.google.com/forum/#!topic/scala-user/LPzpXo3sUVE

0

您可以试着StreamReader类是分析软件包的一部分。

你会使用它是这样的:

val f = StreamReader(fromFile("myfile","UTF-8").reader()) 

parseAll(parser, f) 
0

上面提到的最长匹配结合正则表达式的使用source.subSequence(0,source.length)意味着即使StreamReader也没有帮助。

我最好的答案是使用getLines,正如其他人提到的那样,大块作为接受的答案提到。我的特殊输入要求我一次分两行。你可以从你构建的块中构建一个迭代器,使其稍微不那么难看。