Oh wait… I like this one better.
It allows you to set up the mask and the characters that are to be masked on the fly.
public class StringMasker
{
#region Fields
private HashSet<char> _unlocked = new HashSet<char>();
private StringBuilder _builder = new StringBuilder();//recycle the string builder for gc efficiency
private Func<char, bool> _validate;
private Func<char, char> _mask;
#endregion
#region CONSTRUCTOR
public StringMasker()
{
this.Init(null, null);
}
public StringMasker(Func<char, bool> validateCallback)
{
this.Init(validateCallback, null);
}
public StringMasker(Func<char, bool> validateCallback, Func<char, char> maskCallback)
{
this.Init(validateCallback, maskCallback);
}
private void Init(Func<char, bool> validateCallback, Func<char, char> maskCallback)
{
if(validateCallback == null)
validateCallback = (c) => !char.IsLetter(c);
if (maskCallback == null)
{
var maskSet = new char[] {'
So like if you wanted to mask letters and numbers:
var masker = new StringMasker((c) => !(char.IsLetter(c) || char.IsDigit(c)));
,‘!’, ‘A’, … insert full set of masking characters};
var rand = new Random();
_mask = (c) => maskSet[rand.Next(maskSet.Length)];
}
}
#endregion
#region Properties
/// Returns true if the character should not be masked
public Func<char, bool> Validate
{
get { return _validate; }
set
{
if(value == null) throw new ArgumentNullException();
_validate = value;
}
}
/// Returns a masked character for the given character
public Func<char, char> Mask
{
get { return _mask; }
set
{
if(value == null) throw new ArgumentNullException();
_mask = value;
}
}
#endregion
#region Methods
public bool IsLocked(char c)
{
return !_unlocked.Contains(c);
}
public void SetLocked(char c, bool locked)
{
if(locked)
_unlocked.Remove(c);
else
_unlocked.Add(c);
}
public string Mask(string s)
{
_builder.Clear();
if(s.Length > _builder.Capacity) _builder.Capacity = s.Length;
//use enumerator for gc efficiency
var e = s.GetEnumerator();
while(e.MoveNext())
{
if(_unlocked.Contains(e.Current) || _validate.Contains(e.Current))
_builder.Append(e.Current);
else
_builder.Append(_mask(e.Current));
}
return _builder.ToString();
}
#endregion
}
So like if you wanted to mask letters and numbers:
§DISCOURSE_HOISTED_CODE_1§