2017-07-10 1 views
0

Je voudrais masquer une chaîne en utilisant différents paramètres comme le pourcentage de caractère à masquer, le caractère du masque et la position d'application du masque (Au début , au milieu ou à la fin de la chaîne). J'ai trouvé une solution mais je présume que ce n'est pas la meilleure solution. Ceci est mon code:Comment masquer une chaîne en utilisant différents paramètres de façon efficace et rapide

public static string MaskChars(this string value, char maskToApply = 'X', int percentToApply = 25, MaskOption maskOptions = MaskOption.InTheMiddleOfString) 
    { 
     string valueTrimmed = value.Trim(); 
     int len = valueTrimmed.Length; 

     if (len == 0) 
      return Empty; 
     if (percentToApply >= 100) 
      return maskToApply.ToString(CultureInfo.InvariantCulture).Replicate(len); 

     var charsToMask = (int)Math.Round((decimal)(percentToApply * len)/100); 
     if (charsToMask == 0) 
      charsToMask = 1; 

     int top = len - charsToMask; 
     int maskCounter = 0; 
     var builder = new StringBuilder(len); 

     for (int i = 0; i < len; i++) 
     { 
      if (maskCounter < charsToMask) 
      { 
       switch (maskOptions) 
       { 
        // Apply mask in the middle of the string 
        case MaskOption.InTheMiddleOfString: 
         if (i >= charsToMask && i < top) 
         { 
          builder.Append(maskToApply); 
          maskCounter++; 
         } 
         break; 
        // Apply mask at the begining of the string 
        case MaskOption.AtTheBeginingOfString: 
         if (i < charsToMask) 
         { 
          builder.Append(maskToApply); 
          maskCounter++; 
         } 
         break; 
        // Apply mask at the end of the string 
        case MaskOption.AtTheEndOfString: 
         if (i >= top) 
         { 
          builder.Append(maskToApply); 
          maskCounter++; 
         } 
         break; 
       } 
      } 
      else 
      { 
       builder.Append(valueTrimmed[i]); 
      } 
     } 

     return builder.ToString(); 
    } 

où:

public enum MaskOption : byte 
{ 
    AtTheBeginingOfString = 1, 
    InTheMiddleOfString = 2, 
    AtTheEndOfString = 3 
} 

et Répliquer est une méthode simple pour reproduire une chaîne

public static string Replicate(this string value, int count) 
    { 
     if (IsNullOrEmpty(value)) 
      return Empty; 
     if (count <= 0) 
      return value; 

     var builder = new StringBuilder(); 
     builder.Append(value); 
     for (int i = count; i >= 1; i--) 
      builder.Append(value); 

     return builder.ToString(); 
    } 
+0

Vous voudrez peut-être envisager d'afficher au [Code Review] (https://codereview.stackexchange.com/help/on-topic) au lieu. – CodeCaster

+0

Si quelque chose ne fonctionne pas, veuillez décrire exactement le problème et le code qui ne fonctionne pas. –

Répondre

1

D'abord, je couru votre code pour voir ce que le comportement attendu était et ça ne me semble pas juste. Voici le code de test et la sortie:

var testStr = "This is my string to mask characters in!"; 
Console.WriteLine(testStr.MaskChars('X', 25, Extensions.MaskOption.AtTheBeginingOfString)); 
Console.WriteLine(testStr.MaskChars('X', 25, Extensions.MaskOption.InTheMiddleOfString)); 
Console.WriteLine(testStr.MaskChars(maskOptions: Extensions.MaskOption.AtTheEndOfString)); 

Sortie

enter image description here

J'avais l'impression que la chaîne doit rester la même longueur, et que les personnages masqués serait tout simplement changer de position dans la chaîne. En outre, je ne suis pas sûr de savoir pourquoi vous coupez la chaîne (je ne ferais pas cela dans cette méthode, je laisserais l'appelant décider s'ils voulaient la couper d'abord), mais j'ai laissé cette partie.

Voilà comment je simplifier le code pour le faire:

public static string MaskChars(this string input, char maskChar, 
    int percentToApply, MaskOption maskOptions) 
{ 
    // I would remove this. The caller can trim the string first if they want. 
    var result = input.Trim(); 

    if (result.Length == 0 || percentToApply < 1) return result; 
    if (percentToApply >= 100) return new string(maskChar, result.Length); 

    var maskLength = Math.Max((int) Math.Round(percentToApply * result.Length/100m), 1); 
    var mask = new string(maskChar, maskLength); 

    switch (maskOptions) 
    { 
     case MaskOption.AtTheBeginingOfString: 
      result = mask + result.Substring(maskLength); 
      break; 
     case MaskOption.AtTheEndOfString: 
      result = result.Substring(0, result.Length - maskLength) + mask; 
      break; 
     case MaskOption.InTheMiddleOfString: 
      var maskStart = (result.Length - maskLength)/2; 
      result = result.Substring(0, maskStart) + mask + 
       result.Substring(maskStart + maskLength); 
      break; 
    } 

    return result; 
} 

sortie

enter image description here

la dernière chose que je voudrais faire est de se débarrasser des valeurs d'argument par défaut dans la méthode, et créer certaines méthodes de surcharge utilisent plutôt des valeurs par défaut pour les arguments manquants. De cette façon, les utilisateurs peuvent ajuster les valeurs du défaut (dans votre mise en œuvre, si elles veulent changer seulement le MaskOption, ils doivent reformuler les autres valeurs par défaut ou de l'utilisation des paramètres nommés comme je l'ai fait ci-dessus):

private static char defaultMaskChar = 'X'; 
private static MaskOption defaultMaskOption = MaskOption.InTheMiddleOfString; 
private static int defaultPercentToApply = 25; 

public static string MaskChars(this string input) 
{ 
    return MaskChars(input, defaultMaskChar); 
} 

public static string MaskChars(this string input, char maskChar) 
{ 
    return MaskChars(input, maskChar, defaultPercentToApply); 
} 

public static string MaskChars(this string input, int percentToApply) 
{ 
    return MaskChars(input, defaultMaskChar, percentToApply); 
} 

public static string MaskChars(this string input, MaskOption maskOption) 
{ 
    return MaskChars(input, defaultMaskChar, defaultPercentToApply, maskOption); 
} 

public static string MaskChars(this string input, char maskChar, int percentToApply) 
{ 
    return MaskChars(input, maskChar, percentToApply, defaultMaskOption); 
} 

public static string MaskChars(this string input, char maskChar, MaskOption maskOption) 
{ 
    return MaskChars(input, maskChar, defaultPercentToApply, maskOption); 
} 

public static string MaskChars(this string input, int percentToApply, MaskOption maskOption) 
{ 
    return MaskChars(input, defaultMaskChar, percentToApply, maskOption); 
} 
0

Vous pouvez essayer une autre façon de faire la même chose mince .. Moins de paramètres et plus facile à tester et plus facile à lire.

Rappelez-vous que je n'ai pas posté l'interface et de petits détails comme Guard.

public class StringMask : IStringMask 
    { 
     /// <summary> 
     /// The Mask character 
     /// </summary> 
     private readonly char MaskCharacter; 

     /// <summary> 
     /// The instance 
     /// </summary> 
     private readonly string Instance; 

     /// <summary> 
     /// The Mask 
     /// </summary> 
     private BitArray Mask; 

     /// <summary> 
     /// Initializes a new instance of the <see cref="StringMask"/> class. 
     /// </summary> 
     /// <param name="instance">The string you would like to mask.</param> 
     /// <param name="maskCharacter">The Mask character.</param> 
     public StringMask(string instance, char maskCharacter) 
     { 
      MaskCharacter = maskCharacter; 
      Instance = instance; 
      Mask = new BitArray(instance.Length, false); 
     } 



     /// <summary> 
     /// Shows the first [number] of characters and masks the rest. 
     /// </summary> 
     /// <param name="number">The number of the characters to show.</param> 
     /// <returns>IStringMask.</returns> 
     public IStringMask ShowFirst(int number) 
     { 
      Validate(number); 

      for (int i = 0; i < number; i++) 
      { 
       Mask[i] = true; 
      } 
      return this; 
     } 

     /// <summary> 
     /// Shows the last [number] of characters and masks the rest. 
     /// </summary> 
     /// <param name="number">The number of the characters to show.</param> 
     /// <returns>IStringMask.</returns> 
     public IStringMask ShowLast(int number) 
     { 
      Validate(number); 

      for (int i = 0; i < number; i++) 
      { 
       Mask[Instance.Length - i - 1] = true; 
      } 
      return this; 

     } 

     /// <summary> 
     /// Returns a <see cref="System.String" /> that represents this instance. 
     /// </summary> 
     /// <returns>A <see cref="System.String" /> that represents this instance.</returns> 
     public override string ToString() 
     { 
      var sb = new StringBuilder(); 
      for (int i = 0; i < Instance.Length; i++) 
      { 
       if (Mask[i]) 
        sb.Append(Instance[i]); 
       else 
        sb.Append(MaskCharacter); 
      } 

      return sb.ToString(); 
     } 

     private void Validate(int number) 
     { 
      Guard.IsBetweenExclusive(number, 0, Instance.Length, nameof(number)); 
     } 
    } 

Alors que vous pouvez voir ici les tests pour que:

[TestFixture] 
    internal class MaskTests 
    { 
     private string input = "40770058698999513265"; 
     private char maskChar = 'X'; 
     private IStringMask mask; 

     [SetUp] 
     public void Initiate() 
     { 
      mask = new StringMask(input, maskChar); 
     } 

     [Test] 
     public void MaskShowLast() 
     { 
      var output = mask.ShowLast(10); 
      Console.WriteLine(output); 
      Assert.AreEqual("XXXXXXXXXX8999513265", output.ToString()); 
     } 



     [Test] 
     public void MaskInTheMiddle() 
     { 
      var output = mask.ShowLast(5).ShowFirst(5); 
      Console.WriteLine(output); 
      Assert.AreEqual("40770XXXXXXXXXX13265", output.ToString()); 
     } 

     [Test] 
     public void MaskInTheMiddleTooShort() 
     { 
      Assert.Throws<ArgumentOutOfRangeException>(() => mask.ShowLast(0).ShowFirst(0)); 
     } 

     [Test] 
     public void MaskInTheMiddleTooLong() 
     { 
      Assert.Throws<ArgumentOutOfRangeException>(()=> mask.ShowLast(500).ShowFirst(500)); 
     } 

     [Test] 
     public void MaskAtTheEnd() 
     { 
      var output = mask.ShowFirst(10); 
      Console.WriteLine(output); 
      Assert.AreEqual("4077005869XXXXXXXXXX", output.ToString()); 

     } 
    }