Validasi URL
URL memiliki struktur yang cukup kompleks. Mari bangun pattern-nya bertahap.
Struktur URL
https://www.example.com:8080/path/page?key=value#section
|_____| |_____________||__||_________||________||______|
protocol host port path query hash
Pattern URL Sederhana
const simpleUrl = /^https?:\/\/[\w.-]+\.[a-zA-Z]{2,}/;
simpleUrl.test("https://google.com"); // true
simpleUrl.test("http://localhost"); // false (tidak ada TLD)
simpleUrl.test("ftp://file.server.com"); // false (bukan http/s)
Pattern URL Lebih Lengkap
const urlRegex = /^https?:\/\/[\w.-]+\.[a-zA-Z]{2,}(:\d+)?(\/[\w./-]*)?/;
urlRegex.test("https://belajarweb.dev"); // true
urlRegex.test("http://api.example.com:3000"); // true
urlRegex.test("https://web.dev/learn/css"); // true
urlRegex.test("bukan-url"); // false
Mari bedah:
https?:\/\/— "http://" atau "https://"[\w.-]+— subdomain dan domain\.[a-zA-Z]{2,}— TLD minimal 2 huruf(:\d+)?— port opsional(\/[\w./-]*)?— path opsional
Extract URL dari Teks
const teks = "Kunjungi https://belajarweb.dev atau http://example.com/page untuk info lebih lanjut";
const urls = teks.match(/https?:\/\/[\w.-]+\.[a-zA-Z]{2,}(\/[\w./?&=#-]*)?/g);
console.log(urls);
// ["https://belajarweb.dev", "http://example.com/page"]
Validasi Nomor Telepon Indonesia
Nomor telepon Indonesia punya beberapa format yang umum:
Format yang Perlu Didukung
08123456789 (tanpa separator)
0812-3456-789 (dengan dash)
0812 3456 789 (dengan spasi)
+628123456789 (dengan kode negara)
+62-812-3456-789 (kode negara dengan dash)
(021) 1234567 (telepon rumah)
Pattern untuk Nomor HP
// Nomor HP Indonesia — format 08xx atau +62
const hpRegex = /^(\+62|0)8\d{1,2}[- ]?\d{4}[- ]?\d{2,4}$/;
hpRegex.test("081234567890"); // true
hpRegex.test("0812-3456-7890"); // true
hpRegex.test("+6281234567890"); // true
hpRegex.test("021-1234567"); // false (bukan HP)
Normalisasi Nomor Telepon
Seringkali kita perlu mengubah berbagai format ke satu format standar:
function normalizePhone(phone) {
// Hapus semua non-digit kecuali +
let clean = phone.replace(/[^\d+]/g, "");
// Ubah 08xx ke +628xx
if (clean.startsWith("0")) {
clean = "+62" + clean.slice(1);
}
return clean;
}
console.log(normalizePhone("0812-3456-7890")); // "+6281234567890"
console.log(normalizePhone("+62 812 3456 789")); // "+62812345678 9"
console.log(normalizePhone("081234567890")); // "+6281234567890"
Validasi dengan Named Groups
function parsePhoneNumber(phone) {
const regex = /^(?<prefix>\+62|0)(?<operator>8\d{1,2})[- ]?(?<middle>\d{4})[- ]?(?<last>\d{2,4})$/;
const match = phone.match(regex);
if (!match) return null;
return {
prefix: match.groups.prefix,
operator: match.groups.operator,
number: match.groups.middle + match.groups.last,
formatted: `+62${match.groups.operator}-${match.groups.middle}-${match.groups.last}`
};
}
console.log(parsePhoneNumber("0812-3456-7890"));
// { prefix: "0", operator: "812", number: "34567890", formatted: "+62812-3456-7890" }
Format Otomatis Saat Mengetik
function formatPhoneInput(value) {
const digits = value.replace(/\D/g, "");
if (digits.length <= 4) return digits;
if (digits.length <= 8) return digits.slice(0, 4) + "-" + digits.slice(4);
return digits.slice(0, 4) + "-" + digits.slice(4, 8) + "-" + digits.slice(8, 12);
}
console.log(formatPhoneInput("081234567890")); // "0812-3456-7890"
Format Internasional E.164
Standar internasional untuk nomor telepon adalah E.164: diawali +, kode negara, lalu nomor lokal — total maksimal 15 digit, tanpa spasi atau separator.
// E.164: ^+ diikuti 1 digit non-nol, lalu 1-14 digit
const e164 = /^\+[1-9]\d{1,14}$/;
e164.test("+6281234567890"); // true (Indonesia)
e164.test("+14155552671"); // true (US)
e164.test("+442071838750"); // true (UK)
e164.test("+0812345"); // false (kode negara tidak boleh diawali 0)
e164.test("081234567890"); // false (tidak ada +)
Catatan: Validasi Kode Negara di Regex Tidak Praktis
Setiap negara punya panjang dan format nomor yang berbeda. Memvalidasi semua aturan ini hanya dengan regex akan sangat panjang dan rapuh — kode area baru bisa muncul kapan saja, dan beberapa negara punya panjang nomor yang bervariasi.
Untuk production, pakai library yang dimaintain Google:
// npm install libphonenumber-js
import { parsePhoneNumber, isValidPhoneNumber } from "libphonenumber-js";
isValidPhoneNumber("+6281234567890"); // true
parsePhoneNumber("0812-3456-7890", "ID").number; // "+6281234567890"
Library ini di-update mengikuti perubahan numbering plan tiap negara — sesuatu yang regex statismu tidak akan pernah bisa lakukan.
Regex sangat powerful untuk validasi dan transformasi format data — tapi ingat, untuk validasi production, selalu kombinasikan dengan server-side validation.
🎭 Analogi sehari-hari: URL = alamat rumah lengkap. Protokol = "Jakarta vs Surabaya" (kota). Domain = nama jalan. Path = nomor rumah. Query = note tambahan. Phone Indonesia = nomor PLN: prefix kode area + nomor pelanggan. Format beragam (08xx, +628xx, 628xx) — semua valid, tinggal normalize ke satu format.
💡 libphonenumber > regex untuk phone: Google maintain database global (panjang nomor, format, valid prefix per negara, mobile vs landline). Regex statis = ketinggalan terus. Pakai libphonenumber-js (15kb gzipped) untuk production.
⚠️ Jebakan klasik:
- Validasi telepon Indonesia tanpa normalize —
0812...,+6281...,6281...semua valid, butuh normalize dulu - URL regex include trailing punctuation — "Visit https://site.com." cocok jadi
https://site.com.(titik kalimat termasuk) - Lupa IDN domain — domain
münchen.devalid tapi regex ASCII-only akan reject - Validasi port —
:abcinvalid tapi regex naive:\d*cocok kalau port kosong - Hardcode TLD list —
(com|org|net)ketinggalan TLD baru (.dev, .id, .web)
🎯 URL/phone validation strategy:
- URL: browser
URLconstructor di JS (built-in, robust).try { new URL(str) } catch { invalid } - Phone:
libphonenumber-js(production) - Email: HTML5 + library
- General: regex untuk pre-filter, library untuk strict validation
TL;DR: URL dan phone format kompleks. Regex sederhana untuk basic check, library untuk production. URL: pakai new URL() constructor di JS. Phone: pakai libphonenumber-js. Normalize input sebelum validate.