博客園Markdown模式的MATLAB代碼高亮方案


前言

博客園隨筆寫作可以使用 Markdown 進行編輯,當展示代碼時,可以使用下面的語法來對代碼塊進行展示:

​```language
code-content
​```

一般來說,指明了 language 后,應該是可以是實現語法高亮的。其基本原理就是將代碼中的 關鍵字變量函數 等待字符做正則化匹配,將純文本的代碼內容分塊,與固定語法內容的着色方案(css樣式)對應上。

然鵝!!大部分編程語言都能實現較好的高亮,而 Matlab 效果卻很差,語法樣式是錯誤的!看着很不舒服。

就像下面這樣:

% 為輸出創建文件
!touch testFile.txt
fid = fopen('testFile.txt','w');
for i = 1:10
	frprintf(fid,'%6.2f \n',i);
end

作為強迫症的我想把 Matlab 代碼高亮變成和 Matlab軟件中高亮方式一模一樣。話不多說,開干!


語法高亮的基本內容

在改造之前,首先得理解語法高亮的基本內容。

一般來說,作為一種編程語言,都包括以下基本語法項目:

  • keyword 關鍵字,也就是我們常用 for、if、else、end等等
  • string 字符串,作為文本的一些字符
  • params 變量,自己定義的變量
  • comment 注釋,代碼一般都會有注釋
  • bracket 括號,一般地代碼都會有成對出現的圓括號、花括號

以上這些,就是作為一個語法高亮方案,所需要匹配的基本內容。這些語法項目,都會有一定的規律(不然怎么叫語法),通過正則表達式,可以將寫好的代碼塊中,對應的語法基本項目匹配出來。比如你的代碼中有很多個 if ,那么通過正則表達式,就可以將他們全部匹配到。

貼上樣式標簽

當匹配到基本的語法項目后,將他們貼上對應的樣式標簽,例如對於匹配到的 if ,將其貼上關鍵字標簽:

<span class="matlab-keyword">if</span>

這樣,if 這個關鍵字就會被 matlab-keyword 樣式着色。其他的也和這個一樣,貼上對應的樣式即可。

代碼高亮識別

那么,在一堆文字中,我怎么識別這部分文字就是要高亮的代碼?

在這里我們通過 <pre></pre>這樣一對標簽來包裹代碼內容,讓代碼識別到這段文字是需要高亮的代碼。為了區別其他樣式,一般在markdown中只需要這樣來表示代碼需要高亮成 Matlab 樣式:

<pre class="matlab-code">
% 為輸出創建文件
!touch testFile.txt
fid = fopen('testFile.txt','w');
for i = 1:10
	frprintf(fid,'%6.2f \n',i);
end
</pre>

博客園后台配置

總的來說,實現代碼高亮,基本上主要包括這幾大內容:

  • 配置語法高亮CSS樣式
  • 配置語法正則表達式匹配方案JS
  • Markown 中以特定標簽包裹代碼塊,實現調用

語法高亮的css樣式文件

.cnblogs-markdown .matlab-code{
	display: block;
	color: #333;
	overflow-x: auto;
	background: #F2F4F5 !important;
	border: none !important;
	font-family: 'Microsoft YaHei', 'SF Pro Display', Roboto, Noto, Arial, 'PingFang SC', sans-serif !important;
	padding: 1em !important;
	font-size: 14px !important
}
pre .matlab-keyword, code .matlab-keyword {color: #0000fe;}
pre .matlab-string,  code .matlab-string  {color: #a020ef;}
pre .matlab-number,  code .matlab-number  {color: #333;}
pre .matlab-bracket, code .matlab-bracket {color: #333;}
pre .matlab-comment, code .matlab-comment {color: #228b22;}
pre .matlab-comment span, code .matlab-comment span {color: #228b22; font-weight: normal;}

正則表達式匹配的js文件

/*
MATLAB Highlighter 1.55, a small and lightweight JavaScript library for colorizing your MATLAB syntax.
http://matlabtricks.com/matlab-highlighter
Licensed under the MIT license
Copyright (c) 2013, Zoltan Fegyver
*/
function highlightMATLABCode(d) {
	function g(i) {
		return (i >= "A" && i <= "Z") || (i >= "a" && i <= "z") || (i == ")")
	}

	function m(r, j, i) {
		var s = j.index,
			t;
		while (s >= i) {
			t = r.charAt(--s);
			if (t == "\n") {
				break
			}
			if (t == "'") {
				continue
			} else {
				return !g(t)
			}
		}
		return true
	}

	function a(i) {
		var j = i.length - 1,
			r;
		while (j > 0) {
			r = i.charAt(--j);
			if (r == "\n") {
				return true
			}
			if (r == "%") {
				return false
			}
		}
		return true
	}

	function n(t) {
		var s, u = 0,
			r, v = /(\'[^\'\n]*\')/gi,
			j = [];
		while (s = v.exec(t)) {
			if (m(t, s, u)) {
				var w = t.slice(u, s.index);
				for (var i = j.length - 2; i >= 0; i -= 2) {
					if (w.indexOf("\n") > -1) {
						break
					}
					w = w.concat(j[i])
				}
				if (a(w)) {
					r = s.index + s[1].length;
					j.push(t.slice(u, s.index));
					j.push(t.slice(s.index, r));
					u = r
				}
			}
		}
		j.push(t.slice(u));
		return j
	}

	function b(u, j) {
		var w = '<span class="',
			v = "</span>";
		if (j) {
			return [w, 'matlab-string">', u, v].join("")
		} else {
			var t = [{
				r: /\b('|break|case|catch|classdef|continue|else|elseif|end|for|function|global|if|otherwise|parfor|persistent|return|spmd|switch|try|while|')\b/gi,
				s: "keyword"
			}, {
				r: /\b([0-9]+)\b/gi,
				s: "number"
			}, {
				r: /([(){}\[\]]+)/gi,
				s: "bracket"
			}, {
				r: /(%[^\n]*)/gi,
				s: "comment"
			}];
			for (var r = 0, s = t.length; r < s; r++) {
				u = u.replace(t[r].r, [w, "matlab-", t[r].s, '">$1', v].join(""))
			}
			return u
		}
	}

	function q(u) {
		var w = [],
			s = [];
		if (typeof u === "undefined") {
			u = {
				tagPre: true,
				tagCode: false,
				className: "matlab-code"
			}
		}
		if (typeof u !== "object") {
			w.push(document.getElementById(u))
		} else {
			if (u.tagCode) {
				s.push("code")
			}
			if (u.tagPre) {
				s.push("pre")
			}
			for (var t = 0; t < s.length; t++) {
				var x = document.getElementsByTagName(s[t]);
				for (var r = 0, v = x.length; r < v; r++) {
					if ((u.className == "") || ((x[r].className.toString().length > 0) && ((" " + x[r].className + " ").indexOf(" " +
							u.className + " ") > -1))) {
						w.push(x[r])
					}
				}
			}
		}
		return w
	}
	var p = q(d);
	for (var f = 0, o = p.length; f < o; f++) {
		var c = n(p[f].innerHTML.toString().replace(/<br\s*\/?>/mg, "\n")),
			h = [],
			l = "&nbsp;";
		for (var e = 0, k = c.length; e < k; e++) {
			h.push(b(c[e], e % 2))
		}
		p[f].innerHTML = h.join("").replace(/^[ ]/gm, l).replace(/\n/gm, "<br>").replace(/\t/gm, l + l)
	}
};

調用演示

<pre class="matlab-code">
% 為輸出創建文件
!touch testFile.txt
fid = fopen('testFile.txt','w');
for i = 1:10
	frprintf(fid,'%6.2f \n',i);
end
</pre>

高亮結果

% 為輸出創建文件
!touch testFile.txt
fid = fopen('testFile.txt','w');
for i = 1:10
	frprintf(fid,'%6.2f \n',i);
end

BUG

雖然這樣做可以實現高亮,但是於此同時,代碼塊右上角的 復制按鈕失去了復制功能。原因是正常的代碼塊是這樣被解釋成高亮的

<pre>
<code>
</code>
</pre>

復制調用的js代碼會將 code 部分加上 id = "copy_target_1" 這樣類似的標簽,才能被識別成可以復制的內容,而前面的方法並未出現code,所以功能實現不了!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM