使用 java 实现一个简单的 markdown 语法解析器
1. 什么是 markdown
Markdown 是一种轻量级的「标记语言」,它的优点很多,目前也被越来越多的写作爱好者,撰稿者广泛使用。看到这里请不要被「标记」、「语言」所迷惑,Markdown 的语法十分简单。常用的标记符号也不超过十个,这种相对于更为复杂的HTML 标记语言来说,Markdown 可谓是十分轻量的,学习成本也不需要太多,且一旦熟悉这种语法规则,会有一劳永逸的效果。
2. 使用 java 实现一个简单的 markdown 语法解析器
markdown 语法解析器,可以实现将 markdown 语句转换成对应的 html 语句,之后由浏览器负责对 html 渲染。
2.1 markdown 标签简介
markdown 语法十分简单,常用的标签有:
代码 (```)
引用 (>)
无序列表 ('*','-','+')
有序列表 ('1.','2.','3.')
标题 (#)
图片 (![]())
链接 ([]())
行内引用 (`)
粗体 (**)
斜体 (*)
表格
具体的使用方式可以参见 Markdown——入门指南 和 Markdown的基本语法
2.2 markdown 标签分类
- markdown 标签可以简单分为 2 大类:一类是作用在多行语句或单行语句中的,如 代码、引用、无序列表、有序列表、表格等;另一类是只作用于单行语句中的,如 标题,图片,链接、行内引用、粗体、斜体等。
- 其中,代码、引用、无序列表、有序列表、标题 这 5 类可以直接根据行首是否存在相应的标签直接进行判断这一行是否属于这些类型。如 行首元素为 '>' 可以直接判断这是一个引用行,行首元素为 '-' 可以直接判断这是一个无序列表行等。但需要注意的是,代码区域内不存在其他元素,即代码区域内的其他标签并不会被解析;而引用区域内可以存在其他元素,如 行首元素为 "> *" 可以判断此行为一个引用区域内的无序列表行。
- 除了这 5 类标签外,图片,链接、行内引用、粗体、斜体这 5 类标签可以出现在行内的任意位置,于是要遍历一整行才可以解析出这 5 类标签。
2.3 markdown 解析器的实现
完整代码见 https://github.com/libaoquan95/MarkDownParser
已实现的 markdown 标签:代码、引用、无序列表、有序列表、标题、普通文本、图片、链接、行内引用、粗体、斜体
未实现的 markdown 标签:表格、tab多级结构
2.3.1 主体思路
主要思路是扫描 markdown 文件,对每一行进行标记,确定每一行的 markdown 标签,之后再根据每一行的 markdown 标签将 markdown 语句转换成 html 语句。
- 第一次扫描 markdown 文件,定位
代码区
、引用区
、无序列表区
、有序列表区
,因为这些标签均是可以作用于多行,要根据上下文的 markdown 标签才可以确定其作用范围。在这里需要特别注意代码区
内不含其它区域,引用区
内可以嵌套其它区域。 - 第二次扫描 markdown 文件,根据前一次扫描的定位结果,确定每一行 markdown 语句所对应的 markdown 标签。在这次扫描中可以确定
代码
、引用
、无序列表
、有序列表
、标题
这 5 类可以根据行首元素就能判定出类型的标签,所以不需要扫描全行。 - 第三次扫描 markdown 文件,根据上一次的结果,可以直接将对应的 markdown 标签转换成 html 标签,此外要扫描全行,确定
图片
,链接
、行内引用
、粗体
、斜体
这 5 类元素并直接转换成 html。
2.3.2 读入 markdown 文件
扫描文件后,将文件按行存储至内存。相关成员变量如下:
// 按行存储 markdown 文件
private ArrayList<String> mdList = new ArrayList();
// 存储 markdown 文件的每一行对应类型
private ArrayList<String> mdListType = new ArrayList();
将 markdown 文件存入 mdList,之后多次扫描均是直接在 mdList 上进行修改。在本博客中,展示的事例的 markdown 文件如下
## 什么是 markdown
> Markdown 是一种轻量级的「标记语言」,它的优点很多,目前也被越来越多的写作爱好者...
## markdown 常用标签:
```
代码 (```)
引用 (>)
无序列表 ('*','-','+')
有序列表 ('1.','2.','3.')
标题 (#)
图片 (![]())
链接 ([]())
行内引用 (`)
粗体 (**)
斜体 (*)
表格
```
## markdown 入门1
1. [Markdown——入门指南](http://www.jianshu.com/p/1e402922ee32/)
2. [Markdown的基本语法](http://www.cnblogs.com/libaoquan/p/6812426.html)
### markdown 标签分类
- markdown 标签可以 **简单** 分为 2 大类:...
- 其中,*代码*、`引用`、无序列表、有序列表、标题这 5 类...
- 除了这 5 类标签外,图片,链接、行内引用、粗体、斜体这 5 类...
2.3.3 第一次扫描
在这次扫描中,可以确定出 代码区
定位标签 CODE_BEGIN 和 CODE_END,引用区
定位标签 QUOTE_BEGIN 和 QUOTE_END,无序列表区
定位标签 UNORDER_BEGIN 和 UNORDER_END,有序列表区
定位标签 ORDER_BEGIN 和 ORDER_END。而其他语句在此次扫描中均暂时定义为 OTHER。
/**
* 判断每一段 markdown 语法对应的 html 类型
* @param 空
* @return 空
*/
private void defineAreaType() {
// 定位代码区
ArrayList<String> tempList = new ArrayList();
ArrayList<String> tempType = new ArrayList();
tempType.add("OTHER");
tempList.add(" ");
boolean codeBegin = false, codeEnd = false;
for(int i = 1; i < mdList.size() - 1; i++){
String line = mdList.get(i);
if(line.length() > 2 && line.charAt(0) == '`' && line.charAt(1) == '`' && line.charAt(2) == '`') {
// 进入代码区
if(!codeBegin && !codeEnd) {
tempType.add("CODE_BEGIN");
tempList.add(" ");
codeBegin = true;
}
// 离开代码区
else if(codeBegin && !codeEnd) {
tempType.add("CODE_END");
tempList.add(" ");
codeBegin = false;
codeEnd = false;
}
else {
tempType.add("OTHER");
tempList.add(line);
}
}
else {
tempType.add("OTHER");
tempList.add(line);
}
}
tempType.add("OTHER");
tempList.add(" ");
mdList = (ArrayList<String>)tempList.clone();
mdListType = (ArrayList<String>)tempType.clone();
tempList.clear();
tempType.clear();
// 定位其他区,注意代码区内无其他格式
boolean isCodeArea = false;
tempList.add(" ");
tempType.add("OTHER");
for(int i = 1; i < mdList.size() - 1; i++){
String line = mdList.get(i);
String lastLine = mdList.get(i - 1);
String nextLine = mdList.get(i + 1);
if(mdListType.get(i) == "CODE_BEGIN") {
isCodeArea = true;
tempList.add(line);
tempType.add("CODE_BEGIN");
continue;
}
if(mdListType.get(i) == "CODE_END") {
isCodeArea = false;
tempList.add(line);
tempType.add("CODE_END");
continue;
}
// 代码区不含其他格式
if(!isCodeArea) {
// 进入引用区
if(line.length() > 2 && line.charAt(0) == '>' && lastLine.charAt(0) != '>' && nextLine.charAt(0) == '>') {
tempList.add(" ");
tempList.add(line);
tempType.add("QUOTE_BEGIN");
tempType.add("OTHER");
}
// 离开引用区
else if(line.length() > 2 && line.charAt(0) == '>' && lastLine.charAt(0) == '>' && nextLine.charAt(0) != '>') {
tempList.add(line);
tempList.add(" ");
tempType.add("OTHER");
tempType.add("QUOTE_END");
}
// 单行引用区
else if(line.length() > 2 && line.charAt(0) == '>' && lastLine.charAt(0) != '>' && nextLine.charAt(0) != '>') {
tempList.add(" ");
tempList.add(line);
tempList.add(" ");
tempType.add("QUOTE_BEGIN");
tempType.add("OTHER");
tempType.add("QUOTE_END");
}
// 进入无序列表区
else if((line.charAt(0) == '-' && lastLine.charAt(0) != '-' && nextLine.charAt(0) == '-') ||
(line.charAt(0) == '+' && lastLine.charAt(0) != '+' && nextLine.charAt(0) == '+') ||
(line.charAt(0) == '*' && lastLine.charAt(0) != '*' && nextLine.charAt(0) == '*')){
tempList.add(" ");
tempList.add(line);
tempType.add("UNORDER_BEGIN");
tempType.add("OTHER");
}
// 离开无序列表区
else if((line.charAt(0) == '-' && lastLine.charAt(0) == '-' && nextLine.charAt(0) != '-') ||
(line.charAt(0) == '+' && lastLine.charAt(0) == '+' && nextLine.charAt(0) != '+') ||
(line.charAt(0) == '*' && lastLine.charAt(0) == '*' && nextLine.charAt(0) != '*')){
tempList.add(line);
tempList.add(" ");
tempType.add("OTHER");
tempType.add("UNORDER_END");
}
// 单行无序列表区
else if((line.charAt(0) == '-' && lastLine.charAt(0) != '-' && nextLine.charAt(0) != '-') ||
(line.charAt(0) == '+' && lastLine.charAt(0) != '+' && nextLine.charAt(0) != '+') ||
(line.charAt(0) == '*' && lastLine.charAt(0) != '*' && nextLine.charAt(0) != '*')){
tempList.add(" ");
tempList.add(line);
tempList.add(" ");
tempType.add("UNORDER_BEGIN");
tempType.add("OTHER");
tempType.add("UNORDER_END");
}
// 进入有序列表区
else if((line.length() > 1 && (line.charAt(0) >= '1' || line.charAt(0) <= '9') && (line.charAt(1) == '.')) &&
!(lastLine.length() > 1 && (lastLine.charAt(0) >= '1' || line.charAt(0) <= '9') && (lastLine.charAt(1) == '.')) &&
(nextLine.length() > 1 && (nextLine.charAt(0) >= '1' || line.charAt(0) <= '9') && (nextLine.charAt(1) == '.'))){
tempList.add(" ");
tempList.add(line);
tempType.add("ORDER_BEGIN");
tempType.add("OTHER");
}
// 离开有序列表区
else if((line.length() > 1 && (line.charAt(0) >= '1' || line.charAt(0) <= '9') && (line.charAt(1) == '.')) &&
(lastLine.length() > 1 && (lastLine.charAt(0) >= '1' || line.charAt(0) <= '9') && (lastLine.charAt(1) == '.')) &&
!(nextLine.length() > 1 && (nextLine.charAt(0) >= '1' || line.charAt(0) <= '9') && (nextLine.charAt(1) == '.'))){
tempList.add(line);
tempList.add(" ");
tempType.add("OTHER");
tempType.add("ORDER_END");
}
// 单行有序列表区
else if((line.length() > 1 && (line.charAt(0) >= '1' || line.charAt(0) <= '9') && (line.charAt(1) == '.')) &&
!(lastLine.length() > 1 && (lastLine.charAt(0) >= '1' || line.charAt(0) <= '9') && (lastLine.charAt(1) == '.')) &&
!(nextLine.length() > 1 && (nextLine.charAt(0) >= '1' || line.charAt(0) <= '9') && (nextLine.charAt(1) == '.'))){
tempList.add(" ");
tempList.add(line);
tempList.add(" ");
tempType.add("ORDER_BEGIN");
tempType.add("OTHER");
tempType.add("ORDER_END");
}
// 其他
else {
tempList.add(line);
tempType.add("OTHER");
}
}
else {
tempList.add(line);
tempType.add("OTHER");
}
}
tempList.add(" ");
tempType.add("OTHER");
mdList = (ArrayList<String>)tempList.clone();
mdListType = (ArrayList<String>)tempType.clone();
tempList.clear();
tempType.clear();
}
第一次扫描后,markdown 格式如下,左侧为每一行的标签类型,右侧为文件内容:
OTHER
OTHER ## 什么是 markdown
QUOTE_BEGIN
OTHER > Markdown 是一种轻量级的「标记语言」,它的优点很多,目前也被越来越多的写作爱好者...
QUOTE_END
OTHER
OTHER ## markdown 常用标签:
CODE_BEGIN
OTHER 代码 (```)
OTHER 引用 (>)
OTHER 无序列表 ('*','-','+')
OTHER 有序列表 ('1.','2.','3.')
OTHER 标题 (#)
OTHER 图片 (![]())
OTHER 链接 ([]())
OTHER 行内引用 (`)
OTHER 粗体 (**)
OTHER 斜体 (*)
OTHER 表格
CODE_END
OTHER ## markdown 入门1
ORDER_BEGIN
OTHER 1. [Markdown——入门指南](http://www.jianshu.com/p/1e402922ee32/)
OTHER 2. [Markdown的基本语法](http://www.cnblogs.com/libaoquan/p/6812426.html)
ORDER_END
OTHER
OTHER ### markdown 标签分类
UNORDER_BEGIN
OTHER - markdown 标签可以 **简单** 分为 2 大类:...
OTHER - 其中,*代码*、`引用`、无序列表、有序列表、标题这 5 类...
OTHER - 除了这 5 类标签外,图片,链接、行内引用、粗体、斜体这 5 类...
UNORDER_END
OTHER
2.3.4 第二次扫描
在这次扫描中,可以确定出 代码行
标签 CODE_LINE, 无序列表行
标签 UNORDER_LINE, 有序列表行
标签 ORDER_LINE, 空行
标签 BLANK_LINE, 标题行
标签 TITLE。
/**
* 判断每一行 markdown 语法对应的 html 类型
* @param 空
* @return 空
*/
private void defineLineType() {
Stack<String> st = new Stack();
for(int i = 0; i < mdList.size(); i++){
String line = mdList.get(i);
String typeLine = mdListType.get(i);
if(typeLine == "QUOTE_BEGIN" || typeLine == "UNORDER_BEGIN" || typeLine == "ORDER_BEGIN" || typeLine == "CODE_BEGIN") {
st.push(typeLine);
}
else if(typeLine == "QUOTE_END" || typeLine == "UNORDER_END" || typeLine == "ORDER_END" || typeLine == "CODE_END") {
st.pop();
}
else if(typeLine == "OTHER") {
if(!st.isEmpty()) {
// 引用行
if(st.peek() == "QUOTE_BEGIN") {
mdList.set(i, line.trim().substring(1).trim());
}
// 无序列表行
else if(st.peek() == "UNORDER_BEGIN") {
mdList.set(i, line.trim().substring(1).trim());
mdListType.set(i, "UNORDER_LINE");
}
// 有序列表行
else if(st.peek() == "ORDER_BEGIN") {
mdList.set(i, line.trim().substring(2).trim());
mdListType.set(i, "ORDER_LINE");
}
// 代码行
else {
mdListType.set(i, "CODE_LINE");
}
}
line = mdList.get(i);
typeLine = mdListType.get(i);
// 空行
if(line.trim().isEmpty()) {
mdListType.set(i, "BLANK_LINE");
mdList.set(i, "");
}
// 标题行
else if(line.trim().charAt(0) == '#') {
mdListType.set(i, "TITLE");
mdList.set(i, line.trim());
}
}
}
}
第二次扫描后,markdown 格式如下,左侧为每一行的标签类型,右侧为文件内容:
BLANK_LINE
TITLE ## 什么是 markdown
QUOTE_BEGIN
OTHER Markdown 是一种轻量级的「标记语言」,它的优点很多,目前也被越来越多的写作爱好者...
QUOTE_END
BLANK_LINE
TITLE ## markdown 常用标签:
CODE_BEGIN
CODE_LINE 代码 (```)
CODE_LINE 引用 (>)
CODE_LINE 无序列表 ('*','-','+')
CODE_LINE 有序列表 ('1.','2.','3.')
CODE_LINE 标题 (#)
CODE_LINE 图片 (![]())
CODE_LINE 链接 ([]())
CODE_LINE 行内引用 (`)
CODE_LINE 粗体 (**)
CODE_LINE 斜体 (*)
CODE_LINE 表格
CODE_END
TITLE ## markdown 入门1
ORDER_BEGIN
ORDER_LINE [Markdown——入门指南](http://www.jianshu.com/p/1e402922ee32/)
ORDER_LINE [Markdown的基本语法](http://www.cnblogs.com/libaoquan/p/6812426.html)
ORDER_END
BLANK_LINE
TITLE ### markdown 标签分类
UNORDER_BEGIN
UNORDER_LINE markdown 标签可以 **简单** 分为 2 大类:...
UNORDER_LINE 其中,*代码*、`引用`、无序列表、有序列表、标题这 5 类...
UNORDER_LINE 除了这 5 类标签外,图片,链接、行内引用、粗体、斜体这 5 类...
UNORDER_END
BLANK_LINE
2.3.5 第三次扫描
在这次扫描中,根据每一行的标签,将其转化为 html 代码,并行内扫描确定 图片
、链接
、 行内引用
、 粗体
、 斜体
。
/**
* 根据每一行的类型,将 markdown 语句 转化成 html 语句
* @return 空
*/
private void translateToHtml() {
for(int i = 0; i < mdList.size(); i++){
String line = mdList.get(i);
String typeLine = mdListType.get(i);
// 是空行
if(typeLine == "BLANK_LINE") {
mdList.set(i, "");
}
// 是普通文本行
else if(typeLine == "OTHER") {
mdList.set(i, "<p>" + translateToHtmlInline(line.trim()) + "</p>");
}
// 是标题行
else if(typeLine == "TITLE") {
int titleClass = 1;
for(int j = 1; j < line.length(); j++) {
if(line.charAt(j) == '#') {
titleClass++;
}
else {
break;
}
}
mdList.set(i, "<h" + titleClass + ">"+ translateToHtmlInline(line.substring(titleClass).trim()) +"</h" + titleClass + ">");
}
// 是无序列表行
else if(typeLine == "UNORDER_BEGIN") {
mdList.set(i, "<ul>");
}
else if(typeLine == "UNORDER_END") {
mdList.set(i, "</ul>");
}
else if(typeLine == "UNORDER_LINE") {
mdList.set(i, "<li>" + translateToHtmlInline(line.trim()) + "</li>");
}
// 是有序列表行
else if(typeLine == "ORDER_BEGIN") {
mdList.set(i, "<ol>");
}
else if(typeLine == "ORDER_END") {
mdList.set(i, "</ol>");
}
else if(typeLine == "ORDER_LINE") {
mdList.set(i, "<li>" + translateToHtmlInline(line.trim()) + "</li>");
}
// 是代码行
else if(typeLine == "CODE_BEGIN") {
mdList.set(i, "<pre>");
}
else if(typeLine == "CODE_END") {
mdList.set(i, "</pre>");
}
else if(typeLine == "CODE_LINE") {
mdList.set(i, "<code>" + line + "</code>");
}
// 是引用行
else if(typeLine == "QUOTE_BEGIN") {
mdList.set(i, "<blockquote>");
}
else if(typeLine == "QUOTE_END"){
mdList.set(i, "</blockquote>");
}
}
}
/**
* 将行内的 markdown 语句转换成对应的 html
* @param mark 语句
* @return html 语句
*/
private String translateToHtmlInline( String line) {
String html = "";
for(int i=0; i<line.length();i++) {
// 图片
if(i < line.length() - 4 && line.charAt(i) == '!' && line.charAt(i + 1) == '[') {
int index1 = line.indexOf(']', i + 1);
if(index1 != -1 && line.charAt(index1 + 1) == '(' && line.indexOf(')', index1 + 2) != -1){
int index2 = line.indexOf(')', index1 + 2);
String picName = line.substring(i + 2, index1);
String picPath = line.substring(index1 + 2, index2);
line = line.replace(line.substring(i, index2 + 1), "<img alt='" + picName + "' src='" + picPath + "' />");
}
}
// 链接
if(i < line.length() - 3 && ((i > 0 && line.charAt(i) == '[' && line.charAt(i - 1) != '!') || (line.charAt(0) == '['))) {
int index1 = line.indexOf(']', i + 1);
if(index1 != -1 && line.charAt(index1 + 1) == '(' && line.indexOf(')', index1 + 2) != -1){
int index2 = line.indexOf(')', index1 + 2);
String linkName = line.substring(i + 1, index1);
String linkPath = line.substring(index1 + 2, index2);
line = line.replace(line.substring(i, index2 + 1), "<a href='" + linkPath + "'> " + linkName + "</a>");
}
}
// 行内引用
if(i < line.length() - 1 && line.charAt(i) == '`' && line.charAt(i + 1) != '`') {
int index = line.indexOf('`', i + 1);
if(index != -1) {
String quoteName = line.substring(i + 1, index);
line = line.replace(line.substring(i, index + 1), "<code>" + quoteName + "</code>");
}
}
// 粗体
if(i < line.length() - 2 && line.charAt(i) == '*' && line.charAt(i + 1) == '*') {
int index = line.indexOf("**", i + 1);
if(index != -1) {
String quoteName = line.substring(i + 2, index );
line = line.replace(line.substring(i, index + 2), "<strong>" + quoteName + "</strong>");
}
}
// 斜体
if(i < line.length() - 2 && line.charAt(i) == '*' && line.charAt(i + 1) != '*') {
int index = line.indexOf('*', i + 1);
if(index != -1 && line.charAt(index + 1) != '*') {
String quoteName = line.substring(i + 1, index);
line = line.replace(line.substring(i, index + 1), "<i>" + quoteName + "</i>");
}
}
}
return line;
}
第三次扫描后,markdown 格式如下,左侧为每一行的标签类型,右侧为文件内容:
BLANK_LINE
TITLE <h2>什么是 markdown</h2>
QUOTE_BEGIN <blockquote>
OTHER <p>Markdown 是一种轻量级的「标记语言」,它的优点很多,目前也被越来越多的写作爱好者...</p>
QUOTE_END </blockquote>
BLANK_LINE
TITLE <h2>markdown 常用标签:</h2>
CODE_BEGIN <pre>
CODE_LINE <code>代码 (```)</code>
CODE_LINE <code>引用 (>)</code>
CODE_LINE <code>无序列表 ('*','-','+')</code>
CODE_LINE <code>有序列表 ('1.','2.','3.')</code>
CODE_LINE <code>标题 (#)</code>
CODE_LINE <code>图片 (![]())</code>
CODE_LINE <code>链接 ([]())</code>
CODE_LINE <code>行内高亮 (`)</code>
CODE_LINE <code>粗体 (**)</code>
CODE_LINE <code>斜体 (*)</code>
CODE_LINE <code>表格</code>
CODE_END </pre>
TITLE <h2>markdown 入门1</h2>
ORDER_BEGIN <ol>
ORDER_LINE <li><a href='http://www.jianshu.com/p/1e402922ee32/'> Markdown——入门指南</a></li>
ORDER_LINE <li><a href='http://www.cnblogs.com/libaoquan/p/6812426.html'> Markdown的基本语法</a></li>
ORDER_END </ol>
BLANK_LINE
TITLE <h3>markdown 标签分类</h3>
UNORDER_BEGIN <ul>
UNORDER_LINE <li>markdown 标签可以 <strong>简单</strong> 分为 2 大类:...</li>
UNORDER_LINE <li>其中,<i>代码</i>、<code>引用</code>、无序列表、有序列表、标题这 5 类...</li>
UNORDER_LINE <li>除了这 5 类标签外,图片,链接、行内高亮、粗体、斜体这 5 类...</li>
UNORDER_END </ul>
BLANK_LINE
至此,将 mdList 与 html 头部 与 尾部 写入 html 文件即可。
使用 java 实现一个简单的 markdown 语法解析器的更多相关文章
- 用java实现编译器-算术表达式及其语法解析器的实现
大家在参考本节时,请先阅读以下博文,进行预热: http://blog.csdn.net/tyler_download/article/details/50708807 本节代码下载地址: http: ...
- Boost学习之语法解析器--Spirit
Boost.Spirit能使我们轻松地编写出一个简单脚本的语法解析器,它巧妙利用了元编程并重载了大量的C++操作符使得我们能够在C++里直接使用类似EBNF的语法构造出一个完整的语法解析器(同时也把C ...
- 在.NET Core中使用Irony实现自己的查询语言语法解析器
在之前<在ASP.NET Core中使用Apworks快速开发数据服务>一文的评论部分,.NET大神张善友为我提了个建议,可以使用Compile As a Service的Roslyn为语 ...
- 简单说说Markdown语法
# 简单说说 MarkDown 语法 html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr ...
- Java学习(一)MarkDown语法
Java学习(一)MarkDown语法 一.标题语法 一级标题 一级标题前添加一个#号 二级标题 二级标题前添加两个#号 三级标题 三级标题前添加三个#号 ... 二.字体 1.粗体 hello wo ...
- 使用Java编写一个简单的Web的监控系统cpu利用率,cpu温度,总内存大小
原文:http://www.jb51.net/article/75002.htm 这篇文章主要介绍了使用Java编写一个简单的Web的监控系统的例子,并且将重要信息转为XML通过网页前端显示,非常之实 ...
- java:jsp: 一个简单的自定义标签 tld
java:jsp: 一个简单的自定义标签 tld 请注意,uri都是:http://www.tag.com/mytag,保持统一,要不然报错,不能访问 tld文件 <?xml version=& ...
- 使用JAVA写一个简单的日历
JAVA写一个简单的日历import java.text.DateFormat;import java.text.ParseException;import java.text.SimpleDateF ...
- Java实现一个简单的网络爬虫
Java实现一个简单的网络爬虫 import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileWri ...
随机推荐
- 2017-2018-2 20155315《网络对抗技术》Exp1:PC平台逆向破解
实验目的 本次实践的对象是一个名为pwn1的linux可执行文件. 该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串. 该程序同时包含另一个代码片段,getShe ...
- 20154327 Exp9 Web安全基础
基础问题回答 (1)SQL注入攻击原理,如何防御 原理: 程序员在编写代码的时候,没有对用户输入数据的合法性进行判断,攻击者利用SQL命令欺骗服务器执行恶意的SQL命令,获得某些他想得知的数据. 防御 ...
- Python3抓取javascript生成的html网页
用urllib等抓取网页,只能读取网页的静态源文件,而抓不到由javascript生成的内容. 究其原因,是因为urllib是瞬时抓取,它不会等javascript的加载延迟,所以页面中由javasc ...
- 9.22 下午 (document对象)
document对象 1.找元素:(1)gerElementById()根据ID找 (2)gerElementByClassName()根据Class找,返回数组 (3)gerElem ...
- 5 数据结构、栈、队列、链表、list、dict、迷宫问题
1.什么是数据结构 2.栈:后进先出 1.什么是栈 栈(Stack)是一个数据集合,可以理解为只能在一端进行插入或删除操作的列表. 2.栈的Python实现 stack = [] stack.ap ...
- BZOJ2539 Spoj 10707 Count on a tree II
题面 题解 因为这道题目我也不太会做,所以借鉴了一下大佬heyujun的博客 如果不强制在线,这道题目是树上莫队练手题 我们知道莫队是离线的,但是万一强制在线就凉凉了 于是我们就需要一些操作:树分块 ...
- Sklearn环境搭建与常用包
开发环境搭建 直接安装Anaconda IPython IPython是公认的现代科学计算中最重要的Python工具之一.它是一个加强版的Python交互命令行工具,有以下几个明显的特点: 1. 可以 ...
- SQL语句汇总(终篇)—— 表联接与联接查询
既然是最后一篇那就不能只列出些干枯的标准语句,更何况表联接也是SQL中较难的部分,所以此次搭配题目来详细阐述表联接. 上一篇博文说到相关子查询效率低下,那我们怎么能将不同表的信息一起查询出来呢?这就需 ...
- centos下安装docker,kubelet kubeadm kubectl
目录 安装docker 安装命令 安装 kubelet kubeadm kubectl 安装命令 安装docker 安装命令 yum install docker -y 启动 systemctl en ...
- phpcmsv9广告版位调用方法
<div class="ya"> <?php // pc:get 使用sql语句获取指定条件的广告版位! ?> {pc:get sql="SELE ...