Click here to Skip to main content
15,891,136 members
Articles / Programming Languages / C#

Convert HTML to Plain Text

Rate me:
Please Sign up or sign in to vote.
4.89/5 (49 votes)
6 Oct 2005CPOL2 min read 525.3K   67   109   67
Strip out HTML tags while preserving the basic formatting

Introduction

This article provides the procedure for stripping out HTML tags while preserving most basic formatting. In other words, it converts HTML to plain text.

Background

This example heavily relies on regular expressions, in particular System.Text.RegularExpressions.Regex.Replace() method. You may also find this reference on regular expressions syntax useful.

Using the Code

The code uses System.Text.RegularExpressions namespace and consists of a single function, StripHTML().

First, the development formatting is removed such as tabs used for step-identations and repeated whitespaces. As a result, the input HTML is "flattened" into one continuous string. This serves two reasons:

  1. To remove the formatting ignored by browsers
  2. To make the regexes work reliably (they seem to get confused by escape characters)

Then the header is removed by removing anything between <head> and </head> tags.

Then, all scripts are removed by chopping out anything between <script> and </script> tags inclusive. Similarly with styles.

Then the basic formatting tags, such as <BR> and <DIV> are replaced with \r or \r\r. Also <TR> tags are replaced by line breaks and <TD>s by tabs.

<LI>s are replaced by *s and special characters such as are replaced with their corresponding values.

Finally all the remaining tags are replaced with empty strings.

By this stage, there are likely to be a lot of redundant repeating line breaks and tabs. Any sequence over 2 line breaks long is replaced by two line breaks. Similarly with tabs: sequences over 4 tabs long are replaced by 4 tabs.

C#
private string StripHTML(string source)
{
    try
    {
        string result;

        // Remove HTML Development formatting
        // Replace line breaks with space
        // because browsers inserts space
        result = source.Replace("\r", " ");
        // Replace line breaks with space
        // because browsers inserts space
        result = result.Replace("\n", " ");
        // Remove step-formatting
        result = result.Replace("\t", string.Empty);
        // Remove repeating spaces because browsers ignore them
        result = System.Text.RegularExpressions.Regex.Replace(result,
                                                              @"( )+", " ");

        // Remove the header (prepare first by clearing attributes)
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 @"<( )*head([^>])*>","<head>",
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 @"(<( )*(/)( )*head( )*>)","</head>",
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 "(<head>).*(</head>)",string.Empty,
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);

        // remove all scripts (prepare first by clearing attributes)
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 @"<( )*script([^>])*>","<script>",
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 @"(<( )*(/)( )*script( )*>)","</script>",
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);
        //result = System.Text.RegularExpressions.Regex.Replace(result,
        //         @"(<script>)([^(<script>\.</script>)])*(</script>)",
        //         string.Empty,
        //         System.Text.RegularExpressions.RegexOptions.IgnoreCase);
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 @"(<script>).*(</script>)",string.Empty,
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);

        // remove all styles (prepare first by clearing attributes)
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 @"<( )*style([^>])*>","<style>",
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 @"(<( )*(/)( )*style( )*>)","</style>",
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 "(<style>).*(</style>)",string.Empty,
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);

        // insert tabs in spaces of <td> tags
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 @"<( )*td([^>])*>","\t",
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);

        // insert line breaks in places of <BR> and <LI> tags
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 @"<( )*br( )*>","\r",
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 @"<( )*li( )*>","\r",
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);

        // insert line paragraphs (double line breaks) in place
        // if <P>, <DIV> and <TR> tags
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 @"<( )*div([^>])*>","\r\r",
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 @"<( )*tr([^>])*>","\r\r",
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 @"<( )*p([^>])*>","\r\r",
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);

        // Remove remaining tags like <a>, links, images,
        // comments etc - anything that's enclosed inside < >
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 @"<[^>]*>",string.Empty,
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);

        // replace special characters:
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 @" "," ",
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);

        result = System.Text.RegularExpressions.Regex.Replace(result,
                 @"&bull;"," * ",
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 @"&lsaquo;","<",
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 @"&rsaquo;",">",
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 @"&trade;","(tm)",
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 @"&frasl;","/",
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 @"&lt;","<",
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 @"&gt;",">",
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 @"&copy;","(c)",
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 @"&reg;","(r)",
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);
        // Remove all others. More can be added, see
        // http://hotwired.lycos.com/webmonkey/reference/special_characters/
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 @"&(.{2,6});", string.Empty,
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);

        // for testing
        //System.Text.RegularExpressions.Regex.Replace(result,
        //       this.txtRegex.Text,string.Empty,
        //       System.Text.RegularExpressions.RegexOptions.IgnoreCase);

        // make line breaking consistent
        result = result.Replace("\n", "\r");

        // Remove extra line breaks and tabs:
        // replace over 2 breaks with 2 and over 4 tabs with 4.
        // Prepare first to remove any whitespaces in between
        // the escaped characters and remove redundant tabs in between line breaks
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 "(\r)( )+(\r)","\r\r",
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 "(\t)( )+(\t)","\t\t",
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 "(\t)( )+(\r)","\t\r",
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 "(\r)( )+(\t)","\r\t",
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);
        // Remove redundant tabs
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 "(\r)(\t)+(\r)","\r\r",
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);
        // Remove multiple tabs following a line break with just one tab
        result = System.Text.RegularExpressions.Regex.Replace(result,
                 "(\r)(\t)+","\r\t",
                 System.Text.RegularExpressions.RegexOptions.IgnoreCase);
        // Initial replacement target string for line breaks
        string breaks = "\r\r\r";
        // Initial replacement target string for tabs
        string tabs = "\t\t\t\t\t";
        for (int index=0; index<result.Length; index++)
        {
            result = result.Replace(breaks, "\r\r");
            result = result.Replace(tabs, "\t\t\t\t");
            breaks = breaks + "\r";
            tabs = tabs + "\t";
        }

        // That's it.
        return result;
    }
    catch
    {
        MessageBox.Show("Error");
        return source;
    }
}

Points of Interest

Escape characters such as \n and \r had to be removed first because they cause regexes to cease working as expected.

Moreover, to make the result string display correctly in the textbox, one might need to split it up and set textbox's Lines property instead of assigning to Text property.

C#
this.txtResult.Lines =
      StripHTML(this.txtSource.Text).Split("\r".ToCharArray());

History

  • 6th October, 2005: 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
Australia Australia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
AnswerRe: Same as HtmlUtility.HtmlDecode(string) ? Pin
paceman7-Jan-07 13:49
paceman7-Jan-07 13:49 
GeneralRe: Same as HtmlUtility.HtmlDecode(string) ? Pin
paceman7-Jan-07 13:52
paceman7-Jan-07 13:52 
Generalthanx a lot Pin
FREVDS12-Aug-06 15:21
FREVDS12-Aug-06 15:21 
GeneralRegExp Error : Pin
ziliz21-Feb-06 13:56
ziliz21-Feb-06 13:56 
Generalmethod in vb.net Pin
joshuamorgan23-Oct-05 13:56
joshuamorgan23-Oct-05 13:56 
GeneralRe: method in vb.net Pin
Todd Davis6-Nov-05 4:33
Todd Davis6-Nov-05 4:33 
GeneralRe: method in vb.net Pin
aerodave16-Dec-05 5:56
aerodave16-Dec-05 5:56 
GeneralRe: method in vb.net Pin
jokva25-May-06 3:34
jokva25-May-06 3:34 
This may be a little late, but I thought I should comment. First, to do this in VB, you can pretty much cut and paste the code paceman has supplied in his excellent article. Only a few minor changes are required:

quick and dirty (untested), I would suggest to change only the parts:

<br />
'Remove HTML Development formatting<br />
            result = source.Replace(vbCr, " ")<br />
            result = source.Replace(vbLf, " ")<br />
            result = source.Replace(vbTab, " ")<br />
            result = Regex.Replace(result, "( )+", " ") 'Remove repeating spaces because browsers ignore them<br />
...<br />
<br />
            'insert tabs in spaces of <td> tags<br />
            result = Regex.Replace(result, "<( )*td([^>])*>", vbTab, RegexOptions.IgnoreCase)<br />
<br />
            'insert line breaks in places of <BR> and <LI> tags<br />
            result = Regex.Replace(result, "<( )*br( )*>", vbCr, RegexOptions.IgnoreCase)<br />
            result = Regex.Replace(result, "<( )*li( )*>", vbCr, RegexOptions.IgnoreCase)<br />
<br />
            'insert line paragraphs (double line breaks) in place if <P>, <DIV> and <TR> tags<br />
            result = Regex.Replace(result, "<( )*div([^>])*>", vbCr + vbCr, RegexOptions.IgnoreCase)<br />
            result = Regex.Replace(result, "<( )*tr([^>])*>", vbCr + vbCr, RegexOptions.IgnoreCase)<br />
            result = Regex.Replace(result, "<( )*p([^>])*>", vbCr + vbCr, RegexOptions.IgnoreCase)<br />
.....<br />


that should take care of conversion to VB of the first part.

Then Paceman adds a For Next loop to clean up what now would be the surplus VbCr's in Vb. If you are going through all the trouble of learning/using regex to do your text handling, it is a real shame to resort to For-Nexts to handle something as trivial. Perhaps I am missing something, but I don't see why he is doing that. But if you have the computing power to waste, go ahead.

In my humble opinion, it would probably be better to just stick with the regex logic and convert all breaks to VbCr; remove duplicate VbCr's, and remove double white spaces.

<br />
'make line breaking consistent<br />
result = result.Replace(vbCrLf, vbCr) 'worth remembering this little guy, too.<br />
result = result.Replace(vbLf, vbCr)<br />
'remove all breaks<br />
result = Regex.Replace(result, vbCr, " ")<br />
'remove double breaks<br />
'result = Regex.Replace(result, vbCr + vbCr, vbCr)<br />
result = Regex.Replace(result, vbTab, " ")<br />
'remove double tabs<br />
'result = Regex.Replace(result, vbTab + vbTab, vbTab)<br />
'remove double-spaces<br />
result = Regex.Replace(result, "(\s\s)", " ")<br />
Return result<br />


Of course, you need to decide how much formatting you are going to leave (hence the comments - play around with that). Good luck!


Jokva
GeneralRe: method in vb.net Pin
paceman5-Feb-07 0:07
paceman5-Feb-07 0:07 

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.