繁体   English   中英

如何让字符串解析器终止

[英]How to get string parser to terminate

我有一个双引号字符串的解析器,它通常可以正常工作,但是当缺少结束引号时,它会永远循环并导致应用程序崩溃。

它是用 Elm 编写的 Web 应用程序的一部分,并使用elm/parser

它基于 Elm Github 中的示例

这是一个最小的示例(在 Ellie 中运行它;将 toParse 更改为 "\\"" 并且它会使选项卡崩溃)。

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

我可以看出哪里出了问题 - 即使到达输入的末尾, chompWhile位也会成功。 我需要像这样,但不能完全解决如何做,在这种情况下。

我发现一个解决方案是跟踪解析位置,如果位置没有增加就退出循环。 不过它不是很漂亮; 也许有人会想出更好的东西。

代码如问题中的示例,但有这些更改(新 Ellie ):

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))          

这以缺少引号的所需解析器错误结束。

下面是一个替代的解决方案,对于检查end字符串是否过早地终止(令牌埃利):

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM