History

Renamed folders and separated GSF.Media and GSF.Net into separate projects.

StephenCWills committed 14 years ago

Commit ac1ef661 parent 45bce55628 files · +733 −461Browse files

Showing the changes to Source/Libraries/GSF.Core/StringExtensions.cs (1 of 628 files). Show all

Unified · Split

Source/Libraries/GSF.Core/StringExtensions.cs+1477−0
@@ -0,0 +1,1477 @@
1+//******************************************************************************************************
2+// StringExtensions.cs - Gbtc
3+//
4+// Copyright © 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 02/23/2003 - J. Ritchie Carroll
20+// Generated original version of source code.
21+// 01/24/2006 - J. Ritchie Carroll
22+// Migrated 2.0 version of source code from 1.1 source (GSF.Shared.String).
23+// 06/01/2006 - J. Ritchie Carroll
24+// Added ParseBoolean function to parse strings representing booleans that may be numeric.
25+// 07/07/2006 - J. Ritchie Carroll
26+// Added GetStringSegments function to break a string up into smaller chunks for parsing.
27+// and/or displaying.
28+// 08/02/2007 - J. Ritchie Carroll
29+// Added a CenterText method for centering strings in console applications or fixed width fonts.
30+// 08/03/2007 - Pinal C. Patel
31+// Modified the CenterText method to handle multiple lines.
32+// 08/21/2007 - Darrell Zuercher
33+// Edited code comments.
34+// 09/25/2007 - J. Ritchie Carroll
35+// Added TitleCase function to format a string with the first letter of each word capitalized.
36+// 04/16/2008 - Pinal C. Patel
37+// Made the keys of the string dictionary returned by ParseKeyValuePairs function case-insensitive.
38+// Added JoinKeyValuePairs overloads that does the exact opposite of ParseKeyValuePairs.
39+// 09/19/2008 - J. Ritchie Carroll
40+// Converted to C# extensions.
41+// 12/13/2008 - F. Russell Roberson
42+// Generalized ParseBoolean to include "Y", and "T".
43+// Added IndexOfRepeatedChar - Returns the index of the first character that is repeated.
44+// Added Reverse - Reverses the order of characters in a string.
45+// Added EnsureEnd - Ensures that a string ends with a specified char or string.
46+// Added EnsureStart - Ensures that a string begins with a specified char or string.
47+// Added IsNumeric - Test to see if a string only includes characters that can be interpreted as a number.
48+// Added TrimWithEllipsisMiddle - Adds an ellipsis in the middle of a string as it is reduced to a specified length.
49+// Added TrimWithEllipsisEnd - Trims a string to not exceed a fixed length and adds a ellipsis to string end.
50+// 02/10/2009 - J. Ritchie Carroll
51+// Added ConvertToType overloaded extensions.
52+// 02/17/2009 - Josh L. Patterson
53+// Edited Code Comments.
54+// 09/14/2009 - Stephen C. Wills
55+// Added new header and license agreement.
56+// 01/11/2010 - Galen K. Riley
57+// Bug fixes for unit tests:
58+// ConvertToType - Fix to throw ArgumentNullException instead of NullReferenceException for null value
59+// ConvertToType - Handling failed conversions better. Calling ConvertToType<int>("\0") returns properly
60+// JoinKeyValuePairs - Fix to throw ArgumentNullException instead of NullReferenceException
61+// ReplaceCharacters - Fix to throw ArgumentNullException instead of NullReferenceException for null replacementCharacter
62+// RemoveCharacters - Fix to throw ArgumentNullException instead of NullReferenceException for null characterTestFunction
63+// ReplaceCrLfs - Fix to throw ArgumentNullException instead of NullReferenceException for null value
64+// RegexDecode - Fix to throw ArgumentNullException instead of NullReferenceException for null value
65+// 12/03/2010 - J. Ritchie Carroll
66+// Modifed ParseKeyValuePairs such that it could handle nested pairs to any needed depth.
67+// 12/05/2010 - Pinal C. Patel
68+// Added an overload for ConvertToType() that takes CultureInfo as a parameter.
69+// 12/07/2010 - Pinal C. Patel
70+// Updated ConvertToType() to return the type default if passed in string is null or empty.
71+// 01/04/2011 - J. Ritchie Carroll
72+// Modified ConvertToType culture default to InvariantCulture for English style parsing defaults.
73+// 01/14/2011 - J. Ritchie Carroll
74+// Modified JoinKeyValuePairs to delineate values that contain nested key/value pair expressions
75+// such that the generated expression can correctly parsed.
76+// 03/23/2011 - J. Ritchie Carroll
77+// Modified ParseKeyValuePairs to optionally ignore duplicate keys (default behavior now).
78+// Removed overloads for ParseKeyValuePairs and JoinKeyValuePairs using optional parameters.
79+// 08/02/2011 - Pinal C. Patel
80+// Added RemoveInvalidFileNameCharacters() and ReplaceInvalidFileNameCharacters() methods.
81+// 10/8/2012 - Danyelle Gilliam
82+// Modified Header
83+//
84+//*******************************************************************************************************
85+//
86+//******************************************************************************************************
87+
88+
89+
90+
91+#region [ Contributor License Agreements ]
92+
93+//******************************************************************************************************
94+//
95+// Copyright © 2011, Grid Protection Alliance. All Rights Reserved.
96+//
97+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
98+// not use this file except in compliance with the License. You may obtain a copy of the License at:
99+//
100+// http://www.opensource.org/licenses/eclipse-1.0.php
101+//
102+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
103+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
104+// License for the specific language governing permissions and limitations.
105+//
106+//******************************************************************************************************
107+
108+#endregion
109+
110+using System;
111+using System.Collections.Generic;
112+using System.ComponentModel;
113+using System.Globalization;
114+using System.IO;
115+using System.Text;
116+using System.Text.RegularExpressions;
117+
118+namespace GSF
119+{
120+ /// <summary>Defines extension functions related to string manipulation.</summary>
121+ public static class StringExtensions
122+ {
123+ /// <summary>
124+ /// Parses a string intended to represent a boolean value.
125+ /// </summary>
126+ /// <param name="value">String representing a boolean value.</param>
127+ /// <returns>Parsed boolean value.</returns>
128+ /// <remarks>
129+ /// This function, unlike Boolean.Parse, correctly parses a boolean value, even if the string value
130+ /// specified is a number (e.g., 0 or -1). Boolean.Parse expects a string to be represented as
131+ /// "True" or "False" (i.e., Boolean.TrueString or Boolean.FalseString respectively).
132+ /// </remarks>
133+ public static bool ParseBoolean(this string value)
134+ {
135+ if (string.IsNullOrEmpty(value))
136+ return false;
137+
138+ value = value.Trim();
139+
140+ if (value.Length > 0)
141+ {
142+ // Try to parse string a number
143+ int iresult;
144+
145+ if (int.TryParse(value, out iresult))
146+ {
147+ return (iresult != 0);
148+ }
149+ else
150+ {
151+ // Try to parse string as a boolean
152+ bool bresult;
153+
154+ if (bool.TryParse(value, out bresult))
155+ {
156+ return bresult;
157+ }
158+ else
159+ {
160+ char test = value.ToUpper()[0];
161+ return (test == 'T' || test == 'Y' ? true : false);
162+ }
163+ }
164+ }
165+
166+ return false;
167+ }
168+
169+ /// <summary>
170+ /// Converts this string into the specified type.
171+ /// </summary>
172+ /// <typeparam name="T"><see cref="Type"/> to convert string to.</typeparam>
173+ /// <param name="value">Source string to convert to type.</param>
174+ /// <returns><see cref="String"/> converted to specfied <see cref="Type"/>; default value of specified type T if conversion fails.</returns>
175+ /// <remarks>
176+ /// This function makes use of a <see cref="TypeConverter"/> to convert this <see cref="String"/> to the specified type T,
177+ /// the best way to make sure <paramref name="value"/> can be converted back to its original type is to use the same
178+ /// <see cref="TypeConverter"/> to convert the original object to a <see cref="String"/>; see the
179+ /// <see cref="Common.TypeConvertToString(object)"/> method for an easy way to do this.
180+ /// </remarks>
181+ public static T ConvertToType<T>(this string value)
182+ {
183+ return ConvertToType<T>(value, null);
184+ }
185+
186+ /// <summary>
187+ /// Converts this string into the specified type.
188+ /// </summary>
189+ /// <typeparam name="T"><see cref="Type"/> to convert string to.</typeparam>
190+ /// <param name="value">Source string to convert to type.</param>
191+ /// <param name="type"><see cref="Type"/> to convert string to.</param>
192+ /// <returns><see cref="String"/> converted to specfied <see cref="Type"/>; default value of specified type T if conversion fails.</returns>
193+ /// <remarks>
194+ /// This function makes use of a <see cref="TypeConverter"/> to convert this <see cref="String"/> to the specified <paramref name="type"/>,
195+ /// the best way to make sure <paramref name="value"/> can be converted back to its original type is to use the same
196+ /// <see cref="TypeConverter"/> to convert the original object to a <see cref="String"/>; see the
197+ /// <see cref="Common.TypeConvertToString(object)"/> method for an easy way to do this.
198+ /// </remarks>
199+ public static T ConvertToType<T>(this string value, Type type)
200+ {
201+ return ConvertToType<T>(value, type, null);
202+ }
203+
204+ /// <summary>
205+ /// Converts this string into the specified type.
206+ /// </summary>
207+ /// <typeparam name="T"><see cref="Type"/> to convert string to.</typeparam>
208+ /// <param name="value">Source string to convert to type.</param>
209+ /// <param name="type"><see cref="Type"/> to convert string to.</param>
210+ /// <param name="culture"><see cref="CultureInfo"/> to use for the conversion.</param>
211+ /// <returns><see cref="String"/> converted to specfied <see cref="Type"/>; default value of specified type T if conversion fails.</returns>
212+ /// <remarks>
213+ /// This function makes use of a <see cref="TypeConverter"/> to convert this <see cref="String"/> to the specified <paramref name="type"/>,
214+ /// the best way to make sure <paramref name="value"/> can be converted back to its original type is to use the same
215+ /// <see cref="TypeConverter"/> to convert the original object to a <see cref="String"/>; see the
216+ /// <see cref="Common.TypeConvertToString(object)"/> method for an easy way to do this.
217+ /// </remarks>
218+ public static T ConvertToType<T>(this string value, Type type, CultureInfo culture)
219+ {
220+ // Don't proceed further if string is empty.
221+ if (string.IsNullOrEmpty(value))
222+ return default(T);
223+
224+ // Initialize return type if not specified.
225+ if ((object)type == null)
226+ type = typeof(T);
227+
228+ // Initialize culture info if not specified.
229+ if ((object)culture == null)
230+ culture = CultureInfo.InvariantCulture;
231+
232+ try
233+ {
234+ if (type.IsAssignableFrom(typeof(bool)))
235+ {
236+ // Handle booleans as a special case to allow numeric entries as well as true/false
237+ return (T)((object)value.ParseBoolean());
238+ }
239+ else
240+ {
241+ if (type.IsAssignableFrom(typeof(IConvertible)))
242+ {
243+ // This is faster for native types than using type converter...
244+ return (T)Convert.ChangeType(value, type, culture);
245+ }
246+ else
247+ {
248+ // Handle objects that have type converters (e.g., Enum, Color, Point, etc.)
249+ TypeConverter converter = TypeDescriptor.GetConverter(type);
250+ return (T)converter.ConvertFromString(null, culture, value);
251+ }
252+ }
253+ }
254+ catch
255+ {
256+ return default(T);
257+ }
258+ }
259+
260+ /// <summary>
261+ /// Turns source string into an array of string segements - each with a set maximum width - for parsing or displaying.
262+ /// </summary>
263+ /// <param name="value">Input string to break up into segements.</param>
264+ /// <param name="segmentSize">Maximum size of returned segment.</param>
265+ /// <returns>Array of string segments as parsed from source string.</returns>
266+ /// <remarks>Returns a single element array with an empty string if source string is null or empty.</remarks>
267+ public static string[] GetSegments(this string value, int segmentSize)
268+ {
269+ if (segmentSize <= 0)
270+ throw new ArgumentOutOfRangeException("segmentSize", "segmentSize must be greater than zero.");
271+
272+ if (string.IsNullOrEmpty(value))
273+ return new string[] { "" };
274+
275+ int totalSegments = (int)Math.Ceiling(value.Length / (double)segmentSize);
276+ string[] segments = new string[totalSegments];
277+
278+ for (int x = 0; x < segments.Length; x++)
279+ {
280+ if (x * segmentSize + segmentSize >= value.Length)
281+ segments[x] = value.Substring(x * segmentSize);
282+ else
283+ segments[x] = value.Substring(x * segmentSize, segmentSize);
284+ }
285+
286+ return segments;
287+ }
288+
289+ /// <summary>
290+ /// Combines a dictionary of key-value pairs in to a string.
291+ /// </summary>
292+ /// <param name="pairs">Dictionary of key-value pairs.</param>
293+ /// <param name="parameterDelimeter">Character that delimits one key-value pair from another (eg. ';').</param>
294+ /// <param name="keyValueDelimeter">Character that delimits a key from its value (eg. '=').</param>
295+ /// <param name="startValueDelimeter">Optional character that marks the start of a value such that value could contain other
296+ /// <paramref name="parameterDelimeter"/> or <paramref name="keyValueDelimeter"/> characters (e.g., "{").</param>
297+ /// <param name="endValueDelimeter">Optional character that marks the end of a value such that value could contain other
298+ /// <paramref name="parameterDelimeter"/> or <paramref name="keyValueDelimeter"/> characters (e.g., "}").</param>
299+ /// <returns>A string of key-value pairs.</returns>
300+ /// <remarks>
301+ /// Values will be escaped within <paramref name="startValueDelimeter"/> and <paramref name="endValueDelimeter"/>
302+ /// to contain nested key/value pair expressions like the following: <c>normalKVP=-1; nestedKVP={p1=true; p2=0.001}</c>,
303+ /// when either the <paramref name="parameterDelimeter"/> or <paramref name="keyValueDelimeter"/> are detected in the
304+ /// value of the key/value pair.
305+ /// </remarks>
306+ public static string JoinKeyValuePairs(this Dictionary<string, string> pairs, char parameterDelimeter = ';', char keyValueDelimeter = '=', char startValueDelimeter = '{', char endValueDelimeter = '}')
307+ {
308+ // <pex>
309+ if ((object)pairs == null)
310+ throw new ArgumentNullException("pairs");
311+ // </pex>
312+
313+ char[] delimiters = { parameterDelimeter, keyValueDelimeter };
314+ StringBuilder result = new StringBuilder();
315+ string value;
316+
317+ foreach (string key in pairs.Keys)
318+ {
319+ value = pairs[key];
320+
321+ if (value.IndexOfAny(delimiters) >= 0)
322+ value = startValueDelimeter + value + endValueDelimeter;
323+
324+ result.AppendFormat("{0}{1}{2}{3}", key, keyValueDelimeter, value, parameterDelimeter);
325+ }
326+
327+ return result.ToString();
328+ }
329+
330+ /// <summary>
331+ /// Parses key/value pair expressions from a string. Parameter pairs are delimited by <paramref name="keyValueDelimeter"/>
332+ /// and multiple pairs separated by <paramref name="parameterDelimeter"/>. Supports encapsulated nested expressions.
333+ /// </summary>
334+ /// <param name="value">String containing key/value pair expressions to parse.</param>
335+ /// <param name="parameterDelimeter">Character that delimits one key/value pair from another.</param>
336+ /// <param name="keyValueDelimeter">Character that delimits key from value.</param>
337+ /// <param name="startValueDelimeter">Optional character that marks the start of a value such that value could contain other
338+ /// <paramref name="parameterDelimeter"/> or <paramref name="keyValueDelimeter"/> characters.</param>
339+ /// <param name="endValueDelimeter">Optional character that marks the end of a value such that value could contain other
340+ /// <paramref name="parameterDelimeter"/> or <paramref name="keyValueDelimeter"/> characters.</param>
341+ /// <param name="ignoreDuplicateKeys">Flag determines whether duplicates are ignored. If flag is set to <c>false</c> an
342+ /// <see cref="ArgumentException"/> will be thrown when all key parameters are not unique.</param>
343+ /// <returns>Dictionary of key/value pairs.</returns>
344+ /// <remarks>
345+ /// <para>
346+ /// Parses a string containing key/value pair expressions (e.g., "localPort=5001; transportProtocol=UDP; interface=0.0.0.0").
347+ /// This method treats all "keys" as case-insensitive. Nesting of key/value pair expressions is allowed by encapsulating the
348+ /// value using the <paramref name="startValueDelimeter"/> and <paramref name="endValueDelimeter"/> values (e.g.,
349+ /// "dataChannel={Port=-1;Clients=localhost:8800}; commandChannel={Port=8900}; dataFormat=FloatingPoint;"). There must be one
350+ /// <paramref name="endValueDelimeter"/> for each encountered <paramref name="startValueDelimeter"/> in the value or a
351+ /// <see cref="FormatException"/> will be thrown. Multiple levels of nesting is supported. If the <paramref name="ignoreDuplicateKeys"/>
352+ /// flag is set to <c>false</c> an <see cref="ArgumentException"/> will be thrown when all key parameters are not unique. Note
353+ /// that keys within nested expressions are considered separate key/value pair strings and are not considered when checking
354+ /// for duplicate keys.
355+ /// </para>
356+ /// </remarks>
357+ /// <exception cref="ArgumentNullException">value is null.</exception>
358+ /// <exception cref="ArgumentException">All delimeters must be unique -or- all keys must be unique when
359+ /// <paramref name="ignoreDuplicateKeys"/> is set to <c>false</c>.</exception>
360+ /// <exception cref="FormatException">Total nested key/value value pair expressions are mismatched -or- encountered
361+ /// <paramref name="endValueDelimeter"/> before <paramref name="startValueDelimeter"/>.</exception>
362+ public static Dictionary<string, string> ParseKeyValuePairs(this string value, char parameterDelimeter = ';', char keyValueDelimeter = '=', char startValueDelimeter = '{', char endValueDelimeter = '}', bool ignoreDuplicateKeys = true)
363+ {
364+ if (value == (string)null)
365+ throw new ArgumentNullException("value");
366+
367+ if (parameterDelimeter == keyValueDelimeter ||
368+ parameterDelimeter == startValueDelimeter ||
369+ parameterDelimeter == endValueDelimeter ||
370+ keyValueDelimeter == startValueDelimeter ||
371+ keyValueDelimeter == endValueDelimeter ||
372+ startValueDelimeter == endValueDelimeter)
373+ throw new ArgumentException("All delimeters must be unique");
374+
375+ Dictionary<string, string> keyValuePairs = new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);
376+ StringBuilder escapedValue = new StringBuilder();
377+ string escapedParameterDelimeter = parameterDelimeter.RegexEncode();
378+ string escapedKeyValueDelimeter = keyValueDelimeter.RegexEncode();
379+ string escapedStartValueDelimeter = startValueDelimeter.RegexEncode();
380+ string escapedEndValueDelimeter = endValueDelimeter.RegexEncode();
381+ string[] elements;
382+ string key, unescapedValue;
383+ bool valueEscaped = false;
384+ int delimeterDepth = 0;
385+ char character;
386+
387+ // Escape any parameter or key/value delimeters within tagged value sequences
388+ // For example, the following string:
389+ // "normalKVP=-1; nestedKVP={p1=true; p2=false}")
390+ // would be encoded as:
391+ // "normalKVP=-1; nestedKVP=p1\\u003dtrue\\u003b p2\\u003dfalse")
392+ for (int x = 0; x < value.Length; x++)
393+ {
394+ character = value[x];
395+
396+ if (character == startValueDelimeter)
397+ {
398+ if (!valueEscaped)
399+ {
400+ valueEscaped = true;
401+ continue; // Don't add tag start delimeter to final value
402+ }
403+ else
404+ {
405+ // Handle nested delimeters
406+ delimeterDepth++;
407+ }
408+ }
409+
410+ if (character == endValueDelimeter)
411+ {
412+ if (valueEscaped)
413+ {
414+ if (delimeterDepth > 0)
415+ {
416+ // Handle nested delimeters
417+ delimeterDepth--;
418+ }
419+ else
420+ {
421+ valueEscaped = false;
422+ continue; // Don't add tag stop delimeter to final value
423+ }
424+ }
425+ else
426+ {
427+ 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));
428+ }
429+ }
430+
431+ if (valueEscaped)
432+ {
433+ // Escape any delimeter characters inside nested key/value pair
434+ if (character == parameterDelimeter)
435+ escapedValue.Append(escapedParameterDelimeter);
436+ else if (character == keyValueDelimeter)
437+ escapedValue.Append(escapedKeyValueDelimeter);
438+ else if (character == startValueDelimeter)
439+ escapedValue.Append(escapedStartValueDelimeter);
440+ else if (character == endValueDelimeter)
441+ escapedValue.Append(escapedEndValueDelimeter);
442+ else
443+ escapedValue.Append(character);
444+ }
445+ else
446+ {
447+ escapedValue.Append(character);
448+ }
449+ }
450+
451+ if (delimeterDepth != 0 || valueEscaped)
452+ {
453+ // If value is still escaped, tagged expression was not terminated
454+ if (valueEscaped)
455+ delimeterDepth = 1;
456+
457+ 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 + "\'"));
458+ }
459+
460+ // Parse key/value pairs from escaped value
461+ foreach (string parameter in escapedValue.ToString().Split(parameterDelimeter))
462+ {
463+ // Parse out parameter's key/value elements
464+ elements = parameter.Split(keyValueDelimeter);
465+
466+ if (elements.Length == 2)
467+ {
468+ // Get key expression
469+ key = elements[0].ToString().Trim();
470+
471+ // Get unescaped value expression
472+ unescapedValue = elements[1].ToString().Trim().
473+ Replace(escapedParameterDelimeter, parameterDelimeter.ToString()).
474+ Replace(escapedKeyValueDelimeter, keyValueDelimeter.ToString()).
475+ Replace(escapedStartValueDelimeter, startValueDelimeter.ToString()).
476+ Replace(escapedEndValueDelimeter, endValueDelimeter.ToString());
477+
478+ // Add key/value pair to dictionary
479+ if (ignoreDuplicateKeys)
480+ {
481+ // Add or replace key elements with unescaped value
482+ keyValuePairs[key] = unescapedValue;
483+ }
484+ else
485+ {
486+ // Add key elements with unescaped value throwing an exception for encountered duplicate keys
487+ if (keyValuePairs.ContainsKey(key))
488+ 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));
489+
490+ keyValuePairs.Add(key, unescapedValue);
491+ }
492+ }
493+ }
494+
495+ return keyValuePairs;
496+ }
497+
498+ /// <summary>
499+ /// Ensures parameter is not an empty or null string. Returns a single space if test value is empty.
500+ /// </summary>
501+ /// <param name="testValue">Value to test for null or empty.</param>
502+ /// <returns>A non-empty string.</returns>
503+ public static string NotEmpty(this string testValue)
504+ {
505+ return testValue.NotEmpty(" ");
506+ }
507+
508+ /// <summary>
509+ /// Ensures parameter is not an empty or null string.
510+ /// </summary>
511+ /// <param name="testValue">Value to test for null or empty.</param>
512+ /// <param name="nonEmptyReturnValue">Value to return if <paramref name="testValue">testValue</paramref> is null or empty.</param>
513+ /// <returns>A non-empty string.</returns>
514+ public static string NotEmpty(this string testValue, string nonEmptyReturnValue)
515+ {
516+ if (string.IsNullOrEmpty(nonEmptyReturnValue))
517+ throw new ArgumentException("nonEmptyReturnValue cannot be null or empty");
518+
519+ if (string.IsNullOrEmpty(testValue))
520+ return nonEmptyReturnValue;
521+ else
522+ return testValue;
523+ }
524+
525+ /// <summary>
526+ /// Replaces all characters passing delegate test with specified replacement character.
527+ /// </summary>
528+ /// <param name="value">Input string.</param>
529+ /// <param name="replacementCharacter">Character used to replace characters passing delegate test.</param>
530+ /// <param name="characterTestFunction">Delegate used to determine whether or not character should be replaced.</param>
531+ /// <returns>Returns <paramref name="value" /> with all characters passing delegate test replaced.</returns>
532+ /// <remarks>Allows you to specify a replacement character (e.g., you may want to use a non-breaking space: Convert.ToChar(160)).</remarks>
533+ public static string ReplaceCharacters(this string value, char replacementCharacter, Func<char, bool> characterTestFunction)
534+ {
535+ // <pex>
536+ if (characterTestFunction == (Func<char, bool>)null)
537+ throw new ArgumentNullException("characterTestFunction");
538+ // </pex>
539+ if (string.IsNullOrEmpty(value))
540+ return "";
541+
542+ StringBuilder result = new StringBuilder();
543+ char character;
544+
545+ for (int x = 0; x < value.Length; x++)
546+ {
547+ character = value[x];
548+
549+ if (characterTestFunction(character))
550+ result.Append(replacementCharacter);
551+ else
552+ result.Append(character);
553+ }
554+
555+ return result.ToString();
556+ }
557+
558+ /// <summary>
559+ /// Removes all characters passing delegate test from a string.
560+ /// </summary>
561+ /// <param name="value">Input string.</param>
562+ /// <param name="characterTestFunction">Delegate used to determine whether or not character should be removed.</param>
563+ /// <returns>Returns <paramref name="value" /> with all characters passing delegate test removed.</returns>
564+ public static string RemoveCharacters(this string value, Func<char, bool> characterTestFunction)
565+ {
566+ // <pex>
567+ if (characterTestFunction == (Func<char, bool>)null)
568+ throw new ArgumentNullException("characterTestFunction");
569+ // </pex>
570+ if (string.IsNullOrEmpty(value))
571+ return "";
572+
573+ StringBuilder result = new StringBuilder();
574+ char character;
575+
576+ for (int x = 0; x < value.Length; x++)
577+ {
578+ character = value[x];
579+
580+ if (!characterTestFunction(character))
581+ result.Append(character);
582+ }
583+
584+ return result.ToString();
585+ }
586+
587+ /// <summary>
588+ /// Removes all white space (as defined by IsWhiteSpace) from a string.
589+ /// </summary>
590+ /// <param name="value">Input string.</param>
591+ /// <returns>Returns <paramref name="value" /> with all white space removed.</returns>
592+ public static string RemoveWhiteSpace(this string value)
593+ {
594+ return value.RemoveCharacters(char.IsWhiteSpace);
595+ }
596+
597+ /// <summary>
598+ /// Replaces all white space characters (as defined by IsWhiteSpace) with specified replacement character.
599+ /// </summary>
600+ /// <param name="value">Input string.</param>
601+ /// <param name="replacementCharacter">Character used to "replace" white space characters.</param>
602+ /// <returns>Returns <paramref name="value" /> with all white space characters replaced.</returns>
603+ /// <remarks>Allows you to specify a replacement character (e.g., you may want to use a non-breaking space: Convert.ToChar(160)).</remarks>
604+ public static string ReplaceWhiteSpace(this string value, char replacementCharacter)
605+ {
606+ return value.ReplaceCharacters(replacementCharacter, char.IsWhiteSpace);
607+ }
608+
609+ /// <summary>
610+ /// Removes all control characters from a string.
611+ /// </summary>
612+ /// <param name="value">Input string.</param>
613+ /// <returns>Returns <paramref name="value" /> with all control characters removed.</returns>
614+ public static string RemoveControlCharacters(this string value)
615+ {
616+ return value.RemoveCharacters(char.IsControl);
617+ }
618+
619+ /// <summary>
620+ /// Replaces all control characters in a string with a single space.
621+ /// </summary>
622+ /// <param name="value">Input string.</param>
623+ /// <returns>Returns <paramref name="value" /> with all control characters replaced as a single space.</returns>
624+ public static string ReplaceControlCharacters(this string value)
625+ {
626+ return value.ReplaceControlCharacters(' ');
627+ }
628+
629+ /// <summary>
630+ /// Replaces all control characters in a string with specified replacement character.
631+ /// </summary>
632+ /// <param name="value">Input string.</param>
633+ /// <param name="replacementCharacter">Character used to "replace" control characters.</param>
634+ /// <returns>Returns <paramref name="value" /> with all control characters replaced.</returns>
635+ /// <remarks>Allows you to specify a replacement character (e.g., you may want to use a non-breaking space: Convert.ToChar(160)).</remarks>
636+ public static string ReplaceControlCharacters(this string value, char replacementCharacter)
637+ {
638+ return value.ReplaceCharacters(replacementCharacter, char.IsControl);
639+ }
640+
641+ /// <summary>
642+ /// Removes all carriage returns and line feeds from a string.
643+ /// </summary>
644+ /// <param name="value">Input string.</param>
645+ /// <returns>Returns <paramref name="value" /> with all CR and LF characters removed.</returns>
646+ public static string RemoveCrLfs(this string value)
647+ {
648+ return value.RemoveCharacters(c => c == '\r' || c == '\n');
649+ }
650+
651+ /// <summary>
652+ /// Replaces all carriage return and line feed characters (as well as CR/LF sequences) in a string with specified replacement character.
653+ /// </summary>
654+ /// <param name="value">Input string.</param>
655+ /// <param name="replacementCharacter">Character used to "replace" CR and LF characters.</param>
656+ /// <returns>Returns <paramref name="value" /> with all CR and LF characters replaced.</returns>
657+ /// <remarks>Allows you to specify a replacement character (e.g., you may want to use a non-breaking space: Convert.ToChar(160)).</remarks>
658+ public static string ReplaceCrLfs(this string value, char replacementCharacter)
659+ {
660+ // <pex>
661+ if (value == (string)null)
662+ throw new ArgumentNullException("value");
663+ // </pex>
664+ return value.Replace(Environment.NewLine, replacementCharacter.ToString()).ReplaceCharacters(replacementCharacter, c => c == '\r' || c == '\n');
665+ }
666+
667+ /// <summary>
668+ /// Removes duplicate character strings (adjoining replication) in a string.
669+ /// </summary>
670+ /// <param name="value">Input string.</param>
671+ /// <param name="duplicatedValue">String whose duplicates are to be removed.</param>
672+ /// <returns>Returns <paramref name="value" /> with all duplicated <paramref name="duplicatedValue" /> removed.</returns>
673+ public static string RemoveDuplicates(this string value, string duplicatedValue)
674+ {
675+ if (string.IsNullOrEmpty(value))
676+ return "";
677+ if (string.IsNullOrEmpty(duplicatedValue))
678+ return value;
679+
680+ string duplicate = duplicatedValue + duplicatedValue;
681+
682+ while (value.IndexOf(duplicate) > -1)
683+ {
684+ value = value.Replace(duplicate, duplicatedValue);
685+ }
686+
687+ return value;
688+ }
689+
690+ /// <summary>
691+ /// Removes the terminator ('\0') from a null terminated string.
692+ /// </summary>
693+ /// <param name="value">Input string.</param>
694+ /// <returns>Returns <paramref name="value" /> with all characters to the left of the terminator.</returns>
695+ public static string RemoveNull(this string value)
696+ {
697+ if (string.IsNullOrEmpty(value))
698+ return "";
699+
700+ int nullPos = value.IndexOf('\0');
701+
702+ if (nullPos > -1)
703+ return value.Substring(0, nullPos);
704+ else
705+ return value;
706+ }
707+
708+ /// <summary>
709+ /// Replaces all repeating white space with a single space.
710+ /// </summary>
711+ /// <param name="value">Input string.</param>
712+ /// <returns>Returns <paramref name="value" /> with all duplicate white space removed.</returns>
713+ public static string RemoveDuplicateWhiteSpace(this string value)
714+ {
715+ return value.RemoveDuplicateWhiteSpace(' ');
716+ }
717+
718+ /// <summary>
719+ /// Replaces all repeating white space with specified spacing character.
720+ /// </summary>
721+ /// <param name="value">Input string.</param>
722+ /// <param name="spacingCharacter">Character value to use to insert as single white space value.</param>
723+ /// <returns>Returns <paramref name="value" /> with all duplicate white space removed.</returns>
724+ /// <remarks>This function allows you to specify spacing character (e.g., you may want to use a non-breaking space: <c>Convert.ToChar(160)</c>).</remarks>
725+ public static string RemoveDuplicateWhiteSpace(this string value, char spacingCharacter)
726+ {
727+ if (string.IsNullOrEmpty(value))
728+ return "";
729+
730+ StringBuilder result = new StringBuilder();
731+ bool lastCharWasSpace = false;
732+ char character;
733+
734+ for (int x = 0; x < value.Length; x++)
735+ {
736+ character = value[x];
737+
738+ if (char.IsWhiteSpace(character))
739+ {
740+ lastCharWasSpace = true;
741+ }
742+ else
743+ {
744+ if (lastCharWasSpace)
745+ result.Append(spacingCharacter);
746+
747+ result.Append(character);
748+ lastCharWasSpace = false;
749+ }
750+ }
751+
752+ return result.ToString();
753+ }
754+
755+ /// <summary>
756+ /// Removes all invalid file name characters (\ / : * ? " &lt; &gt; |) from a string.
757+ /// </summary>
758+ /// <param name="value">Input string.</param>
759+ /// <returns>Returns <paramref name="value" /> with all invalid file name characters removed.</returns>
760+ public static string RemoveInvalidFileNameCharacters(this string value)
761+ {
762+ return value.RemoveCharacters(c => Array.IndexOf(Path.GetInvalidFileNameChars(), c) >= 0);
763+ }
764+
765+ /// <summary>
766+ /// Replaces all invalid file name characters (\ / : * ? " &lt; &gt; |) in a string with the specified <paramref name="replacementCharacter"/>.
767+ /// </summary>
768+ /// <param name="value">Input string.</param>
769+ /// <param name="replacementCharacter">Character used to replace the invalid characters.</param>
770+ /// <returns>>Returns <paramref name="value" /> with all invalid file name characters replaced.</returns>
771+ public static string ReplaceInvalidFileNameCharacters(this string value, char replacementCharacter)
772+ {
773+ return value.ReplaceCharacters(replacementCharacter, c => Array.IndexOf(Path.GetInvalidFileNameChars(), c) >= 0);
774+ }
775+
776+ /// <summary>
777+ /// Counts the total number of the occurances of a character in the given string.
778+ /// </summary>
779+ /// <param name="value">Input string.</param>
780+ /// <param name="characterToCount">Character to be counted.</param>
781+ /// <returns>Total number of the occurances of <paramref name="characterToCount" /> in the given string.</returns>
782+ public static int CharCount(this string value, char characterToCount)
783+ {
784+ if (string.IsNullOrEmpty(value))
785+ return 0;
786+
787+ int total = 0;
788+
789+ for (int x = 0; x < value.Length; x++)
790+ {
791+ if (value[x] == characterToCount)
792+ total++;
793+ }
794+
795+ return total;
796+ }
797+
798+ /// <summary>
799+ /// Tests to see if a string is contains only digits based on Char.IsDigit function.
800+ /// </summary>
801+ /// <param name="value">Input string.</param>
802+ /// <returns>True, if all string's characters are digits; otherwise, false.</returns>
803+ /// <seealso cref="char.IsDigit(char)"/>
804+ public static bool IsAllDigits(this string value)
805+ {
806+ if (string.IsNullOrEmpty(value))
807+ return false;
808+
809+ value = value.Trim();
810+ if (value.Length == 0)
811+ return false;
812+
813+ for (int x = 0; x < value.Length; x++)
814+ {
815+ if (!char.IsDigit(value[x]))
816+ return false;
817+ }
818+
819+ return true;
820+ }
821+
822+ /// <summary>
823+ /// Tests to see if a string contains only numbers based on Char.IsNumber function.
824+ /// </summary>
825+ /// <param name="value">Input string.</param>
826+ /// <returns>True, if all string's characters are numbers; otherwise, false.</returns>
827+ /// <seealso cref="char.IsNumber(char)"/>
828+ public static bool IsAllNumbers(this string value)
829+ {
830+ if (string.IsNullOrEmpty(value))
831+ return false;
832+
833+ value = value.Trim();
834+ if (value.Length == 0)
835+ return false;
836+
837+ for (int x = 0; x < value.Length; x++)
838+ {
839+ if (!char.IsNumber(value[x]))
840+ return false;
841+ }
842+
843+ return true;
844+ }
845+
846+ /// <summary>
847+ /// Tests to see if a string's letters are all upper case.
848+ /// </summary>
849+ /// <param name="value">Input string.</param>
850+ /// <returns>True, if all string's letter characters are upper case; otherwise, false.</returns>
851+ public static bool IsAllUpper(this string value)
852+ {
853+ if (string.IsNullOrEmpty(value))
854+ return false;
855+
856+ value = value.Trim();
857+ if (value.Length == 0)
858+ return false;
859+
860+ for (int x = 0; x < value.Length; x++)
861+ {
862+ if (char.IsLetter(value[x]) && !char.IsUpper(value[x]))
863+ return false;
864+ }
865+
866+ return true;
867+ }
868+
869+ /// <summary>
870+ /// Tests to see if a string's letters are all lower case.
871+ /// </summary>
872+ /// <param name="value">Input string.</param>
873+ /// <returns>True, if all string's letter characters are lower case; otherwise, false.</returns>
874+ public static bool IsAllLower(this string value)
875+ {
876+ if (string.IsNullOrEmpty(value))
877+ return false;
878+
879+ value = value.Trim();
880+ if (value.Length == 0)
881+ return false;
882+
883+ for (int x = 0; x < value.Length; x++)
884+ {
885+ if (char.IsLetter(value[x]) && !char.IsLower(value[x]))
886+ return false;
887+ }
888+
889+ return true;
890+ }
891+
892+ /// <summary>
893+ /// Tests to see if a string contains only letters.
894+ /// </summary>
895+ /// <param name="value">Input string.</param>
896+ /// <returns>True, if all string's characters are letters; otherwise, false.</returns>
897+ /// <remarks>Any non-letter character (e.g., punctuation marks) causes this function to return false (See overload to ignore punctuation
898+ /// marks.).</remarks>
899+ public static bool IsAllLetters(this string value)
900+ {
901+ return value.IsAllLetters(false);
902+ }
903+
904+ /// <summary>
905+ /// Tests to see if a string contains only letters.
906+ /// </summary>
907+ /// <param name="value">Input string.</param>
908+ /// <param name="ignorePunctuation">Set to True to ignore punctuation.</param>
909+ /// <returns>True, if all string's characters are letters; otherwise, false.</returns>
910+ public static bool IsAllLetters(this string value, bool ignorePunctuation)
911+ {
912+ if (string.IsNullOrEmpty(value))
913+ return false;
914+
915+ value = value.Trim();
916+ if (value.Length == 0)
917+ return false;
918+
919+ for (int x = 0; x < value.Length; x++)
920+ {
921+ if (ignorePunctuation)
922+ {
923+ if (!(char.IsLetter(value[x]) || char.IsPunctuation(value[x])))
924+ return false;
925+ }
926+ else
927+ {
928+ if (!char.IsLetter(value[x]))
929+ return false;
930+ }
931+ }
932+
933+ return true;
934+ }
935+
936+ /// <summary>
937+ /// Tests to see if a string contains only letters or digits.
938+ /// </summary>
939+ /// <param name="value">Input string.</param>
940+ /// <returns>True, if all string's characters are either letters or digits; otherwise, false.</returns>
941+ /// <remarks>Any non-letter, non-digit character (e.g., punctuation marks) causes this function to return false (See overload to ignore
942+ /// punctuation marks.).</remarks>
943+ public static bool IsAllLettersOrDigits(this string value)
944+ {
945+ return value.IsAllLettersOrDigits(false);
946+ }
947+
948+ /// <summary>
949+ /// Tests to see if a string contains only letters or digits.
950+ /// </summary>
951+ /// <param name="value">Input string.</param>
952+ /// <param name="ignorePunctuation">Set to True to ignore punctuation.</param>
953+ /// <returns>True, if all string's characters are letters or digits; otherwise, false.</returns>
954+ public static bool IsAllLettersOrDigits(this string value, bool ignorePunctuation)
955+ {
956+ if (string.IsNullOrEmpty(value))
957+ return false;
958+
959+ value = value.Trim();
960+ if (value.Length == 0)
961+ return false;
962+
963+ for (int x = 0; x < value.Length; x++)
964+ {
965+ if (ignorePunctuation)
966+ {
967+ if (!(char.IsLetterOrDigit(value[x]) || char.IsPunctuation(value[x])))
968+ return false;
969+ }
970+ else
971+ {
972+ if (!char.IsLetterOrDigit(value[x]))
973+ return false;
974+ }
975+ }
976+
977+ return true;
978+ }
979+
980+ /// <summary>
981+ /// Decodes the specified Regular Expression character back into a standard Unicode character.
982+ /// </summary>
983+ /// <param name="value">Regular Expression character to decode back into a Unicode character.</param>
984+ /// <returns>Standard Unicode character representation of specified Regular Expression character.</returns>
985+ public static char RegexDecode(this string value)
986+ {
987+ // <pex>
988+ if (value == (string)null)
989+ throw new ArgumentNullException("value");
990+ // </pex>
991+ return Convert.ToChar(Convert.ToUInt16(value.Replace("\\u", "0x"), 16));
992+ }
993+
994+ /// <summary>
995+ /// Encodes a string into a base-64 string.
996+ /// </summary>
997+ /// <param name="value">Input string.</param>
998+ /// <remarks>
999+ /// <para>Performs a base-64 style of string encoding useful for data obfuscation or safe XML data string transmission.</para>
1000+ /// <para>Note: This function encodes a "String". Use the Convert.ToBase64String function to encode a binary data buffer.</para>
1001+ /// </remarks>
1002+ /// <returns>A <see cref="String"></see> value representing the encoded input of <paramref name="value"/>.</returns>
1003+ public static string Base64Encode(this string value)
1004+ {
1005+ return Convert.ToBase64String(Encoding.Unicode.GetBytes(value));
1006+ }
1007+
1008+ /// <summary>
1009+ /// Decodes a given base-64 encoded string encoded with <see cref="Base64Encode" />.
1010+ /// </summary>
1011+ /// <param name="value">Input string.</param>
1012+ /// <remarks>Note: This function decodes value back into a "String". Use the Convert.FromBase64String function to decode a base-64 encoded
1013+ /// string back into a binary data buffer.</remarks>
1014+ /// <returns>A <see cref="String"></see> value representing the decoded input of <paramref name="value"/>.</returns>
1015+ public static string Base64Decode(this string value)
1016+ {
1017+ return Encoding.Unicode.GetString(Convert.FromBase64String(value));
1018+ }
1019+
1020+ /// <summary>
1021+ /// Converts the provided string into title case (upper case first letter of each word).
1022+ /// </summary>
1023+ /// <param name="value">Input string.</param>
1024+ /// <remarks>Note: This function performs "ToLower" in input string then applies TextInfo.ToTitleCase for CurrentCulture. This way, even
1025+ /// strings formatted in all-caps will still be properly formatted.</remarks>
1026+ /// <returns>A <see cref="String"/> that has the first letter of each word capitalized.</returns>
1027+ public static string ToTitleCase(this string value)
1028+ {
1029+ if (string.IsNullOrEmpty(value))
1030+ return "";
1031+
1032+ return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(value.ToLower());
1033+ }
1034+
1035+ /// <summary>
1036+ /// Truncates the provided string from the left if it is longer that specified length.
1037+ /// </summary>
1038+ /// <param name="value">A <see cref="String"/> value that is to be truncated.</param>
1039+ /// <param name="maxLength">The maximum number of characters that <paramref name="value"/> can be.</param>
1040+ /// <returns>A <see cref="String"/> that is the truncated version of the <paramref name="value"/> string.</returns>
1041+ public static string TruncateLeft(this string value, int maxLength)
1042+ {
1043+ if (string.IsNullOrEmpty(value))
1044+ return "";
1045+
1046+ if (value.Length > maxLength)
1047+ return value.Substring(value.Length - maxLength);
1048+
1049+ return value;
1050+ }
1051+
1052+ /// <summary>
1053+ /// Truncates the provided string from the right if it is longer that specified length.
1054+ /// </summary>
1055+ /// <param name="value">A <see cref="String"/> value that is to be truncated.</param>
1056+ /// <param name="maxLength">The maximum number of characters that <paramref name="value"/> can be.</param>
1057+ /// <returns>A <see cref="String"/> that is the truncated version of the <paramref name="value"/> string.</returns>
1058+ public static string TruncateRight(this string value, int maxLength)
1059+ {
1060+ if (string.IsNullOrEmpty(value))
1061+ return "";
1062+
1063+ if (value.Length > maxLength)
1064+ return value.Substring(0, maxLength);
1065+
1066+ return value;
1067+ }
1068+
1069+ /// <summary>
1070+ /// Centers text within the specified maximum length, biased to the left.
1071+ /// Text will be padded to the left and right with spaces.
1072+ /// If value is greater than specified maximum length, value returned will be truncated from the right.
1073+ /// </summary>
1074+ /// <remarks>
1075+ /// Handles multiple lines of text separated by Environment.NewLine.
1076+ /// </remarks>
1077+ /// <param name="value">A <see cref="String"/> to be centered.</param>
1078+ /// <param name="maxLength">An <see cref="Int32"/> that is the maximum length of padding.</param>
1079+ /// <returns>The centered string value.</returns>
1080+ public static string CenterText(this string value, int maxLength)
1081+ {
1082+ return value.CenterText(maxLength, ' ');
1083+ }
1084+
1085+ /// <summary>
1086+ /// Centers text within the specified maximum length, biased to the left.
1087+ /// Text will be padded to the left and right with specified padding character.
1088+ /// If value is greater than specified maximum length, value returned will be truncated from the right.
1089+ /// </summary>
1090+ /// <remarks>
1091+ /// Handles multiple lines of text separated by <c>Environment.NewLine</c>.
1092+ /// </remarks>
1093+ /// <param name="value">A <see cref="String"/> to be centered.</param>
1094+ /// <param name="maxLength">An <see cref="Int32"/> that is the maximum length of padding.</param>
1095+ /// <param name="paddingCharacter">The <see cref="char"/> value to pad with.</param>
1096+ /// <returns>The centered string value.</returns>
1097+ public static string CenterText(this string value, int maxLength, char paddingCharacter)
1098+ {
1099+ if ((object)value == null)
1100+ value = "";
1101+
1102+ // If the text to be centered contains multiple lines, centers all the lines individually.
1103+ StringBuilder result = new StringBuilder();
1104+ string[] lines = value.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
1105+ string line;
1106+ int lastLineIndex = lines.Length - 1; //(lines.Length != 0 && lines[lines.Length - 1].Trim() == string.Empty ? lines.Length - 2 : lines.Length - 1);
1107+
1108+ for (int i = 0; i <= lastLineIndex; i++)
1109+ {
1110+ // Gets current line.
1111+ line = lines[i];
1112+
1113+ // Skips the last empty line as a result of split if original text had multiple lines.
1114+ if (i == lastLineIndex && line.Trim().Length == 0)
1115+ continue;
1116+
1117+ if (line.Length >= maxLength)
1118+ {
1119+ // Truncates excess characters on the right.
1120+ result.Append(line.Substring(0, maxLength));
1121+ }
1122+ else
1123+ {
1124+ int remainingSpace = maxLength - line.Length;
1125+ int leftSpaces;
1126+ int rightSpaces;
1127+
1128+ // Splits remaining space between the left and the right.
1129+ leftSpaces = remainingSpace / 2;
1130+ rightSpaces = leftSpaces;
1131+
1132+ // Adds any remaining odd space to the right (bias text to the left).
1133+ if (remainingSpace % 2 > 0)
1134+ rightSpaces++;
1135+
1136+ result.Append(new string(paddingCharacter, leftSpaces));
1137+ result.Append(line);
1138+ result.Append(new string(paddingCharacter, rightSpaces));
1139+ }
1140+
1141+ // Creates a new line only if the original text contains multiple lines.
1142+ if (i < lastLineIndex)
1143+ result.AppendLine();
1144+ }
1145+
1146+ return result.ToString();
1147+ }
1148+ /// <summary>
1149+ /// Performs a case insensitive string replacement.
1150+ /// </summary>
1151+ /// <param name="value">The string to examine.</param>
1152+ /// <param name="fromText">The value to replace.</param>
1153+ /// <param name="toText">The new value to be inserted</param>
1154+ /// <returns>A string with replacements.</returns>
1155+ public static string ReplaceCaseInsensitive(this string value, string fromText, string toText)
1156+ {
1157+ return (new Regex(fromText, RegexOptions.IgnoreCase | RegexOptions.Multiline)).Replace(value, toText);
1158+ }
1159+
1160+ /// <summary>
1161+ /// Ensures a string starts with a specific character.
1162+ /// </summary>
1163+ /// <param name="value">Input string to process.</param>
1164+ /// <param name="startChar">The character desired at string start.</param>
1165+ /// <returns>The sent string with character at the start.</returns>
1166+ public static string EnsureStart(this string value, char startChar)
1167+ {
1168+ return EnsureStart(value, startChar, false);
1169+ }
1170+
1171+ /// <summary>
1172+ /// Ensures a string starts with a specific character.
1173+ /// </summary>
1174+ /// <param name="value">Input string to process.</param>
1175+ /// <param name="startChar">The character desired at string start.</param>
1176+ /// <param name="removeRepeatingChar">Set to <c>true</c> to ensure one and only one instance of <paramref name="startChar"/>.</param>
1177+ /// <returns>The sent string with character at the start.</returns>
1178+ public static string EnsureStart(this string value, char startChar, bool removeRepeatingChar)
1179+ {
1180+ if (string.IsNullOrEmpty(value))
1181+ return "";
1182+
1183+ if (startChar == 0)
1184+ return value;
1185+
1186+ if (value[0] == startChar)
1187+ {
1188+ if (removeRepeatingChar)
1189+ return value.Substring(LastIndexOfRepeatedChar(value, startChar, 0));
1190+ return value;
1191+ }
1192+ else
1193+ return string.Concat(startChar, value);
1194+ }
1195+
1196+ /// <summary>
1197+ /// Ensures a string starts with a specific string.
1198+ /// </summary>
1199+ /// <param name="value">Input string to process.</param>
1200+ /// <param name="startString">The string desired at string start.</param>
1201+ /// <returns>The sent string with string at the start.</returns>
1202+ public static string EnsureStart(this string value, string startString)
1203+ {
1204+ if (string.IsNullOrEmpty(value))
1205+ return "";
1206+
1207+ if (string.IsNullOrEmpty(startString))
1208+ return value;
1209+
1210+ if (value.IndexOf(startString) == 0)
1211+ return value;
1212+ else
1213+ return string.Concat(startString, value);
1214+ }
1215+
1216+ /// <summary>
1217+ /// Ensures a string ends with a specific character.
1218+ /// </summary>
1219+ /// <param name="value">Input string to process.</param>
1220+ /// <param name="endChar">The character desired at string's end.</param>
1221+ /// <returns>The sent string with character at the end.</returns>
1222+ public static string EnsureEnd(this string value, char endChar)
1223+ {
1224+ return EnsureEnd(value, endChar, false);
1225+ }
1226+
1227+ /// <summary>
1228+ /// Ensures a string ends with a specific character.
1229+ /// </summary>
1230+ /// <param name="value">Input string to process.</param>
1231+ /// <param name="endChar">The character desired at string's end.</param>
1232+ /// <param name="removeRepeatingChar">Set to <c>true</c> to ensure one and only one instance of <paramref name="endChar"/>.</param>
1233+ /// <returns>The sent string with character at the end.</returns>
1234+ public static string EnsureEnd(this string value, char endChar, bool removeRepeatingChar)
1235+ {
1236+ if (string.IsNullOrEmpty(value))
1237+ return "";
1238+
1239+ if (endChar == 0)
1240+ return value;
1241+
1242+ if (value[value.Length - 1] == endChar)
1243+ {
1244+ if (removeRepeatingChar)
1245+ {
1246+ int i = LastIndexOfRepeatedChar(value.Reverse(), endChar, 0);
1247+ return value.Substring(0, value.Length - i);
1248+ }
1249+ return value;
1250+ }
1251+ else
1252+ return string.Concat(value, endChar);
1253+ }
1254+
1255+ /// <summary>
1256+ /// Ensures a string ends with a specific string.
1257+ /// </summary>
1258+ /// <param name="value">Input string to process.</param>
1259+ /// <param name="endString">The string desired at string's end.</param>
1260+ /// <returns>The sent string with string at the end.</returns>
1261+ public static string EnsureEnd(this string value, string endString)
1262+ {
1263+ if (string.IsNullOrEmpty(value))
1264+ return "";
1265+
1266+ if (string.IsNullOrEmpty(endString))
1267+ return value;
1268+
1269+ if (value.EndsWith(endString))
1270+ return value;
1271+ else
1272+ return string.Concat(value, endString);
1273+ }
1274+
1275+ /// <summary>
1276+ /// Reverses the order of the characters in a string.
1277+ /// </summary>
1278+ /// <param name="value">Input string to process.</param>
1279+ /// <returns>The reversed string.</returns>
1280+ public static string Reverse(this string value)
1281+ {
1282+ // Experimented with several approaches. This is the fastest.
1283+ // Replaced original code that yielded 1.5% performance increase.
1284+ // This code is faster than Array.Reverse.
1285+
1286+ if (string.IsNullOrEmpty(value))
1287+ return "";
1288+
1289+ char[] arrChar = value.ToCharArray();
1290+ char temp;
1291+ int arrLength = arrChar.Length;
1292+ int j;
1293+
1294+ // Works for odd and even length strings since middle char is not swapped for an odd length string
1295+ for (int i = 0; i < arrLength / 2; i++)
1296+ {
1297+ j = arrLength - i - 1;
1298+ temp = arrChar[i];
1299+ arrChar[i] = arrChar[j];
1300+ arrChar[j] = temp;
1301+ }
1302+
1303+ return new string(arrChar);
1304+ }
1305+
1306+ /// <summary>
1307+ /// Searches a string for a repeated instance of the specified <paramref name="characterToFind"/> from specified <paramref name="startIndex"/>.
1308+ /// </summary>
1309+ /// <param name="value">The string to process.</param>
1310+ /// <param name="characterToFind">The character of interest.</param>
1311+ /// <param name="startIndex">The index from which to begin the search.</param>
1312+ /// <returns>The index of the first instance of the character that is repeated or (-1) if no repeated chars found.</returns>
1313+ public static int IndexOfRepeatedChar(this string value, char characterToFind, int startIndex)
1314+ {
1315+ if (string.IsNullOrEmpty(value))
1316+ return -1;
1317+
1318+ if (startIndex < 0)
1319+ return -1;
1320+
1321+ if (characterToFind == 0)
1322+ return -1;
1323+
1324+ char c = (char)0;
1325+
1326+ for (int i = startIndex; i < value.Length; i++)
1327+ {
1328+ if (value[i] == characterToFind)
1329+ {
1330+ if (value[i] != c)
1331+ c = value[i];
1332+ else
1333+ {
1334+ //at least one repeating character
1335+ return i - 1;
1336+ }
1337+ }
1338+ else
1339+ c = (char)0;
1340+ }
1341+
1342+ return -1;
1343+ }
1344+
1345+ /// <summary>
1346+ /// Searches a string for a repeated instance of the specified <paramref name="characterToFind"/>.
1347+ /// </summary>
1348+ /// <param name="value">The string to process.</param>
1349+ /// <param name="characterToFind">The character of interest.</param>
1350+ /// <returns>The index of the first instance of the character that is repeated or (-1) if no repeated chars found.</returns>
1351+ public static int IndexOfRepeatedChar(this string value, char characterToFind)
1352+ {
1353+ return IndexOfRepeatedChar(value, characterToFind, 0);
1354+ }
1355+
1356+ /// <summary>
1357+ /// Searches a string for an instance of a repeated character.
1358+ /// </summary>
1359+ /// <param name="value">The string to process.</param>
1360+ /// <returns>The index of the first instance of any character that is repeated or (-1) if no repeated chars found.</returns>
1361+ public static int IndexOfRepeatedChar(this string value)
1362+ {
1363+ return IndexOfRepeatedChar(value, 0);
1364+ }
1365+
1366+ /// <summary>
1367+ /// Searches a string for an instance of a repeated character from specified <paramref name="startIndex"/>.
1368+ /// </summary>
1369+ /// <param name="value">The string to process.</param>
1370+ /// <param name="startIndex">The index from which to begin the search.</param>
1371+ /// <returns>The index of the first instance of any character that is repeated or (-1) if no repeated chars found.</returns>
1372+ public static int IndexOfRepeatedChar(this string value, int startIndex)
1373+ {
1374+ if (string.IsNullOrEmpty(value))
1375+ return -1;
1376+
1377+ if (startIndex < 0)
1378+ return -1;
1379+
1380+ char c = (char)0;
1381+
1382+ for (int i = startIndex; i < value.Length; i++)
1383+ {
1384+ if (value[i] != c)
1385+ c = value[i];
1386+ else
1387+ {
1388+ //at least one repeating character
1389+ return i - 1;
1390+ }
1391+ }
1392+ return -1;
1393+ }
1394+
1395+ /// <summary>
1396+ /// Returns the index of the last repeated index of the first group of repeated characters that begin with the <paramref name="characterToFind"/>.
1397+ /// </summary>
1398+ /// <param name="value">String to process.</param>
1399+ /// <param name="characterToFind">The character of interest.</param>
1400+ /// <param name="startIndex">The index from which to begin the search.</param>
1401+ /// <returns>The index of the last instance of the character that is repeated or (-1) if no repeated chars found.</returns>
1402+ private static int LastIndexOfRepeatedChar(string value, char characterToFind, int startIndex)
1403+ {
1404+ if (startIndex > value.Length - 1)
1405+ return -1;
1406+
1407+ int i = value.IndexOf(characterToFind, startIndex);
1408+
1409+ if (i == -1)
1410+ return -1;
1411+
1412+ for (int j = i + 1; j < value.Length; j++)
1413+ {
1414+ if (value[j] != characterToFind)
1415+ return j - 1;
1416+ }
1417+
1418+ return value.Length - 1;
1419+ }
1420+
1421+ /// <summary>
1422+ /// Places an ellipsis in the middle of a string as it is trimmed to length specified.
1423+ /// </summary>
1424+ /// <param name="value">The string to process.</param>
1425+ /// <param name="length">The maximum returned string length; mimimum value is 5.</param>
1426+ /// <returns>
1427+ /// A trimmed string of the specified <paramref name="length"/> or empty string if <paramref name="value"/> is null or empty.
1428+ /// </returns>
1429+ /// <remarks>
1430+ /// Returned string is not padded to fill field length if <paramref name="value"/> is shorter than length.
1431+ /// </remarks>
1432+ public static string TrimWithEllipsisMiddle(this string value, int length)
1433+ {
1434+ if (string.IsNullOrEmpty(value))
1435+ return "";
1436+
1437+ if (length < 5)
1438+ length = 5;
1439+
1440+ value = value.Trim();
1441+
1442+ if (value.Length <= length)
1443+ return value;
1444+
1445+ int s1_Len = (int)(length / 2) - 1;
1446+
1447+ return string.Concat(value.Substring(0, s1_Len), "...", value.Substring(value.Length - s1_Len + 1 - length % 2));
1448+ }
1449+
1450+ /// <summary>
1451+ /// Places an ellipsis at the end of a string as it is trimmed to length specified.
1452+ /// </summary>
1453+ /// <param name="value">The string to process.</param>
1454+ /// <param name="length">The maximum returned string length; mimimum value is 5.</param>
1455+ /// <returns>
1456+ /// A trimmed string of the specified <paramref name="length"/> or empty string if <paramref name="value"/> is null or empty.
1457+ /// </returns>
1458+ /// <remarks>
1459+ /// Returned string is not padded to fill field length if <paramref name="value"/> is shorter than length.
1460+ /// </remarks>
1461+ public static string TrimWithEllipsisEnd(this string value, int length)
1462+ {
1463+ if (string.IsNullOrEmpty(value))
1464+ return "";
1465+
1466+ if (length < 5)
1467+ length = 5;
1468+
1469+ value = value.Trim();
1470+
1471+ if (value.Length <= length)
1472+ return value;
1473+
1474+ return string.Concat(value.Substring(0, length - 3), "...");
1475+ }
1476+ }
1477+}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t