Static C# class with useful string manipulation methods.

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.UI;

namespace Ext.Net.Utilities
{
    public static class StringUtils
    {
        private readonly static Random random;

        static StringUtils()
        {
            StringUtils.random = new Random();
        }

        /// <summary>
        /// Base64 string decoder
        /// </summary>
        /// <param name="text">The text string to decode</param>
        /// <returns>The decoded string</returns>
        public static string Base64Decode(this string text)
        {
            Decoder decoder = (new UTF8Encoding()).GetDecoder();
            byte[] numArray = Convert.FromBase64String(text);
            char[] chrArray = new char[decoder.GetCharCount(numArray, 0, (int)numArray.Length)];
            decoder.GetChars(numArray, 0, (int)numArray.Length, chrArray, 0);
            return new string(chrArray);
        }

        /// <summary>
        /// Base64 string encoder
        /// </summary>
        /// <param name="text">The text string to encode</param>
        /// <returns>The encoded string</returns>
        public static string Base64Encode(this string text)
        {
            byte[] numArray = new byte[text.Length];
            return Convert.ToBase64String(Encoding.UTF8.GetBytes(text));
        }

        /// <summary>
        /// Return a string from between the start and end positions.
        /// </summary>
        public static string Between(string text, string start, string end)
        {
            if (text.IsEmpty())
            {
                return text;
            }
            return text.RightOf(start).LeftOfRightmostOf(end);
        }

        /// <summary>
        /// Chops one character from each end of string.
        /// </summary>
        public static string Chop(this string text)
        {
            return text.Chop(1);
        }

        /// <summary>
        /// Chops the specified number of characters from each end of string.
        /// </summary>
        public static string Chop(this string text, int characters)
        {
            if (text.IsEmpty())
            {
                return text;
            }
            return text.Substring(characters, text.Length - characters - 1);
        }

        /// <summary>
        /// Chops the specified string from each end of the string. If the character does not exist on both ends
        /// of the string, the characters are not chopped.
        /// </summary>
        public static string Chop(this string text, string character)
        {
            if (text.IsEmpty())
            {
                return text;
            }
            if (!text.StartsWith(character) || !text.EndsWith(character))
            {
                return text;
            }
            int length = character.Length;
            return text.Substring(length, text.Length - (length + 1));
        }

        /// <summary>
        /// Add the text string to the source string.
        /// </summary>
        public static string ConcatWith(this string instance, string text)
        {
            return string.Concat(instance, text);
        }

        /// <summary>
        /// Add the args strings the source text string.
        /// </summary>
        public static string ConcatWith(this string instance, params object[] args)
        {
            if (args == null)
            {
                throw new ArgumentNullException(string.Format("The args parameter can not be null when calling {0}.Format().", instance));
            }
            return string.Concat(instance, string.Concat(args));
        }

        /// <summary>
        /// Determines if the string contains any of the args. If yes, returns true, otherwise returns false.
        /// </summary>
        /// <param name="instance">The instance of the string</param>
        /// <param name="args">The string to check if contained within the string instance.</param>
        /// <returns>boolean</returns>
        public static bool Contains(this string instance, params string[] args)
        {
            string[] strArrays = args;
            for (int i = 0; i < (int)strArrays.Length; i++)
            {
                if (instance.Contains(strArrays[i]))
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
        /// </summary>
        /// <param name="text">The string to truncate</param>
        /// <param name="length">The maximum length to allow before truncating</param>
        /// <returns>The converted text</returns>
        public static string Ellipsis(this string text, int length)
        {
            return text.Ellipsis(length, false);
        }

        /// <summary>
        /// Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
        /// </summary>
        /// <param name="text">The string to truncate</param>
        /// <param name="length">The maximum length to allow before truncating</param>
        /// <param name="word">True to try to find a common work break</param>
        /// <returns>The converted text</returns>
        public static string Ellipsis(this string text, int length, bool word)
        {
            if (text == null || text.Length <= length)
            {
                return text;
            }
            if (!word)
            {
                return string.Concat(text.Substring(0, length - 3), "...");
            }
            string str = text.Substring(0, length - 2);
            int num = Math.Max(str.LastIndexOf(' '), Math.Max(str.LastIndexOf('.'), Math.Max(str.LastIndexOf('!'), str.LastIndexOf('?'))));
            if (num != -1 && num >= length - 15)
            {
                return string.Concat(str.Substring(0, num), "...");
            }
            return string.Concat(text.Substring(0, length - 3), "...");
        }

        public static string Enquote(this string text)
        {
            if (text.IsEmpty())
            {
                return text;
            }
            if (string.IsNullOrEmpty(text))
            {
                return string.Empty;
            }
            int length = text.Length;
            StringBuilder stringBuilder = new StringBuilder(length + 4);
            for (int i = 0; i < length; i++)
            {
                char chr = text[i];
                if (chr == '\\' || chr == '\"' || chr == '>')
                {
                    stringBuilder.Append('\\');
                    stringBuilder.Append(chr);
                }
                else if (chr == '\b')
                {
                    stringBuilder.Append("\\b");
                }
                else if (chr == '\t')
                {
                    stringBuilder.Append("\\t");
                }
                else if (chr == '\n')
                {
                    stringBuilder.Append("\\n");
                }
                else if (chr == '\f')
                {
                    stringBuilder.Append("\\f");
                }
                else if (chr == '\r')
                {
                    stringBuilder.Append("\\r");
                }
                else if (chr >= ' ')
                {
                    stringBuilder.Append(chr);
                }
                else
                {
                    string str = new string(chr, 1);
                    string str1 = string.Concat("000", int.Parse(str, NumberStyles.HexNumber));
                    stringBuilder.Append(string.Concat("\\u", str1.Substring(str1.Length - 4)));
                }
            }
            return stringBuilder.ToString();
        }

        public static string EnsureSemiColon(this string text)
        {
            if (text.IsEmpty())
            {
                return text;
            }
            if (string.IsNullOrEmpty(text) || text.EndsWith(";"))
            {
                return text;
            }
            return string.Concat(text, ";");
        }

        private static object Eval(object source, string expression)
        {
            object obj;
            try
            {
                obj = DataBinder.Eval(source, expression);
            }
            catch (HttpException httpException)
            {
                throw new FormatException(null, httpException);
            }
            return obj;
        }

        public static string FormatRegexPattern(this string regex)
        {
            bool flag = !regex.StartsWith("new RegExp");
            if (!regex.StartsWith("/", StringComparison.InvariantCulture) && flag)
            {
                regex = "/{0}".FormatWith(regex);
            }
            if (!regex.EndsWith("/", StringComparison.InvariantCulture) && flag)
            {
                regex = "{0}/".FormatWith(regex);
            }
            return regex;
        }

        /// <summary>
        /// Format the string with the args.
        /// </summary>
        public static string FormatWith(this string format, params object[] args)
        {
            if (args == null)
            {
                throw new ArgumentNullException(string.Format("The args parameter can not be null when calling {0}.FormatWith().", format));
            }
            return string.Format(format, args);
        }

        public static string FormatWith(this string format, IFormatProvider provider, params object[] args)
        {
            Verify.IsNotNull(format, "format");
            return string.Format(provider, format, args);
        }

        public static string FormatWith(this string format, object source)
        {
            return StringUtils.FormatWith(format, null, source);
        }

        // http://james.newtonking.com/archive/2008/03/29/formatwith-2-0-string-formatting-with-named-variables.aspx
        public static string FormatWith(string format, IFormatProvider provider, object source)
        {
            if (format == null)
            {
                throw new ArgumentNullException("format");
            }
            List<object> objs = new List<object>();
            string str = Regex.Replace(format, "(?<start>\\{)+(?<property>[\\w\\.\\[\\]]+)(?<format>:[^}]+)?(?<end>\\})+", (Match m) => {
                Group item = m.Groups["start"];
                Group group = m.Groups["property"];
                Group item1 = m.Groups["format"];
                Group group1 = m.Groups["end"];
                objs.Add((group.Value == "0" ? source : StringUtils.Eval(source, group.Value)));
                int count = item.Captures.Count;
                int num = group1.Captures.Count;
                if (count > num || count % 2 == 0)
                {
                    return m.Value;
                }
                return string.Concat(new object[] { new string('{', count), objs.Count - 1, item1.Value, new string('}', num) });
            }, RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant);
            return string.Format(provider, str, objs.ToArray());
        }

        public static string If(this string text, string test, string valueIfTrue)
        {
            return text.If<string>(() => text == test, valueIfTrue, text);
        }

        public static string IfNot(this string text, string test, string valueIfTrue)
        {
            return text.IfNot<string>(() => text == test, valueIfTrue, text);
        }

        /// <summary>
        /// Determine is the string is null or empty.
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        public static bool IsEmpty(this string text)
        {
            return string.IsNullOrEmpty(text);
        }

        public static bool IsLowerCamelCase(this string text)
        {
            if (text.IsEmpty())
            {
                return false;
            }
            return text.Substring(0, 1).ToLowerInvariant().Equals(text.Substring(0, 1));
        }

        /// <summary>
        /// Determine is the string is NOT null or empty.
        /// </summary>
        public static bool IsNotEmpty(this string text)
        {
            return !text.IsEmpty();
        }

        public static string Join(this IEnumerable items)
        {
            return items.Join(",", "{0}");
        }

        public static string Join(this IEnumerable items, string separator)
        {
            return items.Join(separator, "{0}");
        }

        /// <summary>
        /// Join the items together
        /// </summary>
        /// <param name="items">The items to join.</param>
        /// <param name="separator">The separator.</param>
        /// <param name="template">The template to format the items with.</param>
        /// <returns></returns>
        public static string Join(this IEnumerable items, string separator, string template)
        {
            StringBuilder stringBuilder = new StringBuilder();
            foreach (object item in items)
            {
                if (item == null)
                {
                    continue;
                }
                stringBuilder.Append(separator);
                stringBuilder.Append(string.Format(template, item.ToString()));
            }
            return stringBuilder.ToString().RightOf(separator);
        }

        /// <summary>
        /// Left of the first occurance of c
        /// </summary>
        public static string LeftOf(this string text, char c)
        {
            if (text.IsEmpty())
            {
                return text;
            }
            int num = text.IndexOf(c);
            if (num == -1)
            {
                return text;
            }
            return text.Substring(0, num);
        }

        /// <summary>
        /// Left of the first occurance of text
        /// </summary>
        public static string LeftOf(this string text, string value)
        {
            if (text.IsEmpty())
            {
                return text;
            }
            int num = text.IndexOf(value);
            if (num == -1)
            {
                return text;
            }
            return text.Substring(0, num);
        }

        /// <summary>
        /// Left of the n'th occurance of c
        /// </summary>
        public static string LeftOf(this string text, char c, int n)
        {
            if (text.IsEmpty())
            {
                return text;
            }
            int num = -1;
            while (n != 0)
            {
                num = text.IndexOf(c, num + 1);
                if (num == -1)
                {
                    return text;
                }
                n--;
            }
            return text.Substring(0, num);
        }

        public static string LeftOfRightmostOf(this string text, char c)
        {
            if (text.IsEmpty())
            {
                return text;
            }
            int num = text.LastIndexOf(c);
            if (num == -1)
            {
                return text;
            }
            return text.Substring(0, num);
        }

        public static string LeftOfRightmostOf(this string text, string value)
        {
            if (text.IsEmpty())
            {
                return text;
            }
            int num = text.LastIndexOf(value);
            if (num == -1)
            {
                return text;
            }
            return text.Substring(0, num);
        }

        /// <summary>
        /// Pad the left side of a string with characters to make the total length.
        /// </summary>
        public static string PadLeft(this string text, char c, int totalLength)
        {
            if (text.IsEmpty())
            {
                return text;
            }
            if (totalLength < text.Length)
            {
                return text;
            }
            return string.Concat(new string(c, totalLength - text.Length), text);
        }

        /// <summary>
        /// Pad the right side of a string with a '0' if a single character.
        /// </summary>
        public static string PadRight(this string text)
        {
            return text.PadRight('0', 2);
        }

        /// <summary>
        /// Pad the right side of a string with characters to make the total length.
        /// </summary>
        public static string PadRight(this string text, char c, int totalLength)
        {
            if (text.IsEmpty())
            {
                return text;
            }
            if (totalLength < text.Length)
            {
                return text;
            }
            return string.Concat(text, new string(c, totalLength - text.Length));
        }

        /// <summary>
        /// Generate a random string of character at a certain length
        /// </summary>
        /// <param name="chars">The Characters to use in the random string</param>
        /// <param name="length">The length of the random string</param>
        /// <returns>A string of random characters</returns>
        public static string Randomize(this string chars, int length)
        {
            char[] chrArray = new char[length];
            for (int i = 0; i < length; i++)
            {
                chrArray[i] = chars[StringUtils.random.Next(chars.Length)];
            }
            return new string(chrArray);
        }

        public static string Randomize(this string chars)
        {
            return chars.Randomize(chars.Length);
        }

        /// <summary>
        /// Replaces all occurrences of System.String in the oldValues String Array, with
        /// another specified System.String of newValue.
        /// </summary>
        /// <param name="instance">this string</param>
        /// <param name="oldValues">An Array of String objects to be replaced.</param>
        /// <param name="newValue">The new value to replace old values.</param>
        /// <returns>
        /// The modified original string.
        /// </returns>
        public static string Replace(string instance, string[] oldValues, string newValue)
        {
            if (oldValues == null || (int)oldValues.Length < 1)
            {
                return instance;
            }
            oldValues.Each<string>((string value) => instance = instance.Replace(value, newValue));
            return instance;
        }

        /// <summary>
        /// Replaces all occurrences of System.String in the oldValue String Array, with the
        /// return String value of the specified Function convert.
        /// </summary>
        /// <param name="instance">this string</param>
        /// <param name="oldValues">An Array of String objects to be replaced.</param>
        /// <param name="convert">The Function to convert the found old value.</param>
        /// <returns>
        /// The modified original string.
        /// </returns>
        public static string Replace(this string instance, string[] oldValues, Func<string, string> convert)
        {
            if (oldValues == null || (int)oldValues.Length < 1)
            {
                return instance;
            }
            oldValues.Each<string>((string value) => instance = instance.Replace(value, convert(value)));
            return instance;
        }

        public static string ReplaceLastInstanceOf(this string text, string oldValue, string newValue)
        {
            if (text.IsEmpty())
            {
                return text;
            }

            return string.Format("{0}{1}{2}",
                text.LeftOfRightmostOf(oldValue),
                newValue,
                text.RightOfRightmostOf(oldValue)
            );
        }

        /// <summary>
        /// Right of the first occurance of c
        /// </summary>
        public static string RightOf(this string text, char c)
        {
            if (text.IsEmpty())
            {
                return text;
            }
            int num = text.IndexOf(c);
            if (num == -1)
            {
                return "";
            }
            return text.Substring(num + 1);
        }

        /// <summary>
        /// Right of the first occurance of text
        /// </summary>
        public static string RightOf(this string text, string value)
        {
            if (text.IsEmpty())
            {
                return text;
            }
            int num = text.IndexOf(value);
            if (num == -1)
            {
                return "";
            }
            return text.Substring(num + value.Length);
        }

        /// <summary>
        /// Right of the n'th occurance of c
        /// </summary>
        public static string RightOf(this string text, char c, int n)
        {
            if (text.IsEmpty())
            {
                return text;
            }
            int num = -1;
            while (n != 0)
            {
                num = text.IndexOf(c, num + 1);
                if (num == -1)
                {
                    return "";
                }
                n--;
            }
            return text.Substring(num + 1);
        }

        /// <summary>
        /// Right of the n'th occurance of c
        /// </summary>
        public static string RightOf(this string text, string c, int n)
        {
            if (text.IsEmpty())
            {
                return text;
            }
            int num = -1;
            while (n != 0)
            {
                num = text.IndexOf(c, num + 1);
                if (num == -1)
                {
                    return "";
                }
                n--;
            }
            return text.Substring(num + 1);
        }

        public static string RightOfRightmostOf(this string text, char c)
        {
            if (text.IsEmpty())
            {
                return text;
            }
            int num = text.LastIndexOf(c);
            if (num == -1)
            {
                return text;
            }
            return text.Substring(num + 1);
        }

        public static string RightOfRightmostOf(this string text, string value)
        {
            if (text.IsEmpty())
            {
                return text;
            }
            int num = text.LastIndexOf(value);
            if (num == -1)
            {
                return text;
            }
            return text.Substring(num + value.Length);
        }

        /// <summary>
        /// Return a sub array of this string array.
        /// </summary>
        public static string[] Subarray(this string[] items, int start)
        {
            return items.Subarray(start, (int)items.Length - start);
        }

        /// <summary>
        /// Return a sub array of this string array.
        /// </summary>
        public static string[] Subarray(this string[] items, int start, int length)
        {
            if (start > (int)items.Length)
            {
                throw new ArgumentException(string.Format("The start index [{0}] is greater than the length [{1}] of the array.", start, (int)items.Length));
            }
            if (start + length > (int)items.Length)
            {
                throw new ArgumentException(string.Format("The length [{0}] to return is greater than the length [{1}] of the array.", length, (int)items.Length));
            }
            string[] strArrays = new string[length];
            int num = 0;
            for (int i = start; i < start + length; i++)
            {
                strArrays[num] = items[i];
                num++;
            }
            return strArrays;
        }

        public static bool Test(this string text, string pattern)
        {
            return Regex.IsMatch(text, pattern);
        }

        public static bool Test(this string text, string pattern, RegexOptions options)
        {
            return Regex.IsMatch(text, pattern, options);
        }

        public static string ToCamelCase(this string text)
        {
            if (text.IsEmpty())
            {
                return text;
            }
            return string.Concat(text.Substring(0, 1).ToUpper(CultureInfo.CurrentCulture), text.Substring(1));
        }

        public static string ToCamelCase(this string[] values, string separator)
        {
            string str = "";
            string[] strArrays = values;
            for (int i = 0; i < (int)strArrays.Length; i++)
            {
                string str1 = strArrays[i];
                str = string.Concat(str, separator);
                str = string.Concat(str, str1.ToCamelCase());
            }
            return str;
        }

        public static string ToCamelCase(this string[] values)
        {
            return values.ToCamelCase("");
        }

        /// <summary>
        /// Accepts a string like "ArrowRotateClockwise" and returns "arrow_rotate_clockwise.png".
        /// </summary>
        public static string ToCharacterSeparatedFileName(this string name, char separator, string extension)
        {
            if (name.IsEmpty())
            {
                return name;
            }
            MatchCollection matchCollections = Regex.Matches(name, "([A-Z]+)[a-z]*|\\d{1,}[a-z]{0,}");
            string str = "";
            for (int i = 0; i < matchCollections.Count; i++)
            {
                if (i != 0)
                {
                    str = string.Concat(str, separator);
                }
                str = string.Concat(str, matchCollections[i].ToString().ToLowerInvariant());
            }
            return string.Format((string.IsNullOrEmpty(extension) ? "{0}{1}" : "{0}.{1}"), str, extension);
        }

        public static string ToLowerCamelCase(this string text)
        {
            if (text.IsEmpty())
            {
                return text;
            }
            return string.Concat(text.Substring(0, 1).ToLower(CultureInfo.InvariantCulture), text.Substring(1));
        }

        public static string ToLowerCamelCase(this string[] values)
        {
            if (values == null || (int)values.Length == 0)
            {
                return "";
            }
            return values.ToLowerCamelCase();
        }

        /// <summary>
        /// MD5Hash's a string.
        /// </summary>
        public static string ToMD5Hash(this string text)
        {
            if (text.IsEmpty())
            {
                return text;
            }
            MD5 mD5 = MD5.Create();
            byte[] bytes = Encoding.ASCII.GetBytes(text.Trim());
            byte[] numArray = mD5.ComputeHash(bytes);
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < (int)numArray.Length; i++)
            {
                stringBuilder.Append(numArray[i].ToString("x2"));
            }
            return stringBuilder.ToString();
        }

        /// <summary>
        /// Converts the first character of each word to Uppercase. Example: "the lazy dog" returns "The Lazy Dog"
        /// </summary>
        /// <param name="text">The text to convert to sentence case</param>
        public static string ToTitleCase(this string text)
        {
            if (text.IsEmpty())
            {
                return text;
            }
            char[] chrArray = new char[] { ' ' };
            return text.Split(chrArray).ToTitleCase();
        }

        /// <summary>
        /// Converts the first character of each word to Uppercase. Example: "the lazy dog" returns "The Lazy Dog"
        /// </summary>
        /// <param name="ci"></param>
        /// <param name="text">The text to convert to sentence case</param>
        public static string ToTitleCase(this string text, CultureInfo ci)
        {
            if (text.IsEmpty())
            {
                return text;
            }
            char[] chrArray = new char[] { ' ' };
            return text.Split(chrArray).ToTitleCase(ci);
        }

        /// <summary>
        /// Converts the first character of each word to Uppercase. Example: "the lazy dog" returns "The Lazy Dog"
        /// </summary>
        public static string ToTitleCase(this string[] words)
        {
            return words.ToTitleCase(null);
        }

        /// <summary>
        /// Converts the first character of each word to Uppercase. Example: "the lazy dog" returns "The Lazy Dog"
        /// </summary>
        public static string ToTitleCase(this string[] words, CultureInfo ci)
        {
            if (words == null || (int)words.Length == 0)
            {
                return "";
            }
            for (int i = 0; i < (int)words.Length; i++)
            {
                words[i] = string.Concat((ci != null ? char.ToUpper(words[i][0], ci) : char.ToUpper(words[i][0])), words[i].Substring(1));
            }
            return string.Join(" ", words);
        }

        public static string Wrap(this string text, string wrapByText)
        {
            if (text == null)
            {
                text = "";
            }
            object[] objArray = new object[] { text, wrapByText };
            return wrapByText.ConcatWith(objArray);
        }

        public static string Wrap(this string text, string wrapStart, string wrapEnd)
        {
            if (text == null)
            {
                text = "";
            }
            object[] objArray = new object[] { text, wrapEnd };
            return wrapStart.ConcatWith(objArray);
        }
    }
}