//****************************************************************************************************** // StringExtensions.cs - Gbtc // // Copyright © 2012, Grid Protection Alliance. All Rights Reserved. // // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See // the NOTICE file distributed with this work for additional information regarding copyright ownership. // The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a copy of the License at: // // http://www.opensource.org/licenses/eclipse-1.0.php // // Unless agreed to in writing, the subject software distributed under the License is distributed on an // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the // License for the specific language governing permissions and limitations. // // Code Modification History: // ---------------------------------------------------------------------------------------------------- // 02/23/2003 - J. Ritchie Carroll // Generated original version of source code. // 01/24/2006 - J. Ritchie Carroll // Migrated 2.0 version of source code from 1.1 source (GSF.Shared.String). // 06/01/2006 - J. Ritchie Carroll // Added ParseBoolean function to parse strings representing booleans that may be numeric. // 07/07/2006 - J. Ritchie Carroll // Added GetStringSegments function to break a string up into smaller chunks for parsing. // and/or displaying. // 08/02/2007 - J. Ritchie Carroll // Added a CenterText method for centering strings in console applications or fixed width fonts. // 08/03/2007 - Pinal C. Patel // Modified the CenterText method to handle multiple lines. // 08/21/2007 - Darrell Zuercher // Edited code comments. // 09/25/2007 - J. Ritchie Carroll // Added TitleCase function to format a string with the first letter of each word capitalized. // 04/16/2008 - Pinal C. Patel // Made the keys of the string dictionary returned by ParseKeyValuePairs function case-insensitive. // Added JoinKeyValuePairs overloads that does the exact opposite of ParseKeyValuePairs. // 09/19/2008 - J. Ritchie Carroll // Converted to C# extensions. // 12/13/2008 - F. Russell Roberson // Generalized ParseBoolean to include "Y", and "T". // Added IndexOfRepeatedChar - Returns the index of the first character that is repeated. // Added Reverse - Reverses the order of characters in a string. // Added EnsureEnd - Ensures that a string ends with a specified char or string. // Added EnsureStart - Ensures that a string begins with a specified char or string. // Added IsNumeric - Test to see if a string only includes characters that can be interpreted as a number. // Added TrimWithEllipsisMiddle - Adds an ellipsis in the middle of a string as it is reduced to a specified length. // Added TrimWithEllipsisEnd - Trims a string to not exceed a fixed length and adds a ellipsis to string end. // 02/10/2009 - J. Ritchie Carroll // Added ConvertToType overloaded extensions. // 02/17/2009 - Josh L. Patterson // Edited Code Comments. // 09/14/2009 - Stephen C. Wills // Added new header and license agreement. // 01/11/2010 - Galen K. Riley // Bug fixes for unit tests: // ConvertToType - Fix to throw ArgumentNullException instead of NullReferenceException for null value // ConvertToType - Handling failed conversions better. Calling ConvertToType("\0") returns properly // JoinKeyValuePairs - Fix to throw ArgumentNullException instead of NullReferenceException // ReplaceCharacters - Fix to throw ArgumentNullException instead of NullReferenceException for null replacementCharacter // RemoveCharacters - Fix to throw ArgumentNullException instead of NullReferenceException for null characterTestFunction // ReplaceCrLfs - Fix to throw ArgumentNullException instead of NullReferenceException for null value // RegexDecode - Fix to throw ArgumentNullException instead of NullReferenceException for null value // 12/03/2010 - J. Ritchie Carroll // Modifed ParseKeyValuePairs such that it could handle nested pairs to any needed depth. // 12/05/2010 - Pinal C. Patel // Added an overload for ConvertToType() that takes CultureInfo as a parameter. // 12/07/2010 - Pinal C. Patel // Updated ConvertToType() to return the type default if passed in string is null or empty. // 01/04/2011 - J. Ritchie Carroll // Modified ConvertToType culture default to InvariantCulture for English style parsing defaults. // 01/14/2011 - J. Ritchie Carroll // Modified JoinKeyValuePairs to delineate values that contain nested key/value pair expressions // such that the generated expression can correctly parsed. // 03/23/2011 - J. Ritchie Carroll // Modified ParseKeyValuePairs to optionally ignore duplicate keys (default behavior now). // Removed overloads for ParseKeyValuePairs and JoinKeyValuePairs using optional parameters. // 08/02/2011 - Pinal C. Patel // Added RemoveInvalidFileNameCharacters() and ReplaceInvalidFileNameCharacters() methods. // 10/17/2012 - F Russell Robertson // Added QuoteWrap() method. // 12/14/2012 - Starlynn Danyelle Gilliam // Modified Header. // //****************************************************************************************************** using System; using System.Collections.Generic; using System.ComponentModel; using System.Globalization; using System.IO; using System.Text; using System.Text.RegularExpressions; namespace GSF { /// Defines extension functions related to string manipulation. public static class StringExtensions { /// /// Parses a string intended to represent a boolean value. /// /// String representing a boolean value. /// Parsed boolean value. /// /// This function, unlike Boolean.Parse, correctly parses a boolean value, even if the string value /// specified is a number (e.g., 0 or -1). Boolean.Parse expects a string to be represented as /// "True" or "False" (i.e., Boolean.TrueString or Boolean.FalseString respectively). /// public static bool ParseBoolean(this string value) { if (string.IsNullOrEmpty(value)) return false; value = value.Trim(); if (value.Length > 0) { // Try to parse string a number int iresult; if (int.TryParse(value, out iresult)) return (iresult != 0); // Try to parse string as a boolean bool bresult; if (bool.TryParse(value, out bresult)) return bresult; char test = value.ToUpper()[0]; return (test == 'T' || test == 'Y' ? true : false); } return false; } /// /// Converts this string into the specified type. /// /// to convert string to. /// Source string to convert to type. /// converted to specfied ; default value of specified type T if conversion fails. /// /// This function makes use of a to convert this to the specified type T, /// the best way to make sure can be converted back to its original type is to use the same /// to convert the original object to a ; see the /// method for an easy way to do this. /// public static T ConvertToType(this string value) { return ConvertToType(value, null); } /// /// Converts this string into the specified type. /// /// to convert string to. /// Source string to convert to type. /// to convert string to. /// converted to specfied ; default value of specified type T if conversion fails. /// /// This function makes use of a to convert this to the specified , /// the best way to make sure can be converted back to its original type is to use the same /// to convert the original object to a ; see the /// method for an easy way to do this. /// public static T ConvertToType(this string value, Type type) { return ConvertToType(value, type, null); } /// /// Converts this string into the specified type. /// /// to convert string to. /// Source string to convert to type. /// to convert string to. /// to use for the conversion. /// converted to specfied ; default value of specified type T if conversion fails. /// /// This function makes use of a to convert this to the specified , /// the best way to make sure can be converted back to its original type is to use the same /// to convert the original object to a ; see the /// method for an easy way to do this. /// public static T ConvertToType(this string value, Type type, CultureInfo culture) { // Don't proceed further if string is empty. if (string.IsNullOrEmpty(value)) return default(T); // Initialize return type if not specified. if ((object)type == null) type = typeof(T); // Initialize culture info if not specified. if ((object)culture == null) culture = CultureInfo.InvariantCulture; try { // Handle booleans as a special case to allow numeric entries as well as true/false if (type.IsAssignableFrom(typeof(bool))) return (T)((object)value.ParseBoolean()); // This is faster for native types than using type converter... if (type.IsAssignableFrom(typeof(IConvertible))) return (T)Convert.ChangeType(value, type, culture); // Handle objects that have type converters (e.g., Enum, Color, Point, etc.) TypeConverter converter = TypeDescriptor.GetConverter(type); return (T)converter.ConvertFromString(null, culture, value); } catch { return default(T); } } /// /// Turns source string into an array of string segements - each with a set maximum width - for parsing or displaying. /// /// Input string to break up into segements. /// Maximum size of returned segment. /// Array of string segments as parsed from source string. /// Returns a single element array with an empty string if source string is null or empty. public static string[] GetSegments(this string value, int segmentSize) { if (segmentSize <= 0) throw new ArgumentOutOfRangeException("segmentSize", "segmentSize must be greater than zero."); if (string.IsNullOrEmpty(value)) return new[] { "" }; int totalSegments = (int)Math.Ceiling(value.Length / (double)segmentSize); string[] segments = new string[totalSegments]; for (int x = 0; x < segments.Length; x++) { if (x * segmentSize + segmentSize >= value.Length) segments[x] = value.Substring(x * segmentSize); else segments[x] = value.Substring(x * segmentSize, segmentSize); } return segments; } /// /// Combines a dictionary of key-value pairs in to a string. /// /// Dictionary of key-value pairs. /// Character that delimits one key-value pair from another (eg. ';'). /// Character that delimits a key from its value (eg. '='). /// Optional character that marks the start of a value such that value could contain other /// or characters (e.g., "{"). /// Optional character that marks the end of a value such that value could contain other /// or characters (e.g., "}"). /// A string of key-value pairs. /// /// Values will be escaped within and /// to contain nested key/value pair expressions like the following: normalKVP=-1; nestedKVP={p1=true; p2=0.001}, /// when either the or are detected in the /// value of the key/value pair. /// public static string JoinKeyValuePairs(this Dictionary pairs, char parameterDelimeter = ';', char keyValueDelimeter = '=', char startValueDelimeter = '{', char endValueDelimeter = '}') { // if ((object)pairs == null) throw new ArgumentNullException("pairs"); // char[] delimiters = { parameterDelimeter, keyValueDelimeter }; StringBuilder result = new StringBuilder(); string value; foreach (string key in pairs.Keys) { value = pairs[key]; if (value.IndexOfAny(delimiters) >= 0) value = startValueDelimeter + value + endValueDelimeter; result.AppendFormat("{0}{1}{2}{3}", key, keyValueDelimeter, value, parameterDelimeter); } return result.ToString(); } /// /// Parses key/value pair expressions from a string. Parameter pairs are delimited by /// and multiple pairs separated by . Supports encapsulated nested expressions. /// /// String containing key/value pair expressions to parse. /// Character that delimits one key/value pair from another. /// Character that delimits key from value. /// Optional character that marks the start of a value such that value could contain other /// or characters. /// Optional character that marks the end of a value such that value could contain other /// or characters. /// Flag determines whether duplicates are ignored. If flag is set to false an /// will be thrown when all key parameters are not unique. /// Dictionary of key/value pairs. /// /// /// Parses a string containing key/value pair expressions (e.g., "localPort=5001; transportProtocol=UDP; interface=0.0.0.0"). /// This method treats all "keys" as case-insensitive. Nesting of key/value pair expressions is allowed by encapsulating the /// value using the and values (e.g., /// "dataChannel={Port=-1;Clients=localhost:8800}; commandChannel={Port=8900}; dataFormat=FloatingPoint;"). There must be one /// for each encountered in the value or a /// will be thrown. Multiple levels of nesting is supported. If the /// flag is set to false an will be thrown when all key parameters are not unique. Note /// that keys within nested expressions are considered separate key/value pair strings and are not considered when checking /// for duplicate keys. /// /// /// value is null. /// All delimeters must be unique -or- all keys must be unique when /// is set to false. /// Total nested key/value value pair expressions are mismatched -or- encountered /// before . public static Dictionary ParseKeyValuePairs(this string value, char parameterDelimeter = ';', char keyValueDelimeter = '=', char startValueDelimeter = '{', char endValueDelimeter = '}', bool ignoreDuplicateKeys = true) { if (value == (string)null) throw new ArgumentNullException("value"); if (parameterDelimeter == keyValueDelimeter || parameterDelimeter == startValueDelimeter || parameterDelimeter == endValueDelimeter || keyValueDelimeter == startValueDelimeter || keyValueDelimeter == endValueDelimeter || startValueDelimeter == endValueDelimeter) throw new ArgumentException("All delimeters must be unique"); Dictionary keyValuePairs = new Dictionary(StringComparer.CurrentCultureIgnoreCase); StringBuilder escapedValue = new StringBuilder(); string escapedParameterDelimeter = parameterDelimeter.RegexEncode(); string escapedKeyValueDelimeter = keyValueDelimeter.RegexEncode(); string escapedStartValueDelimeter = startValueDelimeter.RegexEncode(); string escapedEndValueDelimeter = endValueDelimeter.RegexEncode(); string[] elements; string key, unescapedValue; bool valueEscaped = false; int delimeterDepth = 0; char character; // Escape any parameter or key/value delimeters within tagged value sequences // For example, the following string: // "normalKVP=-1; nestedKVP={p1=true; p2=false}") // would be encoded as: // "normalKVP=-1; nestedKVP=p1\\u003dtrue\\u003b p2\\u003dfalse") for (int x = 0; x < value.Length; x++) { character = value[x]; if (character == startValueDelimeter) { if (!valueEscaped) { valueEscaped = true; continue; // Don't add tag start delimeter to final value } // Handle nested delimeters delimeterDepth++; } if (character == endValueDelimeter) { if (valueEscaped) { if (delimeterDepth > 0) { // Handle nested delimeters delimeterDepth--; } else { valueEscaped = false; continue; // Don't add tag stop delimeter to final value } } else { throw new FormatException(string.Format("Failed to parse key/value pairs: invalid delimeter mismatch. Encountered end value delimeter \'{0}\' before start value delimeter \'{1}\'.", endValueDelimeter, startValueDelimeter)); } } if (valueEscaped) { // Escape any delimeter characters inside nested key/value pair if (character == parameterDelimeter) escapedValue.Append(escapedParameterDelimeter); else if (character == keyValueDelimeter) escapedValue.Append(escapedKeyValueDelimeter); else if (character == startValueDelimeter) escapedValue.Append(escapedStartValueDelimeter); else if (character == endValueDelimeter) escapedValue.Append(escapedEndValueDelimeter); else escapedValue.Append(character); } else { escapedValue.Append(character); } } if (delimeterDepth != 0 || valueEscaped) { // If value is still escaped, tagged expression was not terminated if (valueEscaped) delimeterDepth = 1; throw new FormatException(string.Format("Failed to parse key/value pairs: invalid delimeter mismatch. Encountered more {0} than {1}.", delimeterDepth > 0 ? "start value delimeters \'" + startValueDelimeter + "\'" : "end value delimeters \'" + endValueDelimeter + "\'", delimeterDepth < 0 ? "start value delimeters \'" + startValueDelimeter + "\'" : "end value delimeters \'" + endValueDelimeter + "\'")); } // Parse key/value pairs from escaped value foreach (string parameter in escapedValue.ToString().Split(parameterDelimeter)) { // Parse out parameter's key/value elements elements = parameter.Split(keyValueDelimeter); if (elements.Length == 2) { // Get key expression key = elements[0].Trim(); // Get unescaped value expression unescapedValue = elements[1].Trim(). Replace(escapedParameterDelimeter, parameterDelimeter.ToString()). Replace(escapedKeyValueDelimeter, keyValueDelimeter.ToString()). Replace(escapedStartValueDelimeter, startValueDelimeter.ToString()). Replace(escapedEndValueDelimeter, endValueDelimeter.ToString()); // Add key/value pair to dictionary if (ignoreDuplicateKeys) { // Add or replace key elements with unescaped value keyValuePairs[key] = unescapedValue; } else { // Add key elements with unescaped value throwing an exception for encountered duplicate keys if (keyValuePairs.ContainsKey(key)) throw new ArgumentException(string.Format("Failed to parse key/value pairs: duplicate key encountered. Key \"{0}\" is not unique within the string: \"{1}\"", key, value)); keyValuePairs.Add(key, unescapedValue); } } } return keyValuePairs; } /// /// Ensures parameter is not an empty or null string. Returns a single space if test value is empty. /// /// Value to test for null or empty. /// A non-empty string. public static string NotEmpty(this string testValue) { return testValue.NotEmpty(" "); } /// /// Ensures parameter is not an empty or null string. /// /// Value to test for null or empty. /// Value to return if testValue is null or empty. /// A non-empty string. public static string NotEmpty(this string testValue, string nonEmptyReturnValue) { if (string.IsNullOrEmpty(nonEmptyReturnValue)) throw new ArgumentException("nonEmptyReturnValue cannot be null or empty"); if (string.IsNullOrEmpty(testValue)) return nonEmptyReturnValue; return testValue; } /// /// Replaces all characters passing delegate test with specified replacement character. /// /// Input string. /// Character used to replace characters passing delegate test. /// Delegate used to determine whether or not character should be replaced. /// Returns with all characters passing delegate test replaced. /// Allows you to specify a replacement character (e.g., you may want to use a non-breaking space: Convert.ToChar(160)). public static string ReplaceCharacters(this string value, char replacementCharacter, Func characterTestFunction) { // if (characterTestFunction == (Func)null) throw new ArgumentNullException("characterTestFunction"); // if (string.IsNullOrEmpty(value)) return ""; StringBuilder result = new StringBuilder(); char character; for (int x = 0; x < value.Length; x++) { character = value[x]; if (characterTestFunction(character)) result.Append(replacementCharacter); else result.Append(character); } return result.ToString(); } /// /// Removes all characters passing delegate test from a string. /// /// Input string. /// Delegate used to determine whether or not character should be removed. /// Returns with all characters passing delegate test removed. public static string RemoveCharacters(this string value, Func characterTestFunction) { // if (characterTestFunction == (Func)null) throw new ArgumentNullException("characterTestFunction"); // if (string.IsNullOrEmpty(value)) return ""; StringBuilder result = new StringBuilder(); char character; for (int x = 0; x < value.Length; x++) { character = value[x]; if (!characterTestFunction(character)) result.Append(character); } return result.ToString(); } /// /// Removes all white space (as defined by IsWhiteSpace) from a string. /// /// Input string. /// Returns with all white space removed. public static string RemoveWhiteSpace(this string value) { return value.RemoveCharacters(char.IsWhiteSpace); } /// /// Replaces all white space characters (as defined by IsWhiteSpace) with specified replacement character. /// /// Input string. /// Character used to "replace" white space characters. /// Returns with all white space characters replaced. /// Allows you to specify a replacement character (e.g., you may want to use a non-breaking space: Convert.ToChar(160)). public static string ReplaceWhiteSpace(this string value, char replacementCharacter) { return value.ReplaceCharacters(replacementCharacter, char.IsWhiteSpace); } /// /// Removes all control characters from a string. /// /// Input string. /// Returns with all control characters removed. public static string RemoveControlCharacters(this string value) { return value.RemoveCharacters(char.IsControl); } /// /// Replaces all control characters in a string with a single space. /// /// Input string. /// Returns with all control characters replaced as a single space. public static string ReplaceControlCharacters(this string value) { return value.ReplaceControlCharacters(' '); } /// /// Replaces all control characters in a string with specified replacement character. /// /// Input string. /// Character used to "replace" control characters. /// Returns with all control characters replaced. /// Allows you to specify a replacement character (e.g., you may want to use a non-breaking space: Convert.ToChar(160)). public static string ReplaceControlCharacters(this string value, char replacementCharacter) { return value.ReplaceCharacters(replacementCharacter, char.IsControl); } /// /// Removes all carriage returns and line feeds from a string. /// /// Input string. /// Returns with all CR and LF characters removed. public static string RemoveCrLfs(this string value) { return value.RemoveCharacters(c => c == '\r' || c == '\n'); } /// /// Replaces all carriage return and line feed characters (as well as CR/LF sequences) in a string with specified replacement character. /// /// Input string. /// Character used to "replace" CR and LF characters. /// Returns with all CR and LF characters replaced. /// Allows you to specify a replacement character (e.g., you may want to use a non-breaking space: Convert.ToChar(160)). public static string ReplaceCrLfs(this string value, char replacementCharacter) { // if (value == (string)null) throw new ArgumentNullException("value"); // return value.Replace(Environment.NewLine, replacementCharacter.ToString()).ReplaceCharacters(replacementCharacter, c => c == '\r' || c == '\n'); } /// /// Removes duplicate character strings (adjoining replication) in a string. /// /// Input string. /// String whose duplicates are to be removed. /// Returns with all duplicated removed. public static string RemoveDuplicates(this string value, string duplicatedValue) { if (string.IsNullOrEmpty(value)) return ""; if (string.IsNullOrEmpty(duplicatedValue)) return value; string duplicate = duplicatedValue + duplicatedValue; while (value.IndexOf(duplicate) > -1) { value = value.Replace(duplicate, duplicatedValue); } return value; } /// /// Removes the terminator ('\0') from a null terminated string. /// /// Input string. /// Returns with all characters to the left of the terminator. public static string RemoveNull(this string value) { if (string.IsNullOrEmpty(value)) return ""; int nullPos = value.IndexOf('\0'); if (nullPos > -1) return value.Substring(0, nullPos); return value; } /// /// Replaces all repeating white space with a single space. /// /// Input string. /// Returns with all duplicate white space removed. public static string RemoveDuplicateWhiteSpace(this string value) { return value.RemoveDuplicateWhiteSpace(' '); } /// /// Replaces all repeating white space with specified spacing character. /// /// Input string. /// Character value to use to insert as single white space value. /// Returns with all duplicate white space removed. /// This function allows you to specify spacing character (e.g., you may want to use a non-breaking space: Convert.ToChar(160)). public static string RemoveDuplicateWhiteSpace(this string value, char spacingCharacter) { if (string.IsNullOrEmpty(value)) return ""; StringBuilder result = new StringBuilder(); bool lastCharWasSpace = false; char character; for (int x = 0; x < value.Length; x++) { character = value[x]; if (char.IsWhiteSpace(character)) { lastCharWasSpace = true; } else { if (lastCharWasSpace) result.Append(spacingCharacter); result.Append(character); lastCharWasSpace = false; } } return result.ToString(); } /// /// Removes all invalid file name characters (\ / : * ? " < > |) from a string. /// /// Input string. /// Returns with all invalid file name characters removed. public static string RemoveInvalidFileNameCharacters(this string value) { return value.RemoveCharacters(c => Array.IndexOf(Path.GetInvalidFileNameChars(), c) >= 0); } /// /// Replaces all invalid file name characters (\ / : * ? " < > |) in a string with the specified . /// /// Input string. /// Character used to replace the invalid characters. /// >Returns with all invalid file name characters replaced. public static string ReplaceInvalidFileNameCharacters(this string value, char replacementCharacter) { return value.ReplaceCharacters(replacementCharacter, c => Array.IndexOf(Path.GetInvalidFileNameChars(), c) >= 0); } /// /// Wraps in the . /// /// Input string to process /// The char to wrap /// wrapped in public static string QuoteWrap(this string value, char quoteChar = '\"') { if (string.IsNullOrEmpty(value)) return ""; if (quoteChar == 0) return value; if (value[0] != quoteChar) value = string.Concat(quoteChar, value); if (value[value.Length - 1] != quoteChar) value = string.Concat(value, quoteChar); if (!value.StartsWith(quoteChar.ToString())) value = string.Concat(quoteChar, value); return value; } /// /// Counts the total number of the occurances of a character in the given string. /// /// Input string. /// Character to be counted. /// Total number of the occurances of in the given string. public static int CharCount(this string value, char characterToCount) { if (string.IsNullOrEmpty(value)) return 0; int total = 0; for (int x = 0; x < value.Length; x++) { if (value[x] == characterToCount) total++; } return total; } /// /// Tests to see if a string is contains only digits based on Char.IsDigit function. /// /// Input string. /// True, if all string's characters are digits; otherwise, false. /// public static bool IsAllDigits(this string value) { if (string.IsNullOrEmpty(value)) return false; value = value.Trim(); if (value.Length == 0) return false; for (int x = 0; x < value.Length; x++) { if (!char.IsDigit(value[x])) return false; } return true; } /// /// Tests to see if a string contains only numbers based on Char.IsNumber function. /// /// Input string. /// True, if all string's characters are numbers; otherwise, false. /// public static bool IsAllNumbers(this string value) { if (string.IsNullOrEmpty(value)) return false; value = value.Trim(); if (value.Length == 0) return false; for (int x = 0; x < value.Length; x++) { if (!char.IsNumber(value[x])) return false; } return true; } /// /// Tests to see if a string's letters are all upper case. /// /// Input string. /// True, if all string's letter characters are upper case; otherwise, false. public static bool IsAllUpper(this string value) { if (string.IsNullOrEmpty(value)) return false; value = value.Trim(); if (value.Length == 0) return false; for (int x = 0; x < value.Length; x++) { if (char.IsLetter(value[x]) && !char.IsUpper(value[x])) return false; } return true; } /// /// Tests to see if a string's letters are all lower case. /// /// Input string. /// True, if all string's letter characters are lower case; otherwise, false. public static bool IsAllLower(this string value) { if (string.IsNullOrEmpty(value)) return false; value = value.Trim(); if (value.Length == 0) return false; for (int x = 0; x < value.Length; x++) { if (char.IsLetter(value[x]) && !char.IsLower(value[x])) return false; } return true; } /// /// Tests to see if a string contains only letters. /// /// Input string. /// True, if all string's characters are letters; otherwise, false. /// Any non-letter character (e.g., punctuation marks) causes this function to return false (See overload to ignore punctuation /// marks.). public static bool IsAllLetters(this string value) { return value.IsAllLetters(false); } /// /// Tests to see if a string contains only letters. /// /// Input string. /// Set to True to ignore punctuation. /// True, if all string's characters are letters; otherwise, false. public static bool IsAllLetters(this string value, bool ignorePunctuation) { if (string.IsNullOrEmpty(value)) return false; value = value.Trim(); if (value.Length == 0) return false; for (int x = 0; x < value.Length; x++) { if (ignorePunctuation) { if (!(char.IsLetter(value[x]) || char.IsPunctuation(value[x]))) return false; } else { if (!char.IsLetter(value[x])) return false; } } return true; } /// /// Tests to see if a string contains only letters or digits. /// /// Input string. /// True, if all string's characters are either letters or digits; otherwise, false. /// Any non-letter, non-digit character (e.g., punctuation marks) causes this function to return false (See overload to ignore /// punctuation marks.). public static bool IsAllLettersOrDigits(this string value) { return value.IsAllLettersOrDigits(false); } /// /// Tests to see if a string contains only letters or digits. /// /// Input string. /// Set to True to ignore punctuation. /// True, if all string's characters are letters or digits; otherwise, false. public static bool IsAllLettersOrDigits(this string value, bool ignorePunctuation) { if (string.IsNullOrEmpty(value)) return false; value = value.Trim(); if (value.Length == 0) return false; for (int x = 0; x < value.Length; x++) { if (ignorePunctuation) { if (!(char.IsLetterOrDigit(value[x]) || char.IsPunctuation(value[x]))) return false; } else { if (!char.IsLetterOrDigit(value[x])) return false; } } return true; } /// /// Decodes the specified Regular Expression character back into a standard Unicode character. /// /// Regular Expression character to decode back into a Unicode character. /// Standard Unicode character representation of specified Regular Expression character. public static char RegexDecode(this string value) { // if (value == (string)null) throw new ArgumentNullException("value"); // return Convert.ToChar(Convert.ToUInt16(value.Replace("\\u", "0x"), 16)); } /// /// Encodes a string into a base-64 string. /// /// Input string. /// /// Performs a base-64 style of string encoding useful for data obfuscation or safe XML data string transmission. /// Note: This function encodes a "String". Use the Convert.ToBase64String function to encode a binary data buffer. /// /// A value representing the encoded input of . public static string Base64Encode(this string value) { return Convert.ToBase64String(Encoding.Unicode.GetBytes(value)); } /// /// Decodes a given base-64 encoded string encoded with . /// /// Input string. /// Note: This function decodes value back into a "String". Use the Convert.FromBase64String function to decode a base-64 encoded /// string back into a binary data buffer. /// A value representing the decoded input of . public static string Base64Decode(this string value) { return Encoding.Unicode.GetString(Convert.FromBase64String(value)); } /// /// Converts the provided string into title case (upper case first letter of each word). /// /// Input string. /// Note: This function performs "ToLower" in input string then applies TextInfo.ToTitleCase for CurrentCulture. This way, even /// strings formatted in all-caps will still be properly formatted. /// A that has the first letter of each word capitalized. public static string ToTitleCase(this string value) { if (string.IsNullOrEmpty(value)) return ""; return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(value.ToLower()); } /// /// Truncates the provided string from the left if it is longer that specified length. /// /// A value that is to be truncated. /// The maximum number of characters that can be. /// A that is the truncated version of the string. public static string TruncateLeft(this string value, int maxLength) { if (string.IsNullOrEmpty(value)) return ""; if (value.Length > maxLength) return value.Substring(value.Length - maxLength); return value; } /// /// Truncates the provided string from the right if it is longer that specified length. /// /// A value that is to be truncated. /// The maximum number of characters that can be. /// A that is the truncated version of the string. public static string TruncateRight(this string value, int maxLength) { if (string.IsNullOrEmpty(value)) return ""; if (value.Length > maxLength) return value.Substring(0, maxLength); return value; } /// /// Centers text within the specified maximum length, biased to the left. /// Text will be padded to the left and right with spaces. /// If value is greater than specified maximum length, value returned will be truncated from the right. /// /// /// Handles multiple lines of text separated by Environment.NewLine. /// /// A to be centered. /// An that is the maximum length of padding. /// The centered string value. public static string CenterText(this string value, int maxLength) { return value.CenterText(maxLength, ' '); } /// /// Centers text within the specified maximum length, biased to the left. /// Text will be padded to the left and right with specified padding character. /// If value is greater than specified maximum length, value returned will be truncated from the right. /// /// /// Handles multiple lines of text separated by Environment.NewLine. /// /// A to be centered. /// An that is the maximum length of padding. /// The value to pad with. /// The centered string value. public static string CenterText(this string value, int maxLength, char paddingCharacter) { if ((object)value == null) value = ""; // If the text to be centered contains multiple lines, centers all the lines individually. StringBuilder result = new StringBuilder(); string[] lines = value.Split(new[] { Environment.NewLine }, StringSplitOptions.None); string line; int lastLineIndex = lines.Length - 1; //(lines.Length != 0 && lines[lines.Length - 1].Trim() == string.Empty ? lines.Length - 2 : lines.Length - 1); for (int i = 0; i <= lastLineIndex; i++) { // Gets current line. line = lines[i]; // Skips the last empty line as a result of split if original text had multiple lines. if (i == lastLineIndex && line.Trim().Length == 0) continue; if (line.Length >= maxLength) { // Truncates excess characters on the right. result.Append(line.Substring(0, maxLength)); } else { int remainingSpace = maxLength - line.Length; int leftSpaces; int rightSpaces; // Splits remaining space between the left and the right. leftSpaces = remainingSpace / 2; rightSpaces = leftSpaces; // Adds any remaining odd space to the right (bias text to the left). if (remainingSpace % 2 > 0) rightSpaces++; result.Append(new string(paddingCharacter, leftSpaces)); result.Append(line); result.Append(new string(paddingCharacter, rightSpaces)); } // Creates a new line only if the original text contains multiple lines. if (i < lastLineIndex) result.AppendLine(); } return result.ToString(); } /// /// Performs a case insensitive string replacement. /// /// The string to examine. /// The value to replace. /// The new value to be inserted /// A string with replacements. public static string ReplaceCaseInsensitive(this string value, string fromText, string toText) { return (new Regex(fromText, RegexOptions.IgnoreCase | RegexOptions.Multiline)).Replace(value, toText); } /// /// Ensures a string starts with a specific character. /// /// Input string to process. /// The character desired at string start. /// The sent string with character at the start. public static string EnsureStart(this string value, char startChar) { return EnsureStart(value, startChar, false); } /// /// Ensures a string starts with a specific character. /// /// Input string to process. /// The character desired at string start. /// Set to true to ensure one and only one instance of . /// The sent string with character at the start. public static string EnsureStart(this string value, char startChar, bool removeRepeatingChar) { if (string.IsNullOrEmpty(value)) return ""; if (startChar == 0) return value; if (value[0] == startChar) { if (removeRepeatingChar) return value.Substring(LastIndexOfRepeatedChar(value, startChar, 0)); return value; } return string.Concat(startChar, value); } /// /// Ensures a string starts with a specific string. /// /// Input string to process. /// The string desired at string start. /// The sent string with string at the start. public static string EnsureStart(this string value, string startString) { if (string.IsNullOrEmpty(value)) return ""; if (string.IsNullOrEmpty(startString)) return value; if (value.IndexOf(startString) == 0) return value; return string.Concat(startString, value); } /// /// Ensures a string ends with a specific character. /// /// Input string to process. /// The character desired at string's end. /// The sent string with character at the end. public static string EnsureEnd(this string value, char endChar) { return EnsureEnd(value, endChar, false); } /// /// Ensures a string ends with a specific character. /// /// Input string to process. /// The character desired at string's end. /// Set to true to ensure one and only one instance of . /// The sent string with character at the end. public static string EnsureEnd(this string value, char endChar, bool removeRepeatingChar) { if (string.IsNullOrEmpty(value)) return ""; if (endChar == 0) return value; if (value[value.Length - 1] == endChar) { if (removeRepeatingChar) { int i = LastIndexOfRepeatedChar(value.Reverse(), endChar, 0); return value.Substring(0, value.Length - i); } return value; } return string.Concat(value, endChar); } /// /// Ensures a string ends with a specific string. /// /// Input string to process. /// The string desired at string's end. /// The sent string with string at the end. public static string EnsureEnd(this string value, string endString) { if (string.IsNullOrEmpty(value)) return ""; if (string.IsNullOrEmpty(endString)) return value; if (value.EndsWith(endString)) return value; return string.Concat(value, endString); } /// /// Reverses the order of the characters in a string. /// /// Input string to process. /// The reversed string. public static string Reverse(this string value) { // Experimented with several approaches. This is the fastest. // Replaced original code that yielded 1.5% performance increase. // This code is faster than Array.Reverse. if (string.IsNullOrEmpty(value)) return ""; char[] arrChar = value.ToCharArray(); char temp; int arrLength = arrChar.Length; int j; // Works for odd and even length strings since middle char is not swapped for an odd length string for (int i = 0; i < arrLength / 2; i++) { j = arrLength - i - 1; temp = arrChar[i]; arrChar[i] = arrChar[j]; arrChar[j] = temp; } return new string(arrChar); } /// /// Searches a string for a repeated instance of the specified from specified . /// /// The string to process. /// The character of interest. /// The index from which to begin the search. /// The index of the first instance of the character that is repeated or (-1) if no repeated chars found. public static int IndexOfRepeatedChar(this string value, char characterToFind, int startIndex) { if (string.IsNullOrEmpty(value)) return -1; if (startIndex < 0) return -1; if (characterToFind == 0) return -1; char c = (char)0; for (int i = startIndex; i < value.Length; i++) { if (value[i] == characterToFind) { if (value[i] != c) c = value[i]; else { //at least one repeating character return i - 1; } } else { c = (char)0; } } return -1; } /// /// Searches a string for a repeated instance of the specified . /// /// The string to process. /// The character of interest. /// The index of the first instance of the character that is repeated or (-1) if no repeated chars found. public static int IndexOfRepeatedChar(this string value, char characterToFind) { return IndexOfRepeatedChar(value, characterToFind, 0); } /// /// Searches a string for an instance of a repeated character. /// /// The string to process. /// The index of the first instance of any character that is repeated or (-1) if no repeated chars found. public static int IndexOfRepeatedChar(this string value) { return IndexOfRepeatedChar(value, 0); } /// /// Searches a string for an instance of a repeated character from specified . /// /// The string to process. /// The index from which to begin the search. /// The index of the first instance of any character that is repeated or (-1) if no repeated chars found. public static int IndexOfRepeatedChar(this string value, int startIndex) { if (string.IsNullOrEmpty(value)) return -1; if (startIndex < 0) return -1; char c = (char)0; for (int i = startIndex; i < value.Length; i++) { if (value[i] != c) c = value[i]; else { //at least one repeating character return i - 1; } } return -1; } /// /// Returns the index of the last repeated index of the first group of repeated characters that begin with the . /// /// String to process. /// The character of interest. /// The index from which to begin the search. /// The index of the last instance of the character that is repeated or (-1) if no repeated chars found. private static int LastIndexOfRepeatedChar(string value, char characterToFind, int startIndex) { if (startIndex > value.Length - 1) return -1; int i = value.IndexOf(characterToFind, startIndex); if (i == -1) return -1; for (int j = i + 1; j < value.Length; j++) { if (value[j] != characterToFind) return j - 1; } return value.Length - 1; } /// /// Places an ellipsis in the middle of a string as it is trimmed to length specified. /// /// The string to process. /// The maximum returned string length; mimimum value is 5. /// /// A trimmed string of the specified or empty string if is null or empty. /// /// /// Returned string is not padded to fill field length if is shorter than length. /// public static string TrimWithEllipsisMiddle(this string value, int length) { if (string.IsNullOrEmpty(value)) return ""; if (length < 5) length = 5; value = value.Trim(); if (value.Length <= length) return value; int s1_Len = (int)(length / 2) - 1; return string.Concat(value.Substring(0, s1_Len), "...", value.Substring(value.Length - s1_Len + 1 - length % 2)); } /// /// Places an ellipsis at the end of a string as it is trimmed to length specified. /// /// The string to process. /// The maximum returned string length; mimimum value is 5. /// /// A trimmed string of the specified or empty string if is null or empty. /// /// /// Returned string is not padded to fill field length if is shorter than length. /// public static string TrimWithEllipsisEnd(this string value, int length) { if (string.IsNullOrEmpty(value)) return ""; if (length < 5) length = 5; value = value.Trim(); if (value.Length <= length) return value; return string.Concat(value.Substring(0, length - 3), "..."); } } }