Click here to Skip to main content
Click here to Skip to main content

C# - Formatting Text in a RichTextBox by Parsing the Rich Text Format (RTF)

By , 3 Aug 2006
Rate this:
Please Sign up or sign in to vote.
Sample Image - RTFSyntaxColour.jpg

Introduction

This article describes the methodology and presents sample code that shows the basics of parsing the Rich Text Format to automatically add colour to text/syntax displayed in a standard RichTextBox control.

Background

Recently, I have been working with C# and AIML and I thought I'd write a program that allows easy editing and fast creation of multiple tags within the files. While writing this, I thought it would be nice to be able to automatically add colour to the AIML tags when the file is displayed in a RichTextBox so that the structure of the syntax is clearer. There are a few existing articles on the subject, both for C# and VB (see here and here), but they don't go into detail about the methodology used to automatically colour the text.

Overview

There are two basic methods of changing the colour of specific text within a RichTextBox:

  1. Use RichTextBox.Find() and RichTextBox.Select() to highlight individual characters/string within the RichTextBox, and set the colour individually for each char/string found.
  2. Grab the Rich Text Format (RTF) using RichTextBox.RTF, and modify directly.

While method 1 is suitable for when a user edits a file, it is far faster and more of a complete solution to use option 2 and alter the native RTF. It does require learning a little bit about RTF - but learning new stuff is what it's all about, right?! Smile | :)

Rich Text Format

Details on RTF can be found here. The way colour works in RTF is that a colour table is defined in the RTF header, and any changes of colour in the text are referenced by the index of a defined colour in the colour table. For example, the colour table for a simple Rich Text File with three colours (Red, Green and Blue) would look like this:

{\colortbl;\red255\green0\blue0;\red0\green255\blue0;\red0\green0\blue255;}

The colour table is flagged by the \colortbl; tag, and all the colours used in the file are defined by RGB combinations; colours are separated by a semi colon.

The colour of the text in the bulk of the file is changed using the \cf# tag, where # is the index of the colour in the table. For example, using the colour table defined above, \cf1 references red, \cf2 green and \cf3 blue. \cf0 is unalterable and by default references 'automatic', which is usually black.

Parsing the RTF

The simplest way of generating the RTF used to display text in a RichTextBox is simply to use RichTextBox.RTF, which returns a string containing the RTF. The first thing we need to do with this string is to search it to find the RTF header, and add a colour table. The RTF header is present right at the start of any RTF data and is used to store, among other things, information regarding the correct formatting of the text. A simple RTF header generated by a RichTextBox looks a little like this:

{
\rtf1\ansi\ansicpg1252\deff0\deflang1033
{\fonttbl{\f0\fnil\fcharset0 Courier New;}}
}

To add a colour table, we have to do a series of string.IndexOf() function calls:

//Get RTF from richtextbox
string strRTF = richTextBox1.RTF;

// Search for colour table info. If it exists (it shouldn't,
// but we'll check anyway) remove it and replace with our one
int iCTableStart = strRTF.IndexOf("colortbl;");

if (iCTableStart != -1) //then colortbl exists
{
    //find end of colortbl tab by searching
    //forward from the colortbl tab itself
    int iCTableEnd = strRTF.IndexOf('}', iCTableStart);

    //remove the existing colour table
    strRTF = strRTF.Remove(iCTableStart, iCTableEnd - iCTableStart);

    //now insert new colour table at index of old colortbl tag
    strRTF = strRTF.Insert(iCTableStart,
    // CHANGE THIS STRING TO ALTER COLOUR TABLE
    "colortbl;\\red255\\green0\\blue0;\\red0\\green128\\blue0;
        red0\\green0\\blue255;}");
}

//colour table doesn't exist yet, so let's make one
else 
{
    // find index of start of header
    int iRTFLoc = strRTF.IndexOf("\\rtf");
    // get index of where we'll insert the colour table
    // try finding opening bracket of first property of header first                
    int iInsertLoc = strRTF.IndexOf('{', iRTFLoc);

    // if there is no property, we'll insert colour table
    // just before the end bracket of the header
    if (iInsertLoc == -1) iInsertLoc = strRTF.IndexOf('}', iRTFLoc) - 1;

    // insert the colour table at our chosen location                
    strRTF = strRTF.Insert(iInsertLoc,
        // CHANGE THIS STRING TO ALTER COLOUR TABLE
        "{\\colortbl ;\\red128\\green0\\blue0;\\red0\\green128\\blue0;
                d0\\green0\\blue255;}");
}

Let's quickly analyse this code segment. The first thing we do is to check whether a colour table already exists with the RTF, by searching for the colortbl tag. If it exists, we merely snip out the colour table (by removing everything from the tag to the first closing bracket character - '}' - that we find) and replace it with our own. If the colour table doesn't exist, we need to insert it in the right place. This is done by first finding the location of start of the header (the rtf tag). From this index in the RTF string, we either insert our new colour table before the opening bracket of the first header table (e.g. a fonttbl as above), or just before the closing bracket of the header, if no other table exists. This method guarantees that our colour table will be written in the correct place in the header.

All that remains for us to do now is to parse the rest of RTF string, and adding \cf before any text we'd like to display in a different colour. For example, using our colour table above, if we want to ensure that every '<' is blue in colour, and all text after it is red in colour, we could use the code shown below:

/*
 * In our colour table we defined:
 * cf1 = red  
 * cf2 = green
 * cf3 = blue             
 * (cf0 = automatic by default)
 * */
//Parse the string
for (int i = 0; i < strRTF.Length; i++)
{
    //check for correct character
    if (strRTF[i] == '<')
    {
        //add RTF tags after symbol 
        strRTF = strRTF.Insert(i + 1, "\\cf1 ");
        //add RTF before symbol
        strRTF = strRTF.Insert(i, "\\cf3 ");
        //skip forward past the characters we've just added
        //to avoid getting trapped in the loop
        i += 6;
    }
}

This is probably not the most efficient or fastest method of parsing a string and inserting characters, but it will do for the time being. Note the order of adding the RTF tags, and the fact that the iterator index is incremented after tag addition, to make sure we don't get stuck adding tags at the same location infinitely.

In the sample code, I have catered to a couple of other characters so that an AIML file (a sample of which is included in the sample program) is presented as coloured text.

Summary and Further Work

This article has shown you how it is possible to directly access the RTF of a standard RichTextBox control, and modify it so that the characters in the RichTextBox are displayed with different default colours. From this, it shouldn't be too difficult to wade into the RTF format specification (linked to above) and work out how to add all sorts of other default formatting to text, e.g. bold and italics.

History

  • 3rd August, 2006: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Alun Evans
Web Developer
United Kingdom United Kingdom
Alun has a PhD in Medical Image Processing and is currently working on using 3D graphics for interactive media.

Comments and Discussions

 
GeneralMy vote of 5 Pinmemberavisatna3-Aug-13 1:29 
GeneralHere is an adaptation to format chemical formulas Pinmemberpierre poliakoff12-Oct-10 11:45 
GeneralMy vote of 3 Pinmembersyscom028626-Aug-10 0:57 
GeneralSlow performance PinmemberMichael Demeersseman25-May-10 23:09 
GeneralRe: Slow performance PinmemberLuissRicardo4-Aug-10 5:43 
GeneralRe: Slow performance PinmemberMichael Demeersseman6-Aug-10 5:56 
GeneralRe: Slow performance Pinmemberalhambra-eidos11-Jan-11 7:51 
GeneralHelp with formatting richtextbox PinmemberHamorMiklos18-Jan-10 21:27 
GeneralThanks. Pinmembersuperman0125-Nov-09 11:53 
Generalbet it works great Pinmembertstivers19907-Aug-09 13:58 
GeneralRe: bet it works great Pinmemberjohannesnestler17-May-10 1:59 
GeneralRe: bet it works great PinmemberBib3469024-Nov-11 5:44 
GeneralPerformance is great PinmemberJose M. Menendez Poó5-Jan-09 14:35 
GeneralSave to image/bitmap Pinmemberfuzzek3-Sep-08 1:48 
GeneralRe: Save to image/bitmap Pinmembermadooo1220-Aug-09 6:23 
GeneralThank you PinmemberLPlateDeveloper13-Jul-08 23:13 
QuestionRealtime coloring? Pinmembersimplicitylabs28-May-07 20:14 
GeneralAlternative Pinmembermadagaga20-Apr-07 3:31 
GeneralRe: Alternative PinmemberAlun Evans20-Apr-07 4:16 
Generalthank you! Pinmembergiddy_guitarist13-Dec-06 5:06 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140415.2 | Last Updated 3 Aug 2006
Article Copyright 2006 by Alun Evans
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid