Parsing 如何让字符串解析器终止
我有一个用于双引号字符串的解析器,大多数情况下工作正常,但当结束引号丢失时,它将永远循环并使应用程序崩溃 它是用Elm编写的web应用程序的一部分,并使用 它基于来自Elm Github的 下面是一个简单的示例(;将toParse更改为“\”,它会使选项卡崩溃)Parsing 如何让字符串解析器终止,parsing,elm,Parsing,Elm,我有一个用于双引号字符串的解析器,大多数情况下工作正常,但当结束引号丢失时,它将永远循环并使应用程序崩溃 它是用Elm编写的web应用程序的一部分,并使用 它基于来自Elm Github的 下面是一个简单的示例(;将toParse更改为“\”,它会使选项卡崩溃) 模块主显示(主) 导入Html 将解析器导入为P公开((|.),(|=) 导入调试 stringP:P.Parser字符串 斯特林普= 成功身份 |.P.token“\” |=P.loop[]字符串帮助 stringHelp:List
模块主显示(主)
导入Html
将解析器导入为P公开((|.),(|=)
导入调试
stringP:P.Parser字符串
斯特林普=
成功身份
|.P.token“\”
|=P.loop[]字符串帮助
stringHelp:List String->P.Parser(P.Step(List String)String)
stringHelp revChunks=
第1页
[P.token”\“”
|>P.map(\ \ \->P.Done(String.join”“(List.revChunks)))
,P.chompWhile是无趣的
|>P.getChompedString
|>P.map(\chunk->P.Loop(chunk::revChunks))
]
无趣:Char->Bool
这是一个无趣的字符=
char/='\\'&&char/=''''
托帕尔斯=
"\""
主要=
Html.text我发现一个解决方案是跟踪解析位置,如果位置没有增加,就退出循环。不过这不是很漂亮;也许有人会想出更好的方法
代码如问题中的示例所示,但有以下更改():
stringP:P.解析器字符串
斯特林普=
成功身份
|.P.token“\”
|=P.loop([],0)stringHelp
|.P.token“\”
stringHelp:(列表字符串,Int)->P.Parser(P.Step(列表字符串,Int)字符串)
stringHelp(revChunks,offset)=
P.成功(stepHelp补偿)
|=stringHelp2 revChunks
|=P.getOffset
stepHelp:Int->(P.Step(列表字符串)字符串)->Int->P.Step(列表字符串,Int)字符串
stepHelp oldOffset步长newOffset=
案例步骤
P.完成str->
P.完成str
P.循环块->
如果newOffset>oldOffset,则
P.循环(revChunks、newOffset)
其他的
P.完成P.getChompedString
|>P.map(\chunk->P.Loop(chunk::revChunks))
这会导致所需的解析器错误,即缺少引号。这里有一个替代解决方案,如果字符串过早终止(),则检查end
标记:
模块主显示(主)
导入Html
将解析器导入为P公开((|.),(|=)
导入调试
stringP:P.Parser字符串
斯特林普=
(P.1)身份
|.P.token“\”
|=P.loop[]字符串帮助
)|>P.然后
(\res->
案件
确定str->P.成功str
错误消息->P.问题消息
)
stringHelp:List String->P.Parser(P.Step(List String)(结果字符串))
stringHelp revChunks=
第1页
[P.end
|>P.map(\ \ \->P.Done(Err“字符串过早结束”))
,P.token“\”
|>P.map(\ \ \->P.Done(Ok(String.join”“(List.revChunks)))
,P.chompWhile是无趣的
|>P.getChompedString
|>P.map(\chunk->P.Loop(chunk::revChunks))
]
无趣:Char->Bool
这是一个无趣的字符=
char/='\\'&&char/=''''
托帕尔斯=
“嗨”
主要=
Html.text
module Main exposing (main)
import Html
import Parser as P exposing ((|.), (|=))
import Debug
stringP : P.Parser String
stringP =
P.succeed identity
|. P.token "\""
|= P.loop [] stringHelp
stringHelp : List String -> P.Parser (P.Step (List String) String)
stringHelp revChunks =
P.oneOf
[ P.token "\""
|> P.map (\_ -> P.Done (String.join "" (List.reverse revChunks)))
, P.chompWhile isUninteresting
|> P.getChompedString
|> P.map (\chunk -> P.Loop (chunk :: revChunks))
]
isUninteresting : Char -> Bool
isUninteresting char =
char /= '\\' && char /= '"'
toParse =
"\""
main =
Html.text <| Debug.toString <| P.run stringP toParse
stringP : P.Parser String
stringP =
P.succeed identity
|. P.token "\""
|= P.loop ([], 0) stringHelp
|. P.token "\""
stringHelp : (List String, Int) -> P.Parser (P.Step (List String, Int) String)
stringHelp (revChunks, offset) =
P.succeed (stepHelp offset)
|= stringHelp2 revChunks
|= P.getOffset
stepHelp : Int -> (P.Step (List String) String) -> Int -> P.Step (List String, Int) String
stepHelp oldOffset step newOffset =
case step of
P.Done str ->
P.Done str
P.Loop revChunks ->
if newOffset > oldOffset then
P.Loop (revChunks, newOffset)
else
P.Done <| String.join "" <| List.reverse revChunks
stringHelp2 : List String -> P.Parser (P.Step (List String) String)
stringHelp2 revChunks =
P.chompWhile isUninteresting
|> P.getChompedString
|> P.map (\chunk -> P.Loop (chunk :: revChunks))
module Main exposing (main)
import Html
import Parser as P exposing ((|.), (|=))
import Debug
stringP : P.Parser String
stringP =
( P.succeed identity
|. P.token "\""
|= P.loop [] stringHelp
) |> P.andThen
( \res ->
case res of
Ok str -> P.succeed str
Err msg -> P.problem msg
)
stringHelp : List String -> P.Parser (P.Step (List String) (Result String String))
stringHelp revChunks =
P.oneOf
[ P.end
|> P.map (\_ -> P.Done (Err "string ended prematurely"))
, P.token "\""
|> P.map (\_ -> P.Done (Ok (String.join "" (List.reverse revChunks))))
, P.chompWhile isUninteresting
|> P.getChompedString
|> P.map (\chunk -> P.Loop (chunk :: revChunks))
]
isUninteresting : Char -> Bool
isUninteresting char =
char /= '\\' && char /= '"'
toParse =
"\"hi\""
main =
Html.text <| Debug.toString <| P.run stringP toParse