public void MaskRandom() { //Arrange const String TEXT = "The cat is a good friend too."; const Single COVERAGE = 0.5f; const MaskTextMode MODE = MaskTextMode.Random; const Int32 COUNT_MASK_CHARS = 12; //Act var result = StringHelpers.MaskText(TEXT, COVERAGE, MODE); //Assert Assert.AreEqual(COUNT_MASK_CHARS, result.Count(c => c == '*')); }
public void MaskEnding1() { //Arrange const String TEXT = "The cat is a good friend too."; const Single COVERAGE = 1f; const MaskTextMode MODE = MaskTextMode.Ending; const String EXPECTED = "*** *** ** * **** ****** ****"; //Act var result = StringHelpers.MaskText(TEXT, COVERAGE, MODE); //Assert Assert.AreEqual(EXPECTED, result); }
public void MaskIntervaled() { //Arrange const String TEXT = "The cat is a good friend too."; const Single COVERAGE = 0.5f; const MaskTextMode MODE = MaskTextMode.Intervaled; const String EXPECTED = "**e *a* i* a *o*d *r*e*d *o*."; //Act var result = StringHelpers.MaskText(TEXT, COVERAGE, MODE); //Assert Assert.AreEqual(EXPECTED, result); }
public void MaskSkipChars() { //Arrange const String TEXT = "111.111.111-00"; const Single COVERAGE = 0.7f; const MaskTextMode MODE = MaskTextMode.Intervaled; const Int32 COUNT_MASK_CHARS = 8; const Char REPLACEMENT_CHAR = '°'; //Act var result = StringHelpers.MaskText(TEXT, COVERAGE, MODE, REPLACEMENT_CHAR, new[] { '.', '-' }); //Assert Assert.AreEqual(COUNT_MASK_CHARS, result.Count(c => c == REPLACEMENT_CHAR)); }
/// <summary> /// Mask text with a replacement char. /// </summary> /// <param name="text">Text to mask.</param> /// <param name="coverage">Coverage percentage, where 0 is no coverage and 1 is full coverage.</param> /// <param name="mode">Chosse between coverage styles to prevent the text to be guessable.</param> /// <param name="replacementChar">Char to use as the mask.</param> /// <param name="skipChars">Do not mask the char specified by this parameter.</param> /// <returns></returns> public static String MaskText(this String text, Single coverage, MaskTextMode mode, Char replacementChar, Char[] skipChars) { if (coverage < 0 || coverage > 1) { throw new ArgumentOutOfRangeException(nameof(coverage)); } if (String.IsNullOrEmpty(text) || coverage == 0) { return(text); } var maskableChar = new Func <Char, Boolean> (c => c.IsPrintableChar() && (skipChars == null || !skipChars.Contains(c)) ); const Byte MASKABLE_CHAR = 0; const Byte JUMP_CHAR = 1; const Byte MASKED_CHAR = 2; var textMap = new Byte[text.Length]; for (var i = 0; i < text.Length; i++) { textMap[i] = maskableChar(text[i]) ? MASKABLE_CHAR : JUMP_CHAR; } var maskableLength = textMap.Count(t => t == MASKABLE_CHAR); var coverageTargetLength = (Int32)Math.Round(maskableLength * coverage); switch (mode) { case MaskTextMode.Begining: for (var i = 0; i < textMap.Length && coverageTargetLength > 0; i++) { if (textMap[i] == MASKABLE_CHAR) { textMap[i] = MASKED_CHAR; coverageTargetLength--; } } break; case MaskTextMode.Ending: for (var i = textMap.Length - 1; i >= 0 && coverageTargetLength > 0; i--) { if (textMap[i] == MASKABLE_CHAR) { textMap[i] = MASKED_CHAR; coverageTargetLength--; } } break; case MaskTextMode.Center: var diff_center = maskableLength - coverageTargetLength; var countToStart = (Int32)Math.Round(diff_center / 2f); for (var i = 0; i < textMap.Length && coverageTargetLength > 0; i++) { if (textMap[i] == MASKABLE_CHAR && countToStart-- <= 0) { textMap[i] = MASKED_CHAR; coverageTargetLength--; } } break; case MaskTextMode.Ends: var padding_start = (Int32)Math.Floor(coverageTargetLength / 2f); var padding_end = padding_start; if (padding_start + padding_end < coverageTargetLength) { padding_start++; } for (var i = 0; i < textMap.Length && padding_start > 0; i++) { if (textMap[i] == MASKABLE_CHAR) { textMap[i] = MASKED_CHAR; padding_start--; } } for (var i = textMap.Length - 1; i >= 0 && padding_end > 0; i--) { if (textMap[i] == MASKABLE_CHAR) { textMap[i] = MASKED_CHAR; padding_end--; } } break; case MaskTextMode.Intervaled: var interval = (Int32)Math.Round(maskableLength / (Single)coverageTargetLength); if (interval < 2) { interval = 2; } var intervalCount = 0; while (coverageTargetLength > 0) { for (var i = 0; i < textMap.Length; i++) { if (textMap[i] == MASKABLE_CHAR && ++intervalCount >= interval) { textMap[i] = MASKED_CHAR; coverageTargetLength--; intervalCount = 0; if (coverageTargetLength == 0) { break; } } } } break; case MaskTextMode.Random: var random = new Random(); while (coverageTargetLength > 0) { var index = random.Next(0, text.Length); if (textMap[index] == MASKABLE_CHAR) { textMap[index] = MASKED_CHAR; coverageTargetLength--; } } break; } var result = new StringBuilder(text); for (var i = 0; i < text.Length; i++) { if (textMap[i] == MASKED_CHAR) { result[i] = replacementChar; } } return(result.ToString()); }
/// <summary> /// Mask text with a replacement char. /// </summary> /// <param name="text">Text to mask.</param> /// <param name="coverage">Coverage percentage, where 0 is no coverage and 1 is full coverage.</param> /// <param name="mode">Chosse between coverage styles to prevent the text to be guessable.</param> /// <param name="replacementChar">Char to use as the mask.</param> /// <returns></returns> public static String MaskText(this String text, Single coverage, MaskTextMode mode, Char replacementChar) { return(MaskText(text, coverage, mode, replacementChar, null)); }
/// <summary> /// Mask text with a replacement char. /// </summary> /// <param name="text">Text to mask.</param> /// <param name="coverage">Coverage percentage, where 0 is no coverage and 1 is full coverage.</param> /// <param name="mode">Chosse between coverage styles to prevent the text to be guessable.</param> /// <returns></returns> public static String MaskText(this String text, Single coverage, MaskTextMode mode) { return(MaskText(text, coverage, mode, '*')); }