Click here to Skip to main content
15,881,855 members
Articles / Programming Languages / C#
Article

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

Rate me:
Please Sign up or sign in to vote.
4.43/5 (37 votes)
3 Aug 2006CPOL5 min read 416.4K   10.1K   123   21
Automatically colour the text/syntax of string submitted to a RichTextBox, by parsing the Rich Text Format
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?! :)

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:

C#
//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:

C#
/*
 * 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)


Written By
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

 
QuestionA Little Bit of Missing Information Pin
abbefus1-Apr-15 7:39
abbefus1-Apr-15 7:39 
GeneralMy vote of 5 Pin
avisatna3-Aug-13 1:29
avisatna3-Aug-13 1:29 
GeneralHere is an adaptation to format chemical formulas Pin
pierre poliakoff12-Oct-10 11:45
pierre poliakoff12-Oct-10 11:45 
GeneralMy vote of 3 Pin
syscom028626-Aug-10 0:57
syscom028626-Aug-10 0:57 
GeneralSlow performance Pin
Michael Demeersseman25-May-10 23:09
Michael Demeersseman25-May-10 23:09 
GeneralRe: Slow performance Pin
LuissRicardo4-Aug-10 5:43
LuissRicardo4-Aug-10 5:43 
GeneralRe: Slow performance Pin
Michael Demeersseman6-Aug-10 5:56
Michael Demeersseman6-Aug-10 5:56 
GeneralRe: Slow performance Pin
kiquenet.com11-Jan-11 7:51
professionalkiquenet.com11-Jan-11 7:51 
GeneralHelp with formatting richtextbox Pin
HamorMiklos18-Jan-10 21:27
HamorMiklos18-Jan-10 21:27 
GeneralThanks. Pin
superman0125-Nov-09 11:53
superman0125-Nov-09 11:53 
Generalbet it works great Pin
tstivers19907-Aug-09 13:58
tstivers19907-Aug-09 13:58 
GeneralRe: bet it works great Pin
johannesnestler17-May-10 1:59
johannesnestler17-May-10 1:59 
of course - your code is wrong - store the result of Insert() in a string then asign it to textbox.Rtf
Rose | [Rose]
P.S. If my code doesn't work I too first blame Microsoft... D'Oh! | :doh:
GeneralRe: bet it works great Pin
Bib3469024-Nov-11 5:44
Bib3469024-Nov-11 5:44 
GeneralPerformance is great Pin
JoseMenendez5-Jan-09 14:35
JoseMenendez5-Jan-09 14:35 
GeneralSave to image/bitmap Pin
fuzzek3-Sep-08 1:48
fuzzek3-Sep-08 1:48 
GeneralRe: Save to image/bitmap Pin
madooo1220-Aug-09 6:23
madooo1220-Aug-09 6:23 
GeneralThank you Pin
LPlateDeveloper13-Jul-08 23:13
LPlateDeveloper13-Jul-08 23:13 
QuestionRealtime coloring? Pin
simplicitylabs28-May-07 20:14
simplicitylabs28-May-07 20:14 
GeneralAlternative Pin
madagaga20-Apr-07 3:31
madagaga20-Apr-07 3:31 
GeneralRe: Alternative Pin
Alun Evans20-Apr-07 4:16
Alun Evans20-Apr-07 4:16 
Generalthank you! Pin
giddy_guitarist13-Dec-06 5:06
giddy_guitarist13-Dec-06 5:06 

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

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