Pull to refresh

Подсветка синтаксиса несколькими строками javascript

Reading time4 min
Views21K
Да, я знаю, что такое синтаксический анализ. И знаю много разных библиотек для подсветки чего угодно. Только это всё не то, когда надо подсветить простенький примерчик, не содержащий всяких кодоизвращений. И уж совсем негоже тянуть для этого много-много байт _правильно_ разбирающих _любой_ код.

Для случаев без кодоизврата (а их большинство) можно использовать такой код:
code = code
// ключевые слова (список неполон, написал, что в голову пришло)
.replace(/(var|function|typeof|new|return|if|for|in|while|break|do|continue|switch|case)([^a-z0-9\$_])/gi,
'<span class="kwrd">$1</span>$2')
// всякие скобочки
.replace(/(\{|\}|\]|\[|\|)/gi,'<span class="kwrd">$1</span>')
// однострочные комментарии
.replace(/(\/\/[^\n\r]*(\n|\r\n))/g,'<span class="comm">$1</span>')
// строки
.replace(/('.*?')/g,'<span class="str">$1</span>')
// функции (когда после идентификатора идет скобка)
.replace(/([a-z\_\$][a-z0-9_]*)\(/gi,'<span class="func">$1</span>(')
// не люблю восьмизначные табы, пусть лучше будет 4 пробела
.replace(/\t/g,'    ');




CSS


.str{color:red}/* Строки красные */
.func{color:blue}/* Юзер-функции синие */
.comm{color:orange}/* Комменты оранжевые */
.kwrd{font-weight:bold}/* Ключевые слова полужирные */
.str span{color:red;font-weight:normal}/* Всё внутри строки — строка */
.comm span{color:orange;font-weight:normal}/* Всё внутри комментария — комментарий */


Пример


Подсветка синтаксиса - upload images with Picamatic
Обратите внимание на баг в последней строке. Об этом разговор далее

Область применения, баги


Данный код заточен на javascript, о чём можно судить по ключевым словам. Сделать код понимающим любой Си-подобный язык не представляет труда.

Возиться с многострочными комментариями я не стал, как и с многострочными строками, ибо не так уж частно многострочные комменты используются в примерах, а к многострочным строкам в javascript я как-то не привык.

Еще чем плох данный подход — текст «плоский», то есть этот, с позволения сказать, анализатор, считает слово for внутри строки или комментария таким же ключевым словом, как и все их. Нас это не устраивает, поэтому используются css правила .str span и .comm span, дабы возложить на плечи CSS распознавание блочной структуры кода. Одна проблема возникает — когда строка содержит комментарий, который содержит ключевое слово или пользовательскую функцию. В этом случае мы не взирая на окончание строки всё считаем строкой (до символа перевода строки).

И ещё, двойных кавычек не существует. Можно добавить еще один replace:
.replace(/(".*?")/g,'<span class="str">$1</span>')

Но меня от этого что-то удерживает.

Бонус: плагин для jQuery



chainable, multiple

	(function($){

	$.fn.syntax = function(){
		return this.each(function(){
			var jqCode = $(this);
			var code = jqCode.text();
			code = code
			.replace(/(var|function|typeof|new|return|if|for|in|while|break|do|continue|case|switch)([^a-z0-9\$_])/gi,'<span class="kwrd">$1</span>$2')
			.replace(/(\{|\}|\]|\[|\|)/gi,'<span class="kwrd">$1</span>')
			.replace(/(\/\/[^\n\r]*(\n|\r\n))/g,'<span class="comm">$1</span>')
			.replace(/('.*?')/g,'<span class="str">$1</span>')
			.replace(/([a-z\_\$][a-z0-9_]*)\(/gi,'<span class="func">$1</span>(')
			.replace(/\t/g,'    ');
			jqCode.html(code);
		});
	}

	})(jQuery);

	// пример вызова
	$('pre#code').syntax(); // подсветка конкретного блока pre с id=code
	$('pre').syntax(); // подсветка всех pre


Усовершенствованный вариант от etcdema


function Syntax(code){
	var comments	= [];	// Тут собираем все каменты
	var strings		= [];	// Тут собираем все строки
	var res			= [];	// Тут собираем все RegExp
	var all			= { 'C': comments, 'S': strings, 'R': res };
	var safe		= { '<': '<', '>': '>', '&': '&' };

	return code
	// Маскируем HTML
		.replace(/[<>&]/g, function (m)
			{ return safe[m]; })
	// Убираем каменты
		.replace(/\/\*[\s\S]*\*\//g, function(m)
			{ var l=comments.length; comments.push(m); return '~~~C'+l+'~~~';   })
		.replace(/([^\\])\/\/[^\n]*\n/g, function(m, f)
			{ var l=comments.length; comments.push(m); return f+'~~~C'+l+'~~~'; })
	// Убираем regexp
		.replace(/\/(\\\/|[^\/\n])*\/[gim]{0,3}/g, function(m)
			{ var l=res.length; res.push(m); return '~~~R'+l+'~~~';   })
	// Убираем строки
		.replace(/([^\\])((?:'(?:\\'|[^'])*')|(?:"(?:\\"|[^"])*"))/g, function(m, f, s)
			{ var l=strings.length; strings.push(s); return f+'~~~S'+l+'~~~'; })
	// Выделяем ключевые слова
		.replace(/(var|function|typeof|new|return|if|for|in|while|break|do|continue|switch|case)([^a-z0-9\$_])/gi,
			'<span class="kwrd">$1</span>$2')
	// Выделяем скобки
		.replace(/(\{|\}|\]|\[|\|)/gi,
			'<span class="gly">$1</span>')
	// Выделяем имена функций
		.replace(/([a-z\_\$][a-z0-9_]*)[\s]*\(/gi,
			'<span class="func">$1</span>(')
	// Возвращаем на место каменты, строки, RegExp
		.replace(/~~~([CSR])(\d+)~~~/g, function(m, t, i)
			{ return '<span class="'+t+'">'+all[t][i]+'</span>'; })
	// Выставляем переводы строк
		.replace(/\n/g,
			'<br/>')
	// Табуляцию заменяем неразрывными пробелами
		.replace(/\t/g,
			'&nbsp;&nbsp;&nbsp;&nbsp;');
}
Тут понадобятся другие стили:
.S{color:red}/* Строки красные */
.func{color:blue}/* Юзер-функции синие */
.C{color:orange}/* Комменты оранжевые */
.kwrd{font-weight:bold}/* Ключевые слова полужирные */
.R{color:gray} /*Серые регвыражения */


upd: учтя исправления и дополнения, получил скрипт сам себя подсвечивающий, а вот версия от etcdema: dema.ru/syntax
Tags:
Hubs:
+56
Comments30

Articles

Change theme settings