Reputation: 447
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
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
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
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