Проблема при маскировке номера кредитной карты до и/или после пробелов

У меня возникла проблема, когда в CreditCardNo есть пробел до/после.

Например from INV 2420852290 to SAV 0165487. Здесь 2420852290 — 10 цифр, но он все равно маскируется.

Для номера кредитной карты диапазон составляет 12–19 цифр. Причина в пробеле (до и после цифр), который, я думаю, занимает дополнительные 11-й и 12-й символы.

Используемое регулярное выражение

(?<=(?<![\d-*])(?=(?:-?[\d*\s]){12,19}(?![\d-*\s]))[\d-*\s]*)[\d*](?!(?:-?[\d*\s]){0,3}(?![\d-*\s]))

Я попробовал код ниже с регулярным выражением выше. Ожидается, что все сценарии, включая тот, о котором идет речь, должны работать как есть. Последние 4 цифры всегда должны быть замаскированы знаком x.

Их можно протестировать по URL — https://dotnetfiddle.net/Gopzoz. Спасибо

        public static string MaskNewCCNo(this string value)
        {
           var a = Regex.Replace(value, @"(?<=(?<![\d-*])(?=(?:-?[\d*\s]){12,19}(?![\d-*\s]))[\d-*\s]*)[\d*](?!(?:-?[\d*\s]){0,3}(?![\d-*\s]))", "x");

            return a;
        }

прямо сейчас вы маскируете ВСЕ, кроме последних трех цифр, хотя вы заявляете, что хотели бы замаскировать только последние 4. Не могли бы вы предоставить еще пару входных значений и желаемые результаты для каждого из них?

DuesserBaest 22.07.2024 09:19
это регулярное выражение, например, маскирует последние четыре цифры любого числа на 12-19 цифр.
DuesserBaest 22.07.2024 09:23

Да, {0,3} выглядит так, как будто он маскирует последние 3 цифры, но на самом деле, если вы видите результат в dotnetfiddle.net/Gopzoz, он на самом деле маскирует последние 4 цифры. Конечная цель — замаскировать последние 4 цифры и пройти все остальные сценарии, упомянутые в этой ссылке. Спасибо

user3665818 22.07.2024 09:37

Еще одно решение, с которым я столкнулся, заключалось в использовании этого кода:

user3665818 22.07.2024 09:39

частная статическая строка MaskCreditCardNumber (текст этой строки) { if (string.IsNullOrEmpty (текст)) возвращаемый текст; return Regex.Replace(text, "[0-9][0-9 ]{12,}[0-9]", match => { string digits = string.Concat(match.Value .Where(c => char .IsDigit(c))); return digits.Length >= 12 || digits.Length <= 19 ? новая строка('X', digits.Length - 4) + digits.Substring(digits.Length - 4) : match .Ценить; }); }

user3665818 22.07.2024 09:39

Все сценарии, упомянутые в ссылке, будут работать с этим, но для такой строки, как «1234-5678-9123-4567-891», замаскированный вывод должен отображать «xxxx-xxxx-xxxx-xxx7-891», но он отображается как « хххх-хххх-хххх-хххх-891». Если мы сможем решить эту проблему, я думаю, что все сценарии будут учтены.

user3665818 22.07.2024 09:41

пожалуйста, включите тестовые примеры в свой вопрос, чтобы любой, кто читает ваш вопрос, знал, в чем именно вам нужна помощь.

DuesserBaest 22.07.2024 09:44

Как я уже упоминал, существует множество тестовых случаев, о которых необходимо позаботиться при устранении этой проблемы. Эти тестовые примеры являются частью dotnetfiddle.net/Gopzoz. Здесь, в этом конкретном вопросе, мой случай «от INV 2420852290 до SAV 0165487» не должен маскироваться, поскольку 2420852290 находится за пределами диапазона 12-19 цифр, но, поскольку вокруг него есть пробелы, регулярное выражение маскирует его,

user3665818 22.07.2024 09:47
Или вот это демо...
bobble bubble 22.07.2024 10:33

Также посмотрите эту \G идею (обновлена ​​ваша демо-версия). Другая демо (без \G) здесь. Оба регулярных выражения неэффективны, не знаю, что хуже. :D

bobble bubble 22.07.2024 12:13

Круто, спасибо @bobblebubble. Я так понимаю, вы упомянули, что может быть хуже (с \G или без \G) :). Но с точки зрения производительности, вы бы посоветовали использовать \G или без него? Хотя оба решения работают для меня.

user3665818 22.07.2024 13:25

@user3665818 user3665818 Я бы выбрал шаблон на основе \G. Вероятно, он примерно в 10-20 раз эффективнее другого. Другое регулярное выражение выполняет всю конструкцию просмотра-проверки для каждой цифры, тогда как \G выполняет просмотр назад только один раз (от того места, где оно объединяет совпадения) и только менее затратную предпросмотровую проверку для каждого совпадения. Я думаю, что даже другое решение, которое я предоставил, примерно в 5-10 раз быстрее, чем ваше текущее регулярное выражение... вероятно, решение Виктора будет работать лучше. Чтобы это выяснить, сделайте тест.

bobble bubble 22.07.2024 14:22
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
12
164
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы можете добавить декларацию using System.Linq; и использовать

Regex.Replace(value, @"(?<!\d)\d(?:[ -]?\d){11,18}(?!\d)", m => Regex.Replace(m.Value, @"\d(?=(?:[\s-]?\d){4})", "x"))

Посмотрите демонстрацию регулярных выражений .

Подробности:

  1. Получите совпадения 12–19 чисел, разделенных необязательным - или пробелом, см. эту демонстрацию регулярных выражений.

  2. Замаскируйте цифры внутри совпадения. Более подробная информация:

  • \d — цифра, которая...
  • (?=(?:[\s-]?\d){4}) — сразу за ним следуют четыре необязательных - или пробела и цифра.

ПРИМЕЧАНИЕ. Вы можете использовать аналогичную логику для обработки номера счета.

См. обновлённую демонстрацию кода здесь.

Wiktor Stribiżew 22.07.2024 10:20

Это работает во всех сценариях, кроме «Код счета 3038 — Квитанция № 351461637 221414441406». Здесь «351461637» — номер счета, а «221414441406» — CCno. Теперь он отлично работает для CCno, но для номера учетной записи он все маскирует. Он должен маскировать только последние 4 цифры. Таким образом, это должно выглядеть так: «Код счета 3038 — номер квитанции xxxxx1637 xxxxxxxx1406». Это регулярное выражение, которое я использую (?<!\d)\d(?:[\s-]?\d){7,8}(?!\d)", m => Regex.Replace(m.Value , @"\d(?=(?:[\s-]?\d){4}). Номер счета должен состоять только из 8 или 9 цифр.

user3665818 23.07.2024 03:56

Я знаю, что это другой сценарий, которого не было в вопросе, но, поскольку все решения есть на этой странице, я не поднимаю новый вопрос,

user3665818 23.07.2024 04:41
dotnetfiddle.net/ffgakc
user3665818 23.07.2024 04:44

Я опубликовал другой вопрос для обработки сценариев, связанных с моим последним комментарием. stackoverflow.com/questions/78781466/…. Пожалуйста, посмотрите и предложите.

user3665818 23.07.2024 05:33

Я также хотел отметить этот ответ как правильный, но он позволяет мне отметить только 1 правильный ответ.

user3665818 23.07.2024 05:36

Обработку номера вашего счета можно выполнить аналогичным образом, без использования сложных регулярных выражений, с которыми вы сами не сможете справиться. Вы не предоставили никаких требований к регулярному выражению номера счета, я бы включил его в свой ответ. ЕСЛИ номер счета представляет собой блок из 8–9 цифр, разделенных дефисами/пробелами, вы можете использовать решение, указанное в вашем комментарии, вы просто использовали TestCC вместо TestCCAndAccNo.

Wiktor Stribiżew 23.07.2024 15:25

Мне нужно использовать метод TestCCAndAccNo, потому что есть свободное текстовое поле, в котором пользователь может ввести любой текст вместе с номером счета и CCNo. Тогда оба этих числа должны быть замаскированы. Я вызываю MaskCCNo и MaskAccNo из метода MaskIfContainCreditCardPanorAcctNumNew. Все сценарии, кроме «TestCCAndAccNo(»Код счета 3038 — Номер квитанции 3514611 221414441406», «Код счета 3038 — Номер квитанции 3514 611 xxxxxxxx1406»)» проходят успешно. Здесь, поскольку 3514611 содержит менее 8 цифр, MaskCCNo маскирует его, что неверно. Все должно остаться как есть. См. dotnetfiddle.net/l2PDIw

user3665818 24.07.2024 15:31

@user3665818 user3665818 Совпадения нет, см. демонстрацию регулярных выражений. Проблема в том, что предыдущее регулярное выражение (?<!\d)\d(?:[\s-]?\d){11,18}(?!\d) соответствует 3514611. Итак, разрешение зависит от того, каким требованиям вы хотите следовать. Может быть, мы можем предположить, что числа от 5 до 8 цифр не могут быть сопоставлены с помощью регулярного выражения CCNo? Попробуйте Regex.Replace(value, @"(?<!\d)(?!\d{5,8}(?!\d))\d(?:[\s-]?\d){11,18}(?!\d)", m => Regex.Replace(m.Value, @"\d(?=(?:[\s-]?\d){4})", "x"))

Wiktor Stribiżew 24.07.2024 15:55

Вам необходимо учитывать конечные и ведущие пробелы в регулярном выражении. В настоящее время это не так.

Вот пример, как это сделать.

void Main()
{
    string input = "From INV 2420852290 to SAV 0165487";
    string pattern = @"(?<=\b(?<![\d-*])(?=\d{12,19}\b)[\d*\s]*)[\d*](?!(?:-?[\d*\s]){0,4}(?![\d-*\s]))";

    string result = Regex.Replace(input, pattern, "X");
    Console.WriteLine(result);
}

Это возвращает: From INV 2420852290 to SAV 0165487

Если я увеличу число на два следующим образом:

void Main()
{
    string input = "From INV 242085229012 to SAV 0165487";
    string pattern = @"(?<=\b(?<![\d-*])(?=\d{12,19}\b)[\d*\s]*)[\d*](?!(?:-?[\d*\s]){0,4}(?![\d-*\s]))";

    string result = Regex.Replace(input, pattern, "X");
    Console.WriteLine(result);
}

Теперь я понимаю это: From INV XXXXXXXX9012 to SAV 0165487

Вот мои рассуждения: Объяснение:

  • \b (граница слова) используется для того, чтобы мы начинали и заканчивали словом. границы для правильной обработки пробелов вокруг цифр.
  • (?<![\d-*]) гарантирует, что перед нами не стоит цифра, тире или звездочка.
  • (?=\d{12,19}\b) смотрит вперед, чтобы убедиться, что у нас есть от 12 до 19 цифр за которым следует граница слова.
  • [\d*\s]* соответствует цифрам, звездочкам или пространства.
  • [\d*](?!(?:-?[\d*\s]){0,4}(?![\d-*\s])) соответствует цифре или звездочку и гарантирует, что за ней не последуют нежелательные символы внутри определенный диапазон.

Если вы просто хотите всегда маскировать, вы можете сделать что-то простое, например: string pattern = @"\d(?=(?:-?\d){4})";

Ответ принят как подходящий

Причина, по которой ваше текущее регулярное выражение не работает для примера, заключается в том, (?<![\d-*]) цель которого — отделить целое число от текста, но оно просто проверяет один из перечисленных символов. Вместе с [\d*\s]){12,19} это может соответствовать указанному количеству цифр или пробелов.

Кроме того, я бы не стал использовать что-то вроде [\d-*\s]. В этом случае (регулярное выражение .NET) ошибки нет, но все равно выглядит некрасиво. Неэкранированный дефис внутри класса символов используется для обозначения диапазона символов. Чтобы соответствовать буквальному дефису, поместите его в начало/конец класса символов или замените его обратной косой чертой.

Согласно вашему следующему вопросу лучше не используйте для этого одно (огромное) регулярное выражение. Конечно, разумнее воспользоваться идеей Виктора, которую легче адаптировать к меняющимся и растущим требованиям.


Номер кредитной карты (совпадает с полным номером)

Проблема заключается в том, чтобы различить копию и номер счета и отделить их от остального текста. Чтобы быть как можно более точным при сопоставлении номера копии (вместо того, чтобы искать 12–19 цифр с пробелами или дефисами где-нибудь между ними), лучше определите номер копии, начав с 3–4 групп, каждая из которых содержит 4 соседние цифры (необязательно). затем следуют 1-3 цифры. Если группы разделены тире или пробелом, зафиксируйте и сопоставьте, насколько разделитель соответствует.

Посмотрите, соответствует ли вам следующий шаблон (демонстрация регулярного выражения).

(?<!\d-?)\d{4}([ -]?)\d{4}(?:\1\d{4}){1,2}(?:\1\d{1,3})?(?!-?\d)

Номер счета (от вашего нового вопроса)

Вы можете использовать то же регулярное выражение для номера счета, просто заменив часть cc на \d{8,9}. Предполагая, что в учетной записи нет разделителей - нет, как в предоставленных вами образцах (демо регулярного выражения).

(?<!\d-?)\d{8,9}(?!-?\d)

Сочетание обоих узоров

Если это необходимо для вашего приложения, вы также можете объединить оба шаблона в один, чередуя параметры внутри группы без захвата - сначала пробуется более левый вариант (демонстрация регулярного выражения).

(?<!\d-?)(?:\d{4}([ -]?)\d{4}(?:\1\d{4}){1,2}(?:\1\d{1,3})?|\d{8,9})(?!-?\d)

В каждом результирующем совпадении (полные числа) замените, например, \d(?=(?:[ -]?\d){4}) на x, чтобы замаскировать все цифры, кроме последних 4, с использованием метода, который @WiktorStribiżew предоставляет в своем ответе.

Посмотрите обновленную демо-версию (комбинированный шаблон находится в MaskIfContainCreditCardPanorAcctNumNew).

Это работает во всех сценариях, кроме «Код счета 3038 — Квитанция № 351461637 221414441406». Здесь «351461637» — номер счета, а «221414441406» — CCno. Теперь он отлично работает для CCno, но для номера учетной записи он все маскирует. Он должен маскировать только последние 4 цифры. Таким образом, это должно выглядеть так: «Код счета 3038 — номер квитанции xxxxx1637 xxxxxxxx1406». Это регулярное выражение, которое я использую (?<!\d)\d(?:[\s-]?\d){7,8}(?!\d)", m => Regex.Replace(m.Value , @"\d(?=(?:[\s-]?\d){4}). Номер счета должен состоять только из 8 или 9 цифр.

user3665818 23.07.2024 03:56

Пожалуйста, проигнорируйте регулярное выражение в комментарии выше, поскольку оно предназначалось для ответа Виктора. Я также пробовал использовать это регулярное выражение - Regex.Replace(value, @"(?:\G(?!^)|(?<!\d[ -]?)(?=(?:[ -]?\d ){8,9}(?![ -]?\d)))\d(?=(?:[ -]?\d){4})([ -]?)", "x$1") ;

user3665818 23.07.2024 04:24

Я знаю, что это другой сценарий, которого не было в вопросе, но, поскольку все решения есть на этой странице, я не поднимаю новый вопрос,

user3665818 23.07.2024 04:41
dotnetfiddle.net/ffgakc
user3665818 23.07.2024 04:44

Я опубликовал другой вопрос для обработки сценариев, связанных с моим последним комментарием. stackoverflow.com/questions/78781466/…. Пожалуйста, посмотрите и предложите.

user3665818 23.07.2024 05:33

@user3665818 user3665818 Я еще раз обновил свой ответ (полностью изменился... как и требования). Я надеюсь, что со всеми предоставленными ответами вы сможете как-то решить эту проблему.

bobble bubble 24.07.2024 17:00

Спасибо @bobble bubble. Большое спасибо за вашу помощь, и все сценарии в моей демонстрации отлично работают с вашим ответом. Я знаю, что выдвинул новые требования, но сейчас это должно быть последнее. Мне также нужно заменить звездочку (*) вместе с цифрами в CCNo, если они находятся в диапазоне от 12 до 19.

user3665818 26.07.2024 08:46

Таким образом, для строки типа «420657******4405» она должна получить маску «xxxxxxxxxxxx4405». Я использую это регулярное выражение прямо сейчас - Regex.Replace(value, @"(?<!\d-?)\d{4}([ -]?)\d{4}(?:\1\d{4 }){1,2}(?:\1\d{1,3})?(?!-?\d)", m => Regex.Replace(m.Value, @"\d(?=( ?:[ -]?\d){4})", "x"); Такое поведение должно работать и для этого регулярного выражения. Regex.Replace(value, @"(?<!\d-?)(?:\d{4}([ -]?)\d{4}(?:\1\ d{4}){1,2}(?:\1\d{1,3})?|\d{8,9})(?!-?\d)", m => Regex.Replace( m.Value, @"\d(?=(?:[ -]?\d){4})", "x");

user3665818 26.07.2024 08:54

Обновленное демо — dotnetfiddle.net/iYPCeo

user3665818 26.07.2024 08:58

@user3665818 для этого измените все соответствующие \d на [\d*]обновленную демо (номер копии и оба номера). Если вы также ожидаете таких, как *****9123-4567, попробуйте dotnetfiddle.net/7VN03P. Я ушёл из этой темы, рад, что помогло!

bobble bubble 26.07.2024 10:49

Другие вопросы по теме