电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

Java 手動解析不帶引號的JSON字符串的操作

瀏覽:47日期:2022-08-22 15:04:16
1 需求說明

項目中遇到了一批不帶引號的類JSON格式的字符串:

{Name:Heal,Age:20,Tag:[Coding,Reading]}

需要將其解析成JSON對象, 然后插入到Elasticsearch中, 當作Object類型的對象存儲起來.

在對比了阿里的FastJson、Google的Gson, 沒找到想要的功能 ( 可能是博主不夠仔細, 有了解的童學留言告訴我下呀😛), 于是就自己寫了個工具類, 用來實現此需求.

如果是帶有引號的標準JSON字符串, 可直接通過上述2種工具進行解析, 使用方法可參考:

Java - 格式化輸出JSON字符串的兩種方式

2 解析代碼

2.1 實現思路

代碼的主要思路在注釋中都有說明, 主要思路是:

(1) 借助Stack統計字符串首尾的[]、{}符號 —— []代表List, {}代表Map;

(2) 使用String#subString()方法縮減已解析的字符串;

(3) 使用遞歸解析內部的List、Map對象;

(4) 為了便于處理, 最小的key-value都解析成String類型.

需要注意的是: 要解析的字符串內部不要存在無意義的{、}、[、]符號, 否則會導致解析發生異常.

—— 暫時沒想到好的兼容方法, 有想法的童學請直接留言.**

2.2 詳細代碼

package com.healchow.util;import java.security.InvalidParameterException;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.Stack;/** * Java 解析不帶引號的JSON字符串 * * @author Heal Chow * @date 2019/08/13 11:36 */public class ParseJsonStrUtils { public static void main(String[] args) { // 帶引號的字符串, 會將字符串當作key-value的一部分, 因此這類字符串推薦使用fastJson、Gson等工具轉換 // 注意: String內部不要存在無意義的{、}、[、]符號 - 暫時沒想到好的兼容方法 /*String sourceStr = '{'_index':'book_shop',' + ''_id':'1',' + ''_source':{' +''name':'Thinking in Java [4th Edition]',' +''author':'[US] Bruce Eckel',' +''price':109.0,'date':'2007-06-01 00:00:00',' +''tags':['Java',['Programming']' + '}}';*/ // 不帶引號的字符串, 首尾多對[]、{}不影響解析 String sourceStr = '[[[{' + '{' +'Type:1,' +'StoragePath:[{Name:/image/2019-08-01/15.jpeg,DeviceID:4401120000130},{ShotTime:2019-08-01 14:44:24}],' +'Width:140' + '},' + '{' +'Type:2,StoragePath:9090/pic/2019_08_01/src.jpeg,' +'Inner:{DeviceID:44011200},' +'Test:[{ShotTime:2019-08-01 14:50:14}],' +'Width:5600}' + '}}]]]'; List<Map<String, Object>> jsonArray; Map<String, Object> jsonMap; Object obj = null; try { obj = parseJson(sourceStr); } catch (Exception e) { System.out.println('出錯啦: ' + e.getMessage()); e.printStackTrace(); } if (obj instanceof List) { jsonArray = (List<Map<String, Object>>) obj; System.out.println('解析生成了List對象: ' + jsonArray); } else if (obj instanceof Map) { jsonMap = (Map<String, Object>) obj; System.out.println('解析生成了Map對象: ' + jsonMap); } else { System.out.println('需要解析的字符串既不是JSON Array, 也不符合JSON Object!n原字符串: ' + sourceStr); } } /** * 解析 Json 格式的字符串, 封裝為 List 或 Map 并返回 * 注意: (1) key 和 value 不能含有 ',', key 中不能含有 ':' —— 要分別用 ',' 和 ':' 進行分隔 * (2) 要解析的字符串必須符合JSON對象的格式, 只對最外層的多層嵌套做了簡單的處理, * 復雜的如'{a:b},{x:y}'將不能完全識別 —— 正確的應該是'[{a:b},{x:y}]' * @param sourceStr 首尾被'[]'或'{}'包圍的字符串 * @return 生成的JsonObject */ public static Object parseJson(String sourceStr) throws InvalidParameterException { if (sourceStr == null || ''.equals(sourceStr)) { return sourceStr; } // 判斷字符串首尾有沒有多余的、相匹配的 '[]' 和 '{}' String parsedStr = simplifyStr(sourceStr, '[', ']'); parsedStr = simplifyStr(parsedStr, '{', '}'); // 借助棧來實現 '[]' 和 '{}' 的出入 Stack<String> leftSymbolStack = new Stack<>(); Stack<String> rightSymbolStack = new Stack<>(); if ((parsedStr.startsWith('[') && parsedStr.endsWith(']')) || (parsedStr.startsWith('{') && parsedStr.endsWith('}'))) { leftSymbolStack.push(parsedStr.substring(0, 1)); rightSymbolStack.push(parsedStr.substring(parsedStr.length() - 1)); parsedStr = parsedStr.substring(1, parsedStr.length() - 1); // parsedStr 內部還可能是連續的'{{}}' parsedStr = simplifyStr(parsedStr, '{', '}'); } else { throw new InvalidParameterException('要解析的字符串中存在不匹配的’[]’或’{}’, 請檢查!n原字符串為: ' + sourceStr); } // 保存解析的結果, jsonArray中可能只有String, 也可能含有Map<String, Object> List<Object> jsonArray = new ArrayList<>(); Map<String, Object> jsonMap = new HashMap<>(16); // 內部遍歷、解析 innerParseByLoop(parsedStr, leftSymbolStack, rightSymbolStack, jsonArray, jsonMap); // 判斷jsonArray是否為空 if (jsonArray.size() > 0) { return jsonArray; } else { return jsonMap; } } /** * 循環解析內部的List、Map對象 */ private static void innerParseByLoop(String parsedStr, Stack<String> leftSymbolStack, Stack<String> rightSymbolStack, List<Object> jsonArray, Map<String, Object> jsonMap) throws InvalidParameterException { if (parsedStr == null || parsedStr.equals('')) { return; } // 按照','分隔 String[] allKeyValues = parsedStr.split(','); if (allKeyValues.length > 0) { // 遍歷, 并按照':'分隔解析 out: for (String keyValue : allKeyValues) { // 如果keyValue中含有':', 說明該keyValue是List<Map>中的一個對象, 就需要確定第一個':'的位置 —— 可能存在多個':' int index = keyValue.indexOf(':'); if (index > 0) { // 判斷key是否仍然以'{'或'['開始, 如果是, 則壓棧 String key = keyValue.substring(0, index); while (key.startsWith('[') || key.startsWith('{')) { leftSymbolStack.push(key.substring(0, 1)); // 解析過的串要一直跟進 parsedStr = parsedStr.substring(1); key = key.substring(1); } // 判讀和value是否以'['開頭 —— 又是一個 List 對象 —— 遞歸解析 String value = keyValue.substring(index + 1); if (value.startsWith('[')) { int innerIndex = parsedStr.indexOf(']'); List<Object> innerList = (List<Object>) parseJson(parsedStr.substring(key.length() + 1, innerIndex + 1)); jsonMap.put(key, innerList); // 清除最后的']', 并判斷是否存在',' parsedStr = parsedStr.substring(innerIndex + 1); if (parsedStr.indexOf(',') == 0) { parsedStr = parsedStr.substring(1); } // 此內部存在對象, 內部的','已經解析完畢了, 要修正按照','切割的字符串數組, 并繼續遍歷 innerParseByLoop(parsedStr, leftSymbolStack, rightSymbolStack, jsonArray, jsonMap); break; } // 判讀和value是否以 '{' 開頭 —— 又是一個 Map 對象 —— 遞歸解析 else if (value.startsWith('{')) { int innerIndex = parsedStr.indexOf('}'); Map<String, Object> innerMap = (Map<String, Object>) parseJson(parsedStr.substring(key.length() + 1, innerIndex + 1)); jsonMap.put(key, innerMap); // 清除最后的'}', 并判斷是否存在',' parsedStr = parsedStr.substring(innerIndex + 1); if (parsedStr.indexOf(',') == 0) { parsedStr = parsedStr.substring(1); } // 此內部存在對象, 內部的','已經解析完畢了, 要修正按照','切割的字符串數組, 并繼續遍歷 innerParseByLoop(parsedStr, leftSymbolStack, rightSymbolStack, jsonArray, jsonMap); break; } // 最后判斷value尾部是否含有 ']' 或 '}' else { while (value.endsWith(']') || value.endsWith('}')) { // 最右側的字符 String right = value.substring(value.length() - 1); // 此時棧頂元素 String top = leftSymbolStack.peek(); // 如果有相匹配的, 則彈棧, 否則忽略 if (('}'.equals(right) && '{'.equals(top)) || (']'.equals(right) && '['.equals(top))) {leftSymbolStack.pop();value = value.substring(0, value.length() - 1);jsonMap.put(key, value);// 清除最后的'}', 并判斷是否存在','parsedStr = parsedStr.substring(key.length() + 1 + value.length() + 1);if (parsedStr.indexOf(',') == 0) { parsedStr = parsedStr.substring(1);}// 解析完成了一個對象, 則將該元素添加到List中, 并創建新的對象jsonArray.add(jsonMap);jsonMap = new HashMap<>(16);// 繼續進行外層的解析continue out; } // 如果都不匹配, 則有可能是源字符串的最后一個符號 else {rightSymbolStack.push(right);value = value.substring(0, value.length() - 1); } } jsonMap.put(key, value); int length = key.length() + value.length() + 2; if (parsedStr.length() > length) { parsedStr = parsedStr.substring(length); } else { parsedStr = ''; } } } // 如果keyValue中不含':', 說明該keyValue只是List<String>中的一個串, 而非List<Map>中的一個Map, 則直接將其添加到List中即可 else { jsonArray.add(keyValue); } } // 遍歷結束, 處理最后的符號問題 —— 判斷左右棧是否匹配 while (!leftSymbolStack.empty()) { if (leftSymbolStack.peek().equals('{') && parsedStr.equals('}')) { leftSymbolStack.pop(); } if (!rightSymbolStack.empty()) { if (leftSymbolStack.peek().equals('{') && rightSymbolStack.peek().equals('}')) { leftSymbolStack.pop(); rightSymbolStack.pop(); } else if (leftSymbolStack.peek().equals('[') && rightSymbolStack.peek().equals(']')) { leftSymbolStack.pop(); rightSymbolStack.pop(); } else { throw new InvalidParameterException('傳入的字符串中不能被解析成JSON對象!n原字符串為: ' + parsedStr); } } } } } /** * 判斷字符串首尾有沒有多余的、相匹配的 '[]' 和 '{}', 對其進行簡化 */ private static String simplifyStr(String sourceStr, String firstSymbol, String lastSymbol) { while (sourceStr.startsWith(firstSymbol) && sourceStr.endsWith(lastSymbol)) { String second = sourceStr.substring(1, 2); // 如果第二個仍然是'['或'{', 再判斷倒數第二個是不是']'或'}' —— 說明長度至少為3, 不會發生 IndexOutOfBoundsException if (second.equals(firstSymbol)) { String penultimate = sourceStr.substring(sourceStr.length() - 2, sourceStr.length() - 1); if (penultimate.equals(lastSymbol)) { // 縮短要解析的串 sourceStr = sourceStr.substring(1, sourceStr.length() - 1); } else { break; } } else { break; } } return sourceStr; }}

2.3 測試樣例

(1) 帶引號的測試:

// 測試字符串:String sourceStr = '{'_index':'book_shop',' + ''_id':'1',' + ''_source':{' + ''name':'Thinking in Java [4th Edition]',' + ''author':'[US] Bruce Eckel',' + ''price':109.0,'date':'2007-06-01 00:00:00',' + ''tags':['Java',['Programming']' + '}}';

解析結果為:

Java 手動解析不帶引號的JSON字符串的操作

(2) 不帶引號的測試:

// 測試字符串: String sourceStr = '[[[{' + '{' + 'Type:1,' + 'StoragePath:[{Name:/image/2019-08-01/15.jpeg,DeviceID:4401120000130},{ShotTime:2019-08-01 14:44:24}],' + 'Width:140' + '},' + '{' + 'Type:2,StoragePath:9090/pic/2019_08_01/src.jpeg,' + 'Inner:{DeviceID:44011200},' + 'Test:[{ShotTime:2019-08-01 14:50:14}],' + 'Width:5600}' + '}}]]]';

解析結果為:

Java 手動解析不帶引號的JSON字符串的操作

補充知識:將key名不帶雙引號的JSON字符串轉換成JSON對象的方法

根據json.org上面的描述,JSON對象是由對象成員組成,而成員是由key-value鍵值組成。

key值是一個字符串:

字符串由Unicode字符組成,用雙引號包圍,用反斜杠轉義。可以是單個字符。用法跟C或Java里的字符串的用法相似。

但是,在現實應用中,很少有程序員知道JSON里的key需要用雙引號包圍,因為大多數的瀏覽器里并不需要使用雙引號。所以,為什么多此一舉要多寫兩個雙引號呢?

規范的例子:

{'keyName' : 34}

不規范的例子:

{keyName : 34}

雖然在瀏覽器里使用不規范的、不使用雙引號的寫法在瀏覽器里不會出現問題,但并不代表你可以在其它地方不會遇到問題,比如,你有一個字符串:

//字符串格式

’{ keyName : 34 }’

你想把它轉換成JSON對象。把JSON字符串轉換成JSON對象,需要使用 JSON.parse()方法,對于上面的這種key名上不帶雙引號的的JSON字符串,使用JSON.parse()解析時會報錯,無法解析。這就成了一個很麻煩的問題。所以說,盡量使用規范的預防還是有好處的,盡管大多數時候你不會遇到問題。

那么,對于key名不帶雙引號的JSON字符串,如何將它轉換成JSON對象呢?

最直接的方法是手工給key名加上雙引號。

如果你不像手工添加,可以使用函數全文搜索追加雙引號,比如下面的這段代碼:

json_string.replace(/(s*?{s*?|s*?,s*?)([’'])?([a-zA-Z0-9]+)([’'])?:/g, ’$1'$3':’);

eval(’var json = new Object(’ + json_string + ’)’);

最后,最簡單的一種方法是直接用eval()運行它:

var obj = eval(’(’ + invalid_json + ’)’);

但這樣執行時,你需要理解執行的代碼是什么,因為如果它里面含有一些惡意程序,你這樣直接運行很可能引起安全問題。

以上這篇Java 手動解析不帶引號的JSON字符串的操作就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持好吧啦網。

標簽: Java
相關文章:
主站蜘蛛池模板: 电主轴-高速精密电主轴-高速电机厂家-瑞德沃斯品牌有限公司 | 台湾阳明固态继电器-奥托尼克斯光电传感器-接近开关-温控器-光纤传感器-编码器一级代理商江苏用之宜电气 | 深圳品牌设计公司-LOGO设计公司-VI设计公司-未壳创意 | 热缩管切管机-超声波切带机-织带切带机-无纺布切布机-深圳市宸兴业科技有限公司 | 深圳美安可自动化设备有限公司,喷码机,定制喷码机,二维码喷码机,深圳喷码机,纸箱喷码机,东莞喷码机 UV喷码机,日期喷码机,鸡蛋喷码机,管芯喷码机,管内壁喷码机,喷码机厂家 | 厦门网站建设_厦门网站设计_小程序开发_网站制作公司【麦格科技】 | 快干水泥|桥梁伸缩缝止水胶|伸缩缝装置生产厂家-广东广航交通科技有限公司 | 阴离子聚丙烯酰胺价格_PAM_高分子聚丙烯酰胺厂家-河南泰航净水材料有限公司 | 冷镦机-多工位冷镦机-高速冷镦机厂家-温州金诺机械设备制造有限公司 | 自清洗过滤器_全自动过滤器_全自动反冲洗过滤器_量子过滤器-滑漮滴 | Magnescale探规,Magnescale磁栅尺,Magnescale传感器,Magnescale测厚仪,Mitutoyo光栅尺,笔式位移传感器-苏州连达精密量仪有限公司 | 传动滚筒,改向滚筒-淄博建凯机械科技有限公司| 冰雕-冰雪世界-大型冰雕展制作公司-赛北冰雕官网 | 在线浊度仪_悬浮物污泥浓度计_超声波泥位计_污泥界面仪_泥水界面仪-无锡蓝拓仪表科技有限公司 | 单螺旋速冻机-双螺旋-流态化-隧道式-食品速冻机厂家-广州冰泉制冷 | 老城街小面官网_正宗重庆小面加盟技术培训_特色面馆加盟|牛肉拉面|招商加盟代理费用多少钱 | 网站建设-临朐爱采购-抖音运营-山东兆通网络科技 | 广州冷却塔维修厂家_冷却塔修理_凉水塔风机电机填料抢修-广东康明节能空调有限公司 | 馋嘴餐饮网_餐饮加盟店火爆好项目_餐饮连锁品牌加盟指南创业平台 | 飞歌臭氧发生器厂家_水处理臭氧发生器_十大臭氧消毒机品牌 | 欧洲MV日韩MV国产_人妻无码一区二区三区免费_少妇被 到高潮喷出白浆av_精品少妇自慰到喷水AV网站 | 船用锚链|专业锚链生产厂家|安徽亚太锚链制造有限公司 | Q361F全焊接球阀,200X减压稳压阀,ZJHP气动单座调节阀-上海戎钛 | 旗帜网络笔记-免费领取《旗帜网络笔记》电子书 | 除尘器布袋骨架,除尘器滤袋,除尘器骨架,电磁脉冲阀膜片,卸灰阀,螺旋输送机-泊头市天润环保机械设备有限公司 | 工业硝酸钠,硝酸钠厂家-淄博「文海工贸」 | 胶原检测试剂盒,弹性蛋白检测试剂盒,类克ELISA试剂盒,阿达木单抗ELISA试剂盒-北京群晓科苑生物技术有限公司 | 通信天线厂家_室分八木天线_对数周期天线_天线加工厂_林创天线源头厂家 | 东莞动力锂电池保护板_BMS智能软件保护板_锂电池主动均衡保护板-东莞市倡芯电子科技有限公司 | 下水道疏通_管道疏通_马桶疏通_附近疏通电话- 立刻通 | 东莞压铸厂_精密压铸_锌合金压铸_铝合金压铸_压铸件加工_东莞祥宇金属制品 | 企典软件一站式企业管理平台,可私有、本地化部署!在线CRM客户关系管理系统|移动办公OA管理系统|HR人事管理系统|人力 | 营养师网,营养师考试时间,报名入口—网站首页 | 锻造液压机,粉末冶金,拉伸,坩埚成型液压机定制生产厂家-山东威力重工官方网站 | 哈尔滨治「失眠/抑郁/焦虑症/精神心理」专科医院排行榜-京科脑康免费咨询 一对一诊疗 | 喷砂机厂家_自动喷砂机生产_新瑞自动化喷砂除锈设备 | 河南卓美创业科技有限公司-河南卓美防雷公司-防雷接地-防雷工程-重庆避雷针-避雷器-防雷检测-避雷带-避雷针-避雷塔、机房防雷、古建筑防雷等-山西防雷公司 | T恤衫定做,企业文化衫制作订做,广告T恤POLO衫定制厂家[源头工厂]-【汉诚T恤定制网】 | 碎石机设备-欧版反击破-欧版颚式破碎机(站)厂家_山东奥凯诺机械 高低温试验箱-模拟高低温试验箱订制-北京普桑达仪器科技有限公司【官网】 | 垃圾处理设备_餐厨垃圾处理设备_厨余垃圾处理设备_果蔬垃圾处理设备-深圳市三盛环保科技有限公司 | 公交驾校-北京公交驾校欢迎您! 工作心得_读书心得_学习心得_找心得体会范文就上学道文库 |