一、问题
现在有一串字符串2, 2, 3, 4, 4, 3, 4, 4, 5, 5, 5, 5, 5, 3, 4, 4, 4, 4, 4, 3, 4, 4
,其中字符串中的数字
类似于Word文档中的标题级别,最终效果是让它们按照Word文档导航窗格中的标题级别格式进行展示,具体展示效果如下:
二、答案
1、依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.78</version>
</dependency>
2、代码
public class Test {
public static void main(String[] args) {
// 数据准备开始
String numString = "2, 2, 3, 4, 4, 3, 4, 4, 5, 5, 5, 5, 5, 3, 4, 4, 4, 4, 4, 3, 4, 4";
String[] split = numString.split(", ");
List<Integer> list = new ArrayList<>();
for (String s : split) {
list.add(Integer.valueOf(s));
}
// 数据准备结束
// 已处理对象集合
List<Number> numberList = new ArrayList<>();
// 最高级对象
Number result = new Number();
result.setChilds(new ArrayList<>());
for (Integer num : list) {
// 当前对象
Number entity = new Number();
entity.setNum(num);
entity.setChilds(new ArrayList<>());
// 获取父级对象
Number parent = getParent(numberList, num);
if (parent == null) {
result.getChilds().add(entity);
} else {
parent.getChilds().add(entity);
}
// 放入集合
numberList.add(entity);
}
// 数据打印
for (Number child : result.getChilds()) {
printNumber(child, "");
}
}
/**
* 数据打印
*
* @param number 对象
* @param prefix 前缀
**/
private static void printNumber(Number number, String prefix) {
System.out.println(prefix + number.getNum());
List<Number> childs = number.getChilds();
if (childs == null || childs.size() == 0) {
return;
}
for (Number child : childs) {
printNumber(child, prefix + " ");
}
}
/**
* 获取父类(采用反向思维查找)
*
* @param numberList 对象集合
* @param num 数字
* @return 对象
**/
private static Number getParent(List<Number> numberList, Integer num) {
if (numberList.size() == 0) {
return null;
}
for (int i = numberList.size() - 1; i >= 0; i--) {
Number number = numberList.get(i);
if (number.getNum() < num) {
return number;
}
}
return null;
}
}
/**
* 数字类(存储数字和子级对象)
*/
class Number {
private Integer num;
private List<Number> childs;
public Integer getNum() {
return num;
}
public void setNum(Integer num) {
this.num = num;
}
public List<Number> getChilds() {
return childs;
}
public void setChilds(List<Number> childs) {
this.childs = childs;
}
}
3、结果
2
2
3
4
4
3
4
4
5
5
5
5
5
3
4
4
4
4
4
3
4
4
4、思路分析
首先创建一个Number
类,然后类里面的childs
属性是List<Number>
,这是大多数人都可以想到的事情,问题关键在于如何让对应的序号放到对应的childs
属性里面,那也就是找到当前节点的父节点,按照上面的逻辑,子节点的序号肯定大于父节点的序号,并且父节点顺序肯定在子节点的前面,并且具体子节点最近,因此我就把已经处理过的节点存储在numberList
集合里面,然后采用反向思维的方式查找具体当前节点最近的父级节点
当然,如果子级节点没有父级节点,那么它就是最高级节点
三、拓展
1、反向思维
对于上面的问题,如果从正方向出发,其实很难有什么好的思路来进行实现,但是反向思维可以很好的解决该问题,所以以后遇到问题的时候,可以从反向出发来解决问题
2、引用数据类型
我把当前节点都是放在父节点的childs
属性里面,我获取最终结果的时候只需要找到顶级节点就可以了,这其实就是引用数据类型起到的作用
四、实战
1、背景
公司有一个文档导入的项目,可以将docx文档进行导入,然后在页面上进行展示,在处理标题过程中,我们可以从上到下获取到所有的目录html,但是返回给前端的时候需要以目录树的方式返回,因此把这种实际情况进行抽象,其实就是上面的例子,公司项目中文档导入成功的截图如下:
2、实战模拟
2.1、代码
public class Test {
public static void main(String[] args) {
// 原始数据
String jsonStr = "[\"<H2 id =\\\"h_f5ec3fd69a4d497ca4b33a10b3d71aa9\\\" name = \\\"h_f5ec3fd69a4d497ca4b33a10b3d71aa9\\\" style=\\\"mso-line-height-rule:exactly;line-height:28.6pt;font-size:21px;font-family:黑体;\\\"><span style=\\\"line-height:28.6pt;\\\">开发准备</span></H2>\",\"<H2 id =\\\"h_11533fd60df540dcb50e792873665d59\\\" name = \\\"h_11533fd60df540dcb50e792873665d59\\\" style=\\\"mso-line-height-rule:exactly;line-height:28.6pt;font-size:21px;font-family:黑体;\\\"><span style=\\\"line-height:28.6pt;\\\">功能说明</span></H2>\",\"<H3 id =\\\"h_e4569a42140041c98ae045603dbe103a\\\" name = \\\"h_e4569a42140041c98ae045603dbe103a\\\" style=\\\"mso-line-height-rule:exactly;line-height:28.6pt;font-size:21px;font-family:楷体;\\\"><span style=\\\"line-height:28.6pt;\\\">审批方案</span></H3>\",\"<H4 id =\\\"h_c6764240e50746f2bf08b93b36e868c4\\\" name = \\\"h_c6764240e50746f2bf08b93b36e868c4\\\" style=\\\"mso-line-height-rule:exactly;line-height:28.6pt;font-size:21px;font-family:仿宋;\\\"><span style=\\\"line-height:28.6pt;\\\">配置文件</span></H4>\",\"<H4 id =\\\"h_df412c661a324d3d89e73e6e2144cfee\\\" name = \\\"h_df412c661a324d3d89e73e6e2144cfee\\\" style=\\\"mso-line-height-rule:exactly;line-height:28.6pt;font-size:21px;font-family:仿宋;\\\"><span style=\\\"line-height:28.6pt;\\\">属性说明</span></H4>\",\"<H3 id =\\\"h_0bba1e95aa864e2b964254e5a4b13eae\\\" name = \\\"h_0bba1e95aa864e2b964254e5a4b13eae\\\" style=\\\"mso-line-height-rule:exactly;line-height:28.6pt;font-size:21px;font-family:楷体;\\\"><span style=\\\"line-height:28.6pt;\\\">集成接口</span></H3>\",\"<H4 id =\\\"h_f4d7e2cc579746b2b4e5476ed883e15d\\\" name = \\\"h_f4d7e2cc579746b2b4e5476ed883e15d\\\" style=\\\"mso-line-height-rule:exactly;line-height:28.6pt;font-size:21px;font-family:仿宋;\\\"><span style=\\\"line-height:28.6pt;\\\">入口参数</span></H4>\",\"<H4 id =\\\"h_03fcedbe1dae4788b499dae77d05dc41\\\" name = \\\"h_03fcedbe1dae4788b499dae77d05dc41\\\" style=\\\"mso-line-height-rule:exactly;line-height:28.6pt;font-size:21px;font-family:仿宋;\\\"><span style=\\\"line-height:28.6pt;\\\">相关接口</span></H4>\",\"<H5 id =\\\"h_778cdce51d214dde967f868780d0eab8\\\" name = \\\"h_778cdce51d214dde967f868780d0eab8\\\" style=\\\"mso-line-height-rule:exactly;line-height:28.6pt;font-size:21px;font-family:仿宋;\\\"><span style=\\\"line-height:28.6pt;\\\">送审</span></H5>\",\"<H5 id =\\\"h_d0daa8157cd24b39a9d20b6165d2f2ec\\\" name = \\\"h_d0daa8157cd24b39a9d20b6165d2f2ec\\\" style=\\\"mso-line-height-rule:exactly;line-height:28.6pt;font-size:21px;font-family:仿宋;\\\"><span style=\\\"line-height:28.6pt;\\\">同意</span></H5>\",\"<H5 id =\\\"h_40ba3e6901c8478399ffe3d4350932dc\\\" name = \\\"h_40ba3e6901c8478399ffe3d4350932dc\\\" style=\\\"mso-line-height-rule:exactly;line-height:28.6pt;font-size:21px;font-family:仿宋;\\\"><span style=\\\"line-height:28.6pt;\\\">拟同意</span></H5>\",\"<H5 id =\\\"h_a4ae1d569ef94b92a57bd217ddab70d2\\\" name = \\\"h_a4ae1d569ef94b92a57bd217ddab70d2\\\" style=\\\"mso-line-height-rule:exactly;line-height:28.6pt;font-size:21px;font-family:仿宋;\\\"><span style=\\\"line-height:28.6pt;\\\">不同意</span></H5>\",\"<H5 id =\\\"h_2abf049d3ba543638097170dbde425ba\\\" name = \\\"h_2abf049d3ba543638097170dbde425ba\\\" style=\\\"mso-line-height-rule:exactly;line-height:28.6pt;font-size:21px;font-family:仿宋;\\\"><span style=\\\"line-height:28.6pt;\\\">收回</span></H5>\",\"<H3 id =\\\"h_a484ff6248dc4b3486f5716ed5116b82\\\" name = \\\"h_a484ff6248dc4b3486f5716ed5116b82\\\" style=\\\"mso-line-height-rule:exactly;line-height:28.6pt;font-size:21px;font-family:楷体;\\\"><span style=\\\"line-height:28.6pt;\\\">应用案例</span></H3>\",\"<H4 id =\\\"h_6fbc18ae698c43508bfe0894ec441b8f\\\" name = \\\"h_6fbc18ae698c43508bfe0894ec441b8f\\\" style=\\\"mso-line-height-rule:exactly;line-height:28.6pt;font-size:21px;font-family:仿宋;\\\"><span style=\\\"line-height:28.6pt;\\\">送审</span></H4>\",\"<H4 id =\\\"h_81e4902a4db746df87823635a588dcc1\\\" name = \\\"h_81e4902a4db746df87823635a588dcc1\\\" style=\\\"mso-line-height-rule:exactly;line-height:28.6pt;font-size:21px;font-family:仿宋;\\\"><span style=\\\"line-height:28.6pt;\\\">同意</span></H4>\",\"<H4 id =\\\"h_adccf8ec1c9f41fd9f2e8a3c4dfa4958\\\" name = \\\"h_adccf8ec1c9f41fd9f2e8a3c4dfa4958\\\" style=\\\"mso-line-height-rule:exactly;line-height:28.6pt;font-size:21px;font-family:仿宋;\\\"><span style=\\\"line-height:28.6pt;\\\">拟同意</span></H4>\",\"<H4 id =\\\"h_04c7c25c2edb4a5ca083cf50099d5768\\\" name = \\\"h_04c7c25c2edb4a5ca083cf50099d5768\\\" style=\\\"mso-line-height-rule:exactly;line-height:28.6pt;font-size:21px;font-family:仿宋;\\\"><span style=\\\"line-height:28.6pt;\\\">不同意</span></H4>\",\"<H4 id =\\\"h_1273a45625e64b07b680ae66ca7160fc\\\" name = \\\"h_1273a45625e64b07b680ae66ca7160fc\\\" style=\\\"mso-line-height-rule:exactly;line-height:28.6pt;font-size:21px;font-family:仿宋;\\\"><span style=\\\"line-height:28.6pt;\\\">收回</span></H4>\",\"<H3 id =\\\"h_b7455f2532254807bbdd36a08b3e587a\\\" name = \\\"h_b7455f2532254807bbdd36a08b3e587a\\\" style=\\\"mso-line-height-rule:exactly;line-height:28.6pt;font-size:21px;font-family:楷体;\\\"><span style=\\\"line-height:28.6pt;\\\">数据展示</span><span style=\\\"line-height:28.6pt;\\\">的接口</span></H3>\",\"<H4 id =\\\"h_4961ecfa9f7a4a95b6d6abf8f0d3a62c\\\" name = \\\"h_4961ecfa9f7a4a95b6d6abf8f0d3a62c\\\" style=\\\"mso-line-height-rule:exactly;line-height:28.6pt;font-size:21px;font-family:仿宋;\\\"><span style=\\\"line-height:28.6pt;\\\">待提交</span></H4>\",\"<H4 id =\\\"h_9f16c84cc0e1451182b1487237906282\\\" name = \\\"h_9f16c84cc0e1451182b1487237906282\\\" style=\\\"mso-line-height-rule:exactly;line-height:28.6pt;font-size:21px;font-family:仿宋;\\\"><span style=\\\"line-height:28.6pt;\\\">已提交</span></H4>\"]";
// 数据转换
List<String> list = JSONObject.parseArray(jsonStr, String.class);
// 存储最高级节点的集合
List<Catalog> resultList = new ArrayList<>();
// 存放已处理节点集合
List<Catalog> catalogList = new ArrayList<>();
for (String html : list) {
// 获取id,用作前端锚点跳转
String id = getId(html);
// 获取目录名称
String caption = getCaption(html);
// 获取目录序号
Integer num = getNum(html);
// 创建当前对象
Catalog entity = new Catalog();
entity.setId(id);
entity.setCaption(caption);
entity.setNum(num);
// 获取父级对象
Catalog parent = getParent(catalogList, num);
if (parent == null) {
// 最高等级数据插入
resultList.add(entity);
} else {
// 判断父级childs属性是否有值
List<Catalog> childs = parent.getChilds();
if (childs == null) {
parent.setChilds(new ArrayList<>());
}
// 数据插入
parent.getChilds().add(entity);
}
// 放入集合
catalogList.add(entity);
}
// 打印目录树
System.out.println(JSONObject.toJSONString(resultList));
}
/**
* 获取父级节点对象
*
* @param catalogList 已处理节点集合
* @param num 目录序号
* @return 父级节点对象
*/
private static Catalog getParent(List<Catalog> catalogList, Integer num) {
if (catalogList.size() == 0) {
return null;
}
for (int i = catalogList.size() - 1; i >= 0; i--) {
Catalog catalog = catalogList.get(i);
if (catalog.getNum() < num) {
return catalog;
}
}
return null;
}
/**
* 获取id,用作前端锚点跳转
*
* @param html 目录Html
* @return id值
*/
private static String getId(String html) {
// ?<=和?=的使用,可以看博客:https://blog.csdn.net/qq_42449963/article/details/124988267
String pattern = "(?<=id =\").*?(?=\")";
Matcher matcher = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE).matcher(html);
while (matcher.find()) {
String id = matcher.group();
return id;
}
return null;
}
/**
* 获取目录标题
*
* @param html 目录Html
* @return 目录标题
*/
private static String getCaption(String html) {
if (html != null) {
return html.replaceAll("<p.*?>|</p>|<span.*?>|<span>|</span>|<H[1-9].*?>|</H[1-9]>", "");
}
return null;
}
/**
* 获取目录序号
*
* @param html 目录Html
* @return 目录Html
*/
private static Integer getNum(String html) {
String pattern = "(?<=<H).*?(?= id)";
Matcher matcher = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE).matcher(html);
while (matcher.find()) {
String group = matcher.group();
Integer num = Integer.valueOf(group);
return num;
}
return null;
}
}
/**
* 目录
*/
class Catalog {
// id
private String id;
// 标题
private String caption;
// 序号
private Integer num;
private List<Catalog> childs;
public Integer getNum() {
return num;
}
public void setNum(Integer num) {
this.num = num;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getCaption() {
return caption;
}
public void setCaption(String caption) {
this.caption = caption;
}
public List<Catalog> getChilds() {
return childs;
}
public void setChilds(List<Catalog> childs) {
this.childs = childs;
}
}
2.2、结果
建议数据格式化之后再看,格式化网站:https://www.bejson.com/json/format/
[{
"caption":"开发准备","id":"h_f5ec3fd69a4d497ca4b33a10b3d71aa9","num":2},{
"caption":"功能说明","childs":[{
"caption":"审批方案","childs":[{
"caption":"配置文件","id":"h_c6764240e50746f2bf08b93b36e868c4","num":4},{
"caption":"属性说明","id":"h_df412c661a324d3d89e73e6e2144cfee","num":4}],"id":"h_e4569a42140041c98ae045603dbe103a","num":3},{
"caption":"集成接口","childs":[{
"caption":"入口参数","id":"h_f4d7e2cc579746b2b4e5476ed883e15d","num":4},{
"caption":"相关接口","childs":[{
"caption":"送审","id":"h_778cdce51d214dde967f868780d0eab8","num":5},{
"caption":"同意","id":"h_d0daa8157cd24b39a9d20b6165d2f2ec","num":5},{
"caption":"拟同意","id":"h_40ba3e6901c8478399ffe3d4350932dc","num":5},{
"caption":"不同意","id":"h_a4ae1d569ef94b92a57bd217ddab70d2","num":5},{
"caption":"收回","id":"h_2abf049d3ba543638097170dbde425ba","num":5}],"id":"h_03fcedbe1dae4788b499dae77d05dc41","num":4}],"id":"h_0bba1e95aa864e2b964254e5a4b13eae","num":3},{
"caption":"应用案例","childs":[{
"caption":"送审","id":"h_6fbc18ae698c43508bfe0894ec441b8f","num":4},{
"caption":"同意","id":"h_81e4902a4db746df87823635a588dcc1","num":4},{
"caption":"拟同意","id":"h_adccf8ec1c9f41fd9f2e8a3c4dfa4958","num":4},{
"caption":"不同意","id":"h_04c7c25c2edb4a5ca083cf50099d5768","num":4},{
"caption":"收回","id":"h_1273a45625e64b07b680ae66ca7160fc","num":4}],"id":"h_a484ff6248dc4b3486f5716ed5116b82","num":3},{
"caption":"数据展示的接口","childs":[{
"caption":"待提交","id":"h_4961ecfa9f7a4a95b6d6abf8f0d3a62c","num":4},{
"caption":"已提交","id":"h_9f16c84cc0e1451182b1487237906282","num":4}],"id":"h_b7455f2532254807bbdd36a08b3e587a","num":3}],"id":"h_11533fd60df540dcb50e792873665d59","num":2}]