Можно ли переписать эту функцию с помощью регулярного выражения? - PullRequest
0 голосов
/ 04 марта 2019

Я хочу переформатировать и проверить, если пользователь предоставил действительный бельгийский корпоративный номер.Поскольку входными данными могут быть все следующие примеры:

  • BE 0123.321.123
  • BE0123.321.123
  • BE0123 321 123
  • 0123.321.123
  • 123.321.123
  • 123321123

Я написал функцию, которая проверяет и переформатирует ввод в «отображаемую» версию (BE 0123.123.123)и версия «кода» (123123123).Эта функция выглядит следующим образом.

formatAndValidateEnterpriseNumber = enterpriseNumber => {
    if(enterpriseNumber === undefined || !enterpriseNumber || (enterpriseNumber || '').length < 3) return { isValid: false, error: 'Please fill in your enterprise number' };

        //Remove space, dots, ...
        enterpriseNumber = enterpriseNumber.toUpperCase();
        enterpriseNumber = enterpriseNumber.replace(/[. ,:-]+/g, '');

        //Check for double country code
        const reDouble = /^[a-zA-Z]{4}/;
        if (reDouble.test(enterpriseNumber)) enterpriseNumber = enterpriseNumber.substring(2);

        if (enterpriseNumber.length < 9 || enterpriseNumber.length > 12) return { isValid: false, error: 'The length of the provided number is incorrect' };

        //Check country code
        const reBE = /^[a-zA-Z]{2}/;
        if (reBE.test(enterpriseNumber)) {
            //Check if country code = BE
            if (enterpriseNumber.slice(0, 2) !== 'BE') return { isValid: false, error: 'Please fill in a Belgian enterprise number' };
            // Remove country code
            else enterpriseNumber = enterpriseNumber.substring(2);
        }

        //Check if first digit is 0
        if (enterpriseNumber.length === 10 && enterpriseNumber.startsWith('0')) enterpriseNumber = enterpriseNumber.substring(1);

        //Check if enterpriseNumber is valid with modulo test
        if (parseInt(97 - (enterpriseNumber.slice(0, 7) % 97), 10) !== parseInt(enterpriseNumber.slice(7, 9), 10))
            return { isValid: false, error: 'The provided number is invalid'}

      return {
            isValid: true,
            enterpriseNumber: enterpriseNumber,
            displayEnterpriseNumber: `BE 0${enterpriseNumber.substring(0, 3)}.${enterpriseNumber.substring(3, 6)}.${enterpriseNumber.substring(6, 9)}`
      };
};

Я думаю, что это довольно грязно, и мне интересно, можно ли это улучшить с помощью одного / двух тестов регулярных выражений, которые переформатируют и проверяют вводимые пользователем данные?

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

Ответы [ 3 ]

0 голосов
/ 04 марта 2019

Для ваших примеров строк вы можете указать:

^(?:BE\s?)?[01]?(\d{3}([. ])\d{3}\2\d{3}|\d{9})$

Это будет соответствовать

  • ^ Начало строки
  • (?:BE\s?)? Необязательно BEза которым следует необязательный символ пробела
  • [01]? Необязательный ноль или 1
  • ( Группа захвата
    • \d{3} Совпадение с 3 цифрами
    • ([. ])Захват в группе пробел или цифра для использования в качестве обратной ссылки
    • \d{3}\2\d{3} Совпадение с 3 цифрами, точкой или пробелом (\ 2 - обратная ссылка) и 3 цифрами
    • | Или
    • \d{9} Совпадение 9 цифр
  • ) Закрыть группу захвата
  • $ Конец строки

Regex demo

А затем при замене используйте первую группу захвата и замените пробел или точку пустой строкой.

let pattern = /^(?:BE\s?)?[01]?(\d{3}([. ])\d{3}\2\d{3}|\d{9})$/;
let strings = [
  "BE 0123.321.123",
  "BE0123.321.123",
  "BE0123 321 123",
  "0123.321.123",
  "123.321.123",
  "123321123",
];

strings = strings.map(x => x.replace(pattern, function(m, g) {
  let enterpriseNumber = g.replace(/[. ]/g, "");
  return `BE 0${enterpriseNumber.substring(0, 3)}.${enterpriseNumber.substring(3, 6)}.${enterpriseNumber.substring(6, 9)}`
}));

console.log(strings);
0 голосов
/ 05 марта 2019

Вот реализация стиля ввода BE ____.___.___.Шаблон будет сохранен, поэтому входные данные будут иметь префикс «BE», пробел и две точки.Проверка затем может быть сконцентрирована на полноте и тесте по модулю.

Обратите внимание, что для ввода требуется, чтобы первая группа состояла из 4 цифр, где первая цифра должна быть 0 или 1.

const ent = document.getElementById("ent");
const out = document.getElementById("isvalid");

function format() {
    const re = /^\D*[2-9]+|\D+/g;
    const [i, j] = [this.selectionStart, this.selectionEnd].map(i => {
        i = this.value.slice(0, i).replace(re, "").length;
        return i + 3 + (i >= 4 + format.backspace) + (i >= 7 + format.backspace);
    });
    this.value = "BE " + this.value.replace(re, "").padEnd(10, "_")
                                   .replace(/(....)(...)(...).*/, "$1.$2.$3");
    this.setSelectionRange(i, j);
    format.backspace = false;
    out.textContent = validate(this.value) ? "is valid" : "is invalid";
}

function validate(num) {
    return /^BE [01](\d{3}\.){2}\d{3}$/.test(num) 
            && 97 - num.replace(/\D/g, "").slice(0, 8) % 97 === +num.slice(-2);
}

ent.addEventListener("input", format);
ent.addEventListener("keydown", (e) => format.backspace = e.key == "Backspace");
Belgian enterprise number: <input id="ent" value="BE ____.___.___">
<span id="isvalid"></span>
0 голосов
/ 04 марта 2019

Да, вы можете:

^(?:BE)?\s*[0-1]?(\d[. ]*){9}$

Это регулярное выражение должно делать это!

Этот источник (на голландском языке) указывает, для чего нужен номер предприятияБельгия:

У него есть код страны: BE, за которым следует 0 или 1, а затем 9 цифр.

https://regex101.com/r/4SRHxi/4

Объяснение:

  • ^: строка должна начинаться с заданного регулярного выражения
  • (?:BE)?: искать группу с BE, но ? означает, что она соответствует нулюили один раз - ?: означает поиск, но не захватывает
  • \s*: поиск пробела, который соответствует нулю или неограниченному числу раз
  • [0-1]?: проверить, равен ли ноль единицеприсутствует ноль или один раз
  • ((\d[. ]*){9}): Проверьте, следуют ли 9 цифр за оставшейся строкой, независимо от того, сколько точек или пробелов они дополняют.Каждая итерация фиксируется как 1-я группа захвата.Это становится важным, когда мы заменим позже.
  • $: строка должна заканчиваться

Это проверит, проверяет ли ввод.

Редактирование его вcode версия проста:

«code».replace(/^(?:BE)?\s*[0-1]?((\d[. ]*){9})$/g, function(){
      return arguments[1].replace(/\D/g, "");
});

g или глобальный модификатор обеспечит удаление всех нежелательных символов.Используя функцию с заменой для замены всех нецифровых символов.Эта функция выведет желаемый результат.

document.querySelector("pre").textContent.split("\n").forEach(function(element){
  if (element.match(/^(?:BE)?\s*[0-1]?(\d[. ]*){9}$/))
  {
     console.log(element.replace(/^(?:BE)?\s*[0-1]?((\d[. ]*){9})$/g, function(){
      return arguments[1].replace(/\D/g, "");
     }));
  }
  else
  {
    console.log(`REJECTED: ${element}`);
  }

});

BE 0123.321.123
BE0123.321.123
BE0123 321 123
BE 0123  321  123
BE 01 23 32 11 23
BE 0123 32 11 23
1123.321.123
123.321.123
123321123
AAA3434343A
BE  1233 445 4545 442

Восстановление строки в правильном удобном для пользователя виде теперь легко:

document.querySelector("pre").textContent.split("\n").forEach(function(element) {
  if (element.match(/^(?:BE)?\s*[0-1]?((\d[. ]*){9})$/)) {
    var stripped = element.replace(/^(?:BE)?\s*[0-1]?((\d[. ]*){9})$/g, function(){
          return arguments[1].replace(/\D/g, "");
    });

    //with the modulo check from your code added back in.
    if (97 - (parseInt(stripped.slice(0, 7), 10) % 97) == parseInt(stripped.slice(7, 9), 10)) {
      //use a literal string
      //use substring to put the dots between the sections of three numbers.
      var humanReadable = `BE 0${stripped.substring(0,3)}.${stripped.substring(3,6)}.${stripped.substring(6,9)}`;
      console.log(`CODE: ${stripped}`, `UI: ${humanReadable}`);
    }
  }

});

BE 0123.321.123
BE0123.321.123
BE0123 321 123
0123.321.123
123.321.123
123321123
844256524

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

Простая версия:

document.querySelector("div.enterprisenumber > input").addEventListener("keydown", function(e) {
  let value = this.value;

  //prevent the input from going back to 0
  if ( (value.length == 0 && (e.key == "Backspace" || e.key == "Delete"))) {
    e.preventDefault();
    return false;
  }
}, true);

document.querySelector("div.enterprisenumber > input").addEventListener("keyup", function(e) {
  //reset to a value without dots 
  let value = this.value.replace(/\./g, "");

  //strip the leading zero
  const valueWithout = value;
  //calculate how much iterations we need of a groups of three digits.
  const i = Math.floor(valueWithout.length / 3);
  let newValue = "";
  //check if backspace or delete are used to make sure the dot can be deleted.
  if (valueWithout.length < 9 && !(e.key == "Backspace" || e.key == "Delete")) {
    //only fire when higher than zero
    if (i > 0) {
      let t;
      //t is the index
      for (t = 0; t < i; t++) {
      //slice the correct portion of the string and append a dot, unless we are at the end of the groups
        newValue += valueWithout.slice(t * 3, t * 3 + 3) + (t == 2  ? "" : ".");
      }
      //append the remainder that is not a group of three.
      newValue += valueWithout.slice((t) * 3);
    } else {
      //return the value as is.
      newValue = value;
    }
    //set the new value to the input.
    this.value = newValue;
  }
}, true);

document.querySelector("div.enterprisenumber > input").addEventListener("blur", function(e) {
  let passed = false;
  if (this.value.match(/^(?:BE)?\s*[0-1]?((\d[. ]*){9})$/))
  {
    const value = this.value.replace(/\./g, "");
    //with modulo check
    if (97 - (parseInt(value.slice(0,7), 10) % 97) == value.slice(7, 9))
    {
      passed = true;
    }
  }
  document.querySelector(".enterprisenumber").classList[(passed ? "remove" : "add")]("error");
});

//if focus then focus input
document.querySelector("div.enterprisenumber").addEventListener("click", function(e) {
 if (e.target && e.target.nodeName != "SELECT")
 {
  this.querySelector("input").focus();
 }
});
* {
  box-sizing: border-box;
  font-family: tahoma;
  font-size: 10pt;
}

div.enterprisenumber {
  border: 1px solid #747474;
  width: 300px;
  padding: 0px;
  display: grid;
  grid-template-columns: 25px 40px auto;
  border-radius: 10px;
}

div.enterprisenumber.error {
  border: 1px solid #ff0000;
}

div.enterprisenumber>span {
  grid-column: 1;
  border: 0px;
  padding: 5px;
  background: linear-gradient(to right, rgba(0,0,0, 0.8) 33%, rgba(255,243,54, 0.8) 33%, rgba(255, 243, 54, 0.8) 66%, rgba(255, 15, 33, 0.8) 66%, rgba(255, 15, 33, 0.8) 100%);
  color: #ffffff;
  font-weight: bold;
  text-shadow: 1px 1px #000000;
  border-radius: 10px 10px 10px 10px;
}

div.enterprisenumber>select {
  grid-column: 2;
  border: 0px;
  padding: 5px;
}

div.enterprisenumber>input {
  grid-column: 3;
  border: 0px;
  padding: 5px;
  border-radius: 0px 10px 10px 0px;
}
Enter: 844256524
<div class="enterprisenumber">
  <span>BE</span><select><option value="0">0</option><option value="1">1</option><input value="" maxlength="11" />
</div>
...