F# 解析具有多行条目的日志

问题描述 投票:0回答:1

我正在以逐行的方式解析日志文件(以 debug/warning/info 开头的条目),并且遇到了单个日志条目跨越多行的罕见情况 - 例如,这里的警告:

debug: Preparing movie /movies/menu_background.sfd: 272204
info: /init
debug: Playing movie c:\program files (x86)\steam\steamapps\common\supreme commander forged alliance\movies\menu_background.sfd: 272204
warning: Error running OnDestroy script in Entity bsa0001 at 2f8b6908: ...gramdata\faforever\gamedata\lua.nx2\lua\sim\unit.lua(5494): attempt to call method `Destroy' (a nil value)
         stack traceback:
            ...gramdata\faforever\gamedata\lua.nx2\lua\sim\unit.lua(5494): in function <...gramdata\faforever\gamedata\lua.nx2\lua\sim\unit.lua:5489>
            ...orever\gamedata\lua.nx2\lua\sim\units\mobileunit.lua(65): in function `DestroyAllTrashBags'

我当前的代码如下 - 它忽略了附加行(将它们放入 Misclist 中) - 不是我想要的。我想修改代码以包含带有先前信息/警告/调试条目的附加行。我的 C# 大脑可以按程序执行此操作,但在学习 F# 时,我尝试以更实用的方式执行此操作。

let rec sortLines (lines: string list) (warninglist: string list) (debuglist: string list) (infolist: string list) (misclist: string list) : string list list =
    match lines with
    | (h::t) when h.StartsWith("debug") ->
        sortLines t warninglist (h :: debuglist) infolist misclist
    | (h::t) when h.StartsWith("info") ->
        sortLines t warninglist debuglist (h :: infolist) misclist
    | (h::t) when h.StartsWith("warning") ->
        sortLines t (h :: warninglist) debuglist infolist misclist
    | (h::t) ->
        sortLines t warninglist debuglist infolist (h :: misclist)
    | [] ->
        [warninglist; debuglist; infolist; misclist]
functional-programming f#
1个回答
0
投票

当您需要在迭代集合时维护状态时,

fold
通常是您的朋友。我建议这样的解决方案:

type Log =
    {
        Info : List<string>
        Debug : List<string>
        Warning : List<string>
    }

module Log =

    let empty =
        {
            Info = []
            Debug = []
            Warning = []
        }

    let logInfo line log =
        { log with Info = line :: log.Info }

    let logDebug line log =
        { log with Debug = line :: log.Debug }

    let logWarning line log =
        { log with Warning = line :: log.Warning }

    let logInvald line log =
        failwith "Invalid state"

    let read lines =
        let log, _ =
            Seq.fold (fun (log, logger) (line : string) ->
                let logger' =
                    if line.StartsWith("info") then logInfo
                    elif line.StartsWith("debug") then logDebug
                    elif line.StartsWith("warning") then logWarning
                    else logger
                let log' = logger' line log
                log', logger') (empty, logInvald) lines
        log
© www.soinside.com 2019 - 2024. All rights reserved.