Extension methods for the String class.
using System;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
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;
}
/// <summary>
/// Extension method to convert a string into a byte array
/// </summary>
/// <param name="str">String to convert to bytes.</param>
/// <returns>Byte array</returns>
public static byte[] GetBytes(this string str)
{
var bytes = new byte[str.Length * sizeof(char)];
Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
/// <summary>
/// Breaks the specified string into csv components, all commas are considered separators
/// </summary>
/// <param name="str">The string to be broken into csv</param>
/// <param name="size">The expected size of the output list</param>
/// <returns>A list of the csv pieces</returns>
public static List<string> ToCsv(this string str, int size = 4)
{
int last = 0;
var csv = new List<string>(size);
for (int i = 0; i < str.Length; i++)
{
if (str[i] == ',')
{
if (last != 0) last = last + 1;
csv.Add(str.Substring(last, i - last));
last = i;
}
}
if (last != 0) last = last + 1;
csv.Add(str.Substring(last));
return csv;
}
/// <summary>
/// Breaks the specified string into csv components, works correctly with commas in data fields
/// </summary>
/// <param name="str">The string to be broken into csv</param>
/// <param name="size">The expected size of the output list</param>
/// <returns>A list of the csv pieces</returns>
public static List<string> ToCsvData(this string str, int size = 4)
{
var csv = new List<string>(size);
int last = -1;
bool textDataField = false;
for (var i = 0; i < str.Length; i++)
{
switch (str[i])
{
case '"':
textDataField = !textDataField;
break;
case ',':
if (!textDataField)
{
csv.Add(str.Substring(last + 1, (i - last)).Trim(' ', ','));
last = i;
}
break;
default:
break;
}
}
if (last != str.Length - 1)
{
csv.Add(str.Substring(last + 1).Trim());
}
return csv;
}
/// <summary>
/// Extension method to convert strings to stream to be read.
/// </summary>
/// <param name="str">String to convert to stream</param>
/// <returns>Stream instance</returns>
public static Stream ToStream(this string str)
{
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
writer.Write(str);
writer.Flush();
stream.Position = 0;
return stream;
}
/// <summary>
/// Encrypt the token:time data to make our API hash.
/// </summary>
/// <param name="data">Data to be hashed by SHA256</param>
/// <returns>Hashed string.</returns>
public static string ToSHA256(this string data)
{
var crypt = new SHA256Managed();
var hash = new StringBuilder();
var crypto = crypt.ComputeHash(Encoding.UTF8.GetBytes(data), 0,
Encoding.UTF8.GetByteCount(data));
foreach (var theByte in crypto)
{
hash.Append(theByte.ToString("x2"));
}
return hash.ToString();
}
/// <summary>
/// Save values checking length
/// </summary>
/// <returns>The string limit.</returns>
/// <param name="self">String.</param>
/// <param name="limit">Limit.</param>
/// <remarks>http://extensionmethod.net/5447/csharp/string/tostringlimit-limit</remarks>
public static string ToStringLimit(this string self, int limit)
{
if (self.Length > limit)
{
return self.Substring(0, limit);
}
return self;
}
/// <summary>
/// Removes any special characters in the input string not provided
/// in the allowed special character list.
///
/// Sometimes it is required to remove some special characters like
/// carriage return, or new line which can be considered as invalid
/// characters, especially while file processing. This method removes any
/// special characters in the input string which is not included in the
/// allowed special character list.
/// </summary>
/// <param name="input">Input string to process</param>
/// <param name="allowedCharacters">list of allowed special characters </param>
/// <returns>
/// The original string with special charactersremoved.
/// </returns>
/// <example>
///
/// Remove carriage return from the input string:
///
/// var processedString = RemoveSpecialCharacters(
/// "Hello! This is string to process. \r\n", @""",-{}.! "
/// );
///
/// </example>
/// <remarks>
/// http://extensionmethod.net/5470/csharp/string/removespecialcharacters
/// </remarks>
public static string RemoveSpecialCharacters(string input, string allowedCharacters)
{
char[] buffer = new char[input.Length];
int index = 0;
char[] allowedSpecialCharacters = allowedCharacters.ToCharArray();
foreach (char c in input.Where(
c => char.IsLetterOrDigit(c) || allowedSpecialCharacters.Any(
x => x == c)
))
{
buffer[index] = c;
index++;
}
return new string(buffer, 0, index);
}
/// <summary>
/// Splits a string into a NameValueCollection, where each "namevalue"
/// is separated by the "OuterSeparator". The parameter "NameValueSeparator"
/// sets the split between Name and Value.
/// </summary>
/// <param name="self">String to process</param>
/// <param name="outerSeparator">Separator for each "NameValue"</param>
/// <param name="nameValueSeparator">Separator for Name/Value splitting</param>
/// <returns>NameValueCollection of values.</returns>
/// <example>
/// Example:
/// string str = "param1=value1;param2=value2";
/// NameValueCollection nvOut = str.ToNameValueCollection(';', '=');
///
/// The result is a NameValueCollection where:
/// key[0] is "param1" and value[0] is "value1"
/// key[1] is "param2" and value[1] is "value2"
/// </example>
/// <remarks>http://extensionmethod.net/1686/csharp/string/tonamevaluecollection</remarks>
public static System.Collections.Specialized.NameValueCollection ToNameValueCollection(
this string self, char outerSeparator, char nameValueSeparator)
{
System.Collections.Specialized.NameValueCollection nvText = null;
self = self.TrimEnd(outerSeparator);
if (!string.IsNullOrEmpty(self))
{
string[] arrStrings = self.TrimEnd(outerSeparator).Split(outerSeparator);
for (int i = 0; i < arrStrings.Length; i++)
{
string s = arrStrings[i];
int posSep = s.IndexOf(nameValueSeparator);
string name = s.Substring(0, posSep);
string value = s.Substring(posSep + 1);
if (nvText == null)
{
nvText = new System.Collections.Specialized.NameValueCollection();
}
nvText.Add(name, value);
}
}
return nvText;
}
/// <summary>
/// Check that the given string is in a list of potential matches.
/// </summary>
/// <returns><c>true</c>, if any was equalsed, <c>false</c> otherwise.</returns>
/// <param name="str">String.</param>
/// <param name="args">Arguments.</param>
/// <remarks>Inspired by StackOverflow answer http://stackoverflow.com/a/20644611/23199</remarks>
/// <example>
/// string custName = "foo";
/// bool isMatch = (custName.EqualsAny("bar", "baz", "FOO"));
/// </example>
public static bool EqualsAny(this string str, params string[] args)
{
return args.Any(x => StringComparer.OrdinalIgnoreCase.Equals(x, str));
}
/// <summary>
/// Returns the plural form of the specified word.
/// </summary>
/// <param name="count">How many of the specified word there are. A count equal to 1 will not pluralize the specified word.</param>
/// <returns>A string that is the plural form of the input parameter.</returns>
public static string ToPlural(this string @this, int count = 0)
{
return count == 1 ? @this : System.Data.Entity.Design.PluralizationServices.PluralizationService.CreateService(new System.Globalization.CultureInfo("en-US")).Pluralize(@this);
}
/// <summary>
/// Does the string contain an uppercase character?
/// </summary>
/// <param name="value">Value to test.</param>
/// <returns>True/False.</returns>
public static bool ContainsUpper(this string value)
{
return value != value.ToLower();
}
/// <summary>
/// Does the string contain an lowercase character?
/// </summary>
/// <param name="value">Value to test.</param>
/// <returns>True/False.</returns>
public static bool ContainsLower(this string value)
{
return value != value.ToUpper();
}
/// <summary>
/// Duplicates/multiplies a string the number of times specified.
/// </summary>
/// <param name="source">String to multiply.</param>
/// <param name="multiplier">Times to multiply.</param>
/// <returns>Resulting string.</returns>
public static string Multiply(this string source, int multiplier)
{
StringBuilder sb = new StringBuilder(multiplier * source.Length);
for (int i = 0; i < multiplier; i++)
{
sb.Append(source);
}
return sb.ToString();
}
/// <summary>
/// Parse the input string to a valid datetime.
/// </summary>
/// <param name="stringToParse"></param>
/// <returns>A DateTime object if s is a valid datetime string otherwise DateTime.MinValue is returned.</returns>
public static DateTime ToDateTimeSafe(this string stringToParse)
{
DateTime output = DateTime.MinValue;
DateTime.TryParse(stringToParse, out output);
return output;
}
/// <summary>
/// Check if a string is an integer
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static bool IsInteger(this string value)
{
int i;
return Int32.TryParse(value, out i);
}
/// <summary>
/// Checks whether or not a string value is a valid date.
/// </summary>
public static bool IsDate(this string value)
{
DateTime dt;
return DateTime.TryParse(value, out dt);
}
/// <summary>
/// Checks whether or not a string value is a valid bool.
/// </summary>
public static bool IsBool(this string value)
{
Boolean bl;
return Boolean.TryParse(value, out bl);
}
/// <summary>
/// Checks whether or not a string value is a valid double.
/// </summary>
public static bool IsDouble(this string value)
{
Double d;
return Double.TryParse(value, out d);
}
/// <summary>
/// Converts a camel case string such as OneWord to One Word.
/// </summary>
/// <param name="text"></param>
/// <param name="preserveAcronyms"></param>
/// <returns></returns>
public static string SplitCamelCaseWithSpace(this string text)
{
if (string.IsNullOrWhiteSpace(text))
return string.Empty;
if (text.Length == 1)
{
return text.ToUpper();
}
else
{
var spaceAdded = 0;
StringBuilder sb = new StringBuilder(text.Length * 2);
sb.Append(text);
for (var i = 1; i < text.Length; i++)
{
var c = text[i];
if (c >= 'A' && c <= 'Z')
{
sb.Insert(i + spaceAdded, " ");
spaceAdded++;
}
}
return sb.ToString();
}
}
}
}