如何用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 相关文章推荐
Python3基础之基本数据类型概述
Aug 13 Python
Python 读取指定文件夹下的所有图像方法
Apr 27 Python
Python3.5内置模块之shelve模块、xml模块、configparser模块、hashlib、hmac模块用法分析
Apr 27 Python
通过PYTHON来实现图像分割详解
Jun 26 Python
python selenium循环登陆网站的实现
Nov 04 Python
基于Python实现扑克牌面试题
Dec 11 Python
pytorch 实现查看网络中的参数
Jan 06 Python
Tensorflow卷积实现原理+手写python代码实现卷积教程
May 22 Python
pytorch随机采样操作SubsetRandomSampler()
Jul 07 Python
Python pymsql模块的使用
Sep 07 Python
Python 找出英文单词列表(list)中最长单词链
Dec 14 Python
Python基于mediainfo批量重命名图片文件
Dec 29 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/27 PHP
对于PHP 5.4 你必须要知道的
2013/08/07 PHP
PHP删除数组中特定元素的两种方法
2019/02/28 PHP
Javascript this指针
2009/07/30 Javascript
用cssText批量修改样式
2009/08/29 Javascript
JavaScript Event学习第二章 Event浏览器兼容性
2010/02/07 Javascript
js中定义一个变量并判断其是否为空的方法
2014/05/13 Javascript
jQuery分别获取选中的复选框值的示例
2014/06/17 Javascript
js实现简单的验证码
2015/12/25 Javascript
使用Node.js处理前端代码文件的编码问题
2016/02/16 Javascript
原生javascript 学习之js变量全面了解
2016/07/14 Javascript
bootstrap datetimepicker日期插件使用方法
2017/01/13 Javascript
原生js实现返回顶部缓冲效果
2017/01/18 Javascript
async/await与promise(nodejs中的异步操作问题)
2017/03/03 NodeJs
十个免费的web前端开发工具详细整理
2017/09/18 Javascript
jQuery 导航自动跟随滚动的实现代码
2018/05/30 jQuery
python简单实例训练(21~30)
2017/11/15 Python
python中requests和https使用简单示例
2018/01/18 Python
python语言中with as的用法使用详解
2018/02/23 Python
python定时关机小脚本
2018/06/20 Python
python创建文件备份的脚本
2018/09/11 Python
python基于Selenium的web自动化框架
2019/07/14 Python
Python figure参数及subplot子图绘制代码
2020/04/18 Python
英国奢侈皮具品牌:Aspinal of London
2018/09/02 全球购物
澳大利亚巧克力花束和礼品网站:Tastebuds
2019/03/15 全球购物
就业意向书范文
2014/04/01 职场文书
领导班子个人对照检查剖析材料
2014/09/29 职场文书
小学教师师德师风自我剖析材料
2014/09/29 职场文书
小学生安全教育主题班会
2015/08/12 职场文书
2016党员学习作风建设心得体会
2016/01/21 职场文书
六年级数学教学反思
2016/02/16 职场文书
如何书写读后感?(附范文)
2019/07/26 职场文书
在校大学生才艺比赛策划书怎么写?
2019/08/26 职场文书
python自动化调用百度api解决验证码
2021/04/13 Python
关于springboot配置druid数据源不生效问题(踩坑记)
2021/09/25 Java/Android
使用Cargo工具高效创建Rust项目
2022/08/14 Javascript