/ / Stringhe di analisi racchiuse tra virgolette: json, string, haskell

Stringhe che sono circondate da virgolette - json, string, haskell

Sto analizzando alcuni dati che non controllo. Ho valori che sono una matrice di stringhe. Possono essere stringhe normali, una rappresentazione in stringa di un numero o un numero con virgolette attorno.

["This is just a string", ""5"", "3"]

Mi piacerebbe scrivere una funzione toValue che li converte nel tipo appropriato per essere convertiti in JSON.

toValue :: (ToJSON a) => String -> a
toValue (if a number) = parseInt
toValue (if a quoted number) = parseInt . stripQuotes
toValue _ = id

Vorrei rimuovere le virgolette se si tratta di un numero racchiuso tra virgolette, quindi convertirlo in un numero se un numero, altrimenti restituirlo come stringa.

Posso farlo con la corrispondenza del modello? In qualche altro modo?

risposte:

3 per risposta № 1
    import Data.Char
import Data.Bool

parse a@(""":n:""":[]) = bool (Left a) (Right (read [n] :: Int)) (isNumber n)
parse a@(""":n:m:""":[]) = bool (Left a) (Right (read [n,n] :: Int)) (isNumber n && isNumber m)
parse a@(n:[]) = bool (Left a) (Right (read [n] :: Int)) (isNumber n)
parse a@(n:m:[]) = bool (Left a) (Right (read [n,n] :: Int)) (isNumber n && isNumber m)
parse xs = Left xs

> map parse ["This is just a string", ""5"", "3"]
[Left "This is just a string",Right 5,Right 3]

quindi puoi usare either funzione da Data.Either modulo per codificare il numero (Diritti) e la stringa (Sinistra) in JSON.


-1 per risposta № 2

Scrivere una funzione toValue :: ToJSON a => String -> a come stai proponendo non è così difficile: facciamo semplicemente toValue un metodo della classe ToJSON

class ToJSON a where
toValue :: String -> a

e quindi definire l'istanza per Int come

instance ToJSON Int where
toValue s@(""" : _) = read (read s) -- with quotes
toValue s            = read s        -- without quotes

L'istanza per String è leggermente più coinvolto (come String è sinonimo di [Char]) ma in nessun modo scienza missilistica:

class ToJSONList a where
toValues :: String -> [a]

instance ToJSONList Char where
toValues = id

instance ToJSONList a => ToJSON [a] where
toValue = toValues

Ora, testandolo in una sessione interattiva, abbiamo:

> toValue "This is just a string" :: String
"This is just a string"

> toValue ""5"" :: Int
5

> toValue "3" :: Int
3

Tuttavia, dalla tua domanda sembra che tu abbia un caso d'uso che non è ben supportato da tale funzione toValue, ovvero per convertire tutti gli elementi di un elenco nella loro rappresentazione JSON appropriata. Per fare ciò, probabilmente vorrai introdurre un tipo di dati algebrico per rappresentare i valori JSON:

data JSON = JInt Int | JString String deriving Show

e quindi avere la funzione toJSON che porta le stringhe alla loro rappresentazione JSON più appropriata:

toJSON :: String -> JSON
toJSON    s      =
case reads s of
[(n, "")] -> JInt n                                   -- Int, no quotes
_         -> case reads s of
[(s, "")] -> case reads s of
[(n, "")] -> JInt n     -- Int, quotes
_         -> JString s  -- String, quotes
_         -> JString s                 -- String, no quotes

Infatti, per rispondere a quella parte della tua domanda,questa funzione è definita solo dal pattern matching (nidificato). Tuttavia, se la (grammatica del) linguaggio che devi analizzare diventa più complicata dei soli valori letterali interi, letterali interi tra virgolette e letterali stringa, questo modo di definire i parser diventa rapidamente goffo e soggetto a errori, e potresti voler iniziare cerca in combinatori parser o generatori di parser poi.

Per il tuo semplice linguaggio dei valori JSON, questo va probabilmente ancora bene. Ecco un semplice esempio in una sessione interattiva:

> map toJSON ["This is just a string", ""5"", "3"]
[JString "This is just a string",JInt 5,JInt 3]