首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >多行*与attoparsec不匹配

多行*与attoparsec不匹配
EN

Stack Overflow用户
提问于 2016-02-12 09:19:24
回答 1查看 194关注 0票数 0

我在玩解析(PostgreSQL)日志,这些日志可以有多行的条目。

代码语言:javascript
复制
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函数,但我看不出这与应用"not“条件有什么关系。

我也看不出我是怎么匹配的。完全有可能我的大脑已经瘫痪了。

代码语言:javascript
复制
{-# 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

编辑:所以,这就是我最后终于感谢阿罗德的帮助

代码语言:javascript
复制
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
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-02-13 09:57:04

我在许多attoparsec问题上分享了组合器:

代码语言:javascript
复制
notFollowedBy p = p >> fail "not followed by"

你的解决方案应该是

代码语言:javascript
复制
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

我想,*>用于newlineLeftOver表达式的右手还需要做更多的工作,但总体思路是这样的。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35358797

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档