Coding Contest: Create a Programming Pearl

The other day I was solving a seemingly simple problem.  While solving the problem I came across several hiccups one could have to consider (I say could given some unique environments this problem could surface in, ie. performance a primary concern).  While working the solution to completion, I got to thinking about other ways I could solve the problem.  It got me to thinking Programming Pearls, a great book about solving problems effectively.

Now that I've "solved it" myself, I'm curious what you could, the readers of this blog could come up with and I, by extension, can learn from.

The Problem at Hand

When given some text as an input, that text could include some "bad" characters.  For example, in Microsoft Word when typing a hyphen, Word will change the hyphen to a dash, since grammatically speaking a dash is different from a hyphen and most often you, the Word user, mean to use a dash so Word puts on there for you (thumbs up on the usability aspect of this feature Microsoft).  The problem is, the dash character that Word uses is not in the ASCII character set.

With this program, we don't want to allow a certain subset of characters, and instead replace the characters with a different character. Using the Word example of a dash and a hyphen, I want to scrub uses of a dash and replace with the hyphen.

Here are some other common ones:

Character Correct ASCII Value Bad Values
Hyphen 45 8208, 8211, 8212, 8722, 173, 8209, 8259
Single Quote 39 96, 8216, 8217, 8242, 769, 768
Double Quote 34 8220, 8221, 8243, 12291
Space 32 160, 8195, 8194

What the code should do is simply take in a string, and output the string with the offending "bad" characters replaced with a specified character (using the table above).  Very simple.

I've provided the stub code here and a unit test, to provide an example, based on the table above...fill in the blank and submit!

   1: [Test]
   2: public void Input_with_bad_characters_should_be_replaced_with_approprate_character()
   3: {
   4:     var badChars = new[] {(char) 96, (char) 8216, (char) 8217, (char) 8242, (char) 769, (char) 768,
   5:         (char) 8220, (char) 8221, (char) 8243, (char) 12291,(char)8208, (char)8211, (char)8212, 
   6:         (char)8722, (char)173, (char)8209, (char)8259,(char)160, (char)8195, (char)8194};
   7:     var badString = new string(badChars);
   8:  
   9:     var cleanedString = CleanInput(badString);
  10:     
  11:     Assert.That(cleanedString, Is.EqualTo("''''''\"\"\"\"-------   "));   
  12: }
  13:  
  14: public string CleanInput(string input)
  15: {
  16:     // your details here
  17: }

The Judging

The judging of the winner will be entirely based on my discretion.  I'm looking first for correctness, that the problem is in fact solved.  After that I'm open to seeing what you can do.  The only limit is your creativity.

The Prize

I am offering up your choice of a book from Addison-Wesley or a $25 gift certificate to ThinkGeek

I am thoroughly excited to see what you can come up with....

(Please post submissions as a comment to http://gist.github.com  Leave some way for me to get in contact with you)

Updates

Update #1: Please Make All submissions from hence forth to http://gist.github.com (Thanks Tuna)

Update #2: I will stop reviewing submissions one week after post date

Update #3: Feel free to leave your comments on who you think should win and why (I still reserve the right to overrule you :-))


Posted 08-09-2009 10:14 PM by Tim Barcz
Filed under:

[Advertisement]

Comments

Jason Diamond wrote re: Coding Contest: Create a Programming Pearl
on 08-10-2009 12:44 AM

Here's the body of CleanInput:

return input.UnWordify();

For the implementation of UnWordify, see here:

jason.diamond.name/.../my-unwordify-extension-method

Greg wrote re: Coding Contest: Create a Programming Pearl
on 08-10-2009 1:12 AM

private static char[][] m_TranslationTable = new []

      {

      new char[] {(char)45, (char)8208, (char)8211, (char)8212, (char)8722, (char)173, (char)8209, (char)8259}, // Hypen

      new char[] {(char)39, (char)96, (char)8216, (char)8217, (char)8242, (char)769, (char)768}, // Single Quote

      new char[] {(char)34, (char)8220, (char)8221, (char)8243, (char)12291}, // Double Quote

new char[] {(char)32, (char)160, (char)8195, (char)8194}, // Space

      };

public static string CleanInput(string input)

{

StringBuilder outputBuilder = new StringBuilder();

foreach(char inputChar in input)

{

bool replaced = false;

for (int characterTypeIndex = 0; ((characterTypeIndex < m_TranslationTable.Length) && (!replaced)); characterTypeIndex++)

{

for (int badCharIndex = 1; ((badCharIndex < m_TranslationTable[characterTypeIndex].Length) && (!replaced)); badCharIndex++)

{

if (inputChar == m_TranslationTable[characterTypeIndex][badCharIndex])

{

outputBuilder.Append(m_TranslationTable[characterTypeIndex][0]);

replaced = true;

}

}

}

if (!replaced)

outputBuilder.Append(inputChar);

}

return outputBuilder.ToString();

}

Noam Gal wrote re: Coding Contest: Create a Programming Pearl
on 08-10-2009 3:22 AM

It looks better at http://codepaste.net/qqweuo

public string CleanInput(string input)

{

IDictionary<char, char> replaceDictionary = BuildReplaceDictionary();

char[] cleanedArray = Array.ConvertAll<char, char>(input.ToCharArray(),

                                                  delegate(char c)

                                                  {

                                                  return replaceDictionary.ContainsKey(c)

                                                        ? replaceDictionary[c] : c;

                                                  });

return new string(cleanedArray);

}

/// <summary>

/// Builds a dictionary specifying all the "bad" ascii values, mapped to the proper ones

/// </summary>

/// <returns></returns>

private static IDictionary<char, char> BuildReplaceDictionary()

{

IDictionary<char, char> replaceDictionary = new Dictionary<char, char>();

// Hyphen

replaceDictionary[(char)8208] = (char)45;

replaceDictionary[(char)8211] = (char)45;

replaceDictionary[(char)8212] = (char)45;

replaceDictionary[(char)8722] = (char)45;

replaceDictionary[(char)173] = (char)45;

replaceDictionary[(char)8209] = (char)45;

replaceDictionary[(char)8259] = (char)45;

// Single Quote

replaceDictionary[(char)96] = (char)39;

replaceDictionary[(char)8216] = (char)39;

replaceDictionary[(char)8217] = (char)39;

replaceDictionary[(char)8242] = (char)39;

replaceDictionary[(char)769] = (char)39;

replaceDictionary[(char)768] = (char)39;

// Double Quote

replaceDictionary[(char)8220] = (char)34;

replaceDictionary[(char)8221] = (char)34;

replaceDictionary[(char)8243] = (char)34;

replaceDictionary[(char)12291] = (char)34;

// Space

replaceDictionary[(char)160] = (char)32;

replaceDictionary[(char)8195] = (char)32;

replaceDictionary[(char)8194] = (char)32;

return replaceDictionary;

}

Krzysztof Kozmic wrote re: Coding Contest: Create a Programming Pearl
on 08-10-2009 4:25 AM

I don't think I'm allowed to enter the contest but what the heck ;)

kozmic.pl/.../solving-a-programming-puzzle.aspx

Rik Hemsley wrote re: Coding Contest: Create a Programming Pearl
on 08-10-2009 5:42 AM
Rik Hemsley wrote re: Coding Contest: Create a Programming Pearl
on 08-10-2009 6:49 AM

Fixed after making my own tests and seeing it needed help:

http://paste.rikkus.info/188

Paul Batum wrote re: Coding Contest: Create a Programming Pearl
on 08-10-2009 7:18 AM
Nate London wrote re: Coding Contest: Create a Programming Pearl
on 08-10-2009 9:55 AM

       public string CleanInput(string input)

       {

           string cleaned = input;

           foreach (var mappings in _badCharactersToGoodCharacter)

           {

               foreach(char bad in mappings.Key)

               {

                   if (cleaned.IndexOf(bad) >= 0)

                   {

                       cleaned = cleaned.Replace(bad, mappings.Value);

                   }

               }

           }

           return cleaned;

       }

       private static readonly KeyValuePair<char[], char>[] _badCharactersToGoodCharacter = new []

          {

              new KeyValuePair<char[], char>(new []{(char)8208, (char)8211, (char)8212, (char)8722, (char)173, (char)8209, (char)8259},(char)45),

              new KeyValuePair<char[], char>(new []{(char)96,(char)8216,(char)8217,(char)8242,(char)769,(char)768},(char)39 ),

              new KeyValuePair<char[], char>(new []{(char)8220,(char)8221,(char)8243,(char)12291},(char)34),

              new KeyValuePair<char[], char>(new []{(char)160,(char)8195,(char)8194},(char)32)

          };

Nate London wrote re: Coding Contest: Create a Programming Pearl
on 08-10-2009 10:39 AM

// another perspective for posterity

public string CleanInput(string input)

       {

           char[] cleaned = input.ToArray();

           for (int i = 0; i < cleaned.Length; i++)

           {

               char questionableCharacter = input[i];

               if(_badCharacters.Contains(questionableCharacter))

               {

                   cleaned[i] = _badToGoodMappings[questionableCharacter];

               }

           }

           return new string(cleaned);

       }

       private static readonly ReadOnlyCollection<char> _badCharacters = new List<char>()

           {

               (char)8208,(char)8211,(char)8212,(char)8722,(char)173,(char)8209,(char)8259,

               (char)96,(char)8216,(char)8217,(char)8242,(char)769,(char)768,

               (char)8220,(char)8221,(char)8243,(char)12291,

               (char)160,(char)8195,(char)8194

           }.AsReadOnly();

       private static readonly Dictionary<char, char> _badToGoodMappings = new Dictionary<char, char>()

           {

               {(char)8208, (char)45},

               {(char)8211, (char)45},

               {(char)8212, (char)45},

               {(char)8722, (char)45},

               {(char)173, (char)45},

               {(char)8209, (char)45},

               {(char)8259, (char)45},

               {(char)96, (char)39},

               {(char)8216, (char)39},

               {(char)8217, (char)39},

               {(char)8242, (char)39},

               {(char)769, (char)39},

               {(char)768, (char)39},

               {(char)8220, (char)34},

               {(char)8221, (char)34},

               {(char)8243, (char)34},

               {(char)12291, (char)34},

               {(char)160, (char)32},

               {(char)8195, (char)32},

               {(char)8194,  (char)32}                                              

           };

Charlie Solomon wrote re: Coding Contest: Create a Programming Pearl
on 08-10-2009 12:22 PM

I'd use a regular expression:

public string CleanInput(string input)

{

   // Hyphen

   input = ReplaceAsciiSet(

       input,

       new char[] { (char)8208, (char)8211, (char)8212, (char)8722, (char)173, (char)8209, (char)8259 },

       (char) 45);

   // Single Quote

   input = ReplaceAsciiSet(

       input,

       new char[] { (char)96, (char)8216, (char)8217, (char)8242, (char)769, (char)768 },

       (char)39);

   // Double Quote

   input = ReplaceAsciiSet(

       input,

       new char[] { (char)8220, (char)8221, (char)8243, (char)12291 },

       (char)34);

   // Space

   input = ReplaceAsciiSet(

       input,

       new char[] { (char)160, (char)8195, (char)8194 },

       (char)32);

   return input;

}

public string ReplaceAsciiSet(string input, char[] badChars, char goodChar)

{

   string[] badStrings = new string[badChars.Length];

   for (int i=0; i<badChars.Length; i++)

   {

       badStrings[i] = string.Format("\\{0}", badChars[i]);

   }

   Regex regex = new Regex(string.Join("|", badStrings));

   return regex.Replace(input, goodChar.ToString());

}

Contact: My name at gmail dot com

Petar Petrov wrote re: Coding Contest: Create a Programming Pearl
on 08-10-2009 12:39 PM

public string CleanInput(string input)

{

var replacements = new char[12291 + 1];

for (int i = 0; i < replacements.Length; i++)

{

replacements[i] = char.MinValue;

}

foreach (var code in new[] { 8208, 8211, 8212, 8722, 173, 8209, 8259 })

{

replacements[code] = '-';

}

foreach (var code in new[] { 96, 8216, 8217, 8242, 769, 768 })

{

replacements[code] = '\'';

}

foreach (var code in new[] { 8220, 8221, 8243, 12291 })

{

replacements[code] = '"';

}

foreach (var code in new[] { 160, 8195, 8194 })

{

replacements[code] = ' ';

}

var output = new char[input.Length];

for (int i = 0; i < input.Length; i++)

{

var symbol = input[i];

var replacement = replacements[symbol];

if (replacement == char.MinValue)

{

output[i] = symbol;

}

else

{

output[i] = replacement;

}

}

return new string(output);

}

Diego Mijelshon wrote re: Coding Contest: Create a Programming Pearl
on 08-10-2009 12:56 PM

/*

This solutions provides an easily extensible Map to define replacements.

It supports mapping a single char to a string (for "...", for example)

*/

public static string CleanInput(string input)

{

return InputExpression.Replace(input, badChar => Replacements[badChar.Value]);

}

static readonly Dictionary<string, int[]> Map = new Dictionary<string, int[]>

{

{"'", new[]{96, 8216, 8217, 8242, 769, 768}},

{"\"", new[]{8220, 8221, 8243, 12291}},

{"-", new[]{8208, 8211, 8212, 8722, 173, 8209, 8259}},

{" ", new[]{160, 8195, 8194}}

};

static readonly IDictionary<string, string> Replacements = Map

.SelectMany(kvp => kvp.Value

.Select(ch => new { BadCharString = ((char)ch).ToString(), CorrectString = kvp.Key }))

.ToDictionary(p => p.BadCharString, p => p.CorrectString);

static readonly Regex InputExpression = new Regex("[" + string.Join("", Replacements.Keys.ToArray()) + "]",

RegexOptions.Compiled);

Tuna Toksoz wrote re: Coding Contest: Create a Programming Pearl
on 08-10-2009 1:10 PM

I think it would be better if everybody used a site like

http://gist.github.com

Tim, can you add that to the end of the post?

Diego Mijelshon wrote re: Coding Contest: Create a Programming Pearl
on 08-10-2009 1:53 PM
dru wrote re: Coding Contest: Create a Programming Pearl
on 08-10-2009 6:47 PM

Ok, typography fun. Is it a hyphen? or an en-dash?

we know its not an em-dash right. ;)

-d

Aurequi wrote re: Coding Contest: Create a Programming Pearl
on 08-11-2009 11:06 AM
Rik Hemsley wrote re: Coding Contest: Create a Programming Pearl
on 08-11-2009 12:12 PM

/me votes for Diego Mijelshon

Tim Barcz wrote re: Coding Contest: Create a Programming Pearl
on 08-11-2009 12:36 PM

@Rik,

I like the idea of other users voting as well.  Again I make the ultimate decision but the votes of others could play a factor.

Anyone reading comments this far, please feel free to leave your vote if you're interested.

Joshua wrote re: Coding Contest: Create a Programming Pearl
on 08-11-2009 8:09 PM

Since no one has yet I submit a really inefficient yet simple approach

      private Dictionary<char, List<char>> mapping = new Dictionary<char, List<char>>

       {

           {'\'', new List<char>{'\x60', '\x2018', '\x2019', '\x2032', '\x301', '\x300'}},

           {'"', new List<char>{'\x201C', '\x201D', '\x2033', '\x3003'}},

           {'-', new List<char>{'\x2010', '\x2013', '\x2014', '\x2212', '\xAD', '\x2011', '\x2043'}},

           {' ', new List<char>{'\xA0', '\x2003', '\x2002'}}

       };

       //ToDo - Replace with a more efficient implementation

       //I.E. Doesn't walk the string n times and create n new strings

       public string CleanInput(string input)

       {

           foreach (var pair in mapping)

               pair.Value.ForEach(c => input = input.Replace(c, pair.Key));

           return input;

       }

dave-ilsw wrote re: Coding Contest: Create a Programming Pearl
on 08-11-2009 9:29 PM

I like the first submission (by Jason Diamond) the best. Here's my simplistic stab at it:

       static public string CleanInput(string input)

       {

           return input.Replace((char)96, '\'').Replace(

               (char)8216, '\'').Replace((char)8217, '\'').Replace(

               (char)8242, '\'').Replace((char)769, '\'').Replace(

               (char)768, '\'').Replace((char)8220, '"').Replace(

               (char)8221, '"').Replace((char)8243, '"').Replace(

               (char)12291, '"').Replace((char)8208, '-').Replace(

               (char)8211, '-').Replace((char)8212, '-').Replace(

               (char)8722, '-').Replace((char)173, '-').Replace(

               (char)8209, '-').Replace((char)8259, '-').Replace(

               (char)160, ' ').Replace((char)8195, ' ').Replace(

               (char)8194, ' '

           );

       }

RomanN wrote re: Coding Contest: Create a Programming Pearl
on 08-13-2009 7:56 AM
Fantine wrote re: Coding Contest: Create a Programming Pearl
on 10-10-2011 1:21 AM

Boom shakalaka boom boom, proeblm solved.

social bookmark links wrote re: Coding Contest: Create a Programming Pearl
on 01-17-2013 4:45 PM

Ib9fnb Major thankies for the blog post. Want more.

discount generic cialis wrote re: Coding Contest: Create a Programming Pearl
on 01-26-2013 9:12 PM

IZNvzQ A round of applause for your article post.Really thank you!

buy viagra online wrote re: Coding Contest: Create a Programming Pearl
on 02-02-2013 9:35 PM

dzpeyG I truly appreciate this post. Cool.

buy stendra wrote re: Coding Contest: Create a Programming Pearl
on 02-24-2013 3:19 AM

a292iP Awesome article post.Thanks Again. Want more.

clomid no prescription wrote re: Coding Contest: Create a Programming Pearl
on 02-27-2013 8:35 AM

5Cj2nW A round of applause for your article post.Really looking forward to read more. Will read on...

social bookmarking service wrote re: Coding Contest: Create a Programming Pearl
on 03-02-2013 9:39 AM

6yngnB Very informative post.Really thank you! Awesome.

bookmarks wrote re: Coding Contest: Create a Programming Pearl
on 03-13-2013 6:25 PM

t8Stmi I loved your post.Really looking forward to read more. Much obliged.

bookmaring service wrote re: Coding Contest: Create a Programming Pearl
on 03-15-2013 5:17 AM

FPT7rK wow, awesome article post.Really thank you! Awesome.

buy social bookmarks wrote re: Coding Contest: Create a Programming Pearl
on 03-24-2013 7:11 PM

iI1pzQ I really like and appreciate your post.Really thank you! Want more.

stoners wrote re: Coding Contest: Create a Programming Pearl
on 04-06-2013 2:10 AM

Im obliged for the blog. Really Great.

camera buying guide wrote re: Coding Contest: Create a Programming Pearl
on 05-14-2013 5:04 AM

rVnraq Really informative blog article.Much thanks again. Really Cool.

super news that are fun wrote re: Coding Contest: Create a Programming Pearl
on 08-04-2013 9:18 PM

FYHOlO Really informative article. Awesome.

check out these guys! wrote re: Coding Contest: Create a Programming Pearl
on 10-16-2013 12:41 PM

M66kNZ Hey, thanks for the post. Awesome.

link building wrote re: Coding Contest: Create a Programming Pearl
on 10-23-2013 8:27 PM

AjKhFT Major thankies for the blog. Fantastic.

crorkservice wrote re: Coding Contest: Create a Programming Pearl
on 07-18-2014 5:36 AM

iw542i I really like and appreciate your post.Thanks Again.

horny wrote re: Coding Contest: Create a Programming Pearl
on 07-21-2014 6:58 AM

Add a Comment

(required)  
(optional)
(required)  
Remember Me?

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)