UNPKG

anitimejs

Version:

Thư viện xử lý chuỗi số và thời gian trong JavaScript/Typescript

224 lines (223 loc) 8.07 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.numbers = void 0; const numbers = (input, options = {}) => { const { separator, groupSize = 3, toWords = false, compact = false, decimals, rounding = 'round', showPositiveSign = false, decimalSeparator = '.', currency, currencyPosition = 'prefix', parseOptions = { format: 'default' } } = options; // Kiểm tra groupSize if (groupSize < 1 || !Number.isInteger(groupSize)) { throw new Error("`groupSize` phải là số nguyên lớn hơn hoặc bằng 1."); } // Chuyển input thành số let numericValue; if (typeof input === 'number') { numericValue = input; } else if (typeof input === 'string') { numericValue = parseNumericString(input, parseOptions); } else { throw new Error("Tham số đầu vào phải là số hoặc chuỗi."); } // Kiểm tra số hợp lệ if (isNaN(numericValue)) { throw new Error("Không thể chuyển đổi thành số hợp lệ."); } // Chuyển đổi sang chữ nếu cần if (toWords) { const result = numberToWords(numericValue); return result.charAt(0).toUpperCase() + result.slice(1); } // Định dạng số ngắn gọn if (compact) { return compactNumber(numericValue, decimals !== undefined ? decimals : 1); } // Áp dụng việc làm tròn số thập phân nếu được yêu cầu if (decimals !== undefined) { switch (rounding) { case 'floor': numericValue = Math.floor(numericValue * Math.pow(10, decimals)) / Math.pow(10, decimals); break; case 'ceil': numericValue = Math.ceil(numericValue * Math.pow(10, decimals)) / Math.pow(10, decimals); break; case 'round': default: numericValue = Math.round(numericValue * Math.pow(10, decimals)) / Math.pow(10, decimals); } } // Chuyển số thành chuỗi với số thập phân let numStr = decimals !== undefined ? numericValue.toFixed(decimals) : numericValue.toString(); // Xử lý phần nguyên và phần thập phân riêng biệt const parts = numStr.split('.'); // Thêm dấu phân cách cho phần nguyên nếu cần if (separator) { parts[0] = addSeparator(parts[0], groupSize, separator); } // Ghép phần nguyên và phần thập phân numStr = parts.length > 1 ? `${parts[0]}${decimalSeparator}${parts[1]}` : parts[0]; // Thêm dấu cộng cho số dương nếu cần if (showPositiveSign && numericValue > 0) { numStr = `+${numStr}`; } // Thêm đơn vị tiền tệ if (currency) { numStr = currencyPosition === 'prefix' ? `${currency}${numStr}` : `${numStr}${currency}`; } return numStr; }; exports.numbers = numbers; /** * Hàm phân tích chuỗi thành số */ function parseNumericString(input, options = {}) { const { format = 'default', decimalSeparator, thousandSeparator } = options; // Loại bỏ tất cả khoảng trắng let cleanedStr = input.trim().replace(/\s+/g, ''); // Xử lý các định dạng số khác nhau if (format === 'eu') { // Định dạng châu Âu: 1.234,56 cleanedStr = cleanedStr .replace(/\./g, '') // Xóa dấu phân cách hàng nghìn .replace(/,/g, '.'); // Chuyển dấu phẩy thành dấu chấm thập phân } else if (format === 'custom' && decimalSeparator && thousandSeparator) { // Định dạng tùy chỉnh const escapedThousandSep = thousandSeparator.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); const escapedDecimalSep = decimalSeparator.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // Xóa dấu phân cách hàng nghìn, thay dấu thập phân bằng dấu chấm const regex = new RegExp(escapedThousandSep, 'g'); cleanedStr = cleanedStr .replace(regex, '') .replace(escapedDecimalSep, '.'); } else { // Định dạng mặc định: xóa tất cả trừ số, dấu chấm, dấu cộng và dấu trừ cleanedStr = cleanedStr.replace(/[^\d.+-]/g, ''); } return parseFloat(cleanedStr); } /** * Thêm dấu phân cách ngàn vào số */ function addSeparator(num, size, sep) { return num.replace(new RegExp(`\\B(?=(\\d{${size}})+(?!\\d))`, "g"), sep); } /** * Chuyển đổi số sang dạng compact (1k, 1M, 1B) */ function compactNumber(num, decimals = 1) { const absNum = Math.abs(num); const sign = num < 0 ? '-' : ''; if (absNum >= 1e12) return `${sign}${(absNum / 1e12).toFixed(decimals)}T`; if (absNum >= 1e9) return `${sign}${(absNum / 1e9).toFixed(decimals)}B`; if (absNum >= 1e6) return `${sign}${(absNum / 1e6).toFixed(decimals)}M`; if (absNum >= 1e3) return `${sign}${(absNum / 1e3).toFixed(decimals)}k`; return num.toString(); } /** * Chuyển đổi số thành chữ (tiếng Việt) */ function numberToWords(num) { const digits = [ "không", "một", "hai", "ba", "bốn", "năm", "sáu", "bảy", "tám", "chín", ]; const units = ["", "nghìn", "triệu", "tỷ", "nghìn tỷ", "triệu tỷ"]; // Xử lý số âm if (num < 0) { return `âm ${numberToWords(Math.abs(num))}`; } // Xử lý số 0 if (num === 0) return "không"; // Xử lý số thập phân if (num % 1 !== 0) { const parts = num.toString().split('.'); const integerPart = parseInt(parts[0]); const decimalPart = parts[1]; let result = numberToWords(integerPart); result += " phẩy "; // Đọc từng chữ số sau dấu phẩy for (let i = 0; i < decimalPart.length; i++) { result += `${digits[parseInt(decimalPart[i])]} `; } return result.trim(); } const processSegment = (segment) => { if (segment === 0) return ""; let result = ""; const hundred = Math.floor(segment / 100); const ten = Math.floor((segment % 100) / 10); const unit = segment % 10; if (hundred > 0) { result += `${digits[hundred]} trăm `; } if (ten > 1) { result += `${digits[ten]} mươi `; if (unit === 1) { result += "mốt"; } else if (unit === 5) { result += "lăm"; } else if (unit > 0) { result += digits[unit]; } } else if (ten === 1) { result += "mười "; if (unit === 5) { result += "lăm"; } else if (unit > 0) { result += digits[unit]; } } else if (unit > 0 || segment === 0) { // Trường hợp chỉ có đơn vị hoặc là số 0 if (hundred > 0 || ten > 0) { // Nếu có hàng trăm hoặc chục, thì thêm "lẻ" trước đơn vị result += `lẻ ${digits[unit]}`; } else { result += digits[unit]; } } return result.trim(); }; const parts = []; let temp = Math.floor(num); let unitIndex = 0; while (temp > 0) { const segment = temp % 1000; if (segment > 0) { parts.unshift(`${processSegment(segment)} ${units[unitIndex]}`.trim()); } else if (unitIndex > 0 && unitIndex % 3 === 0) { // Thêm đơn vị lớn (tỷ, nghìn tỷ, ...) kể cả khi segment = 0 parts.unshift(units[unitIndex]); } temp = Math.floor(temp / 1000); unitIndex++; } return parts.join(" ").replace(/\s+/g, " ").trim(); }