UNPKG

regex-fa

Version:

Professional JavaScript utility to generate flexible and accurate regex patterns for data validation

184 lines (139 loc) 5.26 kB
/** * Validate value based on Iranian formats like nationalId and postCode. * * @param {Object} options * @param {"nationalId"|"postCode"|"mobile"|"cardNumber"|"sheba"|"bankNumber"|"email"|"date"|"time"|"ipv4"|"ipv6"} options.type - Type of value to validate. * @param {string|number} options.value - The value to validate. * @returns {boolean} */ export default function regexValue({ type, value }) { if (value == null) return false; let str = String(value).trim(); switch (type) { case 'nationalId': { if (!/^\d+$/.test(str)) return false; if (str.length < 8 || str.length > 10) return false; const padded = str.padStart(10, '0'); if (/^(\d)\1{9}$/.test(padded)) return false; const digits = Array.from(padded, Number); const checkDigit = digits[9]; let sum = 0; for (let i = 0; i < 9; i++) { sum += digits[i] * (10 - i); } const mod = sum % 11; const expected = (mod < 2 ? mod : 11 - mod); return expected === checkDigit; } case 'postCode': { const clean = str.replace('-', ''); if (!/^\d{10}$/.test(clean)) return false; if (/^(\d)\1{9}$/.test(clean)) return false; const pattern = /^(?!.*(\d)\1{3})[13-9]{4}[1346-9][0-9]{5}$/; return pattern.test(clean); } case 'mobile': { str = str.replace(/^(\+98|0098)/, '0'); return /^09\d{9}$/.test(str); } case 'cardNumber': { const clean = str.replace(/[\s-]/g, ''); if (!/^\d{16}$/.test(clean)) return false; if (/^(\d)\1{15}$/.test(clean)) return false; const digits = clean.split('').map(Number); let sum = 0; for (let i = 0; i < 16; i++) { let digit = digits[i]; if (i % 2 === 0) { digit *= 2; if (digit > 9) digit -= 9; } sum += digit; } return sum % 10 === 0; } case 'sheba': { const clean = str.toUpperCase().replace(/\s|-/g, ''); if (!/^IR\d{22}$/.test(clean)) return false; const rearranged = clean.slice(4) + clean.slice(0, 4); const converted = rearranged.replace(/[A-Z]/g, ch => (ch.charCodeAt(0) - 55)); let remainder = converted; let block = ''; while (remainder.length > 2) { block = remainder.slice(0, 9); // حداکثر 9 رقم remainder = (parseInt(block, 10) % 97).toString() + remainder.slice(block.length); } const isValid = parseInt(remainder, 10) % 97 === 1; return isValid; } case 'bankNumber': { const clean = str.replace(/\D/g, ''); if (clean.length < 6 || clean.length > 20) return false; if (!/^\d+$/.test(clean)) return false; if (/^(\d)\1+$/.test(clean)) return false; return true; } case 'email': { const clean = String(str).trim().toLowerCase(); if (!clean.includes('@')) return false; if (clean.length < 6 || clean.length > 320) return false; if (!/^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(clean)) return false; return true; } case 'date': { const persianNums = '۰۱۲۳۴۵۶۷۸۹'; const englishNums = '0123456789'; let clean = String(str).trim().replace(/[۰-۹]/g, d => englishNums[persianNums.indexOf(d)]); clean = clean.replace(/[-.]/g, '/'); const regex = /^(13|14)\d{2}\/(0[1-9]|1[0-2])\/(0[1-9]|[12]\d|3[01])$/; return regex.test(clean); } case 'time': { const persianNums = '۰۱۲۳۴۵۶۷۸۹'; const englishNums = '0123456789'; let clean = String(str).trim().replace(/[۰-۹]/g, d => englishNums[persianNums.indexOf(d)]); if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(:\d{2}(\.\d+)?(Z)?)?$/.test(clean)) { const date = new Date(clean); return !isNaN(date.getTime()); } const match = clean.match(/^(\d{1,2}):(\d{1,2})$/); if (!match) return false; const hour = Number(match[1]); const minute = Number(match[2]); if (hour < 0 || hour > 24) return false; if (minute < 0 || minute > 59) return false; if (hour === 24 && minute !== 0) return false; return true; } case 'ipv4': { const clean = String(str).trim(); if (!/^\d{1,3}(\.\d{1,3}){3}$/.test(clean)) return false; const parts = clean.split('.'); for (const part of parts) { if (part.length > 1 && part.startsWith('0')) return false; const num = Number(part); if (num < 0 || num > 255 || isNaN(num)) return false; } return true; } case 'ipv6': { const clean = String(str).trim().toLowerCase(); if (!/^[0-9a-f:]+$/.test(clean)) return false; if ((clean.match(/::/g) || []).length > 1) return false; const parts = clean.split(':'); if (clean.includes('::')) { if (parts.length > 8) return false; } else { if (parts.length !== 8) return false; } for (const part of parts) { if (part.length === 0) continue; if (part.length > 4) return false; if (!/^[0-9a-f]{1,4}$/.test(part)) return false; } return true; } default: throw new Error(`Invalid validation type: ${type}`); } }