diff --git a/lexical.go b/lexical.go index 5c1d8bc..5f30d5d 100644 --- a/lexical.go +++ b/lexical.go @@ -21,7 +21,10 @@ import ( // // Date : 20:52 2022/7/4 func NewLexical(jsonData string) *lexical { - return &lexical{jsonData: jsonData} + return &lexical{ + jsonData: jsonData, + lexicalResult: make([]*lexicalNode, 0), + } } // lexical 词法解析 @@ -32,6 +35,7 @@ func NewLexical(jsonData string) *lexical { type lexical struct { jsonData string keyLeftRightTokenCnt int + lexicalResult []*lexicalNode } // Parse 解析词法 @@ -40,50 +44,64 @@ type lexical struct { // // Date : 18:11 2022/7/4 func (l *lexical) Parse(jsonData string) ([]lexicalNode, error) { - jsonData = strings.ReplaceAll(strings.ReplaceAll(jsonData, "\n", ""), "\t", "") // mt.Println(jsonData) if len(jsonData) < 2 { return nil, errors.New("input data is not json") } - lexicalList := make([]lexicalNode, 0) tmpStr := "" for _, itemChar := range jsonData { currentChar := string(itemChar) - preChar := "-1" - if len(lexicalList) > 0 { - preChar = lexicalList[len(lexicalList)-1].Val - if len(tmpStr) == 0 && preChar == objectLeftToken && currentChar == " " { - // 无意义的空格 - continue - } - if len(tmpStr) == 0 && currentChar == " " && preChar == keyLeftRightToken && l.keyLeftRightTokenCnt%2 == 0 { - // " : 之间的空格无意义 - continue - } - } - if l.inputCharIsToken(currentChar, preChar) { + if l.inputCharIsToken(currentChar, tmpStr) { if currentChar == keyLeftRightToken { // 双引号计数 l.keyLeftRightTokenCnt++ } // 是关键词 if len(tmpStr) > 0 { - lexicalList = append(lexicalList, lexicalNode{ + l.lexicalResult = append(l.lexicalResult, &lexicalNode{ Val: tmpStr, IsToken: false, }) } - lexicalList = append(lexicalList, lexicalNode{ + l.lexicalResult = append(l.lexicalResult, &lexicalNode{ Val: currentChar, IsToken: true, }) tmpStr = "" } else { // 不是关键词, 继续向后走 + if currentChar == " " { + // 当前字符是空格, 只有在字符串内方才有效 + if l.keyLeftRightTokenCnt%2 == 0 { + // 关键字之间的空格, 忽略即可 + continue + } + } tmpStr = tmpStr + currentChar } } - util.JSON.ConsoleOutput(lexicalList) + // 格式化, 去掉 \n \t 等换行符 + format := make([]*lexicalNode, 0) + for idx, val := range l.lexicalResult { + formatVal := strings.ReplaceAll(strings.ReplaceAll(val.Val, "\n", ""), "\t", "") + // 说明是 \n\t 组成的 + if len(formatVal) == 0 { + if idx == 0 { + continue + } + if idx == len(l.lexicalResult)-1 { + break + } + if (!l.lexicalResult[idx-1].IsToken || l.lexicalResult[idx-1].Val != keyLeftRightToken) || + (!l.lexicalResult[idx+1].IsToken || l.lexicalResult[idx+1].Val != keyLeftRightToken) { + // 不是 "" 之间的 \n \t 没有实际意义 + continue + } + } + format = append(format, val) + } + l.lexicalResult = format + util.JSON.ConsoleOutput(l.lexicalResult) return nil, nil } @@ -92,24 +110,151 @@ func (l *lexical) Parse(jsonData string) ([]lexicalNode, error) { // Author : go_developer@163.com<白茶清欢> // // Date : 18:15 2022/7/4 -func (l *lexical) inputCharIsToken(inputChar string, preChar string) bool { - if preChar == escapeCharacterToken { - // 前一个是转义符, 当前不是关键字 - return false +func (l *lexical) inputCharIsToken(inputChar string, tmpStr string) bool { + if len(tmpStr) == 0 && inputChar == keyLeftRightToken { + // 双引号关键字 + return true } - tokenCharList := []string{ - listLeftToken, - listRightToken, - objectLeftToken, - objectRightToken, - keyLeftRightToken, - kvPairSplitToken, - escapeCharacterToken, - } - for _, itemChar := range tokenCharList { - if itemChar == inputChar { + tmpStrByte := []byte(tmpStr) + if len(tmpStrByte) > 0 { + // 字符串拼接过程中, 只有 " 可能是关键字 + // 判断转义符个数 + escapeCharacterTokenCnt := 0 + for i := len(tmpStrByte) - 1; i >= 0; i-- { + if string(tmpStrByte[i]) == escapeCharacterToken { + // 前一个是转义符 + escapeCharacterTokenCnt++ + continue + } + // 非连续的转义符不计数 + break + } + // 0 个 或者 偶数个转义符, " 是关键字 + if escapeCharacterTokenCnt%2 == 0 && inputChar == keyLeftRightToken { return true } } + + var preNode *lexicalNode + if len(l.lexicalResult) > 0 { + preNode = l.lexicalResult[len(l.lexicalResult)-1] + } + + if inputChar == colonToken && nil != preNode && preNode.Val == keyLeftRightToken && l.keyLeftRightTokenCnt > 0 && l.keyLeftRightTokenCnt%2 == 0 { + // : 必须出现在偶数 " 之后才是关键字 + return true + } + + tmpStrType := l.getTpmStrType(tmpStr) + // , 是关键字的场景 + // {"name":"zhangsan", "age":"18"} + // [{"name":"zhangsan", "age":"18"}, {"name":"zhangsan", "age":"18"}] + // [[],[]] + // [1,2,3] + // [true,false,true] + if inputChar == commaToken && len(tmpStr) == 0 && + // 对应 {"name":"zhangsan", "age":"18"} + (nil != preNode && preNode.Val == keyLeftRightToken) || + // 对应[{"name":"zhangsan", "age":"18"}, {"name":"zhangsan", "age":"18"}] + (nil != preNode && preNode.Val == objectRightToken) || + // 对应[[],[]] + (nil != preNode && preNode.Val == listRightToken) || + // 对应 [true,false,true] / [1,2,3] / [1,true,2,false] + (nil != preNode && (preNode.Val == listLeftToken || preNode.Val == commaToken) && (tmpStrType == "number" || tmpStr == "bool")) { // 对应 + return true + } + + // { 可能出现的情况 + // {} + // [{}] [{}, {}] + // {"person": {}} + if inputChar == objectLeftToken && len(tmpStr) == 0 && + (nil == preNode || // 对应 {} + (nil != preNode && preNode.Val == listLeftToken) || // 对应 [{}] + (nil != preNode && preNode.Val == colonToken) || // 对应 {"person": {}} + (nil != preNode && preNode.Val == commaToken)) { // 对应 [{}, {}] + // { 是关键字 + return true + } + + // } 可能出出现的情况 + // {} + // [{}] + // {"name":"zhangsan"} + // {"person": {"name":"zhangsan"}} + // {"person": {"name":"zhangsan", "age": 18}} + // {"person": {"work":true}} + // {"person": {"like":1}} + if inputChar == objectRightToken && len(tmpStr) == 0 && ( + // 对应 {}, [{}] + (nil != preNode && preNode.Val == objectLeftToken) || + // 对应 {"name":"zhangsan"} + (nil != preNode && preNode.Val == keyLeftRightToken) || + // 对应 {"person": {"name":"zhangsan"}} + (nil != preNode && preNode.Val == objectRightToken)) || + // 对应 {"person": {"work":true}} / {"person": {"like":1}} + (nil != preNode && preNode.Val == colonToken && (tmpStr == "number" || tmpStr == "bool")) { + // } 是关键字 + return true + } + + // [ 可能出现的场景 + // [] + // [[],[]] + // "a": [] + if inputChar == listLeftToken && (nil == preNode || // 对应 [] + (nil != preNode && preNode.Val == listLeftToken) || // 对应 [[],[]] + (nil != preNode && preNode.Val == colonToken)) { // 对应 "a": [] + // [ 是关键字 + return true + } + + // ] 可能出现的场景 + // [] + // [[],[]] + // [{}, {}] + // [1,2,3] + // [true, false] + // ["", "" ] + if inputChar == listLeftToken && ( + //对应 [] + (nil != preNode && preNode.Val == listLeftToken) || + // 对应 [[],[]] + (nil != preNode && preNode.Val == listRightToken) || + // [true, false] / + (nil != preNode && preNode.Val == objectRightToken) || + // 对应 [{}, {}] / [1,2,3] + (nil != preNode && (tmpStrType == "number" || tmpStrType == "bool")) || + // 对应 ["", "" ] + (nil != preNode && preNode.Val == keyLeftRightToken)) { + + } return false } + +func (l *lexical) getTpmStrType(tmpStr string) string { + var preNode *lexicalNode + if len(l.lexicalResult) > 0 { + preNode = l.lexicalResult[len(l.lexicalResult)-1] + } + + // 数字只有一个场景 {"age": 18},多以若是数字, 则 前一次解析必为关键字 : + if nil != preNode && preNode.Val == colonToken { + // 判断是否可转数字 + var floatVal float64 + if err := util.ConvertAssign(&floatVal, tmpStr); nil == err { + return "number" + } + } + + // 判断是否为 bool + // bool 只有一个场景 {"work": true/false},多以若是数字, 则 前一次解析必为关键字 : + if nil != preNode && preNode.Val == colonToken { + // 判断是否可转数字 + var boolVal bool + if err := util.ConvertAssign(&boolVal, tmpStr); nil == err { + return "bool" + } + } + return "string" +} diff --git a/lexical_test.go b/lexical_test.go index 6da71a2..b64683a 100644 --- a/lexical_test.go +++ b/lexical_test.go @@ -13,7 +13,7 @@ import ( func Test_parseLexical(t *testing.T) { jsonData := `{ - "name" :"zhangsan", + "name" : "zhangsan", "age":"18", "extension":{ "sex":"man", diff --git a/token.go b/token.go index d1dc91f..5e08207 100644 --- a/token.go +++ b/token.go @@ -18,8 +18,10 @@ const ( objectRightToken = "}" // key 值的起始 keyLeftRightToken = "\"" - // kvPairSplit kv 的分隔符 - kvPairSplitToken = ":" // 转义符 escapeCharacterToken = "\\" + // 冒号 + colonToken = ":" + // 逗号 + commaToken = "," )