Я играл с журналами разбора (PostgreSQL), которые могут содержать многострочные записи.Multi-line * non * match with attoparsec
2016-01-01 01:01:01 entry1
2016-01-01 01:01:02 entry2a
entry2b
2016-01-01 01:01:03 entry3
Так что - с помощью сценария Perl или Python, я бы просто захватить следующую строку, и если он не начинал с меткой времени добавить его к предыдущей записи в журнале. Какой разумный способ приблизиться к этому с помощью attoparsec
подключен до io-streams
? Я явно хочу что-то сделать с lookAhead
и неспособным сопоставить временную метку, но мой мозг просто что-то упустил.
Нет, до сих пор не видно. Я снял все, что у меня есть. Разбор одной строки прост. Я не могу понять, как анализировать «до» другого шаблона синтаксического анализа - я могу видеть функцию lookAhead, которую я могу использовать, но я не вижу, как это вписывается в условие «нет».
Я не вижу, как я могу соответствовать. Весьце возможным мой мозг охватил.
{-# LANGUAGE OverloadedStrings #-}
module DummyParser (
LogStatement (..), parseLogLine
-- and, so we can test it...
, LogTimestamp , parseTimestamp
, parseSqlStmt
, newLineAndTimestamp
) where
{- we want to parse...
TIME001 statement: SELECT true;
TIME002 statement: SELECT 'b',
'c';
TIME003 statement: SELECT 3;
-}
import Data.Attoparsec.ByteString.Char8
import qualified Data.ByteString.Char8 as B
type LogTimestamp = Int
data LogStatement = LogStatement {
l_ts :: LogTimestamp
,l_sql :: String
} deriving (Eq, Show)
restOfLine :: Parser B.ByteString
restOfLine = do
rest <- takeTill (== '\n')
isEOF <- atEnd
if isEOF then
return rest
else
(char '\n') >> return rest
-- e.g. TIME001
parseTimestamp :: Parser LogTimestamp
parseTimestamp = do
string "TIME"
digits <- count 3 digit
return (read digits)
-- e.g. statement: SELECT 1
parseSqlStmt :: Parser String
parseSqlStmt = do
string "statement: "
-- How can I match until the next timestamp?
sql <- restOfLine
return (B.unpack sql)
newLineAndTimestamp :: Parser LogTimestamp
newLineAndTimestamp = (char '\n') *> parseTimestamp
spaces :: Parser()
spaces = do
skipWhile (== ' ')
-- e.g. TIME001 statement: SELECT * FROM schema.table;
parseLogLine :: Parser LogStatement
parseLogLine = do
log_ts <- parseTimestamp
spaces
log_sql <- parseSqlStmt
let ls = LogStatement log_ts log_sql
return ls
EDIT: Так, это было то, что я, наконец, закончил с благодарностью, чтобы arrowd Поможем
isTimestampNext = lookAhead parseTimestamp *> pure()
parseLogLine :: Parser LogStatement
parseLogLine = do
log_ts <- parseTimestamp
spaces
log_sql <- parseSqlStmt
extraLines <- manyTill restOfLine (endOfInput <|> isTimestampNext)
let ls = LogStatement log_ts (log_sql ++ (B.unpack $ B.concat extraLines))
return ls
Я не думаю, что вам нужно посмотреть на это. Просто проанализируйте время разбора, сопоставляя метки времени, и только _within_ каждый элемент времени анализирует подзаголовки. – leftaroundabout
Хм - Кажется, я понимаю, что вы имеете в виду. Я думал об этом линейным образом. Если я сделаю свой разделитель «\ n», мы можем полностью обойти эту проблему. Спасибо. Я попробую сегодня вечером, если у меня появится шанс. –
Не кажется слишком сложным с 'attoparsec', но вы должны опубликовать свою попытку до сих пор. – Jubobs