diff --git a/Parser.fs b/Parser.fs new file mode 100644 index 0000000..48e7a89 --- /dev/null +++ b/Parser.fs @@ -0,0 +1,72 @@ +namespace Sanchime.Json + +module Parser = + + + let (|Match|_|) pattern input = + let result = System.Text.RegularExpressions.Regex.Match(input, pattern) + if result.Success then Some result.Value else None + // 将字符串转为Ststem.Boolean类型 + let bool (value: string) = System.Boolean.Parse(value) + + // 去除引号 + let unquote (str: string) = str.Substring(1, str.Length - 2) + + // 获取Token + let token = function + | Match @"^\s+" str -> str, Whitespace + | Match @"^""[^""\\]*(?:\\.[^""\\]*)*""" str -> str, str |> unquote |> StringLiteral + | Match @"^\{|^\}|^\[|^\]|^:|^," str -> str, str[0] |> Symbol + | Match @"^\d+(\.\d+)?|\.\d+" str -> str, str |> float |> NumberLiteral + | Match @"^true|false" str -> str, str |> bool |> BooleanLiteral + | _ -> failwith "无效的符号" + + // 将字符串拆分为Token列表 + let tokenize str = + let rec loop index (str: string) = + if index = str.Length then [] + else + let next = str.Substring index + let text, token = next |> token + token :: loop (index + text.Length) str + loop 0 str + |> List.choose (function Whitespace -> None | value -> Some value) + + let rec (|Value|_|) = function + // 数字常量字面量由数字组成 + | NumberLiteral number :: tokens -> Some (Number number, tokens) + // 逻辑常量字面了由真假值组成 + | BooleanLiteral bool :: tokens -> Some (Boolean bool, tokens) + // 字符串常量字面量由字符串组成 + | StringLiteral string :: tokens -> Some (String string, tokens) + // 数组由标识符 + 左中括号 + 值列表 + 右中括号组成 + | Symbol '[' :: Values(jsons, Symbol ']' :: tokens) -> Some (Array jsons, tokens) + // 对象由标识符 + 左大括号 + 对象列表 + 右大括号组成 + | Symbol '{' :: Brackets (ps, Symbol '}' :: tokens) -> Some (Object ps, tokens) + | [] -> Some (Null, []) + | _ -> None + // 值列表由逗号分割 + and (|Values|_|) = function + | Value(p, token) -> + let rec aux p' = function + | Symbol ',' :: Value (p, token) -> aux (p :: p') token + | token -> p' |> List.rev, token + Some (aux [p] token) + | _ -> None + // 对象由文本常量字面量 + 冒号 + 值组成 + and (|Bracket|_|) = function + | StringLiteral key :: Symbol ':' :: Value (value, token) -> Some ((key, value), token) + | _ -> None + // 对象数组由对象 + 逗号组成的列表 + and (|Brackets|_|) = function + | Bracket (p, tokens) -> + let rec aux p' = function + | Symbol ',' :: Bracket(p, tokens) -> aux (p :: p') tokens + | tokens -> p' |> List.rev, tokens + Some (aux [p] tokens) + | _ -> None + + let parse str = + str |> tokenize |> function + | Value (value, []) -> value + | _ -> failwith "解析Json失败" \ No newline at end of file diff --git a/Program.fs b/Program.fs new file mode 100644 index 0000000..3883619 --- /dev/null +++ b/Program.fs @@ -0,0 +1,24 @@ +open Sanchime.Json.Parser + +let json = """ + { + "Name": "Bob", + "Email": "bob@example.com", + "IsActive": true, + "Info": { + "Age": 18, + "Gender": "男", + "Address": "江西", + "City": "赣州", + "Record": [ + "小学", + "初中", + "高中" + ] + } + } +""" + +let user = json |> parse + +user |> printfn "%A" \ No newline at end of file diff --git a/Sanchime.Json.Parser.fsproj b/Sanchime.Json.Parser.fsproj new file mode 100644 index 0000000..208e0a7 --- /dev/null +++ b/Sanchime.Json.Parser.fsproj @@ -0,0 +1,11 @@ + + + Exe + net6.0 + + + + + + + \ No newline at end of file diff --git a/Syntax.fs b/Syntax.fs new file mode 100644 index 0000000..977f092 --- /dev/null +++ b/Syntax.fs @@ -0,0 +1,16 @@ +namespace Sanchime.Json + +type Token = + | Whitespace + | Symbol of char + | StringLiteral of string + | NumberLiteral of float + | BooleanLiteral of bool + +type Json = + | String of string + | Array of Json list + | Boolean of bool + | Number of float + | Object of (string * Json) list + | Null