将HTML文本转换为Markdown文本 package util; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.nodes.Node; import org.jsoup.select.Elements; /** * Created by deng on 2018/8/9. */ public class Html2Md { private Html2Md() { } public static String getMarkDownText(String html) { StringBuilder result = new StringBuilder(); Document document = Jsoup.parseBodyFragment(html.replace("&nbsp;", "")); // 遍历所有直接子节点 for (Node node : document.body().childNodes()) { result.append(handleNode(node)); } return result.toString(); } /** * 处理Node,目前支持处理p、pre、ul和ol四种节点 * * @param node * @return */ private static String handleNode(Node node) { String nodeName = node.nodeName(); String nodeStr = node.toString(); switch (nodeName) { case "p": Element pElement = Jsoup.parseBodyFragment(nodeStr).body().getElementsByTag("p").first(); String pStr = pElement.html(); for (Element child : pElement.children()) { pStr = handleInnerHtml(pStr, child); } return pStr + "\n"; case "pre": return "```\n" + Jsoup.parseBodyFragment(nodeStr).body().text() + "\n```\n"; case "ul": Element ulElement = Jsoup.parseBodyFragment(nodeStr).body().getElementsByTag("ul").first(); String ulStr = ulElement.html().replace("<li>", "- ").replace("</li>", ""); for (Element li : ulElement.getElementsByTag("li")) { for (Element child : li.children()) { ulStr = handleInnerHtml(ulStr, child); } } return ulStr + "\n"; case "ol": Element olElement = Jsoup.parseBodyFragment(nodeStr).body().getElementsByTag("ol").first(); String olStr = olElement.html(); Elements liElements = olElement.getElementsByTag("li"); for (int i = 1; i <= liElements.size(); i++) { Element li = liElements.get(i - 1); olStr = olStr.replace(li.toString(), li.toString().replace("<li>", i + ". ").replace("</li>", "")); for (Element child : li.children()) { olStr = handleInnerHtml(olStr, child); } } return olStr + "\n"; // 非HTML元素 case "#text": return "\n"; } return ""; } /** * 处理innerHTML中的HTML元素,目前支持处理的子元素包括strong、img、em * * @param innerHTML * @param child * @return */ private static String handleInnerHtml(String innerHTML, Element child) { switch (child.tag().toString()) { case "strong": innerHTML = innerHTML.replace(child.toString(), "**" + child.text() + "**"); break; case "img": String src = child.attr("src"); if (src.charAt(0) == '/') { src = "https://leetcode-cn.com" + src; } innerHTML = innerHTML.replace(child.toString(), "![img](" + src + ")"); break; case "em": innerHTML = innerHTML.replace(child.toString(), " *" + child.text() + "* "); break; default: innerHTML = innerHTML.replace(child.toString(), child.text()); break; } return innerHTML; } } 利用jsoup解析HTML元素,思路如下: [1] 首先遍历HTML文档的直接子节点,直接子节点只包括p、pre、ul和ol四类元素,其中pre对应的是md中的代码片,ul对应md中的无序列表,ol对应md中的有序列表。实现见handleNode方法。 [2] 其次解析每个一级子节点中的内部的HTML元素,包括strong、em、img,其中strong对应md中的粗体,em对应md中的斜体,img对应md中的图片。实现见handleInnerHTML方法。 运行效果: public static void main(String[] args) { System.out.println(Html2Md.getMarkDownText("<p>实现函数 ToLowerCase(),该函数接收一个字符串参数 str,并将该字符串中的大写字母转换成小写字母,之后返回新的字符串。</p>\n" + "\n" + "<p>&nbsp;</p>\n" + "\n" + "<p><strong>示例 1:</strong></p>\n" + "\n" + "<pre><strong>输入: </strong>\"Hello\"\n" + "<strong>输出: </strong>\"hello\"</pre>\n" + "\n" + "<p><strong>示例 2:</strong></p>\n" + "\n" + "<pre><strong>输入: </strong>\"here\"\n" + "<strong>输出: </strong>\"here\"</pre>\n" + "\n" + "<p><strong>示例</strong><strong>&nbsp;3:</strong></p>\n" + "\n" + "<pre><strong>输入: </strong>\"LOVELY\"\n" + "<strong>输出: </strong>\"lovely\"\n" + "</pre>")); } 运行输出如下图所示: ![请输入图片描述][1] 至此,便完成了对LeetCode编程题项目MD文件的构建。 ...
状态码 说明 100 客户端应当继续发送请求。这个临时响应是用来通知客户端它的部分请求已经被服务器接收,且仍未被拒绝。客户端应当继续发送请求的剩余部...
通过JAVA程序刷新网站的IP访问量,我用到的技术要点:用SWT的browser来访问网站url,用xpcom来修改Mozilla的代理IP。 为了...
一,JAVA性能优化之设计优化 设计优化处于性能优化手段的上层。它往往须要在软件开发之前进行。在软件开发之前,系统架构师应该就评估系统可能存在的各种...
一、Callable 与 Runnable 先说一下java.lang.Runnable吧,它是一个接口,在它里面只声明了一个run()方法: pu...
import java.util.concurrent.Callable; import java.util.concurrent.Executio...
一 架构规划 实验环境是通过SVN提交代码,使用Jenkins一键发布到测试环境进行镜像build和站点安装测试,将DOCKER镜像上传到 私有镜...
线程池原理 Java创建一个线程很方便,只需new Thread()就可以, 但是当有多个任务需要进行进行处理时,频繁的进行创建和启用线程同样需要...
抽象 解析 程序计数器 程序计数器(Program Counter Register)是JVM中一块较小的内存区域,保存着当前线程执行的虚拟机字节码...
前言 万丈高楼平地起,今天的聊点基础而又经常让人忽视的话题,比如“==”与“equals()”区别?为何当我们重写完"equals()&q...
定点爬取 当我们需要对金融行业的股票信息进行爬取的时候,由于股票的价格是一直在变化的,我们不可能手动的去每天定时定点的运行程序,这个时候我们就需要实现定点爬取了,我们引入第三方库quartz的使用: package timeutils; import org.quartz.CronTrigger; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.SchedulerFactory; import org.quartz.impl.StdSchedulerFactory; import java.text.SimpleDateFormat; import java.util.Date; import static org.quartz.CronScheduleBuilder.cronSchedule; import static org.quartz.JobBuilder.newJob; import static org.quartz.TriggerBuilder.newTrigger; /** * Created by paranoid on 17-4-13. */ public class TimeUpdate { public void go() throws Exception { // 首先,必需要取得一个Scheduler的引用(设置一个工厂) SchedulerFactory sf = new StdSchedulerFactory(); //从工厂里面拿到一个scheduler实例 Scheduler sched = sf.getScheduler(); //真正执行的任务并不是Job接口的实例,而是用反射的方式实例化的一个JobDetail实例 JobDetail job = newJob(MyTimeJob.class).withIdentity("job1", "group1").build(); // 定义一个触发器,job 1将每隔执行一次 CronTrigger trigger = newTrigger().withIdentity("trigger1", "group1"). withSchedule(cronSchedule("50 47 17 * * ?")).build(); //执行任务和触发器 Date ft = sched.scheduleJob(job, trigger); //格式化日期显示格式 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss SSS"); System.out.println(job.getKey() + " 已被安排执行于: " + sdf.format(ft) + "," + "并且以如下重复规则重复执行: " + trigger.getCronExpression()); sched.start(); } public static void main(String[] args) throws Exception { TimeUpdate test = new TimeUpdate(); test.go(); } } 在上面的代码中,已经详细的给出了实现定时爬取的基本代码 JobDetail job = newJob(MyTimeJob.class).withIdentity("job1", "group1").build(); 这句代码中的MyTimeJob.class就是我们要执行的任务代码,它是通过类的反射加载机制进行运行的,之后我们设置它为第一组的第一个任务。 要使用这个第三方库我们需要了解一些cron表达式的概念,网上由于对它的说明很多,我就不再这里进行说明 ,大家可以看到: cronSchedule("50 47 17 * * ?") 我设置的是每天的17:47:50秒运行这个程序。 值得注意的是 :我们所要执行的任务必须写在execute方法之中,在下面的代码就是一个实例,也就是我们需要实现的IP代理池。 ...
使用PropertyPlaceholderConfigurer类载入外部配置 在Spring项目中,你可能需要从properties文件中读入配置注...