import { get, includes, isString, split } from "lodash"; import { isNumber } from "util"; /** * 是否是email * @param {String} str 验证内容 */ export function isEmail(str: string): boolean { return /[\w!#$%&'*+/=?^_`{|}~-]+(?:\.[\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])?/.test( str ); } /** * 是否是整形数字 * @param {String|Number} item 验证内容 */ export function isInteger(item: string | number): boolean { if (isString(item)) { const reg = /^[0-9]*$/g; return reg.test(item); } if (isNumber(item)) { return item % 1 === 0; } return false; } const ipv4Maybe = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/; const ipv6Block = /^[0-9A-F]{1,4}$/i; /** * 是否是合法IP地址 * @param {String} str 验证内容 * @param {String} version 4/6 代表ipv4或者ipv6 不传的话都验证 */ export function isIp(str: string, version: string | number = ""): boolean { if (!isString(str)) return false; if (!version) { return isIp(str, 4) || isIp(str, 6); } else if (version+'' === "4") { if (!ipv4Maybe.test(str)) { return false; } const parts = str.split(".").sort((a, b) => Number(a) - Number(b)); return Number(parts[3]) <= 255; } else if (version+'' === "6") { var addressAndZone = [str]; // ipv6 addresses could have scoped architecture // according to https://tools.ietf.org/html/rfc4007#section-11 if (str.includes("%")) { addressAndZone = str.split("%"); if (addressAndZone.length !== 2) { // it must be just two parts return false; } if (!addressAndZone[0].includes(":")) { // the first part must be the address return false; } if (addressAndZone[1] === "") { // the second part must not be empty return false; } } var blocks = addressAndZone[0].split(":"); var foundOmissionBlock = false; // marker to indicate :: // At least some OS accept the last 32 bits of an IPv6 address // (i.e. 2 of the blocks) in IPv4 notation, and RFC 3493 says // that '::ffff:a.b.c.d' is valid for IPv4-mapped IPv6 addresses, // and '::a.b.c.d' is deprecated, but also valid. var foundIPv4TransitionBlock = isIp(blocks[blocks.length - 1], 4); var expectedNumberOfBlocks = foundIPv4TransitionBlock ? 7 : 8; if (blocks.length > expectedNumberOfBlocks) { return false; } // initial or final :: if (str === "::") { return true; } else if (str.substr(0, 2) === "::") { blocks.shift(); blocks.shift(); foundOmissionBlock = true; } else if (str.substr(str.length - 2) === "::") { blocks.pop(); blocks.pop(); foundOmissionBlock = true; } for (var i = 0; i < blocks.length; ++i) { // test for a :: which can not be at the string start/end // since those cases have been handled above if (blocks[i] === "" && i > 0 && i < blocks.length - 1) { if (foundOmissionBlock) { return false; // multiple :: in address } foundOmissionBlock = true; } else if (foundIPv4TransitionBlock && i === blocks.length - 1) { // it has been checked before that the last // block is a valid IPv4 address } else if (!ipv6Block.test(blocks[i])) { return false; } } if (foundOmissionBlock) { return blocks.length >= 1; } return blocks.length === expectedNumberOfBlocks; } return false; } function ipToNumber(ip: string): number { const parts = split(ip, "."); const number = parts.reduce((total, curNumber, index) => { const power = 3 - index; return total + parseInt(curNumber) * Math.pow(255, power); }, 0); return number; } /** * 是否是IP区间 例如:1.1.1.1-1.1.1.2 * @param item 需要验证的ip */ export function isIpRange(item: string) { if (!includes(item, "-")) return false; const ips = split(item, "-"); if (ips.length !== 2) return false; return ips.every(isIp) && ipToNumber(ips[0]) < ipToNumber(ips[1]); } /** * 是否是网段 例如: 111.16.78.0/24 * @param item 需要验证的ip */ export function isIpSeg(item: string) { const parts = split(item, "/"); const subnetMaybe = /^\d{1,2}$/; if (parts.length !== 2) return false; if (!subnetMaybe.test(parts[1])) { return false; } // Disallow preceding 0 i.e. 01, 02, ... if (parts[1].length > 1 && parts[1].startsWith("0")) { return false; } return isIp(parts[0]) && Number(parts[1]) <= 32 && Number(parts[1]) >= 0; } /** * 是否每个内容都是合法IP,支持数组和逗号分隔的字符串 * 支持ipv4,ipv6,网段,IP区间 * @param ips Ip数组或逗号分隔的字符串 */ export function isIps(ips: string[] | string) { const resultIps = isString(ips) ? split(ips, "\n") : ips; return resultIps.every( (item) => isIp(item) || isIpRange(item) || isIpSeg(item) ); } function isInner(ip: number, begin: number, end: number): boolean { return ip >= begin && ip <= end; } /** * 是否是内网IP * A类 10.0.0.0-10.255.255.255 * B类 172.16.0.0-172.31.255.255 * C类 192.168.0.0-192.168.255.255 * D类 127.0.0.0-127.255.255.255(环回地址) * @param ip 需要检测的IP地址 */ export default function isInnerIP(ip: string) { const ipNum = ipToNumber(ip); var aBegin = ipToNumber("10.0.0.0"); var aEnd = ipToNumber("10.255.255.255"); var bBegin = ipToNumber("172.16.0.0"); var bEnd = ipToNumber("172.31.255.255"); var cBegin = ipToNumber("192.168.0.0"); var cEnd = ipToNumber("192.168.255.255"); var dBegin = ipToNumber("127.0.0.0"); var dEnd = ipToNumber("127.255.255.255"); return ( isInner(ipNum, aBegin, aEnd) || isInner(ipNum, bBegin, bEnd) || isInner(ipNum, cBegin, cEnd) || isInner(ipNum, dBegin, dEnd) ); } /** * 是否是URL * @param item */ export function isUrl(item: string) { const pattern = new RegExp( "^(https?:\\/\\/)?" + // protocol "((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.?)+[a-z]{2,}|" + // domain name "((\\d{1,3}\\.){3}\\d{1,3}))" + // OR ip (v4) address "(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*" + // port and path "(\\?[;&a-z\\d%_.~+=-]*)?" + // query string "(\\#[-a-z\\d_]*)?$", "i" ); // fragment locator return pattern.test(item); } // isIpMask // isDomain /** * 是否是合法端口 * @param port */ export function isPort(port: string | number) { if (!port) return false; return port >= 1 && port <= 65535; } // isJSON /** * 长度符合要求 * @example isLength(4)('test') * @param length 长度 */ export function isLength(length: number) { return (item: any) => { return get(item, "length") === length; }; } /** * 是否大于某个数字 * @example isGreaterThan(4)(5) * @param num 对比的数字 * @param include 是否包含等于 */ export function isGreaterThan(num: number, include = false) { return (value: number) => { return include ? value >= num : value > num; }; } /** * 是否小于某个数字 * @example isLessThan(4)(5) * @param num 对比的数字 * @param include 是否包含等于 */ export function isLessThan(num: number, inlcude = false) { return (value: number) => { return inlcude ? value <= num : value < num; }; } /** * 是否在数字区间内 * @param min 最小值 * @param max 最大值 * @param include 是否包含等于边界 */ export function isBetween(min: number, max: number, include = false) { return (value: number) => { return ( isGreaterThan(min, include)(value) && isLessThan(max, include)(value) ); }; } // isMACAddress /** * 是否是电话号码 * @param str */ export function isMobilePhone(str: string) { const reg = /^(0|86|17951)?(13[0-9]|15[012356789]|18[0-9]|14[57]|17[678])[0-9]{8}$/; return reg.test(str); } /** * 是否是中文 * @param str */ export function isChinese(str: string) { return new RegExp("[\\u4E00-\\u9FFF]", "g").test(str); } /** * 是否是通用字符串 * 正则[a-zA-Z0-9@#$%^&+=_.] * @param str */ export function isUsualString(str: string) { const reg = /^[a-zA-Z0-9@#$%^&+=_.]*$/; const strMatch = reg.test(str); return strMatch || isChinese(str); } // isReg /** * 是否是Hash * @param str */ export function isHash(str: string) { const reg = /^[a-fA-F0-9]{64}$/; return reg.test(str); } /** * 为空时,返回true * @example const testIp = canEmpty(isIp) * @param fn */ export function canEmpty(fn: Function) { return (value: any) => { return value === "" || value === undefined ? true : fn(value); }; }