Extension methods for the String class.

using System;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Collections.Generic;

namespace Extensions
{
    public static class StringExtensions
    {
        public static bool EqualsIgnoreCase(this string s1, string s2)
        {
            return string.Equals(s1, s2, StringComparison.OrdinalIgnoreCase);
        }
        internal static bool EqualsOrdinal(this string s1, string s2)
        {
            return string.Equals(s1, s2, StringComparison.Ordinal);
        }

        public static string RestrictTo(this string self, int size)
        {
            if (string.IsNullOrEmpty(self) || self.Length <= size)
            {
                return self;
            }
            return self.Substring(0, size);
        }

        public static string Truncate(this string str, int maxLength = 255, string truncateWith = "")
        {
            if (string.IsNullOrEmpty(str))
            {
                return str;
            }

            if (str.Length < maxLength)
            {
                return str;
            }

            if (string.IsNullOrEmpty(truncateWith))
            {
                return str.Substring(0, Math.Min(str.Length, maxLength));
            }

            return string.Format("{0}{1}", str.Substring(0, Math.Min(str.Length, maxLength)), truncateWith);
        }

        public static string OnlyLettersDigits(this string str)
        {
            if (string.IsNullOrEmpty(str))
            {
                return str;
            }

            return new String(str.Where(c => Char.IsLetter(c) || Char.IsDigit(c)).ToArray());
        }

        public static string OnlyAlpha(this string str)
        {
            if (string.IsNullOrEmpty(str))
            {
                return str;
            }

            return new String(str.ToCharArray().Where(c => !Char.IsLetter(c)).ToArray());
        }

        public static string ReplaceNonAlphanumeric(this string str, char replacementChar)
        {
            if (string.IsNullOrEmpty(str))
            {
                return str;
            }

            var sb = new StringBuilder(str.Length);
            foreach (char c in str)
            {
                if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9')
                {
                    sb.Append(c);
                }
                else
                {
                    sb.Append(replacementChar);
                }
            }

            return sb.ToString();
        }

        // public static string RemoveWhitespace(this string str)
        // {
        //     if (string.IsNullOrEmpty(str))
        //     {
        //         return str;
        //     }
        //     return new String(str.ToCharArray().Where(c => !Char.IsWhiteSpace(c)).ToArray());
        // }

        /// <summary>
        /// Calculates the SHA1 hash of the supplied string and returns a base 64 string.
        /// </summary>
        /// <param name="str">String that must be hashed.</param>
        /// <exception cref="ArgumentException">Occurs when str or key is null or empty.</exception>
        /// <returns>The hashed string or null if hashing failed.</returns>
        public static string GetSha1Hash(this string str)
        {
            if (string.IsNullOrEmpty(str))
            {
                throw new ArgumentException("An empty string value cannot be hashed.", str);
            }

            return Convert.ToBase64String(new SHA1CryptoServiceProvider().ComputeHash(Encoding.UTF8.GetBytes(str)));
        }

        public static bool Contains(this string str, string value, StringComparison comparisonType)
        {
            return str.IndexOf(value, comparisonType) >= 0;
        }

        public static string Left(this string str, int length)
        {
            if (length < 1) return string.Empty;
            if (length < str.Length) return str.Substring(0, length);
            return str;
        }

        public static string Right(this string str, int length)
        {
            if (length < 1) return string.Empty;
            if (length < str.Length) return str.Substring(str.Length - length);
            return str;
        }

        public static string RemoveLeft(this string str, int length)
        {
            if (length < 1) return string.Empty;
            if (length < str.Length) return str.Remove(0, length);
            return str;
        }

        public static string RemoveRight(this string str, int length)
        {
            if (length < 1) return string.Empty;
            if (length < str.Length) return str.Remove(str.Length - length);
            return str;
        }

        public static string Between(this string text, string first, string last, bool isFirstMatchForEnd = false, bool includeFirstAndLast = false)
        {
            int start = text.IndexOf(first);
            if (start < 0) return null;
            if (!includeFirstAndLast) start += first.Length;
            text = text.Substring(start);

            int end = isFirstMatchForEnd ? text.IndexOf(last) : text.LastIndexOf(last);
            if (end < 0) return null;
            if (includeFirstAndLast) end += last.Length;
            return text.Remove(end);
        }

        public static string Repeat(this string str, int count)
        {
            if (!string.IsNullOrEmpty(str) && count > 0)
            {
                StringBuilder sb = new StringBuilder(str.Length * count);
                for (int i = 0; i < count; i++)
                {
                    sb.Append(str);
                }
                return sb.ToString();
            }
            return null;
        }

        public static string Replace(this string str, string oldValue, string newValue, StringComparison comparison)
        {
            if (string.IsNullOrEmpty(oldValue))
            {
                return str;
            }

            StringBuilder sb = new StringBuilder();

            int previousIndex = 0;
            int index = str.IndexOf(oldValue, comparison);
            while (index != -1)
            {
                sb.Append(str.Substring(previousIndex, index - previousIndex));
                sb.Append(newValue);
                index += oldValue.Length;

                previousIndex = index;
                index = str.IndexOf(oldValue, index, comparison);
            }
            sb.Append(str.Substring(previousIndex));

            return sb.ToString();
        }

        public static string ReplaceWith(this string str, string search, string replace,
            int occurrence = 0, StringComparison comparison = StringComparison.InvariantCultureIgnoreCase)
        {
            if (!string.IsNullOrEmpty(search))
            {
                int count = 0, location;

                while (occurrence == 0 || occurrence > count)
                {
                    location = str.IndexOf(search, comparison);
                    if (location < 0) break;
                    count++;
                    str = str.Remove(location, search.Length).Insert(location, replace);
                }
            }

            return str;
        }

        public static bool ReplaceFirst(this string text, string search, string replace, out string result)
        {
            int location = text.IndexOf(search);

            if (location < 0)
            {
                result = text;
                return false;
            }

            result = text.Remove(location, search.Length).Insert(location, replace);
            return true;
        }

        public static string ReplaceAll(this string text, string search, Func<string> replace)
        {
            while (true)
            {
                int location = text.IndexOf(search);

                if (location < 0) break;

                text = text.Remove(location, search.Length).Insert(location, replace());
            }

            return text;
        }

        public static string RemoveWhiteSpaces(this string str)
        {
            StringBuilder result = new StringBuilder();
            foreach (char c in str)
            {
                if (!Char.IsWhiteSpace(c)) result.Append(c);
            }
            return result.ToString();
        }

        public static string Reverse(this string str)
        {
            char[] chars = str.ToCharArray();
            Array.Reverse(chars);
            return new String(chars);
        }

        public static string Truncate(this string str, int maxLength)
        {
            if (!string.IsNullOrEmpty(str) && str.Length > maxLength)
            {
                return str.Substring(0, maxLength);
            }
            return str;
        }

        // public static string Truncate(this string str, int maxLength, string endings, bool truncateFromRight = true)
        // {
        //     if (!string.IsNullOrEmpty(str) && str.Length > maxLength)
        //     {
        //         int length = maxLength - endings.Length;
        //         if (length > 0)
        //         {
        //             if (truncateFromRight)
        //             {
        //                 str = str.Left(length) + endings;
        //             }
        //             else
        //             {
        //                 str = endings + str.Right(length);
        //             }
        //         }
        //     }
        //     return str;
        // }

        public static bool IsValidUrl(this string url)
        {
            return Uri.IsWellFormedUriString(url.Trim(), UriKind.Absolute);
        }

        public static byte[] HexToBytes(this string hex)
        {
            byte[] bytes = new byte[hex.Length / 2];
            for (int i = 0; i < bytes.Length; i++)
            {
                bytes[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
            }
            return bytes;
        }

        public static string ParseQuoteString(this string str)
        {
            str = str.Trim();

            int firstQuote = str.IndexOf('"');
            if (firstQuote >= 0)
            {
                str = str.Substring(firstQuote + 1);
                int secondQuote = str.IndexOf('"');
                if (secondQuote >= 0)
                {
                    str = str.Remove(secondQuote);
                }
            }

            return str;
        }

        public static bool IsNumber(this string text)
        {
            foreach (char c in text)
            {
                if (!char.IsNumber(c)) return false;
            }
            return true;
        }

        public static string[] Lines(this string text)
        {
            return text.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None);
        }

        public static IEnumerable<Tuple<string, string>> ForEachBetween(this string text, string front, string back)
        {
            int f = 0;
            int b = 0;
            while (text.Length > f
                   && 0 <= (f = text.IndexOf(front, f))
                   && 0 <= (b = text.IndexOf(back, f + front.Length)))
            {
                string result = text.Substring(f, (b + back.Length) - f);
                yield return new Tuple<string, string>(result, result.Substring(front.Length, (result.Length - back.Length) - front.Length));
                f += front.Length;
            }
        }

        public static int FromBase(this string text, int radix, string digits)
        {
            if (string.IsNullOrEmpty(digits))
            {
                throw new ArgumentNullException("digits", string.Format("Digits must contain character value representations"));
            }

            radix = Math.Abs(radix);
            if (radix > digits.Length || radix < 2)
            {
                throw new ArgumentOutOfRangeException("radix", radix, string.Format("Radix has to be > 2 and < {0}", digits.Length));
            }

            // Convert to Base 10
            int value = 0;
            if (!string.IsNullOrEmpty(text))
            {
                for (int i = text.Length - 1; i >= 0; --i)
                {
                    int temp = digits.IndexOf(text[i]) * (int)Math.Pow(radix, text.Length - (i + 1));
                    if (0 > temp)
                    {
                        throw new IndexOutOfRangeException("Text contains characters not found in digits.");
                    }
                    value += temp;
                }
            }
            return value;
        }

        public static string ToBase(this string text, int fromRadix, string fromDigits, int toRadix, string toDigits)
        {
            return text.FromBase(fromRadix, fromDigits).ToBase(toRadix, toDigits);
        }

        public static string ToBase(this string text, int from, int to, string digits)
        {
            return text.FromBase(from, digits).ToBase(to, digits);
        }

        public static string RemoveSurroundingQuotes(this string s)
        {
            if (s.Length < 2)
                return s;

            var quoteCharacters = new[] { '"', '\'' };
            char firstCharacter = s[0];
            if (!quoteCharacters.Contains(firstCharacter))
                return s;

            if (firstCharacter != s[s.Length - 1])
                return s;

            return s.Substring(1, s.Length - 2);
        }

        public static Int32 ToInt32(this string s)
        {
            Int32 val;
            return Int32.TryParse(s, out val) ? val : 0;
        }

        /// <summary>
        /// Wrap a string to the specified length.
        /// </summary>
        /// <param name="text">The text string to wrap</param>
        /// <param name="maxLength">The character length to wrap at</param>
        /// <returns>A wrapped string using the platform's default newline
        /// character. This string will end in a newline.</returns>
        public static string Wrap(this string text, int maxLength = 72)
        {
            if (text.Length == 0) return string.Empty;

            var sb = new StringBuilder();
            foreach (var unwrappedLine in text.Split(new[] { Environment.NewLine }, StringSplitOptions.None))
            {
                var line = new StringBuilder();
                foreach (var word in unwrappedLine.Split(' '))
                {
                    var needsLeadingSpace = line.Length > 0;

                    var extraLength = (needsLeadingSpace ? 1 : 0) + word.Length;
                    if (line.Length + extraLength > maxLength)
                    {
                        sb.AppendLine(line.ToString());
                        line.Clear();
                        needsLeadingSpace = false;
                    }

                    if (needsLeadingSpace)
                    {
                        line.Append(" ");
                    }

                    line.Append(word);
                }

                sb.AppendLine(line.ToString());
            }

            return sb.ToString();
        }

        public static Uri ToUriSafe(this string url)
        {
            Uri uri;
            Uri.TryCreate(url, UriKind.Absolute, out uri);
            return uri;
        }

        public static string NormalizeLineEndings(this string self, string lineEnding = null)
        {
            if (String.IsNullOrEmpty(lineEnding))
            {
                lineEnding = Environment.NewLine;
            }

            self = self.Replace("\r\n", "\n");
            if (lineEnding != "\n")
            {
                self = self.Replace("\r\n", lineEnding);
            }

            return self;
        }
    }
}