如何用Python实现简单的Markdown转换器


Posted in Python onJuly 16, 2018

今天心血来潮,写了一个 Markdown 转换器。

import os, re,webbrowser
text = '''
# TextHeader
 ## Header1
  List
   - 1 
   - 2
   - 3
  > **quote**
  》 quote2
 ## Header2
  1. *斜体*
  2. [@以茄之名](https://3water.com/people/e4f87c3476a926c1e2ef51b4fcd18fa3)
  3、 ![](https://3water.com/v2-8560440c136c746730a63813ed701f52_is.jpg)
  
 ## Header3 
  `*[文章地址](https://zhuanlan.zhihu.com/p/39742445)*`
  ·**code1**·
  - [x]是否点赞
'''

程序开头先处理一些行内的语法,比如 code、strong、i 等,用正则直接替换:

text = re.sub(re.compile('([\`·])([^`·]+)[\`·]'), r'<code>\2</code>', text)
text = re.sub(re.compile('\*\*([^\*]+)\*\*'), r'<strong>\1</strong>', text)
text = re.sub(re.compile('([^\*])\*([^\*]+)\*'), r'\1<i>\2</i>', text)

接着是复杂一点的图片和链接:

text = re.sub(re.compile('([^\!])\[([^\]]+)\]\(([^)]+)\)'),
    r'\1<a href="\3" rel="external nofollow" target="_blank">\2</a>', text)
text = re.sub(re.compile('\!\[([^\]]*)\]\(([^)]+)\)'),
    r'<img src="\2" >', text)

接着就处理其他的语法,先把文本按每一行分开:

lines = text.split('\n')
html = ''
list_flag = ''

处理列表和待办事项的问题:

for line in lines:
 line = line.strip(' ')
 if re.match('- \[[ x]\]', line):
  print('matched')
  p_html = ''
  if re.match('- \[x\]', line):
   p_html = ' checked="checked"'
  line = re.sub('- \[[ x]\]', '', line)
  html += '''<label class="cssCheckbox">
  <input type="checkbox" %s />
  <span></span>%s
  </label>''' % (p_html, line)

因为有序列表和无序列表的区别是头尾的ol和ul,所以要用 list_flag 变量来判断

elif re.match('[\+\-\*] ', line):
 if list_flag == '':
  html += '<ul>\n'
  list_flag = 'ul'
 line = re.sub('[\+\-\*] ', '', line)
 html += '<li>%s</li>\n' % (line)
elif re.match('[\d]+[.、] ', line):
 if list_flag == '':
  list_flag = 'ol'
  html += '<ol>\n'
 line = re.sub('[\d]+[.、] ', '', line)
 html += '<li>%s</li>\n' % (line)

处理完后处理其他的语法:

else:
  if list_flag != '':
   html += '</%s>\n' % list_flag
   list_flag = ''
  if re.match('\#+', line):
   well = re.match('\#+', line).group().count('#')
   line = re.sub('\#+', '', line)
   html += '<h%i>%s</h%i>\n' % (well, line, well)
  elif re.match('[>》 ]', line):
   line = re.sub('^\s*[>》 ]', '', line)
   html += '<blockquote>%s</blockquote>\n' % (line)

  # elif re.match('[>》 ]', line):
  #  line = re.sub('^\s*[>》 ]', '', line)
  #  html += '<blockquote>%s</blockquote>\n' % (line)
  else:
   html += line

这里我稍微修改了一点,让 > 和 》 都可以转换成引用,主要是切换中英文标点太难了。

然后就是添加 CSS,自己改了一点马克飞象的进去,因为他的引用做得很漂亮:

with open('markdown.html', 'w', encoding='utf-8')as f:
 f.write('''
<html>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>body{
 margin: 0 auto;
 font-family: "ubuntu", "Tahoma", "Microsoft YaHei", arial,sans-serif;
 color: #444444;
 line-height: 1;
 padding: 30px;
} 
input[type='checkbox']+span::before {
 content:' ';/*不换行空格*/
 display: inline-block;
 vertical-align: 0.2em;
 width:0.8em;
 height:0.8em;
 margin-right: .2em;
 border-radius:.2em;
 background: silver;/*复选框的背景色*/
 text-indent:0.15em;
 line-height: 0.65;
}
input[type='checkbox'] {
 /*隐藏掉原先实际的 checkbox 框,之所以没用 display:none; 这种简单直接的方式,是因为这种方法会把它从键盘 tab 键切换焦点的队列中完全删除*/
 
 position: absolute;
 clip:rect(0,0,0,0);
}
input[type='checkbox']:checked+span::before {
 content:'\u221a'; /*对号的 Unicode字符*/
 background: yellowgreen;/*对号的颜色*/
}
img {
 max-width: 100%;
}
@media screen and (min-width: 1000px) {
 body {
  width: 842px;
  margin: 10px auto;
 }

 
}
h1, h2, h3, h4 {
 color: #111111;
 font-weight: 400;
 margin-top: 1em;
}

h1, h2, h3, h4, h5 {
 font-family: Georgia, Palatino, serif;
}
h1, h2, h3, h4, h5, dl{
 margin-bottom: 16px;
 padding: 0;
}

p {
 margin-top: 8px;
 margin-bottom: 3px;
}
h1 {
 font-size: 48px;
 line-height: 54px;
}
h2 {
 font-size: 36px;
 line-height: 42px;
}
h1, h2 {
 border-bottom: 1px solid #EFEAEA;
 padding-bottom: 10px;
}
h3 {
 font-size: 24px;
 line-height: 30px;
}
h4 {
 font-size: 21px;
 line-height: 26px;
}
h5 {
 font-size: 18px;
 line-height: 23px;
}
a {
 color: #0099ff;
 margin: 0 2px;
 padding: 0;
 vertical-align: baseline;
 text-decoration: none;
}
a:hover {
 text-decoration: none;
 color: #ff6600;
}
a:visited {
 /*color: purple;*/
}
ul, ol {
 padding: 0;
 padding-left: 18px;
 margin: 0;
}
li {
 line-height: 24px;
}
p, ul, ol {
 font-size: 16px;
 line-height: 24px;
}

ol ol, ul ol {
 list-style-type: lower-roman;
}

code, pre {
 font-family: Consolas, Monaco, Andale Mono, monospace;
 background-color:#f7f7f7;
 color: inherit;
}

code {
 font-family: Consolas, Monaco, Andale Mono, monospace;
 margin: 0 2px;
}

pre {
 font-family: Consolas, Monaco, Andale Mono, monospace;
 line-height: 1.7em;
 overflow: auto;
 padding: 6px 10px;
 border-left: 5px solid #6CE26C;
}

pre > code {
 font-family: Consolas, Monaco, Andale Mono, monospace;
 border: 0;
 display: inline;
 max-width: initial;
 padding: 0;
 margin: 0;
 overflow: initial;
 line-height: 1.6em;
 font-size: .95em;
 white-space: pre;
 background: 0 0;

}

code {
 color: #666555;
}

aside {
 display: block;
 float: right;
 width: 390px;
}
blockquote {
 border-left-width: 10px;
 background-color: rgba(102,128,153,0.05);
 border-top-right-radius: 5px;
 border-bottom-right-radius: 5px;
 padding: 15px 20px;
}
blockquote cite {
 font-size:14px;
 line-height:20px;
 color:#bfbfbf;
}
blockquote cite:before {
 content: '\2014 \00A0';
}

blockquote p {
 color: #666;
}
hr {
 text-align: left;
 color: #999;
 height: 2px;
 padding: 0;
 margin: 16px 0;
 background-color: #e7e7e7;
 border: 0 none;
}

dl {
 padding: 0;
}

dl dt {
 padding: 10px 0;
 margin-top: 16px;
 font-size: 1em;
 font-style: italic;
 font-weight: bold;
}

dl dd {
 padding: 0 16px;
 margin-bottom: 16px;
}

dd {
 margin-left: 0;
}

table {
 *border-collapse: collapse; /* IE7 and lower */
 border-spacing: 0;
 width: 100%;
}
table {
 border: solid #ccc 1px;
}

table thead {
 background: #f7f7f7;
}

table thead tr:hover {
 background: #f7f7f7
}
table tr:hover {
 background: #fbf8e9;
 -o-transition: all 0.1s ease-in-out;
 -webkit-transition: all 0.1s ease-in-out;
 -moz-transition: all 0.1s ease-in-out;
 -ms-transition: all 0.1s ease-in-out;
 transition: all 0.1s ease-in-out;
}
table td, .table th {
 border-left: 1px solid #ccc;
 border-top: 1px solid #ccc;
 padding: 10px;
 text-align: left;
}

table th {
 border-top: none;
 text-shadow: 0 1px 0 rgba(255,255,255,.5);
 padding: 5px;
 border-left: 1px solid #ccc;
}

table td:first-child, table th:first-child {
 border-left: none;
}</style></head>''')
 f.write(html)
 f.write('</html>')

用 Chrome 打开网页:

webbrowser.get('C:/Program Files (x86)/CentBrowser/Application/chrome.exe %s').open(
 'file:///'+os.getcwd()+'/markdown.html')

话说这里也是个坑,系统自带的 Edge 一直打开失败,用那个注册器注册 Chrome 也没办法用 ,最后还是在外网找到了解决方案。

最后的效果:

如何用Python实现简单的Markdown转换器

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python 实现插入排序算法
Jun 05 Python
Python天气预报采集器实现代码(网页爬虫)
Oct 07 Python
python复制列表时[:]和[::]之间有什么区别
Oct 16 Python
python实现杨氏矩阵查找
Mar 02 Python
Python高级特性与几种函数的讲解
Mar 08 Python
django项目简单调取百度翻译接口的方法
Aug 06 Python
Python 70行代码实现简单算式计算器解析
Aug 30 Python
flask框架配置mysql数据库操作详解
Nov 29 Python
Tensorflow 卷积的梯度反向传播过程
Feb 10 Python
python使用Geany编辑器配置方法
Feb 21 Python
分享一个python的aes加密代码
Dec 22 Python
Python 爬虫批量爬取网页图片保存到本地的实现代码
Dec 24 Python
详解python里的命名规范
Jul 16 #Python
Python 2.7中文显示与处理方法
Jul 16 #Python
Python定时任务sched模块用法示例
Jul 16 #Python
python中使用print输出中文的方法
Jul 16 #Python
django用户登录和注销的实现方法
Jul 16 #Python
Flask框架实现给视图函数增加装饰器操作示例
Jul 16 #Python
flask框架使用orm连接数据库的方法示例
Jul 16 #Python
You might like
PHP Laravel中的Trait使用方法
2019/01/20 PHP
javascript indexOf函数使用说明
2008/07/03 Javascript
传智播客学习之java 反射
2009/11/22 Javascript
javascript 哈希表(hashtable)的简单实现
2010/01/20 Javascript
Ext JS 4官方文档之三 -- 类体系概述与实践
2012/12/16 Javascript
js 显示base64编码的二进制流网页图片
2014/04/04 Javascript
js调试系列 控制台命令行API使用方法
2014/06/18 Javascript
JS中的form.submit()不能提交表单的错误原因
2014/10/08 Javascript
DOM基础教程之使用DOM控制表格
2015/01/20 Javascript
JavaScript实现简单的二级导航菜单实例
2015/04/15 Javascript
使用jQuery处理AJAX请求的基础学习教程
2016/05/10 Javascript
JS实现关闭当前页而不弹出提示框的方法
2016/06/22 Javascript
JS创建Tag标签的方法详解
2017/06/09 Javascript
jQuery实现获取动态添加的标签对象示例
2018/06/28 jQuery
vue日历/日程提醒/html5本地缓存功能
2019/09/02 Javascript
JavaScript计算正方形面积
2019/11/26 Javascript
使用typescript快速开发一个cli的实现示例
2020/12/09 Javascript
Python获取文件所在目录和文件名的方法
2017/01/12 Python
Python 3.3实现计算两个日期间隔秒数/天数的方法示例
2019/01/07 Python
Python格式化字符串f-string概览(小结)
2019/06/18 Python
Pycharm远程调试原理及具体配置详解
2019/08/08 Python
python3连接mysql获取ansible动态inventory脚本
2020/01/19 Python
使用HTML5和CSS3表单验证功能
2017/05/05 HTML / CSS
Skyscanner台湾:全球知名的旅行比价引擎
2018/07/01 全球购物
房屋改造计划书
2014/01/10 职场文书
安全承诺书范文
2014/03/26 职场文书
个人四风问题对照检查材料思想汇报
2014/10/06 职场文书
八项规定自查自纠报告及整改措施
2014/10/26 职场文书
2014年班主任德育工作总结
2014/12/05 职场文书
2014年挂职干部工作总结
2014/12/06 职场文书
热血教师观后感
2015/06/10 职场文书
MySQL子查询中order by不生效问题的解决方法
2021/08/02 MySQL
vue3引入highlight.js进行代码高亮的方法实例
2022/04/08 Vue.js
GTX1650super好不好 gtx1650super显卡属于什么级别
2022/04/08 数码科技
docker 制作mysql镜像并自动安装
2022/05/20 Servers
Android实现图片九宫格
2022/06/28 Java/Android