View Full Version : Formatting code for display in HTML

09-05-2012, 11:34 PM
I will outline the steps I use to create, display, and store, formatted programming code. Partly because I couldn't find such a summary myself, and partly because I'm quite pleased with my results.

It should be viewed as just an outline of the process, as there are details which will need to be filled in. In particular, creating a database, and creating the full HTML-output of, perhaps, a table to display the code aren't detailed in full.

A textarea (with name and id of txtCode) within a form is used to enter the code. The only requirement is that four spaces are used to provide the code's indenting. When the form is submitted I would normally trim data, but I only rtrim the code/textarea, as I need to preserve the spaces on the left.

[Note that sequences of spaces that are not at the beginning of the line will collapse to a single space. This could be resolved with a little effort, but I'm not too concerned about this for this demonstration. Added: simply replacing any other spaces with & nbsp; should fix this.]

$trimmed_code = rtrim($_POST['txtCode']); // ..then escape for database insertion
$esc_code = mysqli_real_escape_string($dbc, $trimmed_code);
When I retrieve the data from the database I will display the code (having field-name 'code') in a table-row. However, I display it twice (two rows): once as plain text (with display:none for the row), and once as formatted-code. This is not essential, but doing so allows me to add an Edit button to the table that will grab the (hidden) code and place it back into my form for editing. [It would be more complicated to convert the formatted code back to plain text, suitable for the textarea.]

$rowh['code'] = htmlentities($row['code'], ENT_QUOTES); // for the hidden row
$html_code = nl2br($rowh['code']); // for formatted output
The following is the css for the formatted-code. It is contained in a div with the class "blogcode", and uses an ordered list (ol/li):

.blogcode {
margin: 10px 5px 20px 5px; padding: 0 0 0 8px;
background-color: #F6F3F3;
font-family: Consolas, 'Courier New', monospace;
font-size: smaller; color: green;
.blogcode ol {
list-style-position: outside;
margin: 0; padding: 0 0 0 30px;
.blogcode li {
padding: 3px 5px; margin: 0;
border-left: thin solid green;
.blogcode ol li:nth-child(odd) { background: white; }
/* nth-child doesn't work in some older browsers. */
.blogcode li.tab0 { padding-left: 5px; }
.blogcode li.tab1 { padding-left: 35px; }
.blogcode li.tab2 { padding-left: 65px; }
.blogcode li.tab3 { padding-left: 95px; }
.blogcode li.tab4 { padding-left: 125px; }
.blogcode li.tab5 { padding-left: 155px; }
.blogcode li.tab6 { padding-left: 185px; }
.blogcode li.tab7 { padding-left: 215px; }
.blogcode li.tab8 { padding-left: 245px; }
.blogcode li.tab9 { padding-left: 275px; }

I am using padding-left to indent it correctly, and will count the number of spaces (on the left) to determine which class to apply to the li's (tab0, tab1, etc.).

// Having initiated an HTML-table..
// ..for each row fetched from the database
echo "<tr class=\"coded\"><td>$html_code</td></tr>";
echo "<tr class=\"thecode\"><td>";
if (!empty($html_code)) {
echo "<div class=\"blogcode\">";
echo "<ol start=\"1\">";
$html_lines = '';
$code_lines = explode("\n", $rowh['code']);
foreach ($code_lines as $line) {
// work out how many 'tabs' are needed (which class to use)
$count_fours = strlen($line) - strlen(ltrim($line, ' '));
$count_fours = ceil($count_fours / 4); // round up
$line = codeWords($line); // blue keywords (optional)
$html_lines .= "<li class=\"tab$count_fours\">$line</li>";
echo $html_lines;
echo "</ol></div>";
echo "</td></tr>";
// repeat for the next database row.

The above code optionally uses a PHP function named codeWords (shown below) which allows me to colour-code certain keywords - I use blue text :)

// PHP function(s) to colour-code (blue) certain keywords.
function onlyWholeWords(&$value, $key) {
// Used by the following codeWords() function.
// Picks out whole-keywords, but NOT after // comment delimiters.
//$value = "/\b(" . $value . ")\b/";
$value = "/^(?:(?!\/\/).)*\K\b(" . $value . ")\b/";
function codeWords($code) {
// This could be adapted to handle different colours and
// programming languages.
$words = array('break', 'case', 'class', 'continue', 'default', 'do', 'elif',
'else', 'for', 'function', 'if',
'new', 'null', 'return', 'self', 'switch', 'this', 'typeof',
'var', 'void', 'while', 'with');

array_walk($words, 'onlyWholeWords');
$code = preg_replace($words, "<span style='color:blue'>$1</span>", $code);
return $code;

Additionally, I have an Edit button next to the code in the table. I use jQuery to grab text from the (hidden) code-row and place it in the form/textarea. This is easier to achieve if I've already given the td (that contains the hidden code) an id of 'bgCode1', 'bgCode2', etc. (I do this as I initially construct the table with PHP.)

// jQuery to grab the code from the table and insert it into the forms' textarea.
var code_text = $('#bgCode' + bID).text();
$('#txtCode').val(code_text); // 'txtCode' is the id of the textarea for the code

I welcome any feedback, comments or suggestions - although "I already know" that there are plug-ins, frameworks, etc., that can be used to achieve this: they are not as rewarding as doing it oneself!

09-06-2012, 02:06 AM
Unfortunately, as I've found to my annoyance, PHP prior to 5.2.4 does not support the \K lookbehind alternative :(

So I've had to revise the codeWords function to the following and drop the use of onlyWholeWords().

function codeWords($code) {
$words = array('break', 'case', 'class', 'continue', 'default', 'do', 'elif',
'else', 'for', 'function', 'if',
'new', 'null', 'return', 'self', 'switch', 'this', 'typeof',
'var', 'void', 'while', 'with');

//array_walk($words, 'onlyWholeWords');
foreach ($words as $word) {
$code = preg_replace("/\b(" . $word . ")\b/",
"<span style='color:blue'>$1</span>", $code);

return $code;
This means that I can't currently ignore keywords that appear after // comment delimiters.

If you are using PHP >= 5.2.4 then this is not an issue. I'll have to try and re-write my regex using a negative look-behind assertion in some manner. I'll update if (when!) I conquer this. Andy.

09-06-2012, 02:35 AM
So if you are unfortunate enough to be stuck with PHP < 5.2.4 :( then you can use the following to colour keywords blue, but NOT if they occur after // comment delimiters:

function onlyWholeWords(&$value, $key) {
$value = "/^((?:(?!\/\/).)*)\b" . $value . "\b/";
function addSpan(&$value, $key) {
$value = "$1<span style='color:blue'>" . $value . "</span>";
function codeWords($code) {
$words = array('break', 'case', 'class', 'continue', 'default', 'do', 'elif',
'else', 'for', 'function', 'if',
'new', 'null', 'return', 'self', 'switch', 'this', 'typeof',
'var', 'void', 'while', 'with');
$words2 = $words;

array_walk($words, 'onlyWholeWords');
array_walk($words2, 'addSpan');
$code = preg_replace($words, $words2, $code);
return $code;

09-06-2012, 03:53 AM
The attached screenshot is a more complete example. Notice that the word 'function' in 'polymorphic function' is not coloured blue as it appears within a comment, and there are different levels of indenting.