Last active
June 28, 2016 18:27
-
-
Save aarshtalati/bc32f979038833a685adac8e3b94a7f4 to your computer and use it in GitHub Desktop.
Some useful C# helper and extension methods, fresh from the grill
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.ComponentModel; | |
using System.Data; | |
using System.Linq; | |
using System.Reflection; | |
using System.Text; | |
using System.Xml; | |
// The indentation settings in the Gist do not seem to be listening to me. size: 4, mode: tabs, (w)rap: Atlanta hip hop | |
namespace WordPress.WildClick.Helpers | |
{ | |
public class Helper | |
{ | |
static public string BeautifyXml(string rawXmlString) | |
{ | |
var sb = new StringBuilder(); | |
XmlWriterSettings settings = new XmlWriterSettings(); | |
settings.Indent = true; | |
settings.IndentChars = " "; | |
settings.NewLineChars = "\r\n"; | |
settings.NewLineHandling = NewLineHandling.Replace; | |
using (XmlWriter writer = XmlWriter.Create(sb, settings)) | |
{ | |
XmlDocument xDoc = new XmlDocument(); | |
xDoc.LoadXml(rawXmlString); | |
xDoc.Save(writer); | |
} | |
return sb.ToString(); | |
} | |
} | |
public static class ExtensionMethods | |
{ | |
public static IEnumerable<T> Select<T>(this IDataReader reader, Func<IDataReader, T> projection) | |
{ | |
while (reader.Read()) | |
{ | |
yield return projection(reader); | |
} | |
} | |
/// <summary> | |
/// Return null-able type | |
/// </summary> | |
/// <typeparam name="T"></typeparam> | |
/// <param name="s"></param> | |
/// <returns></returns> | |
public static Nullable<T> ToNullable<T>(this string s) where T : struct | |
{ | |
Nullable<T> result = new Nullable<T>(); | |
try | |
{ | |
if (!string.IsNullOrEmpty(s) && s.Trim().Length > 0) | |
{ | |
TypeConverter conv = TypeDescriptor.GetConverter(typeof(T)); | |
result = (T)conv.ConvertFrom(s); | |
} | |
} | |
catch { } // Code sanitized, judge me anyway if you want | |
return result; | |
} | |
public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector) | |
{ | |
HashSet<TKey> seenKeys = new HashSet<TKey>(); | |
foreach (TSource element in source) | |
{ | |
if (seenKeys.Add(keySelector(element))) | |
{ | |
yield return element; | |
} | |
} | |
} | |
/// <summary> | |
/// Checks if a given string contains any of the substrings in the passed array of strings. | |
/// </summary> | |
/// <param name="theString"></param> | |
/// <param name="substrings"></param> | |
/// /// <param name="comparision"></param> | |
/// <returns>System.Boolean</returns> | |
public static bool ContainsAny(this string theString, string[] substrings, StringComparison comparision = StringComparison.Ordinal) | |
{ | |
if (theString == null || (theString.Length == 0 && !substrings.Contains(""))) | |
{ | |
return false; | |
} | |
string substring; | |
for (int i = 0, N = substrings.Length; i < N; i++) | |
{ | |
substring = substrings[i]; | |
if (theString.IndexOf(substring, comparision) >= 0) | |
{ | |
return true; | |
} | |
} | |
return false; | |
} | |
/// <summary> | |
/// exception free way of getting the substring | |
/// </summary> | |
/// <param name="theString"></param> | |
/// <param name="length"></param> | |
/// <returns>System.string</returns> | |
public static string SubString(this string theString, int length) | |
{ | |
return SubString(theString, 0, length); | |
} | |
/// <summary> | |
/// exception free way of getting the substring | |
/// </summary> | |
/// <param name="theString"></param> | |
/// <param name="length"></param> | |
/// <param name="startIndex"></param> | |
/// <returns>System.string</returns> | |
public static string SubString(this string theString, int startIndex, int length) | |
{ | |
if (theString == null || theString.Length == 0) | |
{ | |
return ""; | |
} | |
startIndex = Math.Abs(startIndex); | |
length = Math.Abs(length); | |
if (startIndex > theString.Length) | |
{ | |
return ""; | |
} | |
string substring = ""; | |
if (theString.Length < length && startIndex == 0) | |
{ | |
return theString; | |
} | |
length = Math.Min(startIndex + length, theString.Length) - startIndex; | |
substring = theString.Substring(startIndex, length); | |
return substring; | |
} | |
/// <summary> | |
/// Chops the string by making sure that the words does not cut off | |
/// </summary> | |
/// <param name="theString"></param> | |
/// <param name="start"></param> | |
/// <param name="length"></param> | |
/// <returns>System.string</returns> | |
public static string ChopString(this string theString, int start, int length) | |
{ | |
if (theString == null || theString.Length == 0) | |
{ | |
return ""; | |
} | |
theString = theString.Trim(); | |
while (start != 0 && start < theString.Length && theString[start - 1] != ' ') | |
{ | |
start++; | |
} | |
if (start > theString.Length) | |
{ | |
return ""; | |
} | |
theString = theString.Substring(start); | |
string[] words = theString.Split(new char[] { ' ' }); | |
words = words.Where(w => w != "").ToArray<string>(); | |
if (words.Length > 0) | |
{ | |
if (words[0].Length == length) | |
{ | |
return words[0]; | |
} | |
} | |
StringBuilder sbChoppedString = new StringBuilder(); | |
for (int i = 0; i < words.Length && (sbChoppedString.Length + words[i].Length + 1) <= length; i++) | |
{ | |
sbChoppedString.Append(words[i] + " "); | |
} | |
if (sbChoppedString.Length > 0) | |
{ | |
sbChoppedString.Length--; | |
} | |
return sbChoppedString.ToString().TrimEnd(); | |
} | |
/// <summary> | |
/// ChopString v2.0. This version let's you specify the string, which separates two words | |
/// </summary> | |
/// <param name="theString"></param> | |
/// <param name="start"></param> | |
/// <param name="length"></param> | |
/// <param name="delimiterString"></param> | |
/// <returns></returns> | |
public static string ChopString2(this string theString, int start, int length, string delimiterString = " ") | |
{ | |
if (theString == null || theString.Length == 0) | |
{ | |
return ""; | |
} | |
theString = theString.Trim(); | |
while (start != 0 && start < theString.Length && theString[start - 1] != ' ') | |
{ | |
start++; | |
} | |
if (start > theString.Length) | |
{ | |
return ""; | |
} | |
theString = theString.Substring(start); | |
if (delimiterString == null) | |
{ | |
delimiterString = " "; | |
} | |
char[] delimiter = delimiterString.ToCharArray(); | |
string[] words = theString.Split(delimiter); | |
words = words.Where(w => w != "").ToArray<string>(); | |
if (words.Length > 0) | |
{ | |
if (words[0].Length == length) | |
return words[0]; | |
} | |
StringBuilder sbChoppedString = new StringBuilder(); | |
for (int i = 0; i < words.Length && (sbChoppedString.Length + words[i].Length + 1) <= length; i++) | |
{ | |
sbChoppedString.Append(words[i] + delimiterString); | |
} | |
if (sbChoppedString.Length > 0) | |
{ | |
sbChoppedString.Length -= delimiterString.Length; | |
} | |
return sbChoppedString.ToString().TrimEnd(); | |
} | |
/// <summary> | |
/// Breaks a long string into specified number of smaller string chunk with or without breaking the words | |
/// </summary> | |
/// <param name="theString">The long string which you wanna break down into N chunks of specified width</param> | |
/// <param name="chunkLength">The desired width of each string chunk</param> | |
/// <param name="count">Count of maximum string chunks ( ignores the rest )</param> | |
/// <returns></returns> | |
public static IEnumerable<string> WrapLine(this string theString, int chunkLength) | |
public static IEnumerable<string> WrapLine(this string theString, int chunkLength, int version = 1) | |
{ | |
// Syntactic Sugar for calling the actual extension method with default parameters | |
return WrapLine(theString, chunkLength, (int?)null, false, true); | |
// syntactic sugar for calling the actual extension method with default parameters | |
return WrapLine(theString, chunkLength, (int?)null, false, true, version: version); | |
} | |
/// <summary> | |
/// Breaks a long string into specified number of smaller string chunk with or without breaking the words + more options | |
/// </summary> | |
/// <param name="theString">The long string which you wanna break down into N chunks of specified width</param> | |
/// <param name="chunkLength">The desired width of each string chunk</param> | |
/// <param name="count">Count of maximum string chunks, (int?)Null for all( ignores the rest )</param> | |
/// <param name="breakWord">Flag to specify whether to let the last word break on each segment if it exceeds the specified segment length</param> | |
/// <param name="trimChunks">Trim the white space from both the ends of all string chunk</param> | |
/// <param name="truncateLastLine">If set, and iff count has been specified, the last string chunk might break word to fit in max data</param> | |
/// <returns></returns> | |
public static IEnumerable<string> WrapLine(this string theString, int chunkLength, int? count, bool breakWord = false, bool trimChunks = true, bool truncateLastLine = false) | |
public static IEnumerable<string> WrapLine(this string theString, int chunkLength, int? count, bool breakWord = false, bool trimChunks = true, bool truncateLastLine = false, int version = 1) | |
{ | |
// Simon, Go Back ! | |
if (theString == null || theString.Length == 0) | |
{ | |
return Enumerable.Empty<string>(); | |
} | |
if (count.HasValue && count.Value <= 0) | |
{ | |
return Enumerable.Empty<string>(); | |
} | |
// if yer chunkLength is smaller than the longest word then - can't fit that in, fella ! | |
int longestWordLength = theString | |
.Split(' ') | |
.Aggregate("", (max, current) => max.Length > current.Length ? max : current) | |
.Length; | |
if (chunkLength < longestWordLength) | |
{ | |
return Enumerable.Empty<string>(); | |
} | |
StringBuilder sbTheString = new StringBuilder(theString.Replace(" ", " ")); | |
List<string> carryForwards = new List<string>(); | |
string lastString = null, currentString = null; | |
bool flag = false; | |
if (!breakWord) | |
{ | |
do | |
{ | |
if (count.HasValue && carryForwards.Count == count) | |
{ | |
break; | |
} | |
while (sbTheString.Length > 0 && sbTheString[0] == ' ') | |
{ | |
sbTheString.Remove(0, 1); | |
} | |
if (truncateLastLine && count.HasValue && (carryForwards.Count == count - 1)) | |
{ | |
currentString = sbTheString.ToString().SubString(flag ? 1 : 0, chunkLength); | |
} | |
else | |
{ | |
currentString = sbTheString.ToString().ChopString(flag ? 1 : 0, chunkLength); | |
if (version == 2) | |
{ | |
currentString = sbTheString.ToString().ChopString2(flag ? 1 : 0, chunkLength); | |
} | |
else | |
{ | |
currentString = sbTheString.ToString().ChopString(flag ? 1 : 0, chunkLength); | |
} | |
} | |
flag = carryForwards.Count > 0 | |
&& (lastString != null && lastString.Length > 0) | |
&& (currentString != null && currentString.Length > 0) | |
&& (lastString.Last() == currentString[0]) | |
&& ((theString.IndexOf(lastString) + lastString.Length) < theString.Length) | |
&& (theString[theString.IndexOf(lastString) + lastString.Length] == ' ' && theString[theString.IndexOf(lastString) + lastString.Length - 1] == currentString[0]); | |
if (flag) | |
{ | |
currentString = currentString.Substring(1); | |
} | |
carryForwards.Add(currentString); | |
lastString = currentString; | |
sbTheString.Remove(0, carryForwards.Last().Length); | |
} | |
while (sbTheString.Length > 0); | |
} | |
else | |
{ | |
do | |
{ | |
carryForwards.Add(sbTheString.ToString().Substring(0, Math.Min(chunkLength, sbTheString.Length))); | |
sbTheString.Remove(0, carryForwards.Last().Length); | |
} | |
while (sbTheString.Length > 0); | |
} | |
carryForwards = carryForwards.Where(c => c != "").ToList(); | |
// shave those hairs ! | |
// shave yer beard ! | |
if (trimChunks) | |
{ | |
carryForwards = carryForwards.Select(c => c = c.Trim()).ToList(); | |
} | |
return carryForwards; | |
} | |
/// <summary> | |
/// Safely inserts a string at the end with making sure that the total length does not exceed the specified max length | |
/// </summary> | |
/// <param name="theString"></param> | |
/// <param name="value">string to append safely</param> | |
/// <param name="maxLength">max length</param> | |
/// <returns></returns> | |
public static string SafeAppend(this string theString, string value, int maxLength) | |
{ | |
if (theString == null || theString.Length == 0) | |
{ | |
return ""; | |
} | |
if (value == null || value.Length == 0) | |
{ | |
return theString.Substring(0, Math.Min(maxLength, theString.Length)); | |
} | |
if (theString.Length + value.Length <= maxLength) | |
{ | |
return (theString + value); | |
} | |
theString = theString += value; | |
return theString.Substring(0, Math.Min(theString.Length, maxLength)); | |
} | |
public static string CompleteAppend(this string theString, string value, int maxLength) | |
{ | |
int numberOfAvailableSpaces = maxLength - theString.Length; | |
int numberOfCharactersToRemove = (value.Length + 1) - numberOfAvailableSpaces; | |
string newString; | |
if (numberOfCharactersToRemove > -1) | |
{ | |
newString = theString.Remove(theString.Length - numberOfCharactersToRemove); | |
} | |
else | |
{ | |
newString = theString; | |
} | |
return String.Format("{0} {1}", newString, value); | |
} | |
/// <summary> | |
/// returns index of an item in the list regardless of the case | |
/// </summary> | |
/// <param name="list"></param> | |
/// <param name="item"></param> | |
/// <returns>System.Int32</returns> | |
public static int IndexOfCaseInsensitive(this List<string> list, string item) | |
{ | |
int index = -1; | |
index = list.FindIndex(p => string.Equals(p, item, StringComparison.OrdinalIgnoreCase)); | |
return (index == -1 ? list.Count : index); | |
} | |
/// <summary> | |
/// returns string with only numeric characters, filtering everything else | |
/// </summary> | |
/// <param name="theString"></param> | |
/// <returns></returns> | |
public static string OnlyNumeric(this string theString, bool keepSpace = true) | |
{ | |
if (theString == null || theString.Length == 0) | |
{ | |
return ""; | |
} | |
StringBuilder sb = new StringBuilder(); | |
foreach (var c in theString) | |
{ | |
if ((c == ' ' && keepSpace) || (c >= '0' && c <= '9')) | |
{ | |
sb.Append(c); | |
} | |
} | |
return sb.Length == 0 ? "" : sb.ToString().Replace(" ", " ").Trim(new char[] { ' ' }); | |
} | |
/// <summary> | |
/// returns string with only alphabetical characters, filtering everything else | |
/// </summary> | |
/// <param name="theString"></param> | |
/// <returns></returns> | |
public static string OnlyAlpha(this string theString, bool keepSpace = true) | |
{ | |
if (theString == null || theString.Length == 0) | |
{ | |
return ""; | |
} | |
StringBuilder sb = new StringBuilder(); | |
foreach (var c in theString) | |
{ | |
if ((c == ' ' && keepSpace) || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) | |
{ | |
sb.Append(c); | |
} | |
} | |
return sb.Length == 0 ? "" : sb.ToString().Replace(" ", " ").Trim(new char[] { ' ' }); | |
} | |
/// <summary> | |
/// returns string with only Alpha-Numeric characters, filtering everything else | |
/// </summary> | |
/// <param name="theString"></param> | |
/// <returns></returns> | |
public static string OnlyAlphaNumeric(this string theString, bool keepSpace = true) | |
{ | |
if (theString == null || theString.Length == 0) | |
{ | |
return ""; | |
} | |
StringBuilder sb = new StringBuilder(); | |
foreach (var c in theString) | |
{ | |
if ((c == ' ' && keepSpace) || (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) | |
{ | |
sb.Append(c); | |
} | |
} | |
return sb.Length == 0 ? "" : sb.ToString().Replace(" ", " ").Trim(new char[] { ' ' }); | |
} | |
/// <summary> | |
/// Finds all occurrences of substrings specified in an array and replaces all those substrings with a specified value. Returns null for null or empty string. | |
/// </summary> | |
/// <param name="theString"></param> | |
/// <param name="subStringsToReplace">All targeted substrings (null and empty strings are ignored), returns original string back if not specified / null</param> | |
/// <param name="newValue">String be replaced for targeted substrings, Default is "" and if set to null the original string is bounced back</param> | |
/// <returns></returns> | |
public static string ReplaceAll(this string theString, string[] subStringsToReplace = null, string newValue = "") | |
{ | |
if (theString == null || theString.Length == 0) | |
{ | |
return ""; | |
} | |
if (subStringsToReplace == null || subStringsToReplace.Length == 0 || newValue == null) | |
{ | |
return theString; | |
} | |
if (!theString.ContainsAny(subStringsToReplace)) | |
{ | |
return theString; | |
} | |
var stringsToReplace = subStringsToReplace | |
.Distinct(StringComparer.OrdinalIgnoreCase) | |
.ToList<string>() | |
.Where(x => x != null || x.Length > 0); | |
foreach (var oldValue in stringsToReplace) | |
{ | |
StringBuilder sb; | |
var index = theString.IndexOf(oldValue, 0, theString.Length, StringComparison.OrdinalIgnoreCase); | |
if (index >= 0) | |
{ | |
// Seems like string.Replace should have an overload that takes a StringComparison argument. Since it doesn't I am using following | |
sb = new StringBuilder(); | |
int previousIndex = 0; | |
while (index != -1) | |
{ | |
sb.Append(theString.Substring(previousIndex, index - previousIndex)); | |
sb.Append(newValue); | |
index += oldValue.Length; | |
previousIndex = index; | |
index = theString.IndexOf(oldValue, index, StringComparison.OrdinalIgnoreCase); | |
} | |
sb.Append(theString.Substring(previousIndex)); | |
theString = sb.ToString(); | |
} | |
} | |
return theString; | |
} | |
/// <summary> | |
/// Get CSV | |
/// </summary> | |
/// <typeparam name="T">Generic</typeparam> | |
/// <param name="list">Generic List</param> | |
/// <param name="withHeaders">true, if returning with header names; otherwise, false</param> | |
/// <returns>CSV as a String</returns> | |
public static string GetCSV<T>(this List<T> list, bool withHeaders = false) | |
{ | |
StringBuilder sb = new StringBuilder(); | |
//Get the properties for type T for the headers | |
PropertyInfo[] propertyInfos = typeof(T).GetProperties(); | |
if (withHeaders) | |
{ | |
for (int i = 0; i <= propertyInfos.Length - 1; i++) | |
{ | |
sb.Append(propertyInfos[i].Name); | |
if (i < propertyInfos.Length - 1) | |
{ | |
sb.Append("^"); | |
} | |
} | |
sb.AppendLine(); | |
} | |
//Loop through the collection, then the properties and add the values | |
for (int i = 0; i <= list.Count - 1; i++) | |
{ | |
T item = list[i]; | |
for (int j = 0; j <= propertyInfos.Length - 1; j++) | |
{ | |
object o = item.GetType().GetProperty(propertyInfos[j].Name).GetValue(item, null); | |
if (o != null) | |
{ | |
string value = o.ToString(); | |
////Check if the value contains a comma and place it in quotes if so | |
//if (value.Contains(",")) | |
//{ | |
// value = string.Concat("\"", value, "\""); | |
//} | |
//Replace any \r or \n special characters from a new line with a space | |
if (value.Contains("\r")) | |
{ | |
value = value.Replace("\r", " "); | |
} | |
if (value.Contains("\n")) | |
{ | |
value = value.Replace("\n", " "); | |
} | |
sb.Append(value); | |
} | |
if (j < propertyInfos.Length - 1) | |
{ | |
sb.Append("^"); | |
} | |
} | |
sb.AppendLine(); | |
} | |
return sb.ToString().TrimEnd(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment