Haskell 多行*非*与ATOPASSEC匹配

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实现这一点的合理方法是什么?很明显,我想用前瞻做一些事情,但我的大脑只是缺少了一些东西 没有-还是看

我在玩解析(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
实现这一点的合理方法是什么?很明显,我想用
前瞻
做一些事情,但我的大脑只是缺少了一些东西


没有-还是看不见。我已经把我所有的剥光了。解析一行代码很容易。我不知道如何解析“最多”另一个解析模式——我可以看到一个可以使用的先行函数,但我不知道这如何与应用“不”条件相适应

我也看不出我能比得上谁。完全有可能是我的脑子坏了

{-# 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
,这似乎不太复杂,但您应该将您的尝试发布到目前为止。谢谢。思考失败和提供所需返回值的
*>
这两个想法让我点击它。谢谢。思考失败和提供所需返回值的
*>
这两个想法让我点击它。