ELMによる聖書参照の解析


これは元々はdeanmontgomery.com .
この記事では、ELMでシンプルなパーサーを書く方法について簡単に紹介します.
私たちが解析されることは聖書の参照です:聖書の参照は、1つはすぐに聖書のテキスト内の特定の詩や範囲の詩を見てみましょう速記です.
簡単ですね.

どのようなリファレンスのようですか?


聖書の参照を開始位置と終了位置に分割することができます.それぞれの場所は、本、章と詩から成ります.
それで、リファレンスは似ているかもしれませんGenesis 1:1 - Exodus 2:1 それは創世記の第1章の最初の節から始まり、第2章の第1章で終わりを告げます.
しかし、リファレンスはこれらのいずれかのように見えます.
  • Genesis 1 - 全体の章
  • Genesis 1:1 - 一節
  • Genesis 1:1-20
  • Genesis 1:20-2:24
  • Genesis 1-5 - 複数の章
  • Genesis 1 - Exodus 5
  • Genesis 1:1 - Exodus 5:20
  • Genesis 1:1 - Exodus 5
  • Genesis 1 - Exodus 5:20
  • さらに、聖書のいくつかの本は、単一の章(例えばジュード)を持っている、とコンベンションによって、章番号は参照から削除されます.So Jude 2 ジュードの最初の(そして唯一の)章の2番目の節は、すべてのジュード第2章です.
    パーサを書くとき、これらのケースの全てを処理することを目指します.

    ELMで構文解析を行うには?


    elm/parser スーパーニース解析ライブラリは、エルムの作成者とメンテナによって書かれています.私はそれの詳細にここに行かないtutorial and conference talk あなたがより深く掘りたいならば.
    聖書のリファレンスを2つのステップで解析します.
  • 文字列を構文リストに解析する
  • 次に、有効な参照をチェックする文のリストを検証します
  • 文のリストを取得する


    聖書の参照には、スペース、コロン、誇らしげ、本の名前と数を持つことができます.
    type Statement
        = BookName Book
        | Num Int
        | Dash
        | Colon
    
    とパーサが文字列をリストのリストに変換する
    {-| A `List Statement` parser. We use `P.loop` to consume the whole string
    -}
    parser : P.Parser (List Statement)
    parser =
        P.loop [] statementsHelp
    
    
    statementsHelp : List Statement -> P.Parser (P.Step (List Statement) (List Statement))
    statementsHelp revStmts =
        P.oneOf
            [ P.succeed (\stmt -> P.Loop (stmt :: revStmts))
                |. P.spaces
                |= statement
                |. P.spaces
            , P.succeed ()
                |> P.map (\_ -> P.Done (List.reverse revStmts))
            ]
    
    {-| A `Statement` parser
    -}
    statement : P.Parser Statement
    statement =
        P.oneOf
            [ P.map BookName (P.oneOf bookTokensList)
            , P.map (\_ -> Dash) (P.symbol "-")
            , P.map (\_ -> Colon) (P.symbol ":")
            , P.map Num P.int
            ]
    
    このパーサを使用すると、文字列をList Statement :
    parse : String -> Result String (List Statement)
    parse str =
        P.run parser str
    

    文のリストの妥当性検査


    現在、我々は声明のリストを持っています[Book Genesis, Colon, Num 1] or [Book John, Colon, Num 2, Dash, Num 2] , しかし、我々には声明の有効なコレクションがあることを保証する何もありません.例えば、私たちは[Colon, Colon, Colon] これは明らかに有効ではない.[Book Genesis, Num 52] これは有効ですが、創世記には50冊しかありません.
    まず定義するReference 種類:
    type alias Reference =
        { startBook : Book
        , startChapter : Int
        , startVerse : Int
        , endBook : Book
        , endChapter : Int
        , endVerse : Int
        }
    
    と関数processStatements : List Statement -> Result String Reference これはステートメントのリストを有効にします.この機能は、利用可能なすべての可能な形式を説明し、単一の章の書籍を扱うためにかなり大きいですが、関数は本質的にcase
    processStatementsHelp : List Statement -> Result String Reference
    processStatementsHelp stmts =
        case stmts of
            -- Gen
            [ BookName bk ] ->
                reference
                    bk
                    1
                    1
                    bk
                    (numChapters bk)
                    (numVerses bk (numChapters bk))
    
            -- Gen 1
            [ BookName bk, Num ch ] ->
                if numChapters bk == 1 then
                    reference
                        bk
                        1
                        ch
                        bk
                        1
                        ch
    
                else
                    reference
                        bk
                        ch
                        1
                        bk
                        ch
                        (numVerses bk 1)
    
        -- truncated for brevity (full function can be seen: https://github.com/monty5811/elm-bible/blob/2.0.0/src/Internal/Parser.elm#L38-L243)
    
            -- Genesis - Revelation
            [ BookName startBk, Dash, BookName endBk ] ->
                reference
                    startBk
                    1
                    1
                    endBk
                    (numChapters endBk)
                    (numVerses endBk (numChapters endBk))
    
            [] ->
                Err "No reference found"
    
            _ ->
                Err <| "No valid reference found"
    
    
    今、我々はReference これには、スタートブック、スタート章、開始節、終了章、終了節が含まれていますが、これらのすべてが順番にチェックされていません(例えば、参照が開始される前には参照できません).
    validateRef : Reference -> Result String Reference
    validateRef ref =
        validateBookOrder ref
            |> Result.andThen validateChapterOrder
            |> Result.andThen validateVerseOrder
            |> Result.andThen validateChapterBounds
            |> Result.andThen validateVerseBounds
    
    -- see each validate function here: https://github.com/monty5811/elm-bible/blob/2.0.0/src/Internal/Parser.elm#L363
    
    ついに!我々は、検証聖書リファレンスがあります!
    この検証のすべてをパーサー内で動かすことが可能であり、すべての作業を1ステップで行うことが可能であるべきだと思います.

    結論


    この記事では、ELMでパーサーを作成する方法を示しています.うまくいけば、これはパーサーの構築を開始するのに役立ちます.
    パーサーをビルドするのを気にしないでください、そして、ちょうどあなたのためにこれをするためにELMパッケージが欲しいならば、チェックしてくださいmonty5811/elm-bible それはパーサー、良いフォーマットとコンパクトなエンコーダ/デコーダを提供します.

    モンティ5811 / エルムバイブル



    エルムバイブル



    ELMで聖書参照を解析して、フォーマットしてください.

    機能

  • 文字列から参照を解析する
  • うまく文字列への参照をフォーマットする
  • 参照を並べ替え/比較/記憶のためにコード化された表現に変えてください
  • 以下の参照書式を解析できます:
  • 創世記1
  • 創世記1章1
  • 創世記1章1 - 20
  • 創世記20章2時24分
  • ジェネシス1 - 5
  • エクソダス5
  • エクソダス5 : 20
  • エクソダス5
  • エクソダス5 : 20

  • ( fromstring "gen 1 : 1 "ξ> result . map format )
    === "ジェネシス1 : 1 "
    ( fromstring "gen 1 : 1 - rev 5 ")マップ形式
    = = "創世記1 : 1 -黙示録5 : 14 "
    ( fromstring "gen 1 : 1 - rev 5 ")マップエンコード
    === OK { start = 1001001 , end = 66005014

    貢献


    寄付歓迎open an issue 始める.
    View on GitHub