8

I have HTML string with the JavaScript and CSS code blocks:

<script type="text/javascript">

  alert('hello world');

</script>

<style type="text/css">
  A:link {text-decoration: none}
  A:visited {text-decoration: none}
  A:active {text-decoration: none}
  A:hover {text-decoration: underline; color: red;}
</style>

How to strip those blocks? Any suggestion about the regular expressions that can be used to remove those?

5 Answers 5

20

The quick 'n' dirty method would be a regex like this:

var regex = new Regex(
   "(\\<script(.+?)\\</script\\>)|(\\<style(.+?)\\</style\\>)", 
   RegexOptions.Singleline | RegexOptions.IgnoreCase
);

string ouput = regex.Replace(input, "");

The better* (but possibly slower) option would be to use HtmlAgilityPack:

HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(htmlInput);

var nodes = doc.DocumentNode.SelectNodes("//script|//style");

foreach (var node in nodes)
    node.ParentNode.RemoveChild(node);

string htmlOutput = doc.DocumentNode.OuterHtml;

*) For a discussion about why it's better, see this thread.

Sign up to request clarification or add additional context in comments.

4 Comments

Do you know Tony The Pony?
@GvS: I know about the problems that can arise when you are using regular expressions to process HTML. So for most cases I would strongly recommend an html parser like HtmlAgilityPack, but it depends on the situation. If it is a one-time batch to remove scripts and style blocks, and I know that the input is valid html, then my regex above can be sufficient, especially since <script> tags and <style> tags can't have nested tags.
@GvS: I added an example that uses HtmlAgilityPack.
Be careful of inline scripts also? E.g. <body onload ="doSomething()">? Need to have a far more sophisticated tools to get rid of that.
2

Use HTMLAgilityPack for better results

or try this function

public string RemoveScriptAndStyle(string HTML)
{
    string Pat = "<(script|style)\\b[^>]*?>.*?</\\1>";
    return Regex.Replace(HTML, Pat, "", RegexOptions.IgnoreCase | RegexOptions.Singleline);
}

Comments

1

Just look for an opening <script tag, and then remove everything between it and the closing /script> tag.

Likewise for the style. See Google for string manipulation tips.

2 Comments

doesn't work if your code has document.write("</script>") in it
is it sufficient to just do this in security sense? (prevent javascript from executing)?
1

I made my bike) He may not be as correct as HtmlAgilityPack but it is much faster by about 5-6 times on a page in the 400 kb. Also make symbols lowercase and remove digits(made for tokenizer)

 private static readonly List<byte[]> SPECIAL_TAGS = new List<byte[]>
                                                            {
                                                                Encoding.ASCII.GetBytes("script"),
                                                                Encoding.ASCII.GetBytes("style"),
                                                                Encoding.ASCII.GetBytes("noscript")
                                                            };

    private static readonly List<byte[]> SPECIAL_TAGS_CLOSE = new List<byte[]>
                                                                  {
                                                                      Encoding.ASCII.GetBytes("/script"),
                                                                      Encoding.ASCII.GetBytes("/style"),
                                                                      Encoding.ASCII.GetBytes("/noscript")};

public static string StripTagsCharArray(string source, bool toLowerCase)
    {
        var array = new char[source.Length];
        var arrayIndex = 0;
        var inside = false;
        var haveSpecialTags = false;
        var compareIndex = -1;
        var singleQouteMode = false;
        var doubleQouteMode = false;
        var matchMemory = SetDefaultMemory(SPECIAL_TAGS);
        for (int i = 0; i < source.Length; i++)
        {
            var let = source[i];
            if (inside && !singleQouteMode && !doubleQouteMode)
            {
                compareIndex++;
                if (haveSpecialTags)
                {
                    var endTag = CheckSpecialTags(let, compareIndex, SPECIAL_TAGS_CLOSE, ref matchMemory);
                    if (endTag) haveSpecialTags = false;
                }
                if (!haveSpecialTags)
                {
                    haveSpecialTags = CheckSpecialTags(let, compareIndex, SPECIAL_TAGS, ref matchMemory);
                }
            }
            if (haveSpecialTags && let == '"')
            {
                doubleQouteMode = !doubleQouteMode;
            }
            if (haveSpecialTags && let == '\'')
            {
                singleQouteMode = !singleQouteMode;
            }
            if (let == '<')
            {
                matchMemory = SetDefaultMemory(SPECIAL_TAGS);
                compareIndex = -1;
                inside = true;
                continue;
            }
            if (let == '>')
            {
                inside = false;
                continue;
            }
            if (inside) continue;
            if (char.IsDigit(let)) continue; 
            if (haveSpecialTags) continue;
            array[arrayIndex] = toLowerCase ? Char.ToLowerInvariant(let) : let;
            arrayIndex++;
        }
        return new string(array, 0, arrayIndex);
    }

    private static bool[] SetDefaultMemory(List<byte[]> specialTags)
    {
        var memory = new bool[specialTags.Count];
        for (int i = 0; i < memory.Length; i++)
        {
            memory[i] = true;
        }
        return memory;
    }

Comments

1

Similar to Elian Ebbing's answer and Rajeev's answer, I opted for the more stable solution of using an HTML library, not regular expressions. But instead of using HtmlAgilityPack I used AngleSharp, which gave me jquery-like selectors, in .NET Core 3:

//using AngleSharp;
var context = BrowsingContext.New(Configuration.Default);
var document = await context.OpenAsync(req => req.Content(sourceHtml)); // generate HTML DOM from source html string
var elems = document.QuerySelectorAll("script, style"); // get script and style elements
foreach(var elem in elems)
{
    var parent = elem.Parent;
    parent.RemoveChild(elem); // remove element from DOM
}
var resultHtml = document.DocumentElement.OuterHtml; // HTML result as a string

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.