国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

用Python高亮org-mode代碼塊

2019-11-14 17:25:49
字體:
來源:轉載
供稿:網友

文章同時可在我的github blog上閱讀:http://cheukyin.github.io/python/2014-08/pygments-highlight-src-export-html.html

本文完整代碼可見我的_pygment-html.py

1 前言

最近在研究利用org-mode寫博客,其他一切都深得我心、甚合吾意,就是代碼染色發布html這一點要給差評。org-mode利用htmlize 插件給 src block 中的代碼著色,讓文章中的代碼塊輸出html后的顏色于你在emacs上看到的相同。可問題在于,我emacs上背景是暗黑系的,而我博客上是淺色系,因此代碼高亮風格不相調和,何況高亮主題單一不可定制,輸出代碼行號丑陋不堪,當然這都可以用elisp解決,可是想必是繁雜晦色無比(要調色啊…)

于是,我又再次投入萬能的Python的懷抱,直接利用它的pygments庫高亮代碼。

3 具體實現

完整代碼可見我的_pygment-html.py

3.1 虛擬環境

由于在我的 Jekyll 中,需要寫多個python腳本處理,因此我先建立一個虛擬環境,然后所由腳本都在這個虛擬環境中開發。

3.1.1 Virtualenv

Virtualenv 用于創建獨立的Python環境,多個Python相互獨立,互不影響,它能夠:

  1. 在沒有權限的情況下安裝新套件
  2. 不同應用可以使用不同的套件版本
  3. 套件升級不影響其他應用

安裝: pip install virtualenv

創建: virtualenv /your/path/of/env ,默認情況下,虛擬環境會依賴系統環境中的 site packages ,就是說系統中已經安裝好的第三方 package 也會安裝在虛擬環境中,如果不想依賴這些package,那么可以加上參數 --no-site-packages 建立虛擬環境

啟動虛擬環境: cd /your/path/of/env , source ./bin/activate ,注意此時命令行會多一個 ENV , ENV 為虛擬環境名稱,接下來所有模塊都只會安裝到該目錄中去。

退出虛擬環境: deactivate

3.1.2 VirtualenvWrapper

Virtualenv很有用,但是操作較為麻煩(想想你需要來回切換多個ENV),因此可用 Virtualenvwrapper 簡化操作:

  1. 將所有虛擬環境整合在一個目錄下
  2. 管理(新增,刪除,復制)虛擬環境
  3. 切換虛擬環境

安裝: pip install virtualenvwrapper

把下面的代碼寫入 .bashrc/.zshrc 中:

if [ `id -u` != '0' ]; thenexport VIRTUALENV_USE_DISTRIBUTE=1        # <-- Always use pip/distributeexport WORKON_HOME=$HOME/.virtualenvs       # <-- Where all virtualenvs will be storedsource /usr/local/bin/virtualenvwrapper.shexport PIP_VIRTUALENV_BASE=$WORKON_HOMEexport PIP_RESPECT_VIRTUALENV=truefi

創建 $HOME/.virtualenvs 目錄,以后可在里面創建新的Virtualenv,如果你的Virtualenv不想放在里面,也可以只建立符號鏈接。

使用:

  • 列出虛擬環境列表: workon 或者 lsvirtualenv
  • 新建虛擬環境: mkvirtualenv [虛擬環境名稱]
  • 啟動/切換虛擬環境: workon [虛擬環境名稱]
  • 刪除虛擬環境: rmvirtualenv [虛擬環境名稱]
  • 離開虛擬環境: deactivate

需要注意的是,當你進入ENV后,你所調用的python程序是在 ENV/bin 目錄下,因此腳本開頭的 #!/usr/bin/python 就沒有用了,運行腳本時需要顯式調用python解釋器。

3.1.3 ENV安裝Shell腳本

由于整個ENV目錄不適合上傳至 github page 的倉庫(上傳后出現各種 build page error )。 所以我寫了個安裝ENV的Shell腳本:

mkdir _py_virtualenv pip2 install virtualenv && virtualenv _py_virtualenv --no-site-packages && source _py_virtualenv/bin/activate && pip2 install pygments && pip2 install beautifulsoup4

切記此腳本只能用 source 運行,不能當成可執行文件運行。因為source是直接在當前shell環境中執行,而可執行文件方式只會在新的子shell下執行(執行到source部份就會出錯)

3.2 編碼問題

由于我使用的是python2.7 ,而 python2.7 的編碼問題一直為人所詬病。python2.7默認的是 ascii編碼 ,當程序中出現非ascii編碼 時,python的處理常常會報這樣的錯:

UnicodeEncodeError: 'ascii' codec can't encode characters blalbla

對此有兩種辦法應對:

一種是涉及非ascii編碼的字串后添加 encode("utf8") ,不過這種方法似乎時靈時不靈,而且一旦少寫一個地方,將會導致大量的錯誤報告,不推薦。

另一種是在程序加載之初就將解釋器編碼改為 utf8 ,這也是我所采用的:

import sysreload(sys)sys.setdefaultencoding('utf8')

3.3 命令行交互

本腳本是通過命令行運行的,高亮的文件由用戶通過命令行參數指令,利用 sys 模塊可以很好地解析 cli參數 ,因此用戶可以方便地利用shell的一些特性輸入參數,具體代碼實現如下:

if len(sys.argv)==1:    print 'No Arguments!'else:    for file in sys.argv[1:]:        if '.html' in file:            hightlight_instance = Pygments_Html(file)            hightlight_instance.colorize()

sys.argv 是一個 list , sys.argv[0] 是程序名, sys.argv[1:] 才是cli中的各個參數名。

3.4 Pygments_Html

Pygments_Html 是我寫的用于高亮代碼的類,僅包含兩個函數: __init__ 和 colorize 。

3.4.1 __init__

初始化函數

def __init__(self,file):    self.filename = file    self.language_dict = {'sh':'sh','matlab':'matlab','C':'c','C++':'c++','css':'css',                          'python':'python','scheme':'scheme','latex':'latex',                          'ruby':'ruby','css':'css','html':'html','others':'text'}

filename 為代處理的html文件,而 language_dict 則為 org-mode 支持的語言名到 pygments 支持的語言名的映射(因為兩者會有細微差異),若org-mode中的語言不為pygments所支持,則映射至 text ,以純文本方式輸出。

注: org-mode 所支持的語言可用 ls /usr/share/emacs/site-lisp/org-mode/ob-* 看到,而 pygments 支持的可在pygments.org/docs/lexers 上看到

3.4.2 colorize

高亮函數,對 filename 文件所包含的代碼塊進行高亮。

Read file:

先讀入對應文件流至 file_read :

try:    # open the html file    file = open( self.filename,'r' )except IOError:    print self.filename,'not exists'    returnfile_read = file.read()print "Opening",self.filenamefile.close()

RE:

然后從 file_read 提取出包含在 <div class="org-src-container">...</div> 內的html代碼:

import resrc_html_list = re.findall(r'<div class="org-src-container">.*?</div>',file_read,re.S)

提取是利用 re 模塊進行,正則表達式中 .*? 代表 惰性匹配 ,之所以說是惰性,是因為它會匹配盡可能少的字符,它從第一個字符開始找起,一旦符合條件,立刻保存到匹配集合中,然后繼續進行查找。與之相反的是不加  的 貪婪匹配 。

re.S 是正則表達式的一個 flag ,因為需要尋找的文字跨越多行,若不加這個falg,python的re就只會一行一行地去匹配,若加了這個 flag ,表達式中的 .* 就會匹配包括 /n 在內的換行符。

BeautifulSoup:

接著便要開始對 src_html_list 里的每個元素做處理:

import BeautifulSoup4for src_html in src_html_list:    soup=BeautifulSoup(src_html)    src_soup = soup.find("div",class_="org-src-container")    language = (src_soup.pre['class'][1]).split('-')[1]

這里利用 BeautifulSoup 對 src_html 包含的html進行解析,這里 soup.find 使用了兩個參數,前一個是需要尋找的 tag,后面的 class_ 是 tag 中 class 屬性,返回符合這兩個條件的一個 soup 對象―― src_soup 。代碼塊的語言保存在<pre> 的 class 屬性中,把它提取出來存在 language 里。

將 language 映射至 pygments 所支持的語言名:

if language in self.language_dict:    language = self.language_dict[language]else:    language = self.language_dict['others']

Pygments:

現在可以用 pygments 高亮代碼了:

from pygments import highlightfrom pygments.lexers import get_lexer_by_namefrom pygments.formatters import HtmlFormatterlexer = get_lexer_by_name(language, stripall=True)formatter = HtmlFormatter(linespans='line', cssclass="highlight")src_colorized = highlight(src_soup.text, lexer, formatter)

Pygments 是 python 一個用于高亮代碼的模快

其中第7行中的 src_soup.text 可以將 soup 對象中的 html tags 全部去掉,只剩下純文本的原生代碼。

highlight 函數有三個參數:第一個是用于高亮的代碼串;第二個是 lexer ,用于指定代碼語言;第三個是 formatter ,用于指定輸出樣式。

在這里,指定 formatter 為 HtmlFormatter ,即輸出為 html 代碼,其中 cssclass 用于指定 div 的樣式名字,linespans 指定為 line ,用于指定 <span> 的 id 前綴為 line ,可以用來輸出行號 ,輸出格式如下:

<div class="highlight">  <pre>    <span id="line-1">...<span>    <span id="line-2">...<span>    <span id="line-3">...<span>    <span id="line-4">...<span>  </pre></div>

待會我會為 .hight 設計 CSS ,控制代碼及行號樣式。

Replace:

src_colorized 現在存儲了pygments高亮html代碼,需要替換掉原有的:

file_read = file_read.replace(src_html,src_colorized)

replace 有兩個參數,第一個是需要被替換的舊文本,第二個是新文本。

Rewrite:

for 循環完成后,意味著所有代碼已經高亮完畢,可以將新的html重寫進去:

file = open( self.filename,'w' )file.write(file_read)file.close()

3.5 CSS

上面的 pygments 只負責輸出html結構,而 CSS 卻是尚未指定。

首先生成代碼顏色的樣式:

pygmentize -S default -f html > your/path/pygments.css

生成的樣式文件加到我們的網頁中:

<link rel="stylesheet" href="/your/path/pygments.css">

由于我使用 jekyll ,所以我將 css 文件發在 assets/themes/havee/css/ 下

然后便需要指定行號樣式,上面說了行號由 .hightlight pre span 決定的:

.highlight pre {    counter-reset: linenumbers;}.highlight pre > span:before {  font-size: .9em;  color: #aaa;  content: counter(linenumbers);  counter-increment: linenumbers;  text-align: center;  width: 2.5em;  left: -0.5em;  position: relative;  -webkit-touch-callout: none;  -webkit-user-select: none;  -khtml-user-select: none;  -webkit-user-select: none;  /* Chrome all / Safari all */  -moz-user-select: none;     /* Firefox all */  -ms-user-select: none;      /* IE 10+ */  /* No support for these yet, use at own risk */  -o-user-select: none;  user-select: none;}

行號是由 counter 自動生成,14行至21行的 *-user-select 禁止行號被選中,如此瀏覽代碼是可以很方便地復制代碼。

4 用法

在Shell中運行腳本,shell命令后面跟html文件名


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 湖南省| 宣武区| 浙江省| 衡山县| 额济纳旗| 通山县| 雷山县| 甘南县| 吴忠市| 唐海县| 淮北市| 长武县| 多伦县| 同江市| 井陉县| 黔南| 思茅市| 荆门市| 南开区| 鹤山市| 东乌珠穆沁旗| 株洲市| 隆安县| 类乌齐县| 西乡县| 蛟河市| 宁津县| 徐闻县| 定陶县| 偏关县| 迁安市| 彰化市| 张家口市| 洛阳市| 安康市| 恭城| 昔阳县| 苏尼特右旗| 安西县| 贡嘎县| 彭山县|