Click here to Skip to main content
15,894,405 members
Articles / Web Development / ASP.NET

Zeta Enterprise Library

Rate me:
Please Sign up or sign in to vote.
4.97/5 (14 votes)
16 Jan 2010CPOL3 min read 50.4K   2.3K   48  
A small set of general-purpose classes for using in .NET applications (2.0 or higher)
namespace Zeta.EnterpriseLibrary.Tools
{
	#region Using directives.
	// ----------------------------------------------------------------------

	using System;
	using System.Collections;
	using System.Collections.Generic;
	using System.Collections.Specialized;
	using System.ComponentModel;
	using System.Diagnostics;
	using System.Globalization;
	using System.IO;
	using System.Reflection;
	using System.Runtime.Serialization;
	using System.Runtime.Serialization.Formatters.Binary;
	using System.Security.Cryptography;
	using System.Text;
	using System.Text.RegularExpressions;
	using System.Threading;
	using Common.Collections;
	using Properties;

	// ----------------------------------------------------------------------
	#endregion

	/////////////////////////////////////////////////////////////////////////

	/// <summary>
	/// Miscellaneous helper functions for strings.
	/// </summary>
	public sealed class StringHelper
	{
		#region Special conversions from and to strings.
		// ------------------------------------------------------------------

		/// <summary>
		/// Serializes an object to a string.
		/// </summary>
		/// <param name="o">The object to serialize.</param>
		/// <returns>
		/// Returns the base64-encoded string
		/// that represents the serialized object.
		/// </returns>
		public static string SerializeToString(
			object o )
		{
			if ( o == null )
			{
				return null;
			}
			else
			{
				var dic = o as StringDictionary;

				// Special case for string dictionary.
				if ( dic != null )
				{
					var ht = new Hashtable();

					foreach ( string key in dic.Keys )
					{
						ht[key] = dic[key];
					}

					// Remember.
					ht[stringDictionaryKey] = true;

					o = ht;
				}

				IFormatter f = new BinaryFormatter();
				using ( var stream = new MemoryStream() )
				{
					f.Serialize( stream, o );

					var buf = stream.ToArray();
					return Convert.ToBase64String( buf );
				}
			}
		}

		/// <summary>
		/// 
		/// </summary>
		private const string stringDictionaryKey =
			@"__is_StringDictionary_wrapper__";

		/// <summary>
		/// Deserializes an object from a string.
		/// </summary>
		/// <param name="s">The base64-encoded string
		/// that represents the serialized object.</param>
		/// <returns>Returns the deserialized object.</returns>
		public static object DeserializeFromString(
			string s )
		{
			return DeserializeFromString(
				s,
				true );
		}

		/// <summary>
		/// Deserializes an object from a string.
		/// </summary>
		/// <param name="s">The base64-encoded string
		/// that represents the serialized object.</param>
		/// <param name="ignoreSerializationExceptions">if set to <c>true</c> [ignore serialization exceptions].</param>
		/// <returns>Returns the deserialized object.</returns>
		public static object DeserializeFromString(
			string s,
			bool ignoreSerializationExceptions )
		{
			if ( string.IsNullOrEmpty( s ) )
			{
				return null;
			}
			else
			{
				try
				{
					IFormatter f = new BinaryFormatter();

					using ( var stream = new MemoryStream(
						Convert.FromBase64String( s ) ) )
					{
						var o = f.Deserialize( stream );

						// Special case for string dictionary.
						if ( o is Hashtable )
						{
							var ht = o as Hashtable;

							if ( ht.ContainsKey( stringDictionaryKey ) )
							{
								ht.Remove( stringDictionaryKey );

								var dic = new StringDictionary();

								foreach ( string key in ht.Keys )
								{
									var ob = ht[key];

									if ( ob == null )
									{
										dic[key] = null;
									}
									else
									{
										dic[key] = ob.ToString();
									}
								}

								return dic;
							}
							else
							{
								return o;
							}
						}
						else
						{
							return o;
						}
					}
				}
				catch ( FormatException x )
				{
					if ( ignoreSerializationExceptions )
					{
						// Can happen due to legacy issues.
						// Ignore, but log for statistics.
						Trace.TraceWarning(
							string.Format(
								@"FormatException while deserializing from " +
									@"string with {0} characters length ('{1}'). " +
										@"Returning NULL.",
								s.Length,
								s ), x );

						return null;
					}
					else
					{
						throw;
					}
				}
				catch ( SerializationException x )
				{
					if ( ignoreSerializationExceptions )
					{
						// Can happen due to legacy issues.
						// Ignore, but log for statistics.
						Trace.TraceWarning(
							string.Format(
								@"SerializationException while deserializing " +
									@"from string with {0} characters length ('{1}'). " +
										@"Returning NULL.",
								s.Length,
								s ), x );

						return null;
					}
					else
					{
						throw;
					}
				}
				catch ( FileLoadException x )
				{
					if ( ignoreSerializationExceptions )
					{
						// Can happen due to legacy issues.
						// Ignore, but log for statistics.
						Trace.TraceWarning(
							string.Format(
								@"FileLoadException while deserializing " +
									@"from string with {0} characters length ('{1}'). " +
										@"Returning NULL.",
								s.Length,
								s ), x );

						return null;
					}
					else
					{
						throw;
					}
				}
			}
		}

		// ------------------------------------------------------------------
		#endregion

		#region Encryption/decryption.
		// ------------------------------------------------------------------

		/// <summary>
		/// Encrypt a string.
		/// </summary>
		/// <param name="source">The source.</param>
		/// <returns></returns>
		/// <see cref="http://www.codeproject.com/dotnet/encryption_decryption.asp"/>
		/// <see cref="http://dobon.net/vb/dotnet/string/encryptstring.html"/>
		public static string EncryptString(
			string source )
		{
			if ( string.IsNullOrEmpty( source ) )
			{
				return source;
			}
			else
			{
				byte[] bytIn = Encoding.UTF8.GetBytes( source );

				// create a MemoryStream so that the process can be done without I/O files
				using ( MemoryStream ms = new MemoryStream() )
				{
					using ( DESCryptoServiceProvider mobjCryptoService =
						 new DESCryptoServiceProvider() )
					{
						byte[] bytKey = cryptKey;

						// set the private key
						mobjCryptoService.Key = bytKey;
						mobjCryptoService.IV = bytKey;

						// create an Encryptor from the Provider Service instance
						using ( ICryptoTransform encrypto = mobjCryptoService.CreateEncryptor() )
						{
							// create Crypto Stream that transforms a stream using the encryption
							using ( CryptoStream cs = new CryptoStream(
								ms,
								encrypto,
								CryptoStreamMode.Write ) )
							{
								// write out encrypted content into MemoryStream
								cs.Write( bytIn, 0, bytIn.Length );
								cs.FlushFinalBlock();

								// http://www.codeproject.com/dotnet/encryption_decryption.asp?msg=749582#xx749582xx
								byte[] byteOut = ms.GetBuffer();
								return Convert.ToBase64String(
									byteOut,
									0,
									(int)ms.Length );
							}
						}
					}
				}
			}
		}

		/// <summary>
		/// Decrypt a previously encrypted string.
		/// </summary>
		/// <param name="source">The source.</param>
		/// <returns></returns>
		/// <see cref="http://www.codeproject.com/dotnet/encryption_decryption.asp"/>
		/// <see cref="http://dobon.net/vb/dotnet/string/encryptstring.html"/>
		public static string DecryptString(
			string source )
		{
			if ( string.IsNullOrEmpty( source ) )
			{
				return source;
			}
			else
			{
				// convert from Base64 to binary
				var bytIn = Convert.FromBase64String( source );
				// create a MemoryStream with the input
				using ( var ms = new MemoryStream(
					bytIn,
					0,
					bytIn.Length ) )
				{
					byte[] bytKey = cryptKey;

					// set the private key.
					using ( var mobjCryptoService =
						new DESCryptoServiceProvider() )
					{
						mobjCryptoService.Key = bytKey;
						mobjCryptoService.IV = bytKey;

						// create a Decryptor from the Provider Service instance
						using ( var encrypto =
							mobjCryptoService.CreateDecryptor() )
						{
							// create Crypto Stream that transforms a 
							// stream using the decryption
							using ( var cs = new CryptoStream(
								ms,
								encrypto,
								CryptoStreamMode.Read ) )
							{
								// read out the result from the Crypto Stream
								using ( var sr = new StreamReader(
									cs,
									Encoding.UTF8 ) )
								{
									return sr.ReadToEnd();
								}
							}
						}
					}
				}
			}
		}

		/// <summary>
		/// Gets the crypt key.
		/// </summary>
		/// <value>The crypt key.</value>
		private static byte[] cryptKey
		{
			get
			{
				return new byte[]
				{
					0x0E,
					0x41,
					0x6A,
					0x29,
					0x94,
					0x12,
					0xEB,
					0x63
				};
			}
		}

		// ------------------------------------------------------------------
		#endregion

		#region Miscellaneous routines.
		// ------------------------------------------------------------------

		/// <summary>
		/// Reads the description value from an enumeration.
		/// </summary>
		/// <param name="value">The description of the enum value to
		/// read.</param>
		/// <returns>
		/// Returns the description string or the enum value
		/// as a string, if no description was found.
		/// </returns>
		/// <seealso cref="http://www.codeproject.com/csharp/EnumDescConverter.asp."/>
		public static string GetEnumDescription(
			Enum value )
		{
			string result;
			if ( recentEnumDescriptions.TryGetValue( value, out result ) )
			{
				return result;
			}
			else
			{
				FieldInfo fi = value.GetType().GetField( value.ToString() );

				DescriptionAttribute[] attributes =
					(DescriptionAttribute[])fi.GetCustomAttributes(
					typeof( DescriptionAttribute ),
					false );

				if ( attributes != null &&
					attributes.Length > 0 )
				{
					result = attributes[0].Description;
				}
				else
				{
					result = value.ToString();
				}

				recentEnumDescriptions[value] = result;
				return result;
			}
		}

		/// <summary>
		/// Generate a MD5 hash from a given string.
		/// </summary>
		/// <param name="input">The input.</param>
		/// <returns></returns>
		public static string GenerateHash(
			string input )
		{
			if ( string.IsNullOrEmpty( input ) )
			{
				return input;
			}
			else
			{
				return input.GetHashCode().ToString(
					@"X",
					CultureInfo.InvariantCulture );
			}
		}

		/// <summary>
		/// Converts a numeric value into a string that represents the number
		/// expressed as a size value in bytes, kilobytes, megabytes, or
		/// gigabytes, depending on the size.
		/// </summary>
		/// <param name="fileSize">Size of the file.</param>
		/// <returns></returns>
		public static string FormatFileSize(
			int fileSize )
		{
			return FormatFileSize( (long)fileSize );
		}

		/// <summary>
		/// Converts a numeric value into a string that represents the number
		/// expressed as a size value in bytes, kilobytes, megabytes, or
		/// gigabytes, depending on the size.
		/// </summary>
		/// <param name="fileSize">Size of the file.</param>
		/// <returns></returns>
		public static string FormatFileSize(
			long fileSize )
		{
			const long fileSize1KB = 1024;
			const long fileSize100KB = 102400;
			const long fileSize1MB = 1048576;
			const long fileSize1GB = 1073741824;
			const long fileSize1TB = 1099511627776;

			if ( fileSize < fileSize1KB )
			{
				return string.Format(
					Thread.CurrentThread.CurrentCulture,
					@"{0} {1}",
					fileSize,
					Resources.Str_FormatFileSize_Bytes );
			}
			else if ( fileSize < fileSize100KB )
			{
				return string.Format(
					Thread.CurrentThread.CurrentCulture,
					@"{0:F1} {1}",
					fileSize / (double)fileSize1KB,
					Resources.Str_FormatFileSize_KB );
			}
			else if ( fileSize < fileSize1MB )
			{
				return string.Format(
					Thread.CurrentThread.CurrentCulture,
					@"{0} {1}",
					fileSize / fileSize1KB,
					Resources.Str_FormatFileSize_KB );
			}
			else if ( fileSize < fileSize1GB )
			{
				return string.Format(
					Thread.CurrentThread.CurrentCulture,
					@"{0:F1} {1}",
					fileSize / (double)fileSize1MB,
					Resources.Str_FormatFileSize_MB );
			}
			else if ( fileSize < fileSize1TB )
			{
				return string.Format(
					Thread.CurrentThread.CurrentCulture,
					@"{0:F2} {1}",
					fileSize / (double)fileSize1GB,
					Resources.Str_FormatFileSize_GB );
			}
			else
			{
				return string.Format(
					Thread.CurrentThread.CurrentCulture,
					@"{0:F2} {1}",
					fileSize / (double)fileSize1TB,
					Resources.Str_FormatFileSize_TB );
			}
		}

		/// <summary>
		/// Escape special RX characters.
		/// </summary>
		/// <param name="text">The text.</param>
		/// <param name="ignoreChars">The ignore chars.</param>
		/// <returns></returns>
		public static string EscapeRXCharacters(
			string text,
			params char[] ignoreChars )
		{
			Set<char> ignores = new Set<char>( ignoreChars );

			// As first!
			if ( !ignores.Contains( '\\' ) )
			{
				text = text.Replace( @"\", @"\\" );
			}

			if ( !ignores.Contains( '+' ) )
			{
				text = text.Replace( @"+", @"\+" );
			}
			if ( !ignores.Contains( '+' ) )
			{
				text = text.Replace( @"?", @"\?" );
			}
			if ( !ignores.Contains( '.' ) )
			{
				text = text.Replace( @".", @"\." );
			}
			if ( !ignores.Contains( '*' ) )
			{
				text = text.Replace( @"*", @"\*" );
			}
			if ( !ignores.Contains( '^' ) )
			{
				text = text.Replace( @"^", @"\^" );
			}
			if ( !ignores.Contains( '$' ) )
			{
				text = text.Replace( @"$", @"\$" );
			}
			if ( !ignores.Contains( '(' ) )
			{
				text = text.Replace( @"(", @"\(" );
			}
			if ( !ignores.Contains( ')' ) )
			{
				text = text.Replace( @")", @"\)" );
			}
			if ( !ignores.Contains( '[' ) )
			{
				text = text.Replace( @"[", @"\[" );
			}
			if ( !ignores.Contains( ']' ) )
			{
				text = text.Replace( @"]", @"\]" );
			}
			if ( !ignores.Contains( '{' ) )
			{
				text = text.Replace( @"{", @"\{" );
			}
			if ( !ignores.Contains( '}' ) )
			{
				text = text.Replace( @"}", @"\}" );
			}
			if ( !ignores.Contains( '|' ) )
			{
				text = text.Replace( @"|", @"\|" );
			}

			return text;
		}

		/// <summary>
		/// Generates a <paramref name="matchCode"/>, based on 'name', 
		/// if <paramref name="matchCode"/> is currently NOT a valid 
		/// <paramref name="matchCode"/>. otherwise just returns 
		/// <paramref name="matchCode"/>.
		/// </summary>
		/// <param name="matchCode">Match code to check.</param>
		/// <param name="name">Base for possible match code to generate.</param>
		/// <returns>Returns the ready-to-use match code.</returns>
		public static string GenerateMatchCode(
			string matchCode,
			string name )
		{
			if ( IsValidMatchCode( matchCode ) )
			{
				return matchCode;
			}
			else
			{
				matchCode = name.ToLower();
				matchCode = matchCode.Trim();

				matchCode = RXReplace( matchCode, @"^[^a-z_]", @"_", @"gs" );			// first char.
				matchCode = RXReplace( matchCode, @"[^a-z0-9_]", @"_", @"gs" );		// second+ chars.

				return matchCode;
			}
		}

		/// <summary>
		/// Generates the match code.
		/// </summary>
		/// <param name="matchCode">The match code.</param>
		/// <returns></returns>
		public static string GenerateMatchCode(
			string matchCode )
		{
			return GenerateMatchCode( matchCode, matchCode );
		}

		/// <summary>
		/// Splits the extended.
		/// </summary>
		/// <param name="s">The s.</param>
		/// <param name="separator">The separator.</param>
		/// <returns></returns>
		public static string[] SplitExtended(
			string s,
			string separator )
		{
			if ( string.IsNullOrEmpty( s ) )
			{
				return null;
			}
			else
			{
				var list = new List<string>();

				var lastPos = 0;
				int pos;

				while ( (pos = s.IndexOf( separator, lastPos )) >= 0 )
				{
					list.Add( s.Substring( lastPos, pos - lastPos + 1 ) );

					lastPos = pos + separator.Length;
				}

				if ( lastPos < s.Length - 1 )
				{
					list.Add( s.Substring( lastPos ) );
				}

				return list.ToArray();
			}
		}

		/// <summary>
		/// Splits the extended.
		/// </summary>
		/// <param name="s">The s.</param>
		/// <param name="separator">The separator.</param>
		/// <returns></returns>
		public static string[] SplitExtended(
			string s,
			params char[] separator )
		{
			var t = s.Split( separator );

			// remove empties.
			var list = new List<string>();
			foreach ( var u in t )
			{
				if ( u.Length > 0 )
				{
					list.Add( u );
				}
			}

			return list.ToArray();
		}

		/// <summary>
		/// Check whether a given matchCode is valid.
		/// </summary>
		/// <param name="matchCode">The matchCode to check.</param>
		/// <param name="additionalAllowedChars">The additional allowed chars.</param>
		/// <returns>Returns TRUE if valid, FALSE otherwise.</returns>
		public static bool IsValidMatchCode(
			string matchCode,
			char[] additionalAllowedChars )
		{
			foreach ( char additionalAllowedChar in additionalAllowedChars )
			{
				matchCode = matchCode.Replace( additionalAllowedChar, '_' );
			}

			return IsValidMatchCode( matchCode );
		}

		/// <summary>
		/// Check whether a given matchCode is valid.
		/// </summary>
		/// <param name="matchCode">The matchCode to check.</param>
		/// <returns>Returns TRUE if valid, FALSE otherwise.</returns>
		public static bool IsValidMatchCode(
			string matchCode )
		{
			return RXTest( matchCode, @"^[a-z_][a-z0-9_]*$", @"si" );
		}

		/*
		 * 
		 * ----------
		 * COMMENTED OUT, BECAUSE ERRORNEOUS - APPENDS INSTEAD OF PREPENDS.
		 * ----------
		 * 
		 * 
		/// <summary>
		/// Appends zeros ('0') at the head of the passed string,
		/// until a certain number of total characters is reached.
		/// </summary>
		/// <param name="text">The string to append the zeros.</param>
		/// <param name="length">The required number of characters.</param>
		/// <returns>
		/// Returns the string with the appended number of
		/// characters.
		/// </returns>
		public static string AddZerosPrefix(
			object text,
			int length )
		{
			string s = Convert.ToString( text );

			if ( !string.IsNullOrEmpty( s ) && s.Length < length )
			{
				StringBuilder sb = new StringBuilder( s );
				sb.Append( '0', length - s.Length );

				return sb.ToString();
			}
			else
			{
				return s;
			}
		}
		*/

		/// <summary>
		/// Mimics the CString.Left() function.
		/// </summary>
		/// <param name="s">The s.</param>
		/// <param name="count">The count.</param>
		/// <returns></returns>
		public static string Left(
			string s,
			int count )
		{
			if ( string.IsNullOrEmpty( s ) )
			{
				return s;
			}
			else
			{
				return s.Substring( 0, Math.Min( count, s.Length ) );
			}
		}

		/// <summary>
		/// Mimics the CString.Right() function.
		/// </summary>
		/// <param name="s">The s.</param>
		/// <param name="count">The count.</param>
		/// <returns></returns>
		public static string Right(
			string s,
			int count )
		{
			if ( string.IsNullOrEmpty( s ) )
			{
				return s;
			}
			else
			{
				int length = s.Length;

				if ( s.Length <= count )
				{
					return s;
				}
				else
				{
					return s.Substring( length - count );
				}
			}
		}

		/// <summary>
		/// Indents block of lines.
		/// </summary>
		/// <param name="textToIndent">The textToIndent to indent.</param>
		/// <returns>Returns the indented textToIndent.</returns>
		public static string IndentText(
			string textToIndent )
		{
			return IndentText( textToIndent, @"    " );
		}

		/// <summary>
		/// Indents block of lines.
		/// </summary>
		/// <param name="textToIndent">The textToIndent to indent.</param>
		/// <param name="indentBlankCount">The indent blank count.</param>
		/// <returns>Returns the indented textToIndent.</returns>
		public static string IndentText(
			string textToIndent,
			int indentBlankCount )
		{
			var sb = new StringBuilder();
			sb.Append( ' ', Math.Max( indentBlankCount, 0 ) );

			return IndentText( textToIndent, sb.ToString() );
		}

		/// <summary>
		/// Indents block of lines.
		/// </summary>
		/// <param name="textToIndent">The text to indent.</param>
		/// <param name="linePrefix">The prefix to add before every
		/// found line.</param>
		/// <returns>Returns the indented text to indent.</returns>
		public static string IndentText(
			string textToIndent,
			string linePrefix )
		{
			if ( textToIndent == null )
			{
				return textToIndent;
			}
			else
			{
				textToIndent = textToIndent.Replace(
					@"" + Environment.NewLine, "\n" );
				textToIndent = textToIndent.Replace( '\r', '\n' );

				if ( textToIndent.IndexOf( '\n' ) < 0 )
				{
					return linePrefix + textToIndent;
				}
				else
				{
					string[] lines = textToIndent.Split( '\n' );

					StringBuilder result = new StringBuilder();

					foreach ( string line in lines )
					{
						if ( result.Length > 0 )
						{
							result.Append( Environment.NewLine );
						}

						result.Append( linePrefix );
						result.Append( line );
					}

					return result.ToString();
				}
			}
		}

		// ------------------------------------------------------------------
		#endregion

		#region Conversion checkings.
		// ------------------------------------------------------------------

		/// <summary>
		/// Does some (weak) validations whether the given strings
		/// are valid e-mail addresses.
		/// It only returns TRUE if all strings are valid.
		/// </summary>
		/// <param name="emailAddresses">The strings to check.</param>
		/// <returns>
		/// Returns TRUE if the e-mail addresses seems to be valid,
		/// FALSE if not.
		/// </returns>
		public static bool IsValidEMailAddress(
			string[] emailAddresses )
		{
			if ( emailAddresses == null || emailAddresses.Length <= 0 )
			{
				return false;
			}
			else
			{
				return IsValidEMailAddress(
					string.Join( @";", emailAddresses ) );
			}
		}

		/// <summary>
		/// Does some (weak) validations whether the given string
		/// is a valid e-mail address.
		/// The string can contain multiple e-mail-addresses, separated by
		/// semicolon (";"). It then only returns TRUE if all are valid.
		/// </summary>
		/// <param name="emailAddress">The string to check.</param>
		/// <returns>
		/// Returns TRUE if the e-mail address seems to be valid,
		/// FALSE if not.
		/// </returns>
		public static bool IsValidEMailAddress(
			string emailAddress )
		{
			if ( emailAddress == null || emailAddress.Trim().Length <= 0 )
			{
				return false;
			}
			else
			{
				var rawAddresses =
					emailAddress.Split(
						new[] { @";", @",", "\r", "\n", Environment.NewLine },
						StringSplitOptions.RemoveEmptyEntries );

				if ( rawAddresses.Length <= 0 )
				{
					return false;
				}
				else
				{
					foreach ( var rawAddress in rawAddresses )
					{
						var valid = doIsValidEMailAddress( rawAddress );

						if ( !valid )
						{
							return false;
						}
					}

					// All valid.
					return true;
				}
			}
		}

		private static bool doIsValidEMailAddress( string emailAddress )
		{
			var s = extractEMailAddress( emailAddress ).Trim();

			if ( s.Length <= 0 )
			{
				return false;
			}
			else
			{
				// Location of "@".
				var atPos = s.IndexOf( @"@" );

				if ( atPos < 0 ||
					s.LastIndexOf( @"." ) < atPos + 1 )
				{
					// "@" must exist, and last "." 
					// in string must follow the "@".
					return false;
				}
				else if ( s.IndexOf( @"@", atPos + 1 ) > atPos )
				{
					// String can't have more than one "@".
					return false;
				}
				else if ( s.Substring( atPos + 1, 1 ) == @"." )
				{
					// String can't have "." 
					// immediately following "@".
					return false;
				}
				else if ( s.Substring(
					s.Length - 2 ).IndexOf( @"." ) > 0 )
				{
					// String must have at least 
					// a two-character top-level domain.
					return false;
				}

				return true;
			}
		}

		private static string extractEMailAddress( string address )
		{
			if ( string.IsNullOrEmpty( address ) )
			{
				return string.Empty;
			}
			else
			{
				address = address.Trim();

				if ( string.IsNullOrEmpty( address ) )
				{
					return string.Empty;
				}
				else
				{
					var lb = address.IndexOf( '<' );
					var rb = address.IndexOf( '>' );

					if ( lb >= 0 && rb > lb )
					{
						return address.Substring( lb + 1, rb - lb - 1 );
					}
					else
					{
						return address;
					}
				}
			}
		}

		// ------------------------------------------------------------------
		#endregion

		#region Regular expression routines.
		// ------------------------------------------------------------------

		/// <summary>
		/// Performs a regular expression replace like ( )~ s/ / / in Perl.
		/// </summary>
		/// <param name="text">The text.</param>
		/// <param name="pattern">The pattern.</param>
		/// <param name="replacement">The replacement.</param>
		/// <param name="flags">"i":ignore case and "g":global,
		/// "m":multiline.</param>
		/// <returns></returns>
		public static string RXReplace(
			string text,
			string pattern,
			string replacement,
			string flags )
		{
			RegexOptions options =
				ConvertRXOptionsFromString( flags );

			Regex rx = new Regex( pattern, options );
			if ( flags.Contains( @"g" ) )
			{
				return rx.Replace( text, replacement );
			}
			else
			{
				return rx.Replace( text, replacement, 1 );
			}
		}

		/// <summary>
		/// Performs a regular expression test like ( )~ m/ / in Perl.
		/// </summary>
		/// <param name="text">The text.</param>
		/// <param name="pattern">The pattern.</param>
		/// <param name="flags">"i":ignore case and "m":multiline.</param>
		/// <returns></returns>
		public static bool RXTest(
			string text,
			string pattern,
			string flags )
		{
			if ( string.IsNullOrEmpty( text ) )
			{
				return false;
			}
			else
			{
				RegexOptions options =
					ConvertRXOptionsFromString( flags );

				Regex rx = new Regex(
					pattern,
					options );
				return rx.IsMatch( text );
			}
		}

		/// <summary>
		/// Performs a regular expression test like ( )~ m/ / in Perl.
		/// </summary>
		/// <param name="text">The text.</param>
		/// <param name="pattern">The pattern.</param>
		/// <param name="flags">"i":ignore case and "m":multiline.</param>
		/// <returns>Returns the number of matches.</returns>
		public static int RXTestCount(
			string text,
			string pattern,
			string flags )
		{
			if ( string.IsNullOrEmpty( text ) )
			{
				return 0;
			}
			else
			{
				RegexOptions options =
					ConvertRXOptionsFromString( flags );

				Regex rx = new Regex(
					pattern,
					options );
				return rx.Matches( text ).Count;
			}
		}

		/// <summary>
		/// Converts between Perl-style RX flags and .NET RX options.
		/// </summary>
		/// <param name="flags">The Perl-style RX flags.</param>
		/// <returns>Returns the .NET RX options.</returns>
		public static RegexOptions ConvertRXOptionsFromString(
			string flags )
		{
			RegexOptions options;

			if ( recentRegexOptions.TryGetValue( flags, out options ) )
			{
				return options;
			}
			else
			{
				options = RegexOptions.None;

				if ( flags.Contains( @"i" ) )
				{
					options |= RegexOptions.IgnoreCase;
				}
				if ( flags.Contains( @"x" ) )
				{
					options |= RegexOptions.IgnorePatternWhitespace;
				}
				if ( flags.Contains( @"m" ) )
				{
					options |= RegexOptions.Multiline;
				}
				if ( flags.Contains( @"s" ) )
				{
					options |= RegexOptions.Singleline;
				}

				recentRegexOptions[flags] = options;
				return options;
			}
		}

		// ------------------------------------------------------------------
		#endregion

		#region Private helper.
		// ------------------------------------------------------------------

		/// <summary>
		/// Much faster access by storing previously read values.
		/// </summary>
		private static readonly Dictionary<Enum, string> recentEnumDescriptions =
			new Dictionary<Enum, string>();

		/// <summary>
		/// Much faster access by storing previously read values.
		/// </summary>
		private static readonly Dictionary<string, RegexOptions> recentRegexOptions =
			new Dictionary<string, RegexOptions>();

		// ------------------------------------------------------------------
		#endregion
	}

	/////////////////////////////////////////////////////////////////////////
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Chief Technology Officer Zeta Software GmbH
Germany Germany
Uwe does programming since 1989 with experiences in Assembler, C++, MFC and lots of web- and database stuff and now uses ASP.NET and C# extensively, too. He has also teached programming to students at the local university.

➡️ Give me a tip 🙂

In his free time, he does climbing, running and mountain biking. In 2012 he became a father of a cute boy and in 2014 of an awesome girl.

Some cool, free software from us:

Windows 10 Ereignisanzeige  
German Developer Community  
Free Test Management Software - Intuitive, competitive, Test Plans.  
Homepage erstellen - Intuitive, very easy to use.  
Offline-Homepage-Baukasten

Comments and Discussions