解析用引号括起来的字符串

时间:2014-10-22 17:05:23

标签: json string haskell

我正在解析一些我无法控制的数据。我的值是一个字符串数组。它们可以是普通字符串,数字的字符串表示形式,也可以是带引号的数字。

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

我想编写一个函数toValue,将它们转换为适当的类型以转换为JSON。

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

我想删除引号,如果它是一个被引号括起来的数字,然后将其转换为数字(如果是数字),否则将其作为字符串传回。

我可以使用模式匹配吗?其他一些方式?

2 个答案:

答案 0 :(得分:3)

    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]

然后,您可以使用either模块中的Data.Either函数将数字(权限)和字符串(Lefts)编码为JSON。

答案 1 :(得分:-1)

正如你所提议的那样编写一个函数toValue :: ToJSON a => String -> a并不是那么难:让我们简单地让toValue成为类ToJSON的方法

class ToJSON a where
  toValue :: String -> a

然后将Int的实例定义为

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

String的实例稍微复杂一些(因为String[Char]的同义词),但绝不是火箭科学:

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

instance ToJSONList Char where
  toValues = id

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

现在,在交互式会话中测试它,我们有:

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

> toValue "\"5\"" :: Int
5

> toValue "3" :: Int
3

但是,从您的问题来看,似乎您有一个用例toValue不能很好地支持的用例,即将列表的所有元素转换为适当的JSON表示。为此,您可能希望引入用于表示JSON值的代数数据类型:

data JSON = JInt Int | JString String deriving Show

然后使用函数toJSON将字符串转换为最合适的JSON表示形式:

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

实际上,为了回答你问题的这一部分,这个函数只是通过(嵌套)模式匹配来定义。但是,如果你需要解析的语法(语法)变得更复杂,那么只需要整数文字,引用的整数文字和字符串文字,这种定义解析器的方式很快变得笨拙且容易出错,你可能想要开始然后查看parser combinatorsparser generators

对于JSON值的简单语言,这可以说仍然很好。以下是交互式会话中的一个简单示例:

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