import cn.hutool.http.HtmlUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.suncnpap.dataintell.common.constants.PathConstant;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Jsoup;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
/**
* @author CJJ
* @version 1.0
* @createDate 2021/06/11 10:03
* @see com.suncnpap.dataintell.utils
*/
@Slf4j
public class StrUtil {
public static final String startTag = "<markRed style='color:#e53639'>";
public static final String endTag = "</markRed>";
public static String camel2Snake(String camel) {
StringBuilder chars = new StringBuilder(camel);
for (int i = 0; i < chars.length(); i++) {
if (chars.charAt(i) >= 'A' && chars.charAt(i) <= 'Z') {
chars.insert(i, '_');
}
}
return chars.toString().toUpperCase();
}
/**
* 映射html与纯文本标红
*
* @param object
* @return
*/
public static JSONObject mappingHtmlText(JSONObject object) {
JSONArray result = object.getJSONArray("result");
for (Object o : result) {
//解析返回结果取值
JSONObject jsonObject = (JSONObject) o;
JSONObject sim_content = jsonObject.getJSONObject("sim_content");
JSONArray target = sim_content.getJSONArray("target");
String html = jsonObject.getString("contentHtml");
html = HtmlUtil.unescape(html);
String text = Jsoup.parse(html).text();
LinkedHashMap<Integer, Integer> map = getMappingMap(html, text);
//需要标红的字符
LinkedList<Integer> tagList = new LinkedList<>();
//开始标签索引
LinkedList<Integer> startTagList = new LinkedList<>();
//结束标签索引
LinkedList<Integer> endTagList = new LinkedList<>();
for (Object o1 : target) {
JSONObject clause = (JSONObject) o1;
String content = clause.getString("content");
JSONArray detail = clause.getJSONArray("detail");
Integer start = detail.getInteger(0);
Integer end = detail.getInteger(1) - 1;
if (map.get(start) == null || map.get(end) == null) {
log.error(String.format("获取索引异常:%d=>%d", start, end));
}
for (int i = start; i < end; i++) {
tagList.add(map.get(i));
}
// startTagList.add(map.get(start));
// endTagList.add(map.get(end));
}
String markHtml = getMarkHtml(html, tagList);
jsonObject.put("contentHtml", markHtml);
jsonObject.remove("sim_content");
jsonObject.remove("sim_title");
}
return object;
}
private static String getMarkHtml(String html, LinkedList<Integer> tagList) {
StringBuffer markHtml = new StringBuffer();
char[] htmlChars = html.toCharArray();
for (int i = 0; i < htmlChars.length; i++) {
if (tagList.contains(i)) {
if(!tagList.contains(i-1)){
markHtml.append(startTag);
}
}
markHtml.append(htmlChars[i]);
if (tagList.contains(i)) {
if(!tagList.contains(i+1)){
markHtml.append(endTag);
}
}
}
return markHtml.toString();
}
/**
* 获取标红html片段
*
* @param html
* @param startTagList
* @param endTagList
* @return
*/
private static String getMarkHtml(String html, LinkedList<Integer> startTagList, LinkedList<Integer> endTagList) {
StringBuffer markHtml = new StringBuffer();
char[] htmlChars = html.toCharArray();
for (int i = 0; i < htmlChars.length; i++) {
if (startTagList.contains(i)) {
markHtml.append(startTag);
}
char htmlChar = htmlChars[i];
markHtml.append(htmlChars[i]);
if (endTagList.contains(i)) {
markHtml.append(endTag);
}
}
return markHtml.toString();
}
/**
* 获取html代码和纯文本映射关系
*
* @param html
* @param text
* @return
*/
private static LinkedHashMap<Integer, Integer> getMappingMap(String html, String text) {
char[] htmlChars = html.toCharArray();
//查找原文最小连续文字片段,然后记录html与text对应索引建立mapping
//1.每个字符都分割,然后对每个文字标红,然后再遍历,连续字符片段标红合并
char[] textChars = text.toCharArray();
//必要条件,html与text文本内容顺序一致
LinkedHashMap<Integer, Integer> map = new LinkedHashMap<>();
int last = 0;
for (int i = 0; i < textChars.length; i++) {
for (int j = last; j < htmlChars.length; j++) {
if (textChars[i] == htmlChars[j] && isNotInTag(htmlChars, j)) {
char textChar = textChars[i];
char htmlChar = htmlChars[j];
map.put(i, j);
last = j + 1;
break;
}
}
}
last = -1;
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
Integer key = entry.getKey();
if (key == last + 1) {
last = key;
} else {
log.info("查重标红不连续的索引位置" + key);
}
}
return map;
}
/**
* 判断字符是否在标签内部
*
* @param htmlChars
* @param j
* @return
*/
private static boolean isNotInTag(char[] htmlChars, int j) {
while (j-- > 0) {
if (htmlChars[j] == '>') {
return true;
} else if (htmlChars[j] == '<') {
return false;
}
}
for (; j < htmlChars.length; j++) {
if (htmlChars[j] == '<') {
return true;
} else if (htmlChars[j] == '>') {
return false;
}
}
return true;
}
public static void main(String[] args) throws IOException {
String text = "国家体育总局第15号令《少年儿童体育学校管理办法》 发布时间:2012-01-11 来源:系统管理员 字体: 大 中 小 国 家 体 育 2 1总 局 令 中华人民共和国教育部 第15号 《少年儿童体育学校管理办法》已于2011年5月5日经国家体育总局第10次局长办公会议审议通过,并经教育部同意,现予以发布,自2011年10月1日起施行。 国 家 体 育 总 局局长:刘 鹏 中华人民共和国教育部部长:袁贵仁 二〇一一年九月二日 少年儿童体育学校管理办法 第一章 总则 第一条 为加强少年儿童体育学校的建设和管理,全面贯彻国家体育、教育方针,促进我国体育事业发展,依据《中华人民共和国体育法》、《中华人民共和国教育法》、《中华人民共和国义务教育法》等法律法规,制定本办法。 第二条 本办法所称少年儿童体育学校是指九年义务教育阶段培养少年儿童体育专项运动技能的体育特色学校(含体育中学、单项体育运动学校、少年儿童业余体育学校,以下简称少体校)。 第三条 少体校的主要任务是为国家和社会培养、输送具有良好思想品德、文化素质和体育特长的优秀体育后备人才。 第四条 县级以上体育和教育行政部门在本级人民政府领导下,统筹规划、分工负责、协调管理少体校工作。体育行政部门负责学校的日常管理,学生训练、参赛,教练员配备和培训等;教育行政部门负责与学生文化教育相关事项的管理,包括教学、教师配备和培训等。 第五条 国家鼓励和支持企业事业组织、社会团体和公民个人举办民办少体校。 举办少体校不得以营利为目的。 第二章 设置与审批 第六条 少体校应当从实际出发,采取独立办学或依附普通中小学等形式办学。 第七条 举办少体校的社会组织应当具有法人资格,公民个人应当具有政治权利和完全民事行为能力。少体校应当具有法人资格。 第八条 举办少体校,应当符合国家关于中小学校的相关设置标准,具备与所设置运动项目相适应的训练场馆、器材设施。 少体校独立进行文化教育的,应当具备与办学规模相适应的文化教学设施、设备和师资。依附普通中小学进行文化教育的,应当和所依附的学校签定联合办学协议,明确双方的权利和义务。 第九条 少体校应当根据本地区的体育传统和运动项目布局设置体育项目。 第十条 少体校的设立、变更、终止由县级以上体育行政部门提出意见,同级教育行政部门根据相关法律法规予以审批。 第三章 招生与学籍 第十一条 少体校按学年度面向普通中小学招生。 少体校招生,对拟招收学生进行体检和选材测试。 第十二条 少体校招生后,应当对招收的新生进行试训。经试训不适宜继续进行专项运动训练的学生,仍回原学校。 第十三条 少体校录取的学生学籍的变动和管理,按照当地学籍管理办法执行。";
JSONObject object = MyHttpUtil.builder(PathConstant.PYTHON_URL).keys("content").values(text).postFormData(PathConstant.DUPLICATE);
JSONObject result = mappingHtmlText(object);
log.info(result.toJSONString());
// StringBuffer sb=new StringBuffer();
// sb.append("12345");
// StringBuffer delete = sb.delete(3, 4);
// System.out.println(delete);
}
public static Object getContentText(Object html) {
return Jsoup.parse(HtmlUtil.unescape(html.toString())).text();
}
}