我正在以逐行的方式解析日志文件(以 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]
当您需要在迭代集合时维护状态时,
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