public static String LexicalAdd(this String source, LexicalCharacterSet charSet, Boolean ignoreCase, Boolean treatNonCharsAsSpace, Int32 count)
{
var chars = source.ToCharArray().ToList();
//if (!chars.All(value => char.IsWhiteSpace(value) || charSet.Characters.Contains(value)))
// throw new ArgumentException(
// "The source string contains characters not available in the specified lexical increment character set.");
if (count < 0)
throw new ArgumentOutOfRangeException("count", count, "Only positive numbers can be added lexically at this time.");
var characters = charSet.Characters;
if (ignoreCase && charSet.IsCaseSensitive)
{ //change 'characters' to an upper or lower case version
var lowerCount = chars.Where(char.IsLower).Count();
var upperCount = chars.Where(char.IsUpper).Count();
if (lowerCount > upperCount)
characters = charSet.Characters.Where(value => !char.IsLetter(value) || char.IsLower(value)).ToList();
else
characters = charSet.Characters.Where(value => !char.IsLetter(value) || char.IsUpper(value)).ToList();
}
var mathBase = ignoreCase ? charSet.CaseInsensitiveLength : charSet.CaseSensitiveLength;
Int32 remain = count, carryOver = 0;
//position is counting from the right most character, since we are treating these characters as a number
for (var position = 1; remain > 0 || carryOver > 0 ; position++)
{
if (chars.Count < position)
{
chars.Insert(0, ' ');
}
var positionBase = position == 1 ? 1 : Math.Pow(mathBase, position - 1);
var posCount = ((int)((remain / positionBase) % mathBase)) + carryOver;
if (posCount == mathBase)
{ //no character change, pass along carry over
remain -= ((posCount - carryOver) * (int)positionBase);
carryOver = 1;
}
else if (posCount > 0)
{
var posChar = chars[chars.Count - position];
var posCharIndex = characters.IndexOf(posChar);
if (ignoreCase && posCharIndex == -1 && char.IsLetter(posChar))
{ //Character removed when changing to an upper or lower case version, so get the equivalent case-insensitive character
posChar = char.IsLower(posChar) ? char.ToUpper(posChar) : char.ToLower(posChar);
posCharIndex = characters.IndexOf(posChar);
} //if whitespace char, leave posCharIndex at -1 for replacement
if (posCharIndex == -1 && !char.IsWhiteSpace(posChar) && !treatNonCharsAsSpace)
throw new ArgumentException(
"The source string contains characters not available in the specified lexical increment character set.");
chars[chars.Count - position] = characters[((posCharIndex + posCount) % mathBase)];
carryOver = posCharIndex + posCount < characters.Count ? 0 : 1;
remain = Math.Max(0, remain - posCount * (int)positionBase);
}
}
return String.Concat(chars);
}