Peter
Peter

Reputation: 447

How to highlight a specific word in C#?

I have a form that pop ups for users to leave comments on videos. Inside the form where people enter the message there is a profanity filter in place. It works fine and catches the word if it is in the message. My question is if there is a way to highlight the word that is caught so the user can see which one was considered profane?

Here is the message being formed and going through the filter:

    if (context.Request["postform"] == "1")
    {
        ProfanityFilter filter = new ProfanityFilter();

        // IF NEITHER THE MESSAGE OR FIRSTNAME CONTAINS ANY PROFANITY IN THEM
        if (filter.containsProfanity(context.Request["message"]) == false && filter.containsProfanity(context.Request["first_name_submitter"]) == false)
        {
            videomessage myVideoMessage = new videomessage();

            myVideoMessage.video_id = context.Request["video_id"];
            myVideoMessage.first_name_submitter = context.Request["first_name_submitter"];
            myVideoMessage.last_initial_submitter = context.Request["last_initial_submitter"];
            myVideoMessage.message = context.Request["message"];
            myVideoMessage.status = "0";

            myVideoMessage.Save();

            return_success = "1";                
        }
        else
        {
            return_success = "0";
            return_errormessage = "<span>Contains profanity</span>";
        }                
    }

And here is the ProfanityFilter class:

public class ProfanityFilter
{
    // ***********************************************************************
    // CONSTRUCTORS
    public ProfanityFilter()
    {
    }
    // ***********************************************************************



    // ************************************************************************
    // METHOD: containsProfanity
    public bool containsProfanity(string checkStr)
    {
        bool badwordpresent = false;

        string[] inStrArray = checkStr.Split(new char[] { ' ' });

        string[] words = this.profanityArray();

        // LOOP THROUGH WORDS IN MESSAGE
        for (int x = 0; x < inStrArray.Length; x++)
        {
            // LOOP THROUGH PROFANITY WORDS
            for (int i = 0; i < words.Length; i++)
            {
                // IF WORD IS PROFANITY, SET FLAG AND BREAK OUT OF LOOP
                //if (inStrArray[x].toString().toLowerCase().equals(words[i]))
                if( inStrArray[x].ToLower() == words[i].ToLower() )
                {
                    badwordpresent = true;
                    break;
                }
            }
            // IF FLAG IS SET, BREAK OUT OF OUTER LOOP
            if (badwordpresent == true) break;
        }

        return badwordpresent;
    }
    // ************************************************************************




    // ************************************************************************
    // METHOD: profanityArray()
    // METHOD OF PROFANITY WORDS
    private string[] profanityArray()
    {

        string[] words = { // ARRAY OF WORDS };
return words;
}
}

Is there a way to add something in the else to highlight the word? Or even just change its color from black to red?

Thank you in advance!

Upvotes: 2

Views: 1348

Answers (3)

Eric J.
Eric J.

Reputation: 150108

The most straightforward way to do it is to replace all occurrances of profane words with markup representing that word, e.g.

<span class="profane">PUT_THE_WORD_HERE</span>

In your css, include a rule

span.profane

that provides some sort of visual indication.

Since you should strive for a separation of concerns, I would not do this markup in ProfanityFilter itself. A slick way to do this would be to have ProfanityFilter provide an event for each string fragment it processes. That callback would provide an indicator as to whether the word is deemed profane or not, and the fragment itself. In the event handler, you would reconstruct the original phrase by appending each event's fragment, surrounding it with markup if it is profane. That event would also have to receive whitespace and punctuation so that the full original phrase can be re-created.

Phrase:

"This website sucks.  Really!"

Events:

"This", profane: false
" ", profane: false
"website", profane: false
" ", profane: false
"sucks", profane: true
".  ", profane: false
"Really", profane: false
"!", profane: false

If you don't want to get that elaborate, the ProfanityFilter could return a list of profane words it found, and you could do a global search and replace on the original phrase.

Replace:

public bool containsProfanity(string checkStr)

with

public class ProfanityResult
{
    public bool Profane { get; set; }
    public List<string> ProfanityWords { get; set; }
}


public ProfanityResult containsProfanity(string checkStr)

UPDATE

Assuming you go with the second option, you would do something like:

string markedMessage = context.Request["message"];
if (result.Profane)
{
    foreach (string word in result.ProfanityWords)
    {
        markedMessage = markedMessage.Replace(
                           word, 
                           "<span class=\""profane\"">" + word + "</span>");
    }    
}

This approach isn't terribly efficient as it creates a new copy of the string for each replacement, but if you're taking about a brief comment or post, you will not notice the inefficiency.

Upvotes: 8

Luke Hutton
Luke Hutton

Reputation: 10722

With a small amount of refactoring, you can achieve this, but I would go with a better refactoring as in Eric J's post:

public class ProfanityFilter
{

  public bool containsProfanity(string checkStr, ref List<string> badWords)
  {
    // ...
    if (String.Compare(inStrArray[x], words[i], StringComparison.OrdinalIgnoreCase) == 0)
    {
      badwordpresent = true;
      badWords.Add(inStrArrary[x]);         
    }
    // ...
  }
}

Instead of the else block dealing with the profanity, deal with the message and first_name_submitter first and break out of the method if profanity is found.

List<string> badWords = new List<string>();
if (filter.containsProfanity(context.Request["message"], ref badWords))
{
   return_errormessage = string.Format("<span style=\"color:red\">Message contains the following bad word(s): {0}</span>", 
                          HttpUtility.HtmlEncode(String.Join(" ", badWords.ToArray()));
   return_success = "0";
   return; // break out of method
}

// save video message

return_success = "1"; 

Upvotes: 1

001
001

Reputation: 13533

You could do something like this:

public string containsProfanity(string checkStr)
{
    // .....
    bool badwordpresent = false;

    // LOOP THROUGH WORDS IN MESSAGE
    for (int x = 0; x < inStrArray.Length; x++)
    {
        // LOOP THROUGH PROFANITY WORDS
        for (int i = 0; i < words.Length; i++)
        {
            if( inStrArray[x].ToLower() == words[i].ToLower() )
            {
                inStrArray[x] = "<span class=\"profane\">" + inStrArray[x] + "</span>";
                badwordpresent = true;
                break;
            }
        }
        // if (badwordpresent == true) break; <- removed
    }

    return badwordpresent ? String.join(" ", inStrArray) : null;
}

EDIT: returns null if no bad words found.

Upvotes: 3

Related Questions