Haskell 多行*非*与ATOPASSEC匹配
我在玩解析(PostgreSQL)日志,它可以有多行的条目Haskell 多行*非*与ATOPASSEC匹配,haskell,attoparsec,Haskell,Attoparsec,我在玩解析(PostgreSQL)日志,它可以有多行的条目 2016-01-01 01:01:01 entry1 2016-01-01 01:01:02 entry2a entry2b 2016-01-01 01:01:03 entry3 因此,对于Perl或Python脚本,我只需抓取下一行,如果它不是以时间戳开头,则将其附加到上一个日志条目中。使用连接到io流的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脚本,我只需抓取下一行,如果它不是以时间戳开头,则将其附加到上一个日志条目中。使用连接到io流的attoparsec
实现这一点的合理方法是什么?很明显,我想用前瞻
做一些事情,但我的大脑只是缺少了一些东西
没有-还是看不见。我已经把我所有的剥光了。解析一行代码很容易。我不知道如何解析“最多”另一个解析模式——我可以看到一个可以使用的先行函数,但我不知道这如何与应用“不”条件相适应
我也看不出我能比得上谁。完全有可能是我的脑子坏了
{-# 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
{-#语言重载字符串}
模块DummyParser(
LogStatement(..),parseLogLine
--所以我们可以测试它。。。
,LogTimestamp,parseTimestamp
,parseSqlStmt
,newLineAndTimestamp
)在哪里
{-我们要分析。。。
TIME001语句:选择true;
TIME002语句:选择“b”,
"c";;
TIME003语句:选择3;
-}
导入Data.attopassec.ByteString.Char8
将限定数据.ByteString.Char8作为B导入
类型LogTimestamp=Int
数据LogStatement=LogStatement{
日志时间戳
,l_sql::String
}推导(等式,显示)
restOfLine::解析器B.ByteString
restOfLine=do
休息返回休息
--例如:TIME001
parseTimestamp::解析器日志时间戳
parseTimestamp=do
字符串“TIME”
数字我在许多问题上分享的组合词:
notFollowedBy p = p >> fail "not followed by"
您的解决方案类似于
parseLogLine :: Parser LogStatement
parseLogLine = do
log_ts <- parseTimestamp
spaces
log_sql <- parseSqlStmt
newlineLeftover <- ((notFollowedBy parseTimestamp) *> parseSqlStmt) <|> pure ""
let ls = LogStatement log_ts (log_sql ++ newlineLeftover
return ls
parseLogLine::Parser LogStatement
parseLogLine=do
记录我在许多问题上分享的组合词:
notFollowedBy p = p >> fail "not followed by"
您的解决方案类似于
parseLogLine :: Parser LogStatement
parseLogLine = do
log_ts <- parseTimestamp
spaces
log_sql <- parseSqlStmt
newlineLeftover <- ((notFollowedBy parseTimestamp) *> parseSqlStmt) <|> pure ""
let ls = LogStatement log_ts (log_sql ++ newlineLeftover
return ls
parseLogLine::Parser LogStatement
parseLogLine=do
我想你不需要提前看。只需通过匹配时间戳来解析日志时间,并且只在每个时间条目内解析子条目。嗯,我想我明白你的意思了。我一直在以一种面向行的方式考虑这个问题。如果我使用分隔符“\n”,我们可能会完全回避这个问题。谢谢-如果有机会的话,我今晚会试试。对于attoparsec
,这似乎不太复杂,但您应该将您的尝试发布到目前为止。我认为您不需要对此进行展望。只需通过匹配时间戳来解析日志时间,并且只在每个时间条目内解析子条目。嗯,我想我明白你的意思了。我一直在以一种面向行的方式考虑这个问题。如果我使用分隔符“\n”,我们可能会完全回避这个问题。谢谢-如果有机会的话,我今晚会试试。对于attoparsec
,这似乎不太复杂,但您应该将您的尝试发布到目前为止。谢谢。思考失败和提供所需返回值的*>
这两个想法让我点击它。谢谢。思考失败和提供所需返回值的*>
这两个想法让我点击它。