用原始方法解析复杂字符串,json一定要用JsonMapper么?

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介:

    经常采集数据,肯定会碰到解析字符串,包括整个页面的html,或者json以及一些不标准的json格式。。。

    以前用json序列化,有时候需要实体类,有的时候没有,比较麻烦,听说可以用JsonMapper,解析为字典格式。不过没用过,习惯了用最原始的方法来解析字符串,所以这里分享几个解析的案例。也许会有点作用。

    解析字符串最常用的应该是Splite和Replace了。分割,然后替换一些引号之类的。最后组合。特别是采集的时候,经常会把html页面中某一段要提取出来,可能很多人用正则表达式,可是不会啊,也不愿意去学。那只好用这些原始的方法了,时间久了,也积累一些经验或者函数。看看几个例子。

1.不规则非json字符串

    先看看这个例子,字符串是连在一起,没有换行的,为了方便观察,换行了,程序是原始在一起的:

1
2
3
[11101630,1532,14,'0','0',3,'2015,4,23,16,05,48','4',1,2,0,0],
[11101631,1532,14,'0','0',3,'2015,4,23,16,09,48','0',,,0,0],
[11101632,1532,14,'0','0',3,'2015,4,23,16,03,10','1',2,2,0,0]

    先来分析一下这个字符串的特点,才能找到思路哦:

1.每一组数据都是在[]括号对中,每一组数据用,号分割,所以最终要形成一个数组来访问哦。

2.每一组的数据基本都是用 , 号分割,字符串类型还有单引号 ;

3.第7个数组是一个整体,也使用,号分割,整体是字符串有引号;

4.第2组数据有空值,直接用,号分割,所以splite的时候不能去掉空值,否则数组长度不一样,定位就乱了。

    既然分析都完了,那思路呢?

1.组直接分割使用  ], 标记,然后每一组要Repalce掉 [  和 ] 。主要是最前和最后;

2.组内分割,使用  ,号标记分割,出来之前要把单引号给 替换掉 ;不然也是作为字符串,引号也包括进去了;

3.至于那个 数组 的处理,不能过于想复杂,分割之后,直接在最后增加1个元素,将固定位置7-12的组合起来;这样也许方便点;

4.由于空值有占位,所以每一组的长度是固定的。所以处理的时候直接根据自己想要的位置来组合。

    下面看看代码了,C#版本,相对与一行代码,仔细看,Linq很是一个神器,真的是神奇。。。说多了都是泪,为啥就没早点学呢:

1
2
3
4
5
6
7
8
9
10
11
String str =  @"[11101630,1532,14,'0','0',3,'2015,4,23,16,05,48','4',1,2,0,0],[11101631,1532,14,'0','0',3,'2015,4,23,16,09,48','0',,,0,0],[11101632,1532,14,'0','0',3,'2015,4,23,16,03,10','1',2,2,0,0]" ;
 
var  result = str.Split( new  string [] {  "],"  }, StringSplitOptions.None)   //先整体分割组
                 .Select(n => n.Replace( "[" "" )   //以下是组内分割,并去掉其他干扰字符
                 .Replace( "]" "" )
                 .Replace( "\'" "" )
                 .Split( ',' ).ToList())
                 .Select(n =>      //对中间一个整体单独提取,进行组合,单独增加一个元素
                 {
                     n.Add(String.Format( "{0},{1},{2},{3},{4},{5}" , n[6], n[7], n[8], n[9], n[10], n[11])); return  n;
                 }).ToList();

看看结果怎么样:

blob.png

2.键值对字符串分割函数

  由于json数据格式都是键值对字符串,所以这里特意分享一个经常用到的分割函数,不用Json组件,那就用简单的方法做一个。这个函数来源于Newlife.Core,是X组件的重要部分。源码部分不过多解释,就是按规则将键值对直接分割保持在字典中,使用方法大家可以自己实验一下,或者参考下面的案例,都有用到这个方法。代码如下,为了方便使用,写成了扩展方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public  static  class  StringHelper
{
     /// <summary>拆分字符串成为名值字典</summary>
     /// <param name="str">要分割字符串的</param>
     /// <param name="nameValueSeparator">键值对的分隔符</param>
     /// <param name="separators">分割字符</param>
     /// <returns>键值对字典</returns>
     public  static  IDictionary<String, String> SplitAsDictionary( this  String str, String nameValueSeparator =  "=" params  String[] separators)
     {
         var  dic =  new  Dictionary<String, String>();
         if  (String.IsNullOrWhiteSpace(str))  return  dic;
 
         if  (String.IsNullOrEmpty(nameValueSeparator)) nameValueSeparator =  "=" ;
         if  (separators ==  null  || separators.Length < 1) separators =  new  String[] {  "," ";"  };
 
         String[] ss = str.Split(separators, StringSplitOptions.RemoveEmptyEntries);
         if  (ss ==  null  || ss.Length < 1)  return  null ;
 
         foreach  ( var  item  in  ss)
         {
             Int32 p = item.IndexOf(nameValueSeparator);
             // 在前后都不行
             if  (p <= 0 || p >= item.Length - 1)  continue ;
 
             String key = item.Substring(0, p).Trim();
             dic[key] = item.Substring(p + nameValueSeparator.Length).Trim();
         }
 
         return  dic;
     }
}

  上面默认的键值对分割符号为 = 号,根据实际情况进行修改,json格式里面一般是:冒号比较多。

3.复杂Json格式的字符串

    上面的例子比较简单,这次看一个稍微复杂点的,虽然可能用JsonMapper可以很轻易做到,但试一下最原始的方法吧。还是按照上面的思路,先分析字符串的特点:字符串是连在一起,没有换行的,为了方便观察,换行了,程序是原始在一起的:

1
2
3
4
5
6
7
{1074:['墨聯','墨联','MEX D1','#098000','98'],
  2100:['美乙','美乙','USL D2','#E89B10','98'],
  1024:['阿甲','阿甲','ARG','#00CCFF','98'],
  1052:['哥倫甲','哥伦甲','COLCMA','#888500','98'],
  1028:['K聯賽','K联赛','KORL','#F75000','98'],
  1297:['球會友誼','球会友谊','CF','#5691D8','98'],
  2085:['奧女甲','奧女甲','AFB','#D86220','97']}

还是先分析特点,这个格式应该是json类似的了,比较规则:

  1. 组与之间是使用 , 号分割;前后有{}括号对;观察前后可以使用 ], 字符串将组分开;

  2. 键 是整数,键值是通过 : 号分割;

  3. 值是一个数组,有5个元素,通过 , 号分割

  4. 都有单引号,需要过滤掉;其他没有特殊情况;

代码解决过程:

1
2
3
4
5
6
7
string  text =  @"{1074:['墨聯','墨联','MEX D1','#098000','98'],2100:['美乙','美乙','USL D2','#E89B10','98'],1024:['阿甲','阿甲','ARG','#00CCFF','98'],1052:['哥倫甲','哥伦甲','COLCMA','#888500','98'],1028:['K聯賽','K联赛','KORL','#F75000','98'],1297:['球會友誼','球会友谊','CF','#5691D8','98'],2085:['奧女甲','奧女甲','AFB','#D86220','97']}" ;
var  dic = text.Replace( "\'" "" ).Split( new  String[]{ "]," }, StringSplitOptions.None)  //先组分割
               .Select(n => n.Replace( "{" "" ).Replace( "}" "" //将组里面的干扰字符过滤掉
                             .Replace( "[" "" ).Replace( "]" "" )
               .SplitAsDictionary( ":" "\"" //键值对处理,冒号分隔符
               .ToDictionary(t => t.Key, t => t.Value.Split( ',' ) //值再次进行分割,形成数组
               )).ToArray();

看看结果如何:

blob.png

4.标准的json格式

    在实际的采集过,可能会碰到直接url,返回的就是json格式,比较标准。这里举个例子,如下面这个页面链接:

http://d.dacai.com/zhishu/CorrectCorp.html?matchId=1899040&matchStatusId=41

点击开后,是这个样子:

blob.png

这个应该够复杂了,我们分析一下,篇幅较大,源码对照链接:

  1. 每一大组数据,是用,号分割;整体也是前后大括号对{},有4个大类,键分布是:IndBodans,IndEvenGoals,IndGoalss,IndHalfFulls。

  2. 每一组的子类中,包括的都是同一个类型的数据,每一个子数据组都有N多个小的键值对,如MatchId,CorpId等等,使用},可以分割

    分析完成之后如何解决,思路是类似的,先整体分割,使用},进行,然后每一个之类作为键,对值再次进行分割。。。形成字典列表。其中的引号也是需要过滤的,至于数值类型,实际用到那个的时候,都是根据key去找,再进行Convert转换就可以了。看看源代码:

1
2
3
4
5
6
7
var  dicList = doc.Split( "{\"IndBodans\":[" "],\"IndEvenGoals\":[" //大类分割
                         "],\"IndGoalss\":[" "],\"IndHalfFulls\":[" "]}" )
             .Select(n => n.Replace( "\"" "" ).Split( "},{" ) //对每个大类处理,先过滤,再分割为子类
                .Select(k => k.Replace( "{" "" ).Replace( "}" "" ) //对子类过滤
                           .SplitAsDictionary( ":" "," )) //提取子类的键值对
                   .ToArray()
             ).ToList(); //列表

看看解析的结果如何:

blob.png

注意,有元素是空值的,可以不用管。至于那几个键值对数组,最终属于哪一个大类?虽然没有直接标记出来,但是这个问题随便加一个判断就可以了,因为每一个类别的键名称是不一样的,看看是否包括对应的键就可以确定类别。

5.总结

    虽然过程很简单,也许有更简单的办好,直接和实体类映射,json反序列化更方便,但有时候没有实体类,也挺麻烦。特别是这种变态复杂的,jsonmap直接处理不知道行不行。总之本文的目的是尽可能使用简单原始的方法来解决问题,也是一个思路。虽然有时候我很懒,喜欢用开源组件,但有的时候一旦用上原始的了,也不喜欢改了。

    字符串分析处理的过程虽然繁琐,但基本都是比较简单的,细致一点,都不是事。

  最后把这个测试的源代码发上来,大家别忘了点赞哦。。。

  源代码:SpliteAsDictionaryDemo.rar

本文转自叶小钗 h数据之巅博客园博客,原文链接:http://www.cnblogs.com/asxinyu/p/Parse_String_Splite_NotJsonMapper.html,如需转载请自行联系原作者



相关文章
|
2月前
|
人工智能
歌词结构的巧妙安排:写歌词的方法与技巧解析,妙笔生词AI智能写歌词软件
歌词创作是一门艺术,关键在于巧妙的结构安排。开头需迅速吸引听众,主体部分要坚实且富有逻辑,结尾则应留下深刻印象。《妙笔生词智能写歌词软件》提供多种 AI 功能,帮助创作者找到灵感,优化歌词结构,写出打动人心的作品。
|
6天前
|
安全 Ubuntu Shell
深入解析 vsftpd 2.3.4 的笑脸漏洞及其检测方法
本文详细解析了 vsftpd 2.3.4 版本中的“笑脸漏洞”,该漏洞允许攻击者通过特定用户名和密码触发后门,获取远程代码执行权限。文章提供了漏洞概述、影响范围及一个 Python 脚本,用于检测目标服务器是否受此漏洞影响。通过连接至目标服务器并尝试登录特定用户名,脚本能够判断服务器是否存在该漏洞,并给出相应的警告信息。
120 84
|
2月前
|
人工智能
写歌词的技巧和方法全解析:开启你的音乐创作之旅,妙笔生词智能写歌词软件
怀揣音乐梦想,渴望用歌词抒发情感?掌握关键技巧,你也能踏上创作之旅。灵感来自生活点滴,主题明确,语言简洁,韵律和谐。借助“妙笔生词智能写歌词软件”,AI辅助创作,轻松写出动人歌词,实现音乐梦想。
|
5天前
|
存储 Java 开发者
浅析JVM方法解析、创建和链接
上一篇文章《你知道Java类是如何被加载的吗?》分析了HotSpot是如何加载Java类的,本文再来分析下Hotspot又是如何解析、创建和链接类方法的。
|
17天前
|
负载均衡 网络协议 算法
Docker容器环境中服务发现与负载均衡的技术与方法,涵盖环境变量、DNS、集中式服务发现系统等方式
本文探讨了Docker容器环境中服务发现与负载均衡的技术与方法,涵盖环境变量、DNS、集中式服务发现系统等方式,以及软件负载均衡器、云服务负载均衡、容器编排工具等实现手段,强调两者结合的重要性及面临挑战的应对措施。
44 3
|
1月前
|
JSON PHP 数据格式
PHP解析配置文件的常用方法
INI文件是最常见的配置文件格式之一。
49 12
|
1月前
|
JSON JavaScript 前端开发
|
1月前
|
机器学习/深度学习 人工智能 安全
TPAMI:安全强化学习方法、理论与应用综述,慕工大、同济、伯克利等深度解析
【10月更文挑战第27天】强化学习(RL)在实际应用中展现出巨大潜力,但其安全性问题日益凸显。为此,安全强化学习(SRL)应运而生。近日,来自慕尼黑工业大学、同济大学和加州大学伯克利分校的研究人员在《IEEE模式分析与机器智能汇刊》上发表了一篇综述论文,系统介绍了SRL的方法、理论和应用。SRL主要面临安全性定义模糊、探索与利用平衡以及鲁棒性与可靠性等挑战。研究人员提出了基于约束、基于风险和基于监督学习等多种方法来应对这些挑战。
59 2
|
1月前
|
JSON 人工智能 算法
探索LLM推理全阶段的JSON格式输出限制方法
文章详细讨论了如何确保大型语言模型(LLMs)输出结构化的JSON格式,这对于提高数据处理的自动化程度和系统的互操作性至关重要。
|
2月前
|
安全 Java
Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧
【10月更文挑战第20天】Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧,包括避免在循环外调用wait()、优先使用notifyAll()、确保线程安全及处理InterruptedException等,帮助读者更好地掌握这些方法的应用。
24 1

推荐镜像

更多