如何用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简单获取自身外网IP的方法
Sep 18 Python
对Pyhon实现静态变量全局变量的方法详解
Jan 11 Python
使用Python轻松完成垃圾分类(基于图像识别)
Jul 09 Python
解决Django 在ForeignKey中出现 non-nullable field错误的问题
Aug 06 Python
Python字符串大小写转换拼接删除空白
Sep 19 Python
使用Python给头像加上圣诞帽或圣诞老人小图标附源码
Dec 25 Python
Python实现序列化及csv文件读取
Jan 19 Python
Tensorflow 1.0之后模型文件、权重数值的读取方式
Feb 12 Python
使用Python将图片转正方形的两种方法实例代码详解
Apr 29 Python
只用20行Python代码实现屏幕录制功能
Jun 02 Python
python编程简单几行代码实现视频转换Gif示例
Oct 05 Python
Pyhton爬虫知识之正则表达式详解
Apr 01 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和数据库结合的一个简单的web实例 代码分析 (php初学者)
2011/07/28 PHP
CodeIgniter配置之config.php用法实例分析
2016/01/19 PHP
利用PHP获取访客IP、地区位置、浏览器及来源页面等信息
2017/06/27 PHP
postman的安装与使用方法(模拟Get和Post请求)
2018/08/06 PHP
thinkphp5框架扩展redis类方法示例
2019/05/06 PHP
IE中jscript/javascript的条件编译
2006/09/07 Javascript
JavaScript Event学习第五章 高级事件注册模型
2010/02/07 Javascript
为JavaScript提供睡眠功能(sleep) 自编译JS引擎
2010/08/16 Javascript
jquery 获取dom固定元素 添加样式的简单实例
2014/02/04 Javascript
jquery如何把数组变为字符串传到服务端并处理
2014/04/30 Javascript
用jQuery toggleClass 实现鼠标移上变色
2014/05/14 Javascript
jquery单选框radio绑定click事件实现方法
2015/01/14 Javascript
Jquery检验手机号是否符合规则并根据手机号检测结果将提交按钮设为不同状态
2015/11/26 Javascript
jQuery鼠标悬浮链接弹出跟随图片实例代码
2016/01/08 Javascript
JavaScript中原型链存在的问题解析
2016/09/25 Javascript
JavaScript中boolean类型之三种情景实例代码
2016/11/21 Javascript
页面间固定参数,通过cookie传值的实现方法
2017/05/31 Javascript
Nodejs 和 Electron ubuntu下快速安装过程
2018/05/04 NodeJs
angularjs 动态从后台获取下拉框的值方法
2018/08/13 Javascript
浅谈vue中关于checkbox数据绑定v-model指令的个人理解
2018/11/14 Javascript
JS中比较两个Object数组是否相等方法实例
2019/11/11 Javascript
微信小程序实现滚动Tab选项卡
2020/11/16 Javascript
python中数据爬虫requests库使用方法详解
2018/02/11 Python
对numpy中轴与维度的理解
2018/04/18 Python
Pytorch 使用 nii数据做输入数据的操作
2020/05/26 Python
美国花园雕像和家居装饰网上商店:Design Toscano
2019/03/09 全球购物
英国时尚首饰品牌:Missoma
2020/06/29 全球购物
远东集团网络工程师面试题
2014/10/20 面试题
Linux文件操作命令都有哪些
2015/02/27 面试题
高中三年学习生活的自我评价
2013/10/10 职场文书
感恩母亲节演讲稿
2014/05/07 职场文书
2014年班务工作总结
2014/12/02 职场文书
成绩报告单家长评语
2014/12/30 职场文书
讲文明倡议书
2015/04/29 职场文书
2016优秀大学生个人事迹材料范文
2016/03/01 职场文书
处世之道:关于真诚相待的名言推荐
2019/12/02 职场文书