4
\$\begingroup\$

Does anyone know of a better / cleaner way to write the following:

GetSafeTagName(txtUserInput.text);

public static string GetSafeTagName(string tag)
{
    tag = tag.ToUpper()
    .Replace("'","`")
    .Replace('"','`')
    .Replace("&", "and")
    .Replace(",",":")
    .Replace(@"\","/"); //Do not allow escaped characters from user
    tag = Regex.Replace(tag, @"\s+", " "); //multiple spaces with single spaces
    return tag;
}

Thanks!

\$\endgroup\$
3
  • \$\begingroup\$ wow, I didn't even know that site existed, I will ask over there thanks! \$\endgroup\$
    – ToddBFisher
    Nov 9, 2011 at 17:48
  • \$\begingroup\$ Here is a SO question where the answer recommends using a StringBuilder. \$\endgroup\$
    – user786653
    Nov 9, 2011 at 18:54
  • \$\begingroup\$ I once read an article by Jesse Liberty that said the decent support structure actually slowed the code down........ \$\endgroup\$
    – user15144
    Jul 23, 2012 at 15:41

3 Answers 3

4
\$\begingroup\$

You could use a regular expression and Dictionary<string, string> to do the search replace:

// This regex matches either one of the special characters, or a sequence of 
// more than one whitespace characters.
Regex regex = new Regex("['\"&,\\\\]|\\s{2,}");

var map = new Dictionary<string, string> {
    { "'", "`"},
    { "\"", "`"},
    { "&", "and" },
    { ",", ":" },
    { "\\", "/" }
};

// If the length of the match is greater that 1, then it's a sequence
// of spaces, and we can replace it by a single space. Otherwise, we
// use the dictionary to map the character.
string output = regex.Replace(input.ToUpper(), 
    m => m.Value.Length > 1 ? " " : map[m.Value]);
\$\endgroup\$
1
  • \$\begingroup\$ As elegant as it may seem, sadly this alternative is 3 times slower. \$\endgroup\$
    – detay
    Mar 24, 2015 at 15:21
0
\$\begingroup\$

When I had to do something similar, I used a Dictionary<string, string> to define the replacements.

And then something like this to replace:

foreach( KeyValuePair<string, string> pair in replacements)
{
    str = str.Replace(pair.Key, pair.Value);
}

http://msdn.microsoft.com/en-us/library/5tbh8a42.aspx

\$\endgroup\$
0
\$\begingroup\$

I think your method is pretty readable and clean as it stands. However, if you want to simplify the method itself, I have a decent support structure that would do so and possibly speed it up for particularly long strings:

internal static class SafeTag
{
    private static readonly List<Replacement> replacements = new List<Replacement>
    {
        new Replacement("'", "`"),
        new Replacement("\"", "`"),
        new Replacement("&", "and"),
        new Replacement(",", ":"),
        new Replacement("\\", "/")
    };

    private static readonly Regex spaces = new Regex("\\s+", RegexOptions.Compiled);

    public static string GetSafeTagName(this string tag)
    {
        var parse = new StringBuilder(tag.ToUpper());
        replacements.ForEach(replacement => parse = parse.Replace(replacement.Original, replacement.ToReplaceWith));
        return spaces.Replace(parse.ToString(), " ");
    }

    private struct Replacement
    {
        private readonly string original;

        private readonly string toReplaceWith;

        internal Replacement(string original, string toReplaceWith)
        {
            this.original = original;
            this.toReplaceWith = toReplaceWith;
        }

        internal string Original
        {
            get
            {
                return this.original;
            }
        }

        internal string ToReplaceWith
        {
            get
            {
                return this.toReplaceWith;
            }
        }
    }
}
\$\endgroup\$

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.