LINUX.ORG.RU

Возможно ли сопоставить ругулярное выражение с содержимым файла?


0

1

Необходимо распарсить файл регексом на последовательность записей. Файл может быть fifo или stdin, и первые записи нужны до того так, как он создался, поэтому вычитать весь файл в строку - не выход. Запись занимает несколько строк, так что читать по строкам - тоже не вариант. Грамматика регулярная, так что использовать что-то помимо регексов нецелесообразно. Язык - желательно python или shell.

> Файл может быть fifo или stdin, и первые записи нужны до того так, как он создался

Или речь о телепатии (как читать еще не созданный файл?), или о том, что записи нужны до того, как файл будет записан полностью.

Запись занимает несколько строк, так что читать по строкам - тоже не вариант.

Читать по блокам. Или по строкам, которые тут же объединять в блоки и парсить. Конечно, при этом может быть прочитан неполный блок, но можно же объединять нераспарсенный «хвост» предыдущего блока и следующий блок.

amomymous ★★★
()
Ответ на: комментарий от amomymous

>Или речь о телепатии (как читать еще не созданный файл?), или о том, что записи нужны до того, как файл будет записан полностью.

Именно о втором.

Читать по блокам. Или по строкам, которые тут же объединять в блоки и парсить. Конечно, при этом может быть прочитан неполный блок, но можно же объединять нераспарсенный «хвост» предыдущего блока и следующий блок.

Какое-то это колдунство и котылестроение. Да и производительность будет проседать: если прочитается часть записи, то её придётся матчить второй раз. Хочется такой движок регксов, который читает из файла символы, если они нужны в данный момент, и буферизует, если возможно придётся возвращаться. Неужели до такого никто не додумался? Это кажется тривиальным. (Но не настолько тривиальным, чтобы писать такое ради разовой задачи)

Mihai-gr
() автор топика
Ответ на: комментарий от Mihai-gr

> Хочется такой движок регксов, который читает из файла символы, если они нужны в данный момент, и буферизует, если возможно придётся возвращаться.

В оффтопике были, кстати, memory mapped files, которые представляли собой массив в памяти, при доступе к элементам которого при необходимости считывалось содержимое файла. И если не изменяет память, в linux тоже есть нечто подобное.

То есть передаете своему любимому движку регекспов вместо ссылки на строку ссылку на такой «примонтированный» файл, и он будет парситься именно так, как вы написали выше. Главное позаботиться о том, чтобы при попытке чтения еще незаписанного байта происходило ожидание, а не фейл.

amomymous ★★★
()
Ответ на: комментарий от Mihai-gr

> Это кажется тривиальным.

Только кажется.

Например: (.*)\1 --- нужно буферизовать весь файл (и при любом capture или backreference). Или end$ --- многие regexp engines пытаются начать за три символа до конца строки. Если все эти возможности не нужны, то ищите какой-нибудь lexer или что-то подобное.

anonymous
()
Ответ на: комментарий от anonymous

Очевидно, что «при любом capture или backreference», никакой речи о «регулярности» нет и не может быть.

shylent
()

«Файл может быть fifo или stdin, и первые записи нужны до того так, как он создался, поэтому вычитать весь файл в строку - не выход»

тоесть содержимое файла поступает по байтам

«Запись занимает несколько строк, так что читать по строкам - тоже не вариант»

имхо бы сделал так
читал бы со входа по символам - и на каждый символ в буффер пробовал распарсить буффер регеспами
как тока регекспы чтото выдадут - обнулял буфер и так далее
эт наверно было бы медленно

иль тогда читать блоком - все данные что есть щас на входе - при неблокирующем сокете
а потом буффер распарсивать - а то что отанеться иль перености в начало буффера и опять читать файл - или кольцевой буффер сделать если копировать лениво

ae1234 ★★
()
Ответ на: комментарий от Mihai-gr

>Читать по блокам. Или по строкам, которые тут же объединять в блоки и парсить. Конечно, при этом может быть прочитан неполный блок, но можно же объединять нераспарсенный «хвост» предыдущего блока и следующий блок.

Какое-то это колдунство и котылестроение.

отнюдь, нормальный способ разбора больших файлов - welcome to real world, Neo

Да и производительность будет проседать: если прочитается часть записи, то её придётся матчить второй раз.

её в любом разе надо будет матчить, либо тебе ручками, либо парсеру за занавеской, по факту - никакой разницы

Хочется такой движок регксов, который читает из файла символы, если они нужны в данный момент, и буферизует, если возможно придётся возвращаться.

нафига тебе движок regexp для этого??? сделай свой буффер какой хочешь и натравливай на него движок, медленно тебе кажется? делай это в соседних потоках столько раз сколько нужно

shty ★★★★★
()
Ответ на: комментарий от shty

её в любом разе надо будет матчить, либо тебе ручками, либо парсеру за занавеской, по факту - никакой разницы

разница есть, парсер мог бы любезно сохранять последнее своё состояние и потом доделывать новый блок, некоторые сишные библиотеки так умеют.

И для регэкспов нет свойства линейности, т.е. приминение регэкспа к одному куску не одно и то же что и применение к разным блокам с добавлением хвостов.

mashina ★★★★★
()

>В оффтопике были, кстати, memory mapped files, которые представляли собой массив в памяти, при доступе к элементам которого при необходимости считывалось содержимое файла. И если не изменяет память, в linux тоже есть нечто подобное.

Насколько я понимаю, с fifo такое не прокатит.

Например: (.*)\1 --- нужно буферизовать весь файл (и при любом capture или backreference). Или end$ --- многие regexp engines пытаются начать за три символа до конца строки.

В любом случае, буферизовать придётся не больше, чем если читать содержимое файла сразу.

нафига тебе движок regexp для этого??? сделай свой буффер какой хочешь и натравливай на него движок, медленно тебе кажется? делай это в соседних потоках столько раз сколько нужно

А если буфер окажется меньше, чем одно вхождение регекса? тогда его придётся дочитывать, и натравливать регекс снова, и так пока не сматчится. То есть накладные расходы. Вот если бы можно было сохранять состояния движка и начинать с того же места, но уже с обновлённым буффером, это был бы вариант. Хотя в таком решении будут проблемы жадными патернами и backtracking'ом. В идеале, буфер должен дочитываться, когда движок доползёт до его конца, даже если есть возможность откатиться.

P. S. не обязательно python или shell. Если такое можно сделать в perl, я готов выучить perl. Вообще, самое близкое к тому, что я описываю, я видел в haskell, если лениво прочитать строку и натравить на неё регекс. Но использовать haskell не представляется возможным.

Mihai-gr
() автор топика
Ответ на: комментарий от Mihai-gr

Си готов учить? Если да, см pcre и man pcrepartial. Ещё можно озадачиться вопросом, а действительно ли для твоей задачи нужны regexp'ы.

mashina ★★★★★
()
Ответ на: комментарий от mashina

разница есть, парсер мог бы любезно сохранять последнее своё состояние и потом доделывать новый блок, некоторые сишные библиотеки так умеют.

ога, вот ищете Вы паттерн: f.*r, и пришла к Вам строка: «floor», вроде подходит, но нифига, нужная Вам строка: «floor blur», просто она не дошла ещё, а матч уже получен и что? как Вы себе представляете разруливание таких косяков?

это уже не говоря про паттерны с $ и ^ и прочая, прочая

сами же говорите:

И для регэкспов нет свойства линейности, т.е. приминение регэкспа к одному куску не одно и то же что и применение к разным блокам с добавлением хвостов.

короче в таком разе проще дождаться буфер целиком и обработать его

shty ★★★★★
()
Ответ на: комментарий от Mihai-gr

А если буфер окажется меньше, чем одно вхождение регекса? тогда его придётся дочитывать, и натравливать регекс снова, и так пока не сматчится. То есть накладные расходы.

да, всё так, накладные расходы, но как часто они у Вас возникать станут при реальной работе?

будут проблемы жадными патернами и backtracking'ом

и не только с ними

shty ★★★★★
()
Ответ на: комментарий от shty

ога, вот ищете Вы паттерн: f.*r, и пришла...

Есть определённые ограничения для такого режима парсинга.

короче в таком разе проще дождаться буфер целиком и обработать его

Проще полностью отказаться от regexp для задачи топикстартера или, по крайней мере, использовать препарсер который будет делить поток на небольшие логические строки для применения паттерна.

mashina ★★★★★
()
Ответ на: комментарий от mashina

Проще полностью отказаться от regexp для задачи топикстартера или, по крайней мере, использовать препарсер который будет делить поток на небольшие логические строки для применения паттерна.

первое как-то радикально, а второе мне больше нравится

shty ★★★★★
()

Всем спасибо. Таки обошёлся без регекосв.

Всё-таки обидно, что добавить костыль в программу, выдающую текстовый файл, оказалось проще, чем обработать его сторонними средствами. Юникс-вей не прошёл.

Mihai-gr
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.