简体   繁体   English

屏蔽除字符串的前 6 位和后 4 位以外的所有数字(长度不同)

[英]mask all digits except first 6 and last 4 digits of a string( length varies )

I have a card number as a string, for example:我有一个卡号作为字符串,例如:

string  ClsCommon.str_CardNumbe r = "3456123434561234";

The length of this card number can vary from 16 to 19 digits, depending on the requirement.此卡号的长度可以从 16 到 19 位不等,具体取决于要求。

My requirement is that I have to show the first six digits and the last 4 digits of a card number and mask the other characters in between with the character 'X'.我的要求是我必须显示卡号的前六位和后四位数字,并用字符“X”屏蔽中间的其他字符。

I have tried using subString and implemented it separately for 16,17,18,19 digits..我试过使用 subString 并分别为 16、17、18、19 位数字实现它。

I split string(ClsCommon.str_CardNumber) to 5 strings (str_cardNum1, str_cardNum2, str_cardNum3, str_cardNum4, str_cardNum5 - 4 digits for each string..remaining digits for 5th string)我将字符串 (ClsCommon.str_CardNumber) 拆分为 5 个字符串(str_cardNum1、str_cardNum2、str_cardNum3、str_cardNum4、str_cardNum5 - 每个字符串 4 位数字......第 5 个字符串的剩余数字)

All the strings are placed in ClsCommon file.所有字符串都放在 ClsCommon 文件中。 Based on that I implemented the below, which works perfectly:基于此,我实施了以下内容,效果很好:

if (ClsCommon.str_CardNumber.Length == 16) {
    txtmskcrdnum.Text = string.Concat(ClsCommon.str_cardNum1, " ", ClsCommon.str_cardNum2.Substring(0, 2), "XX", " ", "XXXX", " ", ClsCommon.str_cardNum4);

}
if (ClsCommon.str_CardNumber.Length == 17) {
    txtmskcrdnum.Text = string.Concat(ClsCommon.str_cardNum1, " ", ClsCommon.str_cardNum2.Substring(0, 2), "XX", " ", "XXXX", " ", "X", ClsCommon.str_cardNum4.Substring(1, 3), " ", ClsCommon.str_cardNum5);
}
if (ClsCommon.str_CardNumber.Length == 18) {
    txtmskcrdnum.Text = string.Concat(ClsCommon.str_cardNum1, " ", ClsCommon.str_cardNum2.Substring(0, 2), "XX", " ", "XXXX", " ", "XX", ClsCommon.str_cardNum4.Substring(2, 2), " ", ClsCommon.str_cardNum5);
}


if (ClsCommon.str_CardNumber.Length == 19) {
    txtmskcrdnum.Text = string.Concat(ClsCommon.str_cardNum1, " ", ClsCommon.str_cardNum2.Substring(0, 2), "XX", " ", "XXXX", " ", "XXX", ClsCommon.str_cardNum4.Substring(3, 1), " ", ClsCommon.str_cardNum5);
}
txtmskcrdnum.Text = ClsCommon.str_CardNumber.PadLeft(ClsCommon.str_CardNumber.Length, 'X').Substring(ClsCommon.str_CardNumber.Length - 4);

For multiple lengths, the above approach is not useful.对于多个长度,上述方法没有用。

I want a single approach which displays the first 6 and last 4 digits and masks other digits with X. The final string should have a space between every 4 digits.我想要一种显示前 6 位和后 4 位数字并用 X 屏蔽其他数字的单一方法。最终字符串应该在每 4 位数字之间有一个空格。

This will work with any card number length: 这适用于任何卡号长度:

var cardNumber = "3456123434561234";

var firstDigits = cardNumber.Substring(0, 6);
var lastDigits = cardNumber.Substring(cardNumber.Length - 4, 4);

var requiredMask = new String('X', cardNumber.Length - firstDigits.Length - lastDigits.Length);

var maskedString = string.Concat(firstDigits, requiredMask, lastDigits);
var maskedCardNumberWithSpaces = Regex.Replace(maskedString, ".{4}", "$0 ");

I would do something like this (pseudo C# - take as rough idea to build upon). 我会做这样的事情(伪C# - 以粗略的想法为基础)。

Untested code ahead... 未经测试的代码......

string MaskDigits(string input)
{
    //take first 6 characters
    string firstPart = input.Substring(0, 6);

    //take last 4 characters
    int len = input.Length;
    string lastPart = input.Substring(len - 4, 4);

    //take the middle part (XXXXXXXXX)
    int middlePartLenght = input.Substring(6, len - 4).Count();
    string middlePart = new String('X', 5);

    return firstPart + middlePart + lastPart;
}

Try this one. 试试这个吧。 Simple and straight forward. 简单直接。

public static class StringExtensions
{
    public static string Masked(this string source, int start, int count)
    {
        return source.Masked('x', start, count);
    }

    public static string Masked(this string source, char maskValue, int start, int count)
    {
        var firstPart = source.Substring(0, start);
        var lastPart = source.Substring(start + count);
        var middlePart = new string(maskValue, count);

        return firstPart + middlePart + lastPart;
    }
}

I'm sure there is a cleaner way to do this: 我确信有一种更清洁的方法可以做到这一点:

int currentChar = 0;
string maskable = "11111144441111";

string masked = maskable;
int length = masked.Length;

int startMaskPoint = 6;
int endMaskPoint = length - 4 - startMaskPoint;

masked = masked.Remove(startMaskPoint, endMaskPoint);

int numRemoved = length - masked.Length;
string Mask = "";
while (numRemoved != 0)
{
    Mask = Mask + "#";
    numRemoved--;
}

masked = masked.Insert(startMaskPoint, Mask);
string returnableString = masked;
while (length > 4)
{
    returnableString = returnableString.Insert(currentChar + 4, " ");
    currentChar = currentChar + 5;
    length = length - 4;
}

Possible implementation (acccepts varios formats eg numbers can be divided into groups etc.): 可能的实现(接受varios格式,例如数字可以分成组等):

private static String MaskedNumber(String source) {
  StringBuilder sb = new StringBuilder(source);

  const int skipLeft = 6;
  const int skipRight = 4;

  int left = -1;

  for (int i = 0, c = 0; i < sb.Length; ++i) {
    if (Char.IsDigit(sb[i])) {
      c += 1;

      if (c > skipLeft) {
        left = i;

        break;
      }
    }
  }

  for (int i = sb.Length - 1, c = 0; i >= left; --i)
    if (Char.IsDigit(sb[i])) {
      c += 1;

      if (c > skipRight)
        sb[i] = 'X';
    }

  return sb.ToString();
}

// Tests 

  // 3456-12XX-XXXX-1234
  Console.Write(MaskedNumber("3456-1234-3456-1234"));
  // 3456123XXXXX1234
  Console.Write(MaskedNumber("3456123434561234"));

this implementation just masks the digits and preserve the format. 此实现只是屏蔽数字并保留格式。

One method: 一种方法:

string masked = null;
for (int i = 0; i < str_CardNumber.Length; i++) {
    masked += (i > 5 && i < str_CardNumber.Length - 4) ? 'X' : str_CardNumber[i];
    if ((i + 1) % 4 == 0)
        masked += " ";
}

How about replacing a specific matched group using Regex : 如何使用Regex替换特定的匹配组:

        string cardNumber = "3456123434561234";
        var pattern = "^(.{6})(.+)(.{4})$";
        var maskedNumber = Regex.Replace(cardNumber, pattern, (match) =>
        {
           return Regex.Replace(String.Format("{0}{1}{2}",
           match.Groups[1].Value, // the first 6 digits
           new String('X', match.Groups[2].Value.Length), // X times the 'X' char
           match.Groups[3].Value) /*the last 4 digits*/,".{4}", "$0 "); //finally add a separator every 4 char
        });

Many of the given solutions parse the input multiple times. 许多给定的解决方案多次解析输入。 Below I present a solution that parses the input only once. 下面我提出一个只解析输入一次的解决方案。 But I have no experience in C#, so the function is written in Scheme. 但是我没有C#的经验,所以函数是用Scheme编写的。

The function is divided into two: 功能分为两个:

(1) visit-first-6 parses the first six characters and concatenates them to the rest of the computation. (1)visit-first-6解析前六个字符并将它们连接到其余的计算中。 When visit-first-6 has parsed the first six characters, it calls visit-rest. 当visit-first-6解析了前六个字符时,它会调用visit-rest。

(2) visit-rest exploits the fact that we can delay some computation until we have gained more knowledge. (2)访问 - 休息利用我们可以延迟一些计算直到我们获得更多知识的事实。 In this case, we wait to determine whether the element in the list should be shown until we know how many characters are left. 在这种情况下,我们等待确定是否应该显示列表中的元素,直到我们知道剩下多少个字符。

(define (mask xs)
  (letrec ([visit-first-6 (lambda (xs chars-parsed)
                            (cond
                              [(null? xs)
                               ;; Shorter than 6 characters.
                               '()]
                              [(< chars-parsed 6)
                               ;; Still parsing the first 6 characters
                               (cons (car xs)
                                     (visit-first-6 (cdr xs)
                                                    (1+ chars-parsed)))]
                              [else
                               ;; The first 6 characters have been parsed.
                               (visit-rest xs
                                           (lambda (ys chars-left)
                                             ys))]))]
           [visit-rest (lambda (xs k)
                         (if (null? xs)
                             ;; End of input
                             (k '() 0)
                             ;; Parsing rest of the input
                             (visit-rest (cdr xs)
                                         (lambda (rest chars-left)
                                           (if (< chars-left 4)
                                               ;; Show the last 4 characters
                                               (k (cons (car xs) rest)
                                                  (1+ chars-left))
                                               ;; Don't show the middle characters
                                               (k (cons "X"
                                                        rest)
                                                  (1+ chars-left)))))))])
    (visit-first-6 xs
                   0)))

Running mask in the Petite Chez Scheme interpreter 在Petite Chez Scheme翻译中运行面具

> (mask '(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18))
(1 2 3 4 5 6 "X" "X" "X" "X" "X" "X" "X" "X" 15 16 17 18)
> (mask '())
()
> (mask '(1 2 3 4))
(1 2 3 4)
> (mask '(1 2 3 4 5))
(1 2 3 4 5)
> (mask '(1 2 3 4 5 6 7 8 9))
(1 2 3 4 5 6 7 8 9)
> (mask '(1 2 3 4 5 6 7 8 9 10))
(1 2 3 4 5 6 7 8 9 10)
> (mask '(1 2 3 4 5 6 7 8 9 10 11))
(1 2 3 4 5 6 "X" 8 9 10 11)

NB. NB。 I saw this as a funny exercise and I figured I might as well share it. 我认为这是一个有趣的练习,我想我也可以分享它。 Yannick Meeus has already provided an easily understandable solution. Yannick Meeus已经提供了一个易于理解的解决方案。 So, this only serves for the interested. 所以,这只适合感兴趣的人。

Linq saves coding lines, small code snippet. Linq保存了编码行,小代码片段。

Replaces with (*) char above 6 and bellow CardPan length minus 4 用(*)char替换6以上,低于CardPan长度减去4

var CardPan = "1234567890123456";
var maskedPan = CardPan.Aggregate(string.Empty, (value, next) =>
{
    if (value.Length >= 6 && value.Length < CardPan.Length - 4)
    {
        next = '*';
    }
    return value + next;
});
str.substring(0, 5) +
                str.substring(5, str.length() - 3)
                .replaceAll("[\\d]", "x") +
                str.substring(str.length() - 3, str.length());

//Here is the simple way to do //这里是最简单的方法

I think this one is the simplest form.我认为这是最简单的形式。 PadLeft/PadRight did not help me. PadLeft/PadRight 没有帮助我。

Suppose I have credit card no( "2512920040512345") and mask all digit except last 4 digit ("XXXXXXXXXXXX2345").假设我有信用卡号(“2512920040512345”)并屏蔽除最后 4 位数字(“XXXXXXXXXXXX2345”)之外的所有数字。

//C# code will give you the desired output. Replace the string with your CreditCardno variable
new string('X', "2512920040512345".Length-4)+ "2512920040512345".Substring( "2512920040512345".Length-4, 4)

The better way to do it is by using string format as seen below:更好的方法是使用如下所示的字符串格式:

YourData = string.Format("************{0}", YourData.Trim().Substring(12, 4));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM