前端开发中常用的一些正则校验及工具函数, 你get了吗

210 阅读5分钟

前端开发中常用的一些正则校验及工具函数, 你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)
// 得到如下结果

sku.png