JavaScript RegEx: Formatuj ciąg z dynamiczną długością do formatu blokowego
Następujące formaty RegEx podane są jako ciąg do następującego wzorca bloku wyjściowego:
123 456 78 90 (= 3 cyfry 3 cyfry 2 cyfry 2 cyfry)
RegEx:
string.replace(/^(\d{3})(\d{3})(\d{2})(\d{2})$/g, '$1 $2 $3 $4');
Ten przykład działa tylko wtedy, gdy dany ciąg wejściowy odpowiada dokładnej długości 10 cyfr.
Jak mogę dostosować wyrażenie RegEx do pracy z każdą długością ciągu?
- 1234 -> 123 4
- 1234567 -> 123 456 7
- 123456789 -> 123 456 78 9
- 1234567890123 -> 123 456 78 90 12 3
Tło: Chcę bezpośrednio sformatować ciąg wejściowy pola wejściowego formularza, gdy użytkownik wprowadzi liczbę ...
Odpowiedzi
Korzystając z nowoczesnego lookbehind JavaScript, który umożliwia dynamiczne potwierdzanie długości, możesz użyć tego wyrażenia regularnego, aby dopasować:
/(?<=^(?:\d{6}(?:\d{2})*|(?:\d{3}){1,2}))(?=\d+$)/g
Po prostu zastąp to pojedynczą spacją, tj " "
RegEx Demo
Spojrzeć za siebie:
(?<=: Rozpocznij asercję^(?:\d{6}(?:\d{2})*: Upewnij się, że mamy 6 cyfr, po których następuje 0 lub więcej par cyfr|: LUB(?:\d{3}){1,2}): Spraw, abyśmy mieli za sobą jeden lub dwa zestawy 3-cyfrowych zestawów
): Koniec asercji
Patrz przed siebie:
(?=\d+$): Upewnij się, że mamy przed sobą co najmniej jedną cyfrę
Rozwiązania anubhavy i Wiktora są sprytne, ale nie sądzę, żebym użył do tego wyrażenia regularnego; rozwiązania wydają się zbyt skomplikowane, aby je utrzymać. (To jest wezwanie do oceny). Oto podejście, które pobiera poszczególne cyfry i wstawia spacje po trzeciej cyfrze i po każdej kolejnej cyfrze, której pozycja indeksu jest liczbą nieparzystą:
result = [...str].map((d, i) => d + (i === 2 || (i >= 5 && i % 2 === 1) ? " " : "")).join("");
Przykład na żywo:
const tests = [
["1234", "123 4"],
["1234567", "123 456 7"],
["123456789", "123 456 78 9"],
["1234567890123", "123 456 78 90 12 3"],
];
function format(str) {
return [...str].map((d, i) => d + (i === 2 || (i >= 5 && i % 2 === 1) ? " " : "")).join("");
}
for (const [str, expected] of tests) {
const result = format(str);
console.log(`|${str}|`, "=>", `|${result}|`, result === expected ? "OK" : "*** ERROR");
}
Oto wersja, która działa tylko w środowiskach ES5:
result = str.split("").map(function(d, i) {
return d + (i === 2 || (i >= 5 && i % 2 === 1) ? " " : "");
}).join("");
Możesz użyć
const rx = /^(\d{3})(\d{1,3})?(\d{1,2})?(\d{1,2})?$/; $('body').on('input', '.info', function(e) {
this.value = this.value.replace(/\s+/g,'')
.replace(/^(\d{10}).*/, '$1') .replace(rx, (_,w,x,y,z) => z ? `${w} ${x} ${y} ${z}` : y ? `${w} ${x} ${y}` :
x ? `${w} ${x}` : w);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input class="info" maxlength=13>
Wyrażenie ^(\d{3})(\d{1,3})?(\d{1,2})?(\d{1,2})?$regularne wykona formatowanie na żywo razem z funkcją wywołania zwrotnego używaną jako argument zastępczy. Pierwsze trzy cyfry są obowiązkowe, drugie, trzecie i czwarte bloki są opcjonalne, ale zawierają co najmniej jedną cyfrę. Spacje są dodawane tylko wtedy, gdy w bloku jest co najmniej jedna cyfra. Numer jest ponownie formatowany za każdym razem, gdy jest edytowany:
.replace(/\s+/g,'')usuwa dodane spacje.replace(/^(\d{10}).*/, '$1')zachowuje tylko pierwsze dziesięć cyfr, jeśli jest ich więcej