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

Обратите внимание на баг в последней строке. Об этом разговор далее
Данный код заточен на javascript, о чём можно судить по ключевым словам. Сделать код понимающим любой Си-подобный язык не представляет труда.
Возиться с многострочными комментариями я не стал, как и с многострочными строками, ибо не так уж частно многострочные комменты используются в примерах, а к многострочным строкам в javascript я как-то не привык.
Еще чем плох данный подход — текст «плоский», то есть этот, с позволения сказать, анализатор, считает слово for внутри строки или комментария таким же ключевым словом, как и все их. Нас это не устраивает, поэтому используются css правила .str span и .comm span, дабы возложить на плечи CSS распознавание блочной структуры кода. Одна проблема возникает — когда строка содержит комментарий, который содержит ключевое слово или пользовательскую функцию. В этом случае мы не взирая на окончание строки всё считаем строкой (до символа перевода строки).
И ещё, двойных кавычек не существует. Можно добавить еще один replace:
Но меня от этого что-то удерживает.
chainable, multiple
upd: учтя исправления и дополнения, получил скрипт сам себя подсвечивающий, а вот версия от etcdema: dema.ru/syntax
Для случаев без кодоизврата (а их большинство) можно использовать такой код:
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}/* Всё внутри комментария — комментарий */Пример
Обратите внимание на баг в последней строке. Об этом разговор далее
Область применения, баги
Данный код заточен на 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,
' ');
}Тут понадобятся другие стили:.S{color:red}/* Строки красные */
.func{color:blue}/* Юзер-функции синие */
.C{color:orange}/* Комменты оранжевые */
.kwrd{font-weight:bold}/* Ключевые слова полужирные */
.R{color:gray} /*Серые регвыражения */upd: учтя исправления и дополнения, получил скрипт сам себя подсвечивающий, а вот версия от etcdema: dema.ru/syntax
