Skip to content

Instantly share code, notes, and snippets.

@Hallmanac
Last active August 19, 2017 22:34
Show Gist options
  • Save Hallmanac/8f0f9cfe4ad667fc78f2907d85aa6327 to your computer and use it in GitHub Desktop.
Save Hallmanac/8f0f9cfe4ad667fc78f2907d85aa6327 to your computer and use it in GitHub Desktop.
C# String Extensions
using System.Linq;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using System.Text.RegularExpressions;
namespace System
{
public static class StringExtensions
{
public static bool IsNullOrEmpty(this string str)
{
return string.IsNullOrEmpty(str);
}
public static bool IsNullOrWhiteSpace(this string @this)
{
return string.IsNullOrWhiteSpace(@this);
}
/// <summary>
/// Tries to parse the string and get an integer value. If there are letters inside the string then
/// this will get all the numeric digits from the string and combine them to return a single integer
/// value.
/// </summary>
/// <param name="this"></param>
/// <returns></returns>
public static int AsInt(this string @this)
{
if (string.IsNullOrEmpty(@this))
{
return 0;
}
try
{
var digits = @this.GetDigits();
var result = int.Parse(digits);
return result;
}
catch (Exception)
{
return 0;
}
}
/// <summary>
/// Tries to parse the string into a decimal type and returns 0 if invalid
/// </summary>
/// <returns></returns>
public static decimal AsDecimal(this string @this)
{
if (string.IsNullOrEmpty(@this))
{
return 0;
}
try
{
var result = decimal.Parse(@this);
return result;
}
catch (Exception)
{
return 0;
}
}
/// <summary>
/// Truncates the string to a length equal to the given qtyOfChars parameter value and appends an elipsis (3 dots)
/// on the end.
/// </summary>
/// <param name="qtyOfChars">Max length of string (excluding the elipsis)</param>
public static string FirstXChars(this string @this, int qtyOfChars)
{
if (string.IsNullOrEmpty(@this))
{
return "";
}
if (@this.Length > qtyOfChars)
{
return @this.Substring(0, qtyOfChars) + "...";
}
return @this;
}
/// <summary>
/// Puts a space betweeen Pascal cased letters inside the given string. For example, SomeStringValue becomes "Some
/// String
/// Value".
/// </summary>
public static string AddSpaceBetweenPascalCase(this string givenString, bool bodyToLowerCase = false)
{
var builder = new StringBuilder();
if (bodyToLowerCase)
{
for (var i = 0; i < givenString.Length; i++)
{
var character = givenString[i];
if (i == 0)
{
builder.Append(character);
continue;
}
if (char.IsUpper(character) && builder.Length > 0)
{
builder.Append(' ');
}
builder.Append(char.ToLower(character));
}
}
else
{
for (var i = 0; i < givenString.Length; i++)
{
var character = givenString[i];
if (i == 0)
{
builder.Append(character);
continue;
}
if (char.IsUpper(character) && builder.Length > 0)
{
builder.Append(' ');
}
builder.Append(character);
}
}
return builder.ToString();
}
/// <summary>
/// Creates an array of strings splitting on the upper case characters iniside a Pascal cased (or camel cased) string.
/// </summary>
public static string[] SplitByUpperCase(this string str)
{
var spacedString = str.AddSpaceBetweenPascalCase();
var spacedSplit = spacedString.Split(' ');
var cleanedResult = spacedSplit.Where(s => !string.IsNullOrWhiteSpace(s)).ToArray();
return cleanedResult;
}
/// <summary>
/// For a given string, this method capitalizes the first letter of each word and removes the spaces to make
/// the result a PascalCased string
/// </summary>
public static string ToPascalCase(this string str)
{
var sb = new StringBuilder();
var trimmed = str.Trim();
var capitalizeNext = true;
for (var i = 0; i < trimmed.Length; i++)
{
var character = str[i];
if (capitalizeNext && char.IsLetter(character))
{
sb.Append(char.ToUpper(character));
capitalizeNext = false;
continue;
}
if (character == ' ')
{
capitalizeNext = true;
continue;
}
if (character == '.')
{
sb.Append(character);
capitalizeNext = true;
continue;
}
sb.Append(character);
}
return sb.ToString();
}
public static string ToTitleCase(this string str)
{
var sb = new StringBuilder();
var trimmed = str.Trim();
var allWords = trimmed.Split(' ');
for (var i = 0; i < allWords.Length; i++)
{
var word = allWords[i];
if (string.IsNullOrEmpty(word))
{
continue;
}
var firstCharacter = word[0];
var restOfString = word.Substring(1);
var splitOnDash = word.Split('-');
if (splitOnDash.Length > 1)
{
var subSb = new StringBuilder();
for (var j = 0; j < splitOnDash.Length; j++)
{
var subWord = splitOnDash[j];
var firstSubChar = subWord[0];
var restOfSubChar = subWord.Substring(1);
if (!char.IsLetter(firstSubChar))
subSb.Append(subWord + "-");
else
{
subSb.Append(char.ToUpper(firstSubChar));
subSb.Append(restOfSubChar + "-");
}
}
var subString = subSb.ToString();
restOfString = subString.Substring(1, subString.Length - 2);
}
if (!char.IsLetter(firstCharacter))
{
sb.Append(word + " ");
}
else
{
sb.Append(char.ToUpper(firstCharacter));
sb.Append(restOfString + " ");
}
}
return sb.ToString().Trim();
}
public static bool IsValidEmailAddress(this string str)
{
if (string.IsNullOrEmpty(str))
{
return false;
}
const string regexString = @"^[\w!#$%&'*+\-/=?\^_`{|}~]+(\.[\w!#$%&'*+\-/=?\^_`{|}~]+)*"
+ "@"
+ @"((([\-\w]+\.)+[a-zA-Z]{2,4})|(([0-9]{1,3}\.){3}[0-9]{1,3}))\z";
return Regex.IsMatch(str, regexString);
}
public static string ReplaceDashesWithSpaces(this string str)
{
var strSplit = str.Split('-');
var sBuilder = new StringBuilder();
for (var i = 0; i < strSplit.Length; i++)
{
if (i != (strSplit.Length - 1))
{
sBuilder.Append(strSplit[i] + " ");
}
else
{
sBuilder.Append(strSplit[i]);
}
}
return sBuilder.ToString();
}
public static string ReplaceSpacesWithDashes(this string str)
{
var strSplit = str.Split(' ');
var sBuilder = new StringBuilder();
for (var i = 0; i < strSplit.Length; i++)
{
if (i != (strSplit.Length - 1))
{
sBuilder.Append(strSplit[i] + "-");
}
else
{
sBuilder.Append(strSplit[i]);
}
}
return sBuilder.ToString();
}
public static string ReplaceBackSlashesWithForwardSlashes(this string str)
{
var strArray = str.Split('\\');
var sb = new StringBuilder();
foreach (var s in strArray)
{
sb.Append(s);
if (!string.Equals(s, strArray[strArray.Length - 1]))
{
sb.Append("/");
}
}
return sb.ToString();
}
/// <summary>
/// Parses a string for a boolean value (True or False). The parse is wrapped in a try/catch and if an exception is
/// thrown
/// false is returned.
/// </summary>
public static bool ParseBool(this string str)
{
try
{
if (string.Equals("1", str))
{
return true;
}
if (string.Equals("0", str))
{
return false;
}
var value = bool.Parse(str);
return value;
}
catch (Exception)
{
return false;
}
}
public static string ConvertToUnsecureString(this SecureString secureString)
{
if (secureString == null)
{
throw new ArgumentNullException(nameof(secureString));
}
var unmanagedString = IntPtr.Zero;
try
{
unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(secureString);
return Marshal.PtrToStringUni(unmanagedString);
}
finally
{
Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString);
}
}
/// <summary>
/// Parses a string and returns all the numbers as a string of numbers.
/// </summary>
public static string GetDigits(this string str)
{
return new string(str.Where(char.IsDigit).ToArray());
}
/// <summary>
/// Parses a string and returns all the numbers as a string of numbers with a decimal point placed in the
/// appropriate place to create a string that is able to be parsed by a decimal type.
/// </summary>
/// <param name="this">The string to parse</param>
/// <param name="decimalPlaces">Number of decimal places to indicate</param>
public static string GetDecimalDigits(this string @this, int decimalPlaces)
{
var digits = new string(@this.Where(char.IsDigit).ToArray());
var digitsLength = digits.Length;
var sb = new StringBuilder();
if (digitsLength < decimalPlaces)
{
for (var i = 0; i < decimalPlaces - digitsLength; i++)
{
sb.Append("0");
}
sb.Append(digits);
sb.Insert(0, ".");
sb.Insert(0, "0");
}
else
{
sb.Append(digits);
sb.Insert(digitsLength - decimalPlaces, ".");
}
var result = sb.ToString();
return result;
}
/// <summary>
/// Extracts the decimal number from the string by looking for the last decimal point and any digits.
/// </summary>
public static string FindDecimalNumber(this string @this)
{
var digitsWithPeriod = new string(@this.Where(c => char.IsDigit(c) || c == '.').ToArray());
var lastPeriodIndex = digitsWithPeriod.LastIndexOf('.');
var sb = new StringBuilder();
for (var i = 0; i < digitsWithPeriod.Length; i++)
{
var d = digitsWithPeriod[i];
if (d != '.' || i == lastPeriodIndex)
{
sb.Append(d);
}
}
return sb.ToString();
}
/// <summary>
/// Appends the given value onto the end of the string and returns a new string.
/// </summary>
/// <param name="this">String to which the appendedValue is being appended</param>
/// <param name="appendedValue">Value to append</param>
/// <returns></returns>
public static string Append(this string @this, string appendedValue)
{
if (string.IsNullOrEmpty(appendedValue))
return @this;
var sb = new StringBuilder();
sb.Append(@this);
sb.Append(appendedValue);
return sb.ToString();
}
}
}
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace System
{
[TestClass]
public class StringExtensionsTests
{
[TestMethod]
public void String_Should_Be_NullOrEmpty()
{
const string stringEmpty = "";
const string stringNull = null;
const string stringWhitespace = " ";
Assert.IsTrue(stringEmpty.IsNullOrEmpty());
Assert.IsTrue(stringNull.IsNullOrEmpty());
Assert.IsTrue(!stringWhitespace.IsNullOrEmpty());
}
[TestMethod]
public void String_Should_Be_NullOrWhitespace()
{
const string stringEmpty = "";
const string stringNull = null;
const string stringWhitespace = " ";
Assert.IsTrue(stringEmpty.IsNullOrWhiteSpace());
Assert.IsTrue(stringNull.IsNullOrWhiteSpace());
Assert.IsTrue(stringWhitespace.IsNullOrWhiteSpace());
}
[TestMethod]
public void String_Should_Return_Zero_For_Non_Integer()
{
const string stringWithNumber = "abc 12334";
const string stringNull = null;
const string stringWhitespace = "@ ";
Assert.AreEqual(stringWithNumber.AsInt(), 12334);
Assert.IsTrue(stringNull.AsInt() == 0);
Assert.IsTrue(stringWhitespace.AsInt() == 0);
}
[TestMethod]
public void String_Should_Return_Zero_For_Non_Decimal()
{
const string stringWithNumber = "abc 12.334";
const string stringNull = null;
const string stringWhitespace = "@ ";
const string stringDecimal = "12.334";
Assert.AreEqual(stringWithNumber.AsDecimal(), 0);
Assert.AreEqual(stringDecimal.AsDecimal(), 12.334m);
Assert.IsTrue(stringNull.AsDecimal() == 0);
Assert.IsTrue(stringWhitespace.AsDecimal() == 0);
}
[TestMethod]
public void String_Should_Return_Truncated_String_With_Elipsis_When_Exceeding_Max_Length()
{
const string paragraph = "Try-hard chartreuse craft beer four loko you probably haven't heard of them deep v. Kinfolk hella master cleanse taxidermy. Thundercats subway tile health goth, sustainable four dollar toast air plant celiac synth quinoa occupy. Iceland biodiesel truffaut, lumbersexual humblebrag lo-fi tote bag keytar street art. Gastropub gluten-free quinoa tacos, swag leggings vexillologist pop-up air plant 90's food truck lyft fixie dreamcatcher skateboard. La croix four dollar toast ugh put a bird on it, vinyl pok pok marfa pabst sartorial snackwave selvage succulents brooklyn lyft lomo. Sustainable four loko small batch, banh mi master cleanse pinterest gastropub butcher meggings cold-pressed fixie.";
const string expectedResult = "Try-hard chartreuse craft beer four loko you probably haven'...";
const int maxLength = 60;
Assert.AreEqual(paragraph.FirstXChars(maxLength), expectedResult);
}
[TestMethod]
public void String_Should_Return_Same_Value_When_Not_Exceeding_Max_Length()
{
const string paragraph = "Try-hard chartreuse craft beer four loko you probably";
const int maxLength = 60;
Assert.AreEqual(paragraph.FirstXChars(maxLength), paragraph);
}
[TestMethod]
public void String_Should_Return_Space_Between_Pascal_Case_Words()
{
const string input = "ThisIsAPascalCasedPhrase";
const string expected = "This Is A Pascal Cased Phrase";
Assert.AreEqual(input.AddSpaceBetweenPascalCase(), expected);
}
[TestMethod]
public void String_Should_Split_On_Upper_Case_Characters()
{
const string input = "ThisIsPascalCased Hello";
var expected = new[] {"This", "Is", "Pascal", "Cased", "Hello"};
var evaluated = input.SplitByUpperCase();
Assert.AreEqual(evaluated[0], expected[0]);
Assert.AreEqual(evaluated[1], expected[1]);
Assert.AreEqual(evaluated[2], expected[2]);
Assert.AreEqual(evaluated[3], expected[3]);
Assert.AreEqual(evaluated[4], expected[4]);
}
[TestMethod]
public void String_Should_Convert_Phrase_To_PascalCase()
{
const string input = "This is not pascal cased hello";
const string expected = "ThisIsNotPascalCasedHello";
var evaluated = input.ToPascalCase();
Assert.AreEqual(evaluated, expected);
}
[TestMethod]
public void String_Should_Be_Converted_To_Title_Case()
{
const string lowerCaseString = "this string started as lower case";
const string titleCaseString = "This String Started As Lower Case";
var titleCase = lowerCaseString.ToTitleCase();
Assert.AreEqual(titleCaseString, titleCase);
}
[TestMethod]
public void String_Should_Be_Converted_To_Title_Case_And_Extra_Spaces_Removed()
{
const string givenString = "5555 lowland RD DR plains 7 ";
const string expected = "5555 Lowland RD DR Plains 7";
var titleCase = givenString.ToTitleCase();
Assert.AreEqual(expected, titleCase, "The title case did not remove extra spaces");
}
[TestMethod]
public void Value_Should_Be_Appended_To_String()
{
const string givenString = "5555 Lowland RD Plains";
const string expected = "5555 Lowland RD Plains 8";
var actual = givenString.Append(" 8");
Assert.AreEqual(expected, actual);
}
[TestMethod]
public void Space_Should_Be_Appended_To_String()
{
const string givenString = "5555 Lowland RD Plains";
const string expected = "5555 Lowland RD Plains ";
var actual = givenString.Append(" ");
Assert.AreEqual(expected, actual);
}
[TestMethod]
public void GetDigits_Should_Return_Only_Numbers()
{
const string testString = "abc.$, space #* 1 sx 2 bbc3 ss45 () 6";
const string expected = "123456";
var actual = testString.GetDigits();
Assert.AreEqual(expected, actual);
}
[TestMethod]
public void GetDecimalDigits_Should_Return_Number_With_Correct_Decimal_Places()
{
const string testString = "abc.$, space #* 1 sx 2 bbc3 ss45 () 6";
const string expected = "1234.56";
var actual = testString.GetDecimalDigits(2);
Assert.AreEqual(expected, actual);
}
[TestMethod]
public void GetDecimalDigits_Should_Return_Padded_Number_With_Correct_Decimal_Places()
{
const string testString = "abc.$, space #* 1 sx 2 bbc3 ss45 () 6";
const string expected = "0.000000123456";
var actual = testString.GetDecimalDigits(12);
Assert.AreEqual(expected, actual);
}
[TestMethod]
public void FindDecimalNumber_Should_Return_Number_String_With_Correct_Decimal_Places()
{
const string testString = "abc.$, space #* 1 sx 2 bbc3 ss4.5 () 6";
const string expected = "1234.56";
var actual = testString.FindDecimalNumber();
Assert.AreEqual(expected, actual);
}
[TestMethod]
public void FindDecimalNumber_Should_Return_Number_String_With_Zero_Decimal_Places()
{
const string testString = "abc$, space #* 1 sx 2 bbc3 ss45 () 6";
const string expected = "123456";
var actual = testString.FindDecimalNumber();
Assert.AreEqual(expected, actual);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment