Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

Enhanced String Handling II

, 16 Dec 2010
Overcoming limitations of: Enhanced String Handling
EnhancedStringEvaluate.zip
EnhancedStringEvaluate
bin
Debug
ConfigEvaluate.vshost.exe
ConfigEvaluate.vshost.exe.manifest
EnhancedStringEvaluate.dll
EnhancedStringEvaluate.pdb
ConcordPairEvaluate.csproj.vs10x
EnhancedStringEvaluate.csproj.user
EnhancedStringEvaluate.csproj.vs10x
obj
Debug
Decl
EnhancedStringEvaluate.dll
EnhancedStringEvaluate.pdb
DesignTimeResolveAssemblyReferencesInput.cache
EnhancedStringEvaluate.dll
EnhancedStringEvaluate.pdb
Refactor
ConfigEvaluate.dll
ResolveAssemblyReference.cache
TempPE
Properties
EvaluateTest
bin
Debug
EnhancedStringEvaluate.dll
EnhancedStringEvaluate.pdb
EvaluateSampleTest.dll
EvaluateSampleTest.pdb
EvaluateTest.dll
EvaluateTest.pdb
TestEvaluation.exe
TestEvaluation.pdb
EvaluateSampleTest.csproj.vs10x
EvaluateTest.csproj.vs10x
obj
Debug
Decl
EvaluateSampleTest.dll
EvaluateSampleTest.pdb
DesignTimeResolveAssemblyReferencesInput.cache
EvaluateSampleTest.dll
EvaluateSampleTest.pdb
EvaluateTest.dll
EvaluateTest.pdb
ResolveAssemblyReference.cache
TempPE
Properties
TestEvaluate
bin
Debug
abc.text
EnhancedStringEvaluate.dll
EnhancedStringEvaluate.pdb
TestEvaluate.exe
TestEvaluate.pdb
TestEvaluate.vshost.exe.manifest
TestEvaluation.exe
TestEvaluation.pdb
TestEvaluation.vshost.exe
TestEvaluation.vshost.exe.manifest
TestOnTheFlyConfig.vshost.exe
TestOnTheFlyConfig.vshost.exe.manifest
obj
Debug
Decl
TestEvaluation.exe
TestEvaluation.pdb
DesignTimeResolveAssemblyReferencesInput.cache
Refactor
ResolveAssemblyReference.cache
TempPE
TestEvaluate.exe
TestEvaluate.pdb
TestEvaluation.exe
TestEvaluation.pdb
ProcessEvaluate
Properties
TestEvaluate.csproj.vs10x
TestEvaluation.csproj.user
TestEvaluation.csproj.vs10x
TestOnTheFlyConfig.csproj.vs10x
using System;
using System.Text.RegularExpressions;


namespace EnhancedStringEvaluate
{
	/// <summary>
	/// Purpose:
	///		Encapsulate delimiter and separator handling.
	/// </summary>
	public class DelimitersAndSeparator : IDelimitersAndSeparator
	{
		private const string cDefaultSeparator = "::";

		/// <summary>
		/// Evaluating if an expression is "simple" is entirely in the syntax of the delimiters and separator.
		/// An expression is simple if it has:
		///		-	Open delimiter
		///		-	Non-empty identifier
		///		-	Separator
		///		-	Close delimiter
		///		Moreover, this expression does not contain a nested expressions.
		/// </summary>
		private Regex _smplExprEvaluator;

		/// <summary>Alternate, single character, for open delimiter and single char for close delimiter</summary>
		private const string cOpenAlternate = "\u0001";
		private const string cCloseAlternate = "\u0002";
		private const string cSeparatorAlternate = "\u0003";

		/// <summary>Default Open/Close delimiters</summary>
		private const string cDefaultOpen = "{";
		private const string cDefaultClose = "}";

		/// <summary>Default values allowing static access</summary>
		public static readonly IDelimitersAndSeparator DefaultDelimitedString = new DelimitersAndSeparator(cDefaultOpen, cDefaultClose);

		/// <summary>
		/// .ctor
		/// </summary>
		/// <param name="openDelim"></param>
		/// <param name="closeDelim"></param>
		/// <param name="separator"></param>
		public DelimitersAndSeparator(string openDelim = cDefaultOpen, string closeDelim = cDefaultClose, string separator = cDefaultSeparator)
		{
			Validator(openDelim, closeDelim, separator);

			OpenDelimOrig = openDelim;
			CloseDelimOrig = closeDelim;

			IsOpenDelimOrigSingleChar = Regex.Unescape(OpenDelimOrig).Length == 1;
			IsCloseDelimOrigSingleChar = Regex.Unescape(CloseDelimOrig).Length == 1;

			string balanceOpenClose = BalancePattern;
			BalancedEvaluator = new Regex(balanceOpenClose, RegexOptions.Singleline);

			Separator = separator;

			//string pattern = @"({)(?<SmplExpr>[^{}]+::[^{}]*?)(})";
			string pattern = string.Format(@"({0})(?<reSmplExpr>[^{0}{1}]+{2}[^{0}{1}]*?)({1})",
												OpenDelimEquivalent, CloseDelimEquivalent, Separator);
			_smplExprEvaluator = new Regex(pattern, RegexOptions.Singleline);
		}

		/// <summary>
		/// Purpose:
		///		Validate open/close delimiters.
		///		*	They are not allowed to be ws (white space)
		///		*	They are not allowed to be the same as one another.
		///		*	Constructor employs this function
		///		Validate separator.
		///		*	It may not be ws.
		///		*	It may not equal neither open nor close delimiters
		/// </summary>
		/// <param name="openDelim"></param>
		/// <param name="closeDelim"></param>
		/// <param name="separator"></param>
		protected virtual void Validator(string openDelim, string closeDelim, string separator)
		{
			// The string.isNullOrWhiteSpace is new to .Net 4.0 in prior versions you will need
			// to issue: (string.IsNullOrEmpty(value) || value.Trim().Length == 0)
			if (string.IsNullOrWhiteSpace(openDelim))
				throw new EnhancedStringException(null, EnhancedStrPairElement.Empty, "Open delimiter cannot be null, empty or white-space");

			if (string.IsNullOrWhiteSpace(closeDelim))
				throw new EnhancedStringException(null, EnhancedStrPairElement.Empty, "Close delimiter cannot be null, empty or white-space");

			if (string.Compare(openDelim, closeDelim, StringComparison.CurrentCultureIgnoreCase) == 0)
				throw new EnhancedStringException(null, EnhancedStrPairElement.Empty, "Open/close delimiters are one and the same (up to case difference)");

			if (string.IsNullOrWhiteSpace(separator))
				throw new EnhancedStringException(null, EnhancedStrPairElement.Empty, "Separator cannot be null, empty or white-space");

			if (string.Compare(separator, openDelim, StringComparison.CurrentCultureIgnoreCase) == 0)
				throw new EnhancedStringException(null, EnhancedStrPairElement.Empty, "Separator cannot equal open delimiter");

			if (string.Compare(separator, closeDelim, StringComparison.CurrentCultureIgnoreCase) == 0)
				throw new EnhancedStringException(null, EnhancedStrPairElement.Empty, "Separator cannot equal close delimiter");
		}

		#region IDelimiters Members

		public virtual string OpenDelimOrig { get; private set; }
		public virtual string OpenDelimAlternate { get { return cOpenAlternate; } }
		public virtual string OpenDelimEquivalent { get { return IsOpenDelimOrigSingleChar ? OpenDelimOrig : OpenDelimAlternate; } }

		public virtual string CloseDelimOrig { get; private set; }
		public virtual string CloseDelimAlternate { get { return cCloseAlternate; } }
		public virtual string CloseDelimEquivalent { get { return IsCloseDelimOrigSingleChar ? CloseDelimOrig : CloseDelimAlternate; } }

		public string Separator { get; private set; }
		public string SeparatorAlternate { get { return cSeparatorAlternate; } }

		public virtual bool IsBalancedOpenClose(string text)
		{
			string preText = PreMatch(text);
			Match m = BalancedEvaluator.Match(preText);
			return m.Success;
		}

		/// <summary>
		/// Transform multi-char delimiters to single-char delimiters
		/// </summary>
		/// <param name="text"></param>
		/// <returns></returns>
		public virtual string PreMatch(string text)
		{
			string pre1 = IsOpenDelimOrigSingleChar ? text : text.Replace(OpenDelimOrig, OpenDelimAlternate);
			string pre2 = IsCloseDelimOrigSingleChar ? pre1 : pre1.Replace(CloseDelimOrig, CloseDelimAlternate);
			return pre2;
		}

		/// <summary>
		/// Transform back to the original delimiters
		/// </summary>
		/// <param name="text"></param>
		/// <returns></returns>
		public virtual string PostMatch(string text)
		{
			string post1 = IsCloseDelimOrigSingleChar ? text : text.Replace(CloseDelimAlternate, CloseDelimOrig);
			string post2 = IsOpenDelimOrigSingleChar ? post1 : post1.Replace(OpenDelimAlternate, OpenDelimOrig);
			return post2;
		}

		/// <summary>
		/// Purpose:
		///		Determines if the text contains a simple express.
		///	
		/// Comment:
		///		Simple expression has no inner expressions.  Therefore, {key::Abc} is a simple 
		///		expression, while {key::Abc_{key::ip address}} is not a simple expression.  
		/// </summary>
		/// <param name="text"></param>
		/// <returns></returns>
		public virtual bool IsSimpleExpression(string text)
		{
			string preText = PreMatch(text);
			Match m = _smplExprEvaluator.Match(preText);
			return m.Success;
		}

		#endregion

		public virtual bool IsOpenDelimOrigSingleChar { get; private set; }
		public virtual bool IsCloseDelimOrigSingleChar { get; private set; }
		public Regex BalancedEvaluator { get; private set; }

		/// <summary>
		/// Note: OpenDelimEquivalent and CloseDelimEquivalent are single character in length
		/// </summary>
		public string BalancePattern
		{
			get
			{
				//string fmt = @"^[^{}]*(((?<Open>{)[^{}]*)+((?<Close-Open>(}))[^{}]*)+)*(?(Open)(?!))$";
				string fmt = @"^[^{0}{1}]*(((?<Open>{0})[^{0}{1}]*)+((?<Close-Open>({1}))[^{0}{1}]*)+)*(?(Open)(?!))$";
				return string.Format(fmt, OpenDelimEquivalent, CloseDelimEquivalent);
			}
		}
	}
}

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)

Share

About the Author

Avi Farah

United States United States
avifarah@gmail.com

| Advertise | Privacy | Mobile
Web02 | 2.8.140821.2 | Last Updated 16 Dec 2010
Article Copyright 2010 by Avi Farah
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid