前端开发中常用的一些正则校验及工具函数, 你get了吗
前言
在平时的开发中, 如果遇到的一些类似于表单的提交或者数值的提交, 我们根据业务需求以及业界的一些规范常识, 我们往往需要对提交的数据进行规则的校验(为了双重保险, 其实前后端都需要校验), 前端作为用户的直接展示端, 正则校验成为重中之重。同时, 我们处理一些功能的时候, 也希望有一些封装好的工具函数供给我们使用。
一、业务中常用到的一些正则校验 (持续更新~)
1. 手机号码或座机号码
/**
* 手机号码或座机号码校验
* @param {string} phone 手机号码或座机号码
* @param {0 | 1 | '' | 不传} type 校验类型(0-手机号码, 1-座机号码, 默认则满足手机号码或座机两者任何之一)
*/
function handlePhoneReg(phone, type = "") {
let phoneReg = "";
if (type === 0) {
phoneReg = /(^0{0,1}1[3|4|5|6|7|8|9][0-9]{9}$)/;
} else if (type === 1) {
phoneReg = /(^(([0\+]\d{2,3}-)?(0\d{2,3})-)(\d{7,8})(-(\d{3,}))?$)/;
} else {
phoneReg =
/(^(([0\+]\d{2,3}-)?(0\d{2,3})-)(\d{7,8})(-(\d{3,}))?$)|(^0{0,1}1[3|4|5|6|7|8|9][0-9]{9}$)/;
}
return phoneReg.test(phone);
}
handlePhoneReg('13026703942', 0) // true
handlePhoneReg('021-56668885', 1) // true
handlePhoneReg('021-56668885', 0) // false
handlePhoneReg('021-56668885') // true
2. 电子邮箱
/**
* 电子邮箱校验
* @param {string} email 电子邮箱号码
*/
function handleEmailReg(email) {
const emailReg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return emailReg.test(email);
}
handleEmailReg('2206162221@qq.com') // true
handleEmailReg('2206162221,qq.com') // false
handleEmailReg('2206162221@qq') // false
3. 网站
/**
* 网站
* @param {string} url 网站地址
*/
function handleWebsiteReg(url) {
const websiteReg =
/^(https?|http|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/;
return websiteReg.test(url);
}
handleWebsiteReg('https://www.baidu.com/') // true
handleWebsiteReg('www.baidu.com') // false
4. 判断是否是数字
/**
* 判断是否是数字
* @param {any} value 验证的值
*/
function handleNumberRegular(value) {
return /^\d+(\.\d+)?$/.test(value)
};
handleNumberRegular(123) // true
handleNumberRegular(123) // true
handleNumberRegular('123.11') // true
handleNumberRegular('test') // false
handleNumberRegular([1,2,3]) // false
二、业务中常用到的一些工具函数 (持续更新~)
1. 随机生成多位数字符串
/**
* 随机生成多位数字符串
* @param {number} length 生成字符串的长度
*/
function generateRandomString(length) {
let result = "";
const characters =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * characters.length));
}
return result;
}
generateRandomString(10) // 'GIVCxPv0Lo'
generateRandomString(15) // 'j8LQoksemIFcAJk'
generateRandomString(18) // 'sepQJ3jxcMozKr84x4'
2. 时间戳转为年月日时分秒
/**
* 时间戳转为年月日时分秒
* @param {number} timestamp 时间戳的值
*/
function formatTimestamp(timestamp) {
const date = new Date(timestamp);
const year = date.getFullYear();
const month = ("0" + (date.getMonth() + 1)).slice(-2);
const day = ("0" + date.getDate()).slice(-2);
const hours = ("0" + date.getHours()).slice(-2);
const minutes = ("0" + date.getMinutes()).slice(-2);
const seconds = ("0" + date.getSeconds()).slice(-2);
const formattedDate =
year +
"-" +
month +
"-" +
day +
" " +
hours +
":" +
minutes +
":" +
seconds;
return formattedDate;
}
formatTimestamp(new Date().getTime()) // '2024-06-03 14:36:16'
formatTimestamp(1717396666854) // '2024-06-03 14:37:46'
3. 判断时间戳距离当前时间过去多久
function handleFormatTimeAgo(time) {
const now = new Date().getTime();
const timeDiff = now - time;
const minute = 60 * 1000; // 1 minute in ms
const hour = 60 * minute; // 1 hour in ms
const day = 24 * hour; // 1 day in ms
const week = 7 * day; // 1 week in ms
const month = 30 * day; // 1 month in ms
const year = 365 * day; // 1 year in ms
if (timeDiff < minute) {
return "几秒前";
} else if (timeDiff < hour) {
return Math.round(timeDiff / minute) + "分钟前";
} else if (timeDiff < day) {
return Math.round(timeDiff / hour) + "小时前";
} else if (timeDiff < week) {
return Math.round(timeDiff / day) + "天前";
} else if (timeDiff < month) {
return Math.round(timeDiff / week) + "周前";
} else if (timeDiff < year) {
return Math.round(timeDiff / month) + "月前";
} else {
return Math.round(timeDiff / year) + "年前";
}
};
handleFormatTimeAgo(1717396666854) // '6分钟前'
4. 判断字符串化的数值是否超过多少位小数点
/**
* 判断字符串化的数值是否超过多少位小数点
* @param {number | string} value 数值
* @param {number} num 超过的位数
*/
function handleDecimalPointCounter(value, num = 2) {
const stringValue = String(value);
if (!stringValue.includes(".")) {
return false;
}
const parts = stringValue.split(".");
// 检查小数点后是否有超过多少位
return parts.length > 1 && parts[1].length > num;
}
handleDecimalPointCounter(0.234, 1) // true
handleDecimalPointCounter(0.234, 2) // true
handleDecimalPointCounter(0.234, 3) // false
5. 处理两数相加、相减、相乘、相除可能导致的精度丢失问题
5.1 简单的 toFixed 处理
Number((0.1 + 0.2).toFixed(2)) // 0.3
Number((100 / 6).toFixed(2)) // 16.67
Number((12 * 0.14).toFixed(2)) // 1.68
Number((0.3 - 0.2).toFixed(2)) // 0.1
5.2 封装自定义方法处理, 思路是尽量将两数调整到整数再处理, 扩大多少倍数处理完结果后再减少多少倍
/**
*
* @param {number} num1 第一个数
* @param {number} num2 第二个数
* @param {1 | 2 | 3 | 4 | 不传} type 计算的类型(1-相加, 2-相减, 3-相乘, 4-相除, 不传则默认值为1)
*/
function handleComputePrecision(num1, num2, type = 1) {
if (type === 1) {
let baseNum, baseNum1, baseNum2;
try {
baseNum1 = num1.toString().split(".")[1].length;
} catch (e) {
baseNum1 = 0;
}
try {
baseNum2 = num2.toString().split(".")[1].length;
} catch (e) {
baseNum2 = 0;
}
baseNum = Math.pow(10, Math.max(baseNum1, baseNum2));
return Math.round(num1 * baseNum + num2 * baseNum) / baseNum;
} else if (type === 2) {
let r1, r2, m, n, result;
try {
r1 = num1.toString().split(".")[1].length;
} catch (e) {
r1 = 0;
}
try {
r2 = num2.toString().split(".")[1].length;
} catch (e) {
r2 = 0;
}
m = Math.pow(10, Math.max(r1, r2));
n = r1 >= r2 ? r1 : r2;
result = (Math.round(num1 * m - num2 * m) / m).toFixed(n);
return Number(result);
} else if (type === 3) {
let m, s1, s2;
m = 0;
s1 = num1.toString();
s2 = num2.toString();
try {
m += s1.split(".")[1].length;
} catch (e) {}
try {
m += s2.split(".")[1].length;
} catch (e) {}
return (
(Number(s1.replace(".", "")) * Number(s2.replace(".", ""))) /
Math.pow(10, m)
);
} else if (type === 4) {
let t1, t2, r1, r2;
try {
t1 = num1.toString().split(".")[1].length;
} catch (e) {
t1 = 0;
}
try {
t2 = num2.toString().split(".")[1].length;
} catch (e) {
t2 = 0;
}
r1 = Number(num1.toString().replace(".", ""));
r2 = Number(num2.toString().replace(".", ""));
return (r1 / r2) * Math.pow(10, t2 - t1);
}
}
handleComputePrecision(0.1, 0.2, 1) // 0.3
handleComputePrecision(0.3, 0.2, 2) // 0.1
handleComputePrecision(0.1, 0.2, 3) // 0.02
handleComputePrecision(0.3, 0.1, 4) // 3
6. 格式化银行卡号码每四位一组, 以空格符隔开; 除最后四个字母, 其余用 * 号处理
/**
* 格式化银行卡号码每四位一组, 以空格符隔开; 除最后四个字母, 其余用 * 号处理
* @param {string} cardNumber 银行卡号码
*/
function formatBankCardNumber(cardNumber) {
// 检查卡号是否有效(这里假设有效的卡号长度为16位或19位)
if (!/^\d{16}|\d{19}$/.test(cardNumber)) {
return "无效的银行卡号";
}
let maskedNumber = cardNumber;
// 用星号替换除了最后四位之外的所有数字
maskedNumber =
cardNumber.slice(0, -4).replace(/\d/g, "*") + cardNumber.slice(-4);
// 每隔四位插入空格
const maskedAndSpacedNumber = maskedNumber.replace(/(.{4})/g, "$& ");
// 移除最后一个多余的空格
const finalMaskedNumber = maskedAndSpacedNumber.trim();
return finalMaskedNumber;
}
formatBankCardNumber('1234567897894561') // '**** **** **** 4561'
formatBankCardNumber('1234567897894561123') // '**** **** **** ***1 123'
formatBankCardNumber('123456789789') // '无效的银行卡号'
7. js实现超简单sku组合算法(不同属性的排列组合), 此算法类似笛卡尔积;
/**
* js实现超简单sku组合算法(不同属性的排列组合), 此算法类似笛卡尔积;
* @param {*} list 二维数组
*/
function skuPermutation(list) {
function cartesianProductOf() {
return Array.prototype.reduce.call(
arguments,
function (a, b) {
var ret = [];
a.forEach(function (a) {
b.forEach(function (b) {
ret.push(a.concat([b]));
});
});
return ret;
},
[[]]
);
}
const allArrList = cartesianProductOf(...list);
return allArrList
}
const list = [
[1, 2],
[3, 4],
[5, 6],
];
skuPermutation(list)
// 得到如下结果