JavaScript RegEx: Format string dengan panjang dinamis untuk memblokir format

Aug 31 2020

Format RegEx berikut memberikan string ke pola blok keluaran berikut:

123456 78 90 (= 3 digit 3 digit 2 digit 2 digit)

RegEx:

string.replace(/^(\d{3})(\d{3})(\d{2})(\d{2})$/g, '$1 $2 $3 $4');

Contoh ini hanya berfungsi, jika string input yang diberikan cocok dengan panjang tepat 10 digit.

Bagaimana cara menyesuaikan RegEx agar berfungsi dengan setiap panjang string?

  • 1234 -> 123 4
  • 1234567 -> 123456 7
  • 123456789 -> 123456 78 9
  • 1234567890123 -> 123456 78 90 12 3

Latar Belakang: Saya ingin memformat string input dari bidang input formulir secara langsung, ketika pengguna memasukkan nomor ...

Jawaban

2 anubhava Aug 31 2020 at 15:05

Menggunakan tampilan Javascript modern yang memungkinkan pernyataan panjang dinamis, Anda dapat menggunakan ekspresi reguler ini untuk mencocokkan:

/(?<=^(?:\d{6}(?:\d{2})*|(?:\d{3}){1,2}))(?=\d+$)/g

Ganti saja dengan satu spasi yaitu " "

Demo RegEx

Lihat kebelakang:

  • (?<=: Mulai pernyataan
    • ^(?:\d{6}(?:\d{2})*: Pastikan kita memiliki 6 digit diikuti dengan 0 atau lebih pasangan digit di belakang
    • |: ATAU
    • (?:\d{3}){1,2}): Buatlah kita memiliki satu atau dua set set 3 digit di belakang
  • ): Akhiri pernyataan

Lihat ke depan:

  • (?=\d+$): Pastikan kami memiliki setidaknya satu digit di depan
3 T.J.Crowder Aug 31 2020 at 15:08

Solusi anubhava dan Wiktor pintar, tapi saya rasa saya tidak akan menggunakan ekspresi reguler untuk melakukannya; solusi terasa terlalu rumit untuk dipertahankan. (Ini adalah panggilan penilaian.) Berikut adalah pendekatan yang mendapatkan digit individu dan menyisipkan spasi setelah digit ketiga dan setelah setiap digit berikutnya yang posisi indeksnya adalah angka ganjil:

result = [...str].map((d, i) => d + (i === 2 || (i >= 5 && i % 2 === 1) ? " " : "")).join("");

Contoh Langsung:

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");
}

Berikut adalah versi yang berfungsi di lingkungan khusus ES5:

result = str.split("").map(function(d, i) {
    return d + (i === 2 || (i >= 5 && i % 2 === 1) ? " " : "");
}).join("");
2 WiktorStribiżew Aug 31 2020 at 15:09

Kamu bisa memakai

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>

The ^(\d{3})(\d{1,3})?(\d{1,2})?(\d{1,2})?$regex akan melakukan format hidup bersama-sama dengan fungsi callback digunakan sebagai argumen pengganti. Tiga digit pertama wajib diisi, blok kedua, ketiga dan keempat bersifat opsional, tetapi mengandung setidaknya satu digit. Spasi hanya ditambahkan jika setidaknya ada satu digit di blok. Nomor diformat ulang setiap kali nomor diedit:

  • .replace(/\s+/g,'') menghapus spasi yang ditambahkan
  • .replace(/^(\d{10}).*/, '$1') hanya menyimpan sepuluh digit pertama jika ada lebih banyak