2016-06-19 15 views
3

, was ich versuche zu tun String mit regulärem Ausdruck zu analysieren und Html Element als Ausgabe erhalten, so sollte die Funktion Signatur sein wie folgend:ELM/Haskell: Verwenden Sie Regulärer Ausdruck (Regex) einen String zu suchen und machen HTML-Ansicht

parse : String -> Html Msg 

, bevor wir in den Code tauchen lassen wir ein Beispiel, wie der Code, um eine klare Vorstellung zu haben, da eine der folgenden Zeichenkette wie unten verhalten soll:

Eingang: hallo (! fett!) ich bin ein fettgedruckter Text (! BOLD!) bla bla la

erwartete Ausgabe: div [] [Text "Hallo", b []

myReplace str expression = 
    replace (All) (regex expression) matchToString str 
--myreplace "hello (!BOLD!) bold (!BOLD!) " "(!BOLD!)" == "hello b[][] hello" 
:]

, um dieses Ziel zu erreichen, ich habe die Regex-Bibliothek zur Verfügung gestellt in ELM Paket

replace : HowMany -> Regex -> (Match -> String) -> String -> String 

oben auf der obigen Funktion, i erstellt die 2-Funktion aufgeführt hier nach dem Gebrauch

mit der unten stehenden Hilfsfunktion, ist diese Funktion ein Spiel nehmen und den Anfang und das Ende für den regulären Ausdruck

matchToString : Match -> String 
matchToString match = 
    case match.number `rem` 2 of 
    0 ->"]" -- mtaches the close bracket 
    _ -> "B [][" --mtaches the open bracket 

angeben, aber was ich will bekommen, ist: div [][text "hello", b[][text "bold"]]

, wie ich meinen Code verbessern könnte und schreibe den kompletten Parser? oder wie könnte ich den gleichen Zweck in Haskell erreichen?

Referenz: elm regex source

Antwort

4

Reguläre Ausdrücke beginnen, ihre Macht zu verlieren und übermäßig in Fällen wie diesem komplexer geworden. Stattdessen empfehle ich, in Parser Combinators zu schauen, die viel leistungsfähiger sind, während sie einfacher zu pflegen und zu begründen sind.

In diesem Beispiel werde ich das Bogdanp/elm-combine Paket verwenden.

Hier werden wir einen Parser aufbauen, der eine Zeichenfolge annimmt und annimmt, dass sie unstyled ist, bis sie (!BOLD!) erreicht und fett bleibt, bis sie einen weiteren (!BOLD!) Eintrag findet. Die Ausgabe wird eine Liste von Tupeln von Zeichen sein und ob sie Unstyled oder Bold sind.Nachteil: es gibt wahrscheinlich prägnanter combinators dies zu erreichen, aber ich bin relativ neu in der Kunst

import Html exposing (..) 
import Html.Attributes exposing (..) 
import Combine exposing (..) 
import Combine.Char exposing (..) 
import Combine.Infix exposing (..) 
import String 
import List.Extra exposing (groupWhile) 

type Style 
    = Unstyled 
    | Bold 

styleParser : Bool -> Parser (List (Char, Style)) 
styleParser bolded = 
    let 
    style = if bolded then Bold else Unstyled 
    in 
    (end `andThen` always (succeed [])) 
     <|> (string "(!BOLD!)" `andThen` \_ -> styleParser (not bolded)) 
     <|> (anyChar 
      `andThen` \c -> styleParser bolded 
      `andThen` \cs -> (succeed ((c, style) :: cs))) 

Das Ergebnis dieser Parser für das Beispiel "a(!BOLD!)b(!BOLD!)c" würde die Liste enthalten [('a', Unstyled), ('b', Bold), ('c', Unstyled)], so müssen wir tun einige Mapping und Falten um die in eine Liste von Html msg Werte zu drehen:

htmlParser : Parser (List (Html msg)) 
htmlParser = 
    styleParser False 
    `andThen` (succeed << foldStyledHtml) 

foldStyledHtml : List (Char, Style) -> List (Html msg) 
foldStyledHtml chars = 
    let 
    foldSingleStyledHtml = 
     List.foldr (\(c, s) (cs, _) -> (c :: cs, s)) ([], Unstyled) 
     >> \(chars, style) -> 
      let str = String.fromList chars 
      in case style of 
       Unstyled -> text str 
       Bold -> b [] [ text str ] 
    in 
    groupWhile (\a b -> snd a == snd b) chars 
     |> List.map foldSingleStyledHtml 

Sie können dann einige Beispieltext mit Ausgabe der folgende:

main = 
    case parse htmlParser testInput of 
    (Ok htmls, _) -> div [] htmls 
    (Err err, _) -> div [ style [("color", "red")] ] [ text <| toString <| err] 

Ich habe die vollständige Quelle dieser in a gist veröffentlicht. Sie benötigen auch das Paket elm-community/list-extra. Hoffe das hilft!