2013-09-25 2 views
2

Я использую библиотеку встроенного анализатора парсеров в scala, и я бы хотел использовать его для анализа большого количества больших файлов. У меня установлены мои комбайнаторы, но файл, который я пытаюсь разобрать, слишком велик, чтобы сразу считывать его в память. Я бы хотел, чтобы поток из входного файла через мой синтаксический анализатор и прочитал его обратно на диск, так что мне не нужно хранить его все в памяти сразу. Моя текущая система выглядит примерно так:Scala Parser Combanators: Разбор в потоке

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

Один простой способ сделать это, чтобы захватить Iterator от Source объекта, а затем пройти через линию, как так:

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 не помогает.

Лучший ответ kludgy У меня есть использование getLines, как упомянули другие, и кусок, как говорится в принятом ответе. Мой конкретный вход потребовал от меня поместить 2 строки за раз. Вы могли бы построить итератор из кусков, которые вы создали, чтобы сделать его немного менее уродливым.

Смежные вопросы