如何用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画出三角形外接圆和内切圆的方法
Jan 25 Python
python3 破解 geetest(极验)的滑块验证码功能
Feb 24 Python
Python读取本地文件并解析网页元素的方法
May 21 Python
Python单向链表和双向链表原理与用法实例详解
Aug 31 Python
python自动发送测试报告邮件功能的实现
Jan 22 Python
对Python3中dict.keys()转换成list类型的方法详解
Feb 03 Python
python实现文件助手中查看微信撤回消息
Apr 29 Python
Python使用matplotlib绘制三维参数曲线操作示例
Sep 10 Python
使用python去除图片白色像素的实例
Dec 12 Python
使用Python给头像加上圣诞帽或圣诞老人小图标附源码
Dec 25 Python
tensorflow:指定gpu 限制使用量百分比,设置最小使用量的实现
Feb 06 Python
python Gabor滤波器讲解
Oct 26 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 设计模式之观察者模式介绍
2012/02/22 PHP
PHP中Session和Cookie是如何操作的
2015/10/10 PHP
PHP文件上传处理案例分析
2016/10/15 PHP
Yii2 queue的队列使用详解
2019/07/19 PHP
js cookies 常见网页木马挂马代码 24小时只加载一次
2009/04/13 Javascript
JavaScript Event学习第九章 鼠标事件
2010/02/08 Javascript
ExtJs使用总结(非常详细)
2012/03/22 Javascript
jquery实现图片按比例缩放示例
2014/07/01 Javascript
jQuery scrollFix滚动定位插件
2015/04/01 Javascript
使用JavaScript实现连续滚动字幕效果的方法
2015/07/07 Javascript
11种ASP连接数据库的方法
2015/09/18 Javascript
浅谈js的异步执行
2016/10/18 Javascript
通过bootstrap全面学习less
2016/11/09 Javascript
vue.js入门(3)——详解组件通信
2016/12/02 Javascript
js实现5秒倒计时重新发送短信功能
2017/02/05 Javascript
JS和Canvas实现图片的预览压缩和上传功能
2018/03/30 Javascript
vue组件文档(.md)中如何自动导入示例(.vue)详解
2019/01/25 Javascript
Echarts动态加载多条折线图的实现代码
2019/05/24 Javascript
深入解析koa之异步回调处理
2019/06/17 Javascript
微信小程序表单验证插件WxValidate的二次封装功能(终极版)
2019/09/03 Javascript
Python版实现微信公众号扫码登陆
2020/05/28 Javascript
[06:37]2014DOTA2国际邀请赛 昔日王者渴望重回巅峰
2014/07/12 DOTA
[01:09:23]KG vs TNC 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/16 DOTA
Python跳出循环语句continue与break的区别
2014/08/25 Python
Python模仿POST提交HTTP数据及使用Cookie值的方法
2014/11/10 Python
常用python编程模板汇总
2016/02/12 Python
浅谈python3.x pool.map()方法的实质
2019/01/16 Python
Python标准库json模块和pickle模块使用详解
2020/03/10 Python
python爬虫中采集中遇到的问题整理
2020/11/27 Python
澳大利亚儿童鞋在线:The Trybe
2019/07/16 全球购物
竞聘演讲稿范文
2014/01/12 职场文书
小孩百日宴答谢词
2014/01/15 职场文书
教师见习报告范文
2014/11/03 职场文书
2015年安全月活动总结
2015/03/26 职场文书
公司联欢会主持词
2015/07/04 职场文书
Python利用capstone实现反汇编
2022/04/06 Python