validatorUtil.js 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143
  1. /* eslint-disable */
  2. let validatorUtil = { version: '4.5.2' };
  3. let emailUserPart = /^[a-z\d!#\$%&'\*\+\-\/=\?\^_`{\|}~]+$/i;
  4. let quotedEmailUser = /^([\s\x01-\x08\x0b\x0c\x0e-\x1f\x7f\x21\x23-\x5b\x5d-\x7e]|(\\[\x01-\x09\x0b\x0c\x0d-\x7f]))*$/i;
  5. let emailUserUtf8Part = /^[a-z\d!#\$%&'\*\+\-\/=\?\^_`{\|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+$/i;
  6. let quotedEmailUserUtf8 = /^([\s\x01-\x08\x0b\x0c\x0e-\x1f\x7f\x21\x23-\x5b\x5d-\x7e\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|(\\[\x01-\x09\x0b\x0c\x0d-\x7f\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))*$/i;
  7. let displayName = /^[a-z\d!#\$%&'\*\+\-\/=\?\^_`{\|}~\.\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+[a-z\d!#\$%&'\*\+\-\/=\?\^_`{\|}~\.\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\s]*<(.+)>$/i;
  8. let creditCard = /^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$/;
  9. let isin = /^[A-Z]{2}[0-9A-Z]{9}[0-9]$/;
  10. let isbn10Maybe = /^(?:[0-9]{9}X|[0-9]{10})$/
  11. , isbn13Maybe = /^(?:[0-9]{13})$/;
  12. let macAddress = /^([0-9a-fA-F][0-9a-fA-F]:){5}([0-9a-fA-F][0-9a-fA-F])$/;
  13. let ipv4Maybe = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/
  14. , ipv6Block = /^[0-9A-F]{1,4}$/i;
  15. let uuid = {
  16. '3': /^[0-9A-F]{8}-[0-9A-F]{4}-3[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i
  17. , '4': /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
  18. , '5': /^[0-9A-F]{8}-[0-9A-F]{4}-5[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
  19. , all: /^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i
  20. };
  21. let alpha = /^[A-Z]+$/i
  22. , alphanumeric = /^[0-9A-Z]+$/i
  23. , numeric = /^[-+]?[0-9]+$/
  24. , int = /^(?:[-+]?(?:0|[1-9][0-9]*))$/
  25. , float = /^(?:[-+]?(?:[0-9]+))?(?:\.[0-9]*)?(?:[eE][\+\-]?(?:[0-9]+))?$/
  26. , hexadecimal = /^[0-9A-F]+$/i
  27. , decimal = /^[-+]?([0-9]+|\.[0-9]+|[0-9]+\.[0-9]+)$/
  28. , hexcolor = /^#?([0-9A-F]{3}|[0-9A-F]{6})$/i
  29. , id = /^[0-9]+$/; //纯数字没有加减号,想不到更好的名字了
  30. let ascii = /^[\x00-\x7F]+$/
  31. , multibyte = /[^\x00-\x7F]/
  32. , fullWidth = /[^\u0020-\u007E\uFF61-\uFF9F\uFFA0-\uFFDC\uFFE8-\uFFEE0-9a-zA-Z]/
  33. , halfWidth = /[\u0020-\u007E\uFF61-\uFF9F\uFFA0-\uFFDC\uFFE8-\uFFEE0-9a-zA-Z]/;
  34. let surrogatePair = /[\uD800-\uDBFF][\uDC00-\uDFFF]/;
  35. let base64 = /^(?:[A-Z0-9+\/]{4})*(?:[A-Z0-9+\/]{2}==|[A-Z0-9+\/]{3}=|[A-Z0-9+\/]{4})$/i;
  36. let phones = {
  37. 'zh-CN': /^(\+?0?86\-?)?((13\d|14[57]|15[^4,\D]|17[678]|18\d)\d{8}|170[0589]\d{7})$/,
  38. 'zh-TW': /^(\+?886\-?|0)?9\d{8}$/,
  39. 'en-ZA': /^(\+?27|0)\d{9}$/,
  40. 'en-AU': /^(\+?61|0)4\d{8}$/,
  41. 'en-HK': /^(\+?852\-?)?[569]\d{3}\-?\d{4}$/,
  42. 'fr-FR': /^(\+?33|0)[67]\d{8}$/,
  43. 'pt-PT': /^(\+351)?9[1236]\d{7}$/,
  44. 'el-GR': /^(\+?30)?(69\d{8})$/,
  45. 'en-GB': /^(\+?44|0)7\d{9}$/,
  46. 'en-US': /^(\+?1)?[2-9]\d{2}[2-9](?!11)\d{6}$/,
  47. 'en-ZM': /^(\+26)?09[567]\d{7}$/,
  48. 'ru-RU': /^(\+?7|8)?9\d{9}$/,
  49. 'nb-NO': /^(\+?47)?[49]\d{7}$/,
  50. 'nn-NO': /^(\+?47)?[49]\d{7}$/,
  51. 'vi-VN': /^(0|\+?84)?((1(2([0-9])|6([2-9])|88|99))|(9((?!5)[0-9])))([0-9]{7})$/,
  52. 'en-NZ': /^(\+?64|0)2\d{7,9}$/,
  53. 'en-IN': /^(\+?91|0)?[789]\d{9}$/
  54. };
  55. // from http://goo.gl/0ejHHW
  56. let iso8601 = /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/;
  57. function merge(obj, defaults) {
  58. obj = obj || {};
  59. for (let key in defaults) {
  60. if (typeof obj[key] === 'undefined') {
  61. obj[key] = defaults[key];
  62. }
  63. }
  64. return obj;
  65. }
  66. function currencyRegex(options) {
  67. let symbol = '(\\' + options.symbol.replace(/\./g, '\\.') + ')' + (options.require_symbol ? '' : '?')
  68. , negative = '-?'
  69. , whole_dollar_amount_without_sep = '[1-9]\\d*'
  70. , whole_dollar_amount_with_sep = '[1-9]\\d{0,2}(\\' + options.thousands_separator + '\\d{3})*'
  71. , valid_whole_dollar_amounts = ['0', whole_dollar_amount_without_sep, whole_dollar_amount_with_sep]
  72. , whole_dollar_amount = '(' + valid_whole_dollar_amounts.join('|') + ')?'
  73. , decimal_amount = '(\\' + options.decimal_separator + '\\d{2})?';
  74. let pattern = whole_dollar_amount + decimal_amount;
  75. // default is negative sign before symbol, but there are two other options (besides parens)
  76. if (options.allow_negatives && !options.parens_for_negatives) {
  77. if (options.negative_sign_after_digits) {
  78. pattern += negative;
  79. }
  80. else if (options.negative_sign_before_digits) {
  81. pattern = negative + pattern;
  82. }
  83. }
  84. // South African Rand, for example, uses R 123 (space) and R-123 (no space)
  85. if (options.allow_negative_sign_placeholder) {
  86. pattern = '( (?!\\-))?' + pattern;
  87. }
  88. else if (options.allow_space_after_symbol) {
  89. pattern = ' ?' + pattern;
  90. }
  91. else if (options.allow_space_after_digits) {
  92. pattern += '( (?!$))?';
  93. }
  94. if (options.symbol_after_digits) {
  95. pattern += symbol;
  96. } else {
  97. pattern = symbol + pattern;
  98. }
  99. if (options.allow_negatives) {
  100. if (options.parens_for_negatives) {
  101. pattern = '(\\(' + pattern + '\\)|' + pattern + ')';
  102. }
  103. else if (!(options.negative_sign_before_digits || options.negative_sign_after_digits)) {
  104. pattern = negative + pattern;
  105. }
  106. }
  107. return new RegExp(
  108. '^' +
  109. // ensure there's a dollar and/or decimal amount, and that it doesn't start with a space or a negative sign followed by a space
  110. '(?!-? )(?=.*\\d)' +
  111. pattern +
  112. '$'
  113. );
  114. }
  115. /* --------- 自定义添加的规则 ---------- */
  116. let num_decimal2 = /^\+?(\d*(\.\d{1,2})?)$/;
  117. /**
  118. * 数字 并且 最多两位小数, 并且大于min 小于等于max
  119. *
  120. * @public
  121. * @method module:pool/component-validation/src/util/validatorUtil.Validator#isSoftDecimal2
  122. * @param {Number} num 传入的数值
  123. * @param {Number} [min=0] 数值区间的最小值,默认为0
  124. * @param {Number} max 数值区间的最大值
  125. * @return {Boolean}
  126. */
  127. validatorUtil.isSoftDecimal2 = function (num, min, max) {
  128. min = min | 0;
  129. return num_decimal2.test(num) && (parseFloat(num) > min) && (max ? parseFloat(num) <= max: true);
  130. };
  131. validatorUtil.extend = function (name, fn) {
  132. validatorUtil[name] = function () {
  133. let args = Array.prototype.slice.call(arguments);
  134. args[0] = validatorUtil.toString(args[0]);
  135. return fn.apply(validatorUtil, args);
  136. };
  137. };
  138. //Right before exporting the validatorUtil object, pass each of the builtins
  139. //through extend() so that their first argument is coerced to a string
  140. validatorUtil.init = function () {
  141. for (let name in validatorUtil) {
  142. if (typeof validatorUtil[name] !== 'function' || name === 'toString' ||
  143. name === 'toDate' || name === 'extend' || name === 'init') {
  144. continue;
  145. }
  146. validatorUtil.extend(name, validatorUtil[name]);
  147. }
  148. };
  149. /**
  150. * 转换成字符串
  151. *
  152. * @public
  153. * @method module:pool/component-validation/src/util/validatorUtil.Validator#toString
  154. * @param {String} input 传入的数值
  155. * @return {String}
  156. */
  157. validatorUtil.toString = function (input) {
  158. if (typeof input === 'object' && input !== null && input.toString) {
  159. input = input.toString();
  160. } else if (input === null || typeof input === 'undefined' || (isNaN(input) && !input.length)) {
  161. input = '';
  162. }
  163. return '' + input;
  164. };
  165. /**
  166. * 转换成时间
  167. *
  168. * @public
  169. * @method module:pool/component-validation/src/util/validatorUtil.Validator#toDate
  170. * @param {String} date 传入的数值
  171. * @return {Date}
  172. */
  173. validatorUtil.toDate = function (date) {
  174. if (Object.prototype.toString.call(date) === '[object Date]') {
  175. return date;
  176. }
  177. date = Date.parse(date);
  178. return !isNaN(date) ? new Date(date) : null;
  179. };
  180. /**
  181. * 转换成Float数值
  182. *
  183. * @public
  184. * @method module:pool/component-validation/src/util/validatorUtil.Validator#toFloat
  185. * @param {String} str 传入的值
  186. * @return {Boolean}
  187. */
  188. validatorUtil.toFloat = function (str) {
  189. return parseFloat(str);
  190. };
  191. /**
  192. * 校验输入的字是否在控制的区间之内
  193. *
  194. * @public
  195. * @method module:pool/component-validation/src/util/validatorUtil.Validator#inputTips
  196. * @param {String} str 传入的值
  197. * @param {String} [min=0] 最小值
  198. * @param {String} max 最大值
  199. * @param {String} [afterText='个字'] 后缀显示的单位
  200. * @return {{success: Boolean, message: String}}
  201. */
  202. validatorUtil.inputTips = function(str, min, max, isRealTime, afterText){
  203. min = min || 0;
  204. //结尾文字
  205. afterText = afterText || '个字';
  206. let len = Math.ceil(validatorUtil.getStrLength(str.trim())/2),
  207. defaultStatus = {
  208. message: '',
  209. success: true
  210. };
  211. if(len < min){
  212. return {
  213. message: "至少输入" + (min) + afterText,
  214. success: false
  215. }
  216. }else if(len > max) { //_max undefined 则不进入
  217. return {
  218. message: "超出" + (len - max) + afterText,
  219. success: false
  220. }
  221. }else if(isRealTime && max){ //如果要实时输出还可以输入几个字
  222. return {
  223. message: "还可以输入" + (max - len) + afterText,
  224. success: true
  225. }
  226. }
  227. return defaultStatus;
  228. };
  229. /**
  230. * 转换数值为Int
  231. *
  232. * @public
  233. * @method module:pool/component-validation/src/util/validatorUtil.Validator#toInt
  234. * @param {String} num 传入的数值
  235. * @param {number} [radix=10] 进制
  236. * @return {number}
  237. */
  238. validatorUtil.toInt = function (num, radix) {
  239. return parseInt(num, radix || 10);
  240. };
  241. /**
  242. * 转换数值为bool值
  243. *
  244. * @public
  245. * @method module:pool/component-validation/src/util/validatorUtil.Validator#toBoolean
  246. * @param {String} str 传入的数值
  247. * @param {Boolean} [strict=10] 是否强制模式,强制模式下返回只判断str==='1'||str==='true'
  248. * @return {Boolean}
  249. */
  250. validatorUtil.toBoolean = function (str, strict) {
  251. if (strict) {
  252. return str === '1' || str === 'true';
  253. }
  254. return str !== '0' && str !== 'false' && str !== '';
  255. };
  256. /**
  257. * 对比comparison转换为字符串后的内容是否和str一致
  258. *
  259. * @public
  260. * @method module:pool/component-validation/src/util/validatorUtil.Validator#equals
  261. * @param {String} str 传入的数值
  262. * @param {String} comparison 比对的内容
  263. * @return {Boolean}
  264. */
  265. validatorUtil.equals = function (str, comparison) {
  266. return str === validatorUtil.toString(comparison);
  267. };
  268. /**
  269. * 判断str是否包含elem
  270. *
  271. * @public
  272. * @method module:pool/component-validation/src/util/validatorUtil.Validator#contains
  273. * @param {String} str
  274. * @param {String} elem
  275. * @return {Boolean}
  276. */
  277. validatorUtil.contains = function (str, elem) {
  278. return str.indexOf(validatorUtil.toString(elem)) >= 0;
  279. };
  280. /**
  281. * 正则判断
  282. *
  283. * @public
  284. * @method module:pool/component-validation/src/util/validatorUtil.Validator#matches
  285. * @param {String} str 输入的内容
  286. * @param {String} pattern 正则表达式
  287. * @param {String} modifiers 正则表达式的参数
  288. * @return {Boolean}
  289. */
  290. validatorUtil.matches = function (str, pattern, modifiers) {
  291. if (Object.prototype.toString.call(pattern) !== '[object RegExp]') {
  292. pattern = new RegExp(pattern, modifiers);
  293. }
  294. return pattern.test(str);
  295. };
  296. let default_email_options = {
  297. allow_display_name: false,
  298. allow_utf8_local_part: true,
  299. require_tld: true
  300. };
  301. /**
  302. * 判断是否是邮件格式
  303. *
  304. * @public
  305. * @method module:pool/component-validation/src/util/validatorUtil.Validator#isEmail
  306. * @param {String} str 输入的内容
  307. * @param {String} options
  308. * @param {String} [options.allow_display_name=false] If allow_display_name is set to true, the validatorUtil will also match Display Name <email-address>
  309. * @param {String} [options.allow_utf8_local_part=true] f allow_utf8_local_part is set to false, the validatorUtil will not allow any non-English UTF8 character in email address' local part.
  310. * @param {String} [options.require_tld=true] If require_tld is set to false, e-mail addresses without having TLD in their domain will also be matched.
  311. * @return {Boolean}
  312. */
  313. validatorUtil.isEmail = function (str, options) {
  314. options = merge(options, default_email_options);
  315. if (options.allow_display_name) {
  316. let display_email = str.match(displayName);
  317. if (display_email) {
  318. str = display_email[1];
  319. }
  320. }
  321. let parts = str.split('@')
  322. , domain = parts.pop()
  323. , user = parts.join('@');
  324. let lower_domain = domain.toLowerCase();
  325. if (lower_domain === 'gmail.com' || lower_domain === 'googlemail.com') {
  326. user = user.replace(/\./g, '').toLowerCase();
  327. }
  328. if (!validatorUtil.isByteLength(user, {max: 64}) ||
  329. !validatorUtil.isByteLength(domain, {max: 256})) {
  330. return false;
  331. }
  332. if (!validatorUtil.isFQDN(domain, {require_tld: options.require_tld})) {
  333. return false;
  334. }
  335. if (user[0] === '"') {
  336. user = user.slice(1, user.length - 1);
  337. return options.allow_utf8_local_part ?
  338. quotedEmailUserUtf8.test(user) :
  339. quotedEmailUser.test(user);
  340. }
  341. let pattern = options.allow_utf8_local_part ?
  342. emailUserUtf8Part : emailUserPart;
  343. let user_parts = user.split('.');
  344. for (let i = 0; i < user_parts.length; i++) {
  345. if (!pattern.test(user_parts[i])) {
  346. return false;
  347. }
  348. }
  349. return true;
  350. };
  351. let default_url_options = {
  352. protocols: [ 'http', 'https', 'ftp' ]
  353. , require_tld: true
  354. , require_protocol: false
  355. , require_valid_protocol: true
  356. , allow_underscores: false
  357. , allow_trailing_dot: false
  358. , allow_protocol_relative_urls: false
  359. };
  360. /**
  361. * 判断是否是url
  362. *
  363. * @public
  364. * @method module:pool/component-validation/src/util/validatorUtil.Validator#isURL
  365. * @param {String} url 输入的内容
  366. * @param {String} options
  367. * @return {Boolean}
  368. */
  369. validatorUtil.isURL = function (url, options) {
  370. if (!url || url.length >= 2083 || /\s/.test(url)) {
  371. return false;
  372. }
  373. if (url.indexOf('mailto:') === 0) {
  374. return false;
  375. }
  376. options = merge(options, default_url_options);
  377. let protocol, auth, host, hostname, port,
  378. port_str, split;
  379. split = url.split('://');
  380. if (split.length > 1) {
  381. protocol = split.shift();
  382. if (options.require_valid_protocol && options.protocols.indexOf(protocol) === -1) {
  383. return false;
  384. }
  385. } else if (options.require_protocol) {
  386. return false;
  387. } else if (options.allow_protocol_relative_urls && url.substr(0, 2) === '//') {
  388. split[0] = url.substr(2);
  389. }
  390. url = split.join('://');
  391. split = url.split('#');
  392. url = split.shift();
  393. split = url.split('?');
  394. url = split.shift();
  395. split = url.split('/');
  396. url = split.shift();
  397. split = url.split('@');
  398. if (split.length > 1) {
  399. auth = split.shift();
  400. if (auth.indexOf(':') >= 0 && auth.split(':').length > 2) {
  401. return false;
  402. }
  403. }
  404. hostname = split.join('@');
  405. split = hostname.split(':');
  406. host = split.shift();
  407. if (split.length) {
  408. port_str = split.join(':');
  409. port = parseInt(port_str, 10);
  410. if (!/^[0-9]+$/.test(port_str) || port <= 0 || port > 65535) {
  411. return false;
  412. }
  413. }
  414. if (!validatorUtil.isIP(host) && !validatorUtil.isFQDN(host, options) &&
  415. host !== 'localhost') {
  416. return false;
  417. }
  418. if (options.host_whitelist &&
  419. options.host_whitelist.indexOf(host) === -1) {
  420. return false;
  421. }
  422. if (options.host_blacklist &&
  423. options.host_blacklist.indexOf(host) !== -1) {
  424. return false;
  425. }
  426. return true;
  427. };
  428. /**
  429. * 判断是否是MACAddress
  430. *
  431. * @public
  432. * @method module:pool/component-validation/src/util/validatorUtil.Validator#isMACAddress
  433. * @param {String} str 输入的内容
  434. * @return {Boolean}
  435. */
  436. validatorUtil.isMACAddress = function (str) {
  437. return macAddress.test(str);
  438. };
  439. /**
  440. * 判断是否是isIP
  441. *
  442. * @public
  443. * @method module:pool/component-validation/src/util/validatorUtil.Validator#isIP
  444. * @param {String} str 输入的内容
  445. * @param {String} version ipv版本 4或者6
  446. * @return {Boolean}
  447. */
  448. validatorUtil.isIP = function (str, version) {
  449. version = validatorUtil.toString(version);
  450. if (!version) {
  451. return validatorUtil.isIP(str, 4) || validatorUtil.isIP(str, 6);
  452. } else if (version === '4') {
  453. if (!ipv4Maybe.test(str)) {
  454. return false;
  455. }
  456. let parts = str.split('.').sort(function (a, b) {
  457. return a - b;
  458. });
  459. return parts[3] <= 255;
  460. } else if (version === '6') {
  461. let blocks = str.split(':');
  462. let foundOmissionBlock = false; // marker to indicate ::
  463. // At least some OS accept the last 32 bits of an IPv6 address
  464. // (i.e. 2 of the blocks) in IPv4 notation, and RFC 3493 says
  465. // that '::ffff:a.b.c.d' is valid for IPv4-mapped IPv6 addresses,
  466. // and '::a.b.c.d' is deprecated, but also valid.
  467. let foundIPv4TransitionBlock = validatorUtil.isIP(blocks[blocks.length - 1], 4);
  468. let expectedNumberOfBlocks = foundIPv4TransitionBlock ? 7 : 8;
  469. if (blocks.length > expectedNumberOfBlocks)
  470. return false;
  471. // initial or final ::
  472. if (str === '::') {
  473. return true;
  474. } else if (str.substr(0, 2) === '::') {
  475. blocks.shift();
  476. blocks.shift();
  477. foundOmissionBlock = true;
  478. } else if (str.substr(str.length - 2) === '::') {
  479. blocks.pop();
  480. blocks.pop();
  481. foundOmissionBlock = true;
  482. }
  483. for (let i = 0; i < blocks.length; ++i) {
  484. // test for a :: which can not be at the string start/end
  485. // since those cases have been handled above
  486. if (blocks[i] === '' && i > 0 && i < blocks.length -1) {
  487. if (foundOmissionBlock)
  488. return false; // multiple :: in address
  489. foundOmissionBlock = true;
  490. } else if (foundIPv4TransitionBlock && i == blocks.length - 1) {
  491. // it has been checked before that the last
  492. // block is a valid IPv4 address
  493. } else if (!ipv6Block.test(blocks[i])) {
  494. return false;
  495. }
  496. }
  497. if (foundOmissionBlock) {
  498. return blocks.length >= 1;
  499. } else {
  500. return blocks.length === expectedNumberOfBlocks;
  501. }
  502. }
  503. return false;
  504. };
  505. let default_fqdn_options = {
  506. require_tld: true
  507. , allow_underscores: false
  508. , allow_trailing_dot: false
  509. };
  510. /**
  511. * 判断是否是FQDN
  512. *
  513. * @public
  514. * @method module:pool/component-validation/src/util/validatorUtil.Validator#isFQDN
  515. * @param {String} str 输入的内容
  516. * @return {Boolean}
  517. */
  518. validatorUtil.isFQDN = function (str, options) {
  519. options = merge(options, default_fqdn_options);
  520. /* Remove the optional trailing dot before checking validity */
  521. if (options.allow_trailing_dot && str[str.length - 1] === '.') {
  522. str = str.substring(0, str.length - 1);
  523. }
  524. let parts = str.split('.');
  525. if (options.require_tld) {
  526. let tld = parts.pop();
  527. if (!parts.length || !/^([a-z\u00a1-\uffff]{2,}|xn[a-z0-9-]{2,})$/i.test(tld)) {
  528. return false;
  529. }
  530. }
  531. for (let part, i = 0; i < parts.length; i++) {
  532. part = parts[i];
  533. if (options.allow_underscores) {
  534. if (part.indexOf('__') >= 0) {
  535. return false;
  536. }
  537. part = part.replace(/_/g, '');
  538. }
  539. if (!/^[a-z\u00a1-\uffff0-9-]+$/i.test(part)) {
  540. return false;
  541. }
  542. if (/[\uff01-\uff5e]/.test(part)) {
  543. // disallow full-width chars
  544. return false;
  545. }
  546. if (part[0] === '-' || part[part.length - 1] === '-') {
  547. return false;
  548. }
  549. if (part.indexOf('---') >= 0 && part.slice(0, 4) !== 'xn--') {
  550. return false;
  551. }
  552. }
  553. return true;
  554. };
  555. /**
  556. * 判断是否是Bool值
  557. *
  558. * @public
  559. * @method module:pool/component-validation/src/util/validatorUtil.Validator#isBoolean
  560. * @param {String} str 输入的内容
  561. * @return {Boolean}
  562. */
  563. validatorUtil.isBoolean = function(str) {
  564. return (['true', 'false', '1', '0'].indexOf(str) >= 0);
  565. };
  566. /**
  567. * 判断是否是字母
  568. *
  569. * @public
  570. * @method module:pool/component-validation/src/util/validatorUtil.Validator#isAlpha
  571. * @param {String} str 输入的内容
  572. * @return {Boolean}
  573. */
  574. validatorUtil.isAlpha = function (str) {
  575. return alpha.test(str);
  576. };
  577. /**
  578. * 判断是否是字母或数字
  579. *
  580. * @public
  581. * @method module:pool/component-validation/src/util/validatorUtil.Validator#isAlphanumeric
  582. * @param {String} str 输入的内容
  583. * @return {Boolean}
  584. */
  585. validatorUtil.isAlphanumeric = function (str) {
  586. return alphanumeric.test(str);
  587. };
  588. /**
  589. * 判断是否是数字
  590. *
  591. * @public
  592. * @method module:pool/component-validation/src/util/validatorUtil.Validator#isNumeric
  593. * @param {String} str 输入的内容
  594. * @return {Boolean}
  595. */
  596. validatorUtil.isNumeric = function (str) {
  597. return numeric.test(str);
  598. };
  599. /**
  600. * 判断是否是10进制数字
  601. *
  602. * @public
  603. * @method module:pool/component-validation/src/util/validatorUtil.Validator#isDecimal
  604. * @param {String} str 输入的内容
  605. * @return {Boolean}
  606. */
  607. validatorUtil.isDecimal = function (str) {
  608. return str !== '' && decimal.test(str);
  609. };
  610. /**
  611. * 判断是否是16进制数字
  612. *
  613. * @public
  614. * @method module:pool/component-validation/src/util/validatorUtil.Validator#isHexadecimal
  615. * @param {String} str 输入的内容
  616. * @return {Boolean}
  617. */
  618. validatorUtil.isHexadecimal = function (str) {
  619. return hexadecimal.test(str);
  620. };
  621. /**
  622. * 判断是否是16进制颜色值
  623. *
  624. * @public
  625. * @method module:pool/component-validation/src/util/validatorUtil.Validator#isHexColor
  626. * @param {String} str 输入的内容
  627. * @return {Boolean}
  628. */
  629. validatorUtil.isHexColor = function (str) {
  630. return hexcolor.test(str);
  631. };
  632. /**
  633. * 判断是否是小写
  634. *
  635. * @public
  636. * @method module:pool/component-validation/src/util/validatorUtil.Validator#isLowercase
  637. * @param {String} str 输入的内容
  638. * @return {Boolean}
  639. */
  640. validatorUtil.isLowercase = function (str) {
  641. return str === str.toLowerCase();
  642. };
  643. /**
  644. * 判断是否是大写
  645. *
  646. * @public
  647. * @method module:pool/component-validation/src/util/validatorUtil.Validator#isUppercase
  648. * @param {String} str 输入的内容
  649. * @return {Boolean}
  650. */
  651. validatorUtil.isUppercase = function (str) {
  652. return str === str.toUpperCase();
  653. };
  654. validatorUtil.isInt = function (str, options) {
  655. options = options || {};
  656. return int.test(str) && (!options.hasOwnProperty('min') || (+str) >= options.min) && (!options.hasOwnProperty('max') || (+str) <= options.max);
  657. };
  658. validatorUtil.isId = function (str) {
  659. return id.test(str);
  660. };
  661. validatorUtil.isFloat = function (str, options) {
  662. options = options || {};
  663. if (str === '' || str === '.') {
  664. return false;
  665. }
  666. return float.test(str) && (!options.hasOwnProperty('min') || str >= options.min) && (!options.hasOwnProperty('max') || str <= options.max);
  667. };
  668. validatorUtil.isDivisibleBy = function (str, num) {
  669. return validatorUtil.toFloat(str) % validatorUtil.toInt(num) === 0;
  670. };
  671. validatorUtil.isNull = function (str) {
  672. return str.length === 0;
  673. };
  674. validatorUtil.isLength = function (str, options) {
  675. let min, max;
  676. if (typeof(options) === 'object') {
  677. min = options.min || 0;
  678. max = options.max;
  679. } else { // backwards compatibility: isLength(str, min [, max])
  680. min = arguments[1] || 0;
  681. max = arguments[2];
  682. }
  683. let len = validatorUtil.getStrLength(str.trim())/2;
  684. return (Math.floor(len) >= min) && (typeof max === 'undefined' || Math.ceil(len) <= max);
  685. };
  686. validatorUtil.isByteLength = function (str, options) {
  687. let min, max;
  688. if (typeof(options) === 'object') {
  689. min = options.min || 0;
  690. max = options.max;
  691. } else { // backwards compatibility: isByteLength(str, min [, max])
  692. min = arguments[1] || 0;
  693. max = arguments[2];
  694. }
  695. let len = encodeURI(str).split(/%..|./).length - 1;
  696. return len >= min && (typeof max === 'undefined' || len <= max);
  697. };
  698. validatorUtil.isUUID = function (str, version) {
  699. let pattern = uuid[version ? version : 'all'];
  700. return pattern && pattern.test(str);
  701. };
  702. function getTimezoneOffset(str) {
  703. let iso8601Parts = str.match(iso8601)
  704. , timezone, sign, hours, minutes;
  705. if (!iso8601Parts) {
  706. str = str.toLowerCase();
  707. timezone = str.match(/(?:\s|gmt\s*)(-|\+)(\d{1,4})(\s|$)/);
  708. if (!timezone) {
  709. return str.indexOf('gmt') !== -1 ? 0 : null;
  710. }
  711. sign = timezone[1];
  712. let offset = timezone[2];
  713. if (offset.length === 3) {
  714. offset = '0' + offset;
  715. }
  716. if (offset.length <= 2) {
  717. hours = 0;
  718. minutes = parseInt(offset);
  719. } else {
  720. hours = parseInt(offset.slice(0, 2));
  721. minutes = parseInt(offset.slice(2, 4));
  722. }
  723. } else {
  724. timezone = iso8601Parts[21];
  725. if (!timezone) {
  726. // if no hour/minute was provided, the date is GMT
  727. return !iso8601Parts[12] ? 0 : null;
  728. }
  729. if (timezone === 'z' || timezone === 'Z') {
  730. return 0;
  731. }
  732. sign = iso8601Parts[22];
  733. if (timezone.indexOf(':') !== -1) {
  734. hours = parseInt(iso8601Parts[23]);
  735. minutes = parseInt(iso8601Parts[24]);
  736. } else {
  737. hours = 0;
  738. minutes = parseInt(iso8601Parts[23]);
  739. }
  740. }
  741. return (hours * 60 + minutes) * (sign === '-' ? 1 : -1);
  742. }
  743. validatorUtil.isDate = function (str) {
  744. let normalizedDate = new Date(Date.parse(str));
  745. if (isNaN(normalizedDate)) {
  746. return false;
  747. }
  748. // normalizedDate is in the user's timezone. Apply the input
  749. // timezone offset to the date so that the year and day match
  750. // the input
  751. let timezoneOffset = getTimezoneOffset(str);
  752. if (timezoneOffset !== null) {
  753. let timezoneDifference = normalizedDate.getTimezoneOffset() -
  754. timezoneOffset;
  755. normalizedDate = new Date(normalizedDate.getTime() +
  756. 60000 * timezoneDifference);
  757. }
  758. let day = String(normalizedDate.getDate());
  759. let dayOrYear, dayOrYearMatches, year;
  760. //check for valid double digits that could be late days
  761. //check for all matches since a string like '12/23' is a valid date
  762. //ignore everything with nearby colons
  763. dayOrYearMatches = str.match(/(^|[^:\d])[23]\d([^:\d]|$)/g);
  764. if (!dayOrYearMatches) {
  765. return true;
  766. }
  767. dayOrYear = dayOrYearMatches.map(function(digitString) {
  768. return digitString.match(/\d+/g)[0];
  769. }).join('/');
  770. year = String(normalizedDate.getFullYear()).slice(-2);
  771. if (dayOrYear === day || dayOrYear === year) {
  772. return true;
  773. } else if ((dayOrYear === (day + '/' + year)) || (dayOrYear === (year + '/' + day))) {
  774. return true;
  775. }
  776. return false;
  777. };
  778. validatorUtil.isAfter = function (str, date) {
  779. let comparison = validatorUtil.toDate(date || new Date())
  780. , original = validatorUtil.toDate(str);
  781. return !!(original && comparison && original > comparison);
  782. };
  783. validatorUtil.isBefore = function (str, date) {
  784. let comparison = validatorUtil.toDate(date || new Date())
  785. , original = validatorUtil.toDate(str);
  786. return !!(original && comparison && original < comparison);
  787. };
  788. validatorUtil.isIn = function (str, options) {
  789. let i;
  790. if (Object.prototype.toString.call(options) === '[object Array]') {
  791. let array = [];
  792. for (i in options) {
  793. array[i] = validatorUtil.toString(options[i]);
  794. }
  795. return array.indexOf(str) >= 0;
  796. } else if (typeof options === 'object') {
  797. return options.hasOwnProperty(str);
  798. } else if (options && typeof options.indexOf === 'function') {
  799. return options.indexOf(str) >= 0;
  800. }
  801. return false;
  802. };
  803. validatorUtil.isWhitelisted = function (str, chars) {
  804. for (let i = str.length - 1; i >= 0; i--) {
  805. if (chars.indexOf(str[i]) === -1) {
  806. return false;
  807. }
  808. }
  809. return true;
  810. };
  811. validatorUtil.isCreditCard = function (str) {
  812. let sanitized = str.replace(/[^0-9]+/g, '');
  813. if (!creditCard.test(sanitized)) {
  814. return false;
  815. }
  816. let sum = 0, digit, tmpNum, shouldDouble;
  817. for (let i = sanitized.length - 1; i >= 0; i--) {
  818. digit = sanitized.substring(i, (i + 1));
  819. tmpNum = parseInt(digit, 10);
  820. if (shouldDouble) {
  821. tmpNum *= 2;
  822. if (tmpNum >= 10) {
  823. sum += ((tmpNum % 10) + 1);
  824. } else {
  825. sum += tmpNum;
  826. }
  827. } else {
  828. sum += tmpNum;
  829. }
  830. shouldDouble = !shouldDouble;
  831. }
  832. return !!((sum % 10) === 0 ? sanitized : false);
  833. };
  834. validatorUtil.isISIN = function (str) {
  835. if (!isin.test(str)) {
  836. return false;
  837. }
  838. let checksumStr = str.replace(/[A-Z]/g, function(character) {
  839. return parseInt(character, 36);
  840. });
  841. let sum = 0, digit, tmpNum, shouldDouble = true;
  842. for (let i = checksumStr.length - 2; i >= 0; i--) {
  843. digit = checksumStr.substring(i, (i + 1));
  844. tmpNum = parseInt(digit, 10);
  845. if (shouldDouble) {
  846. tmpNum *= 2;
  847. if (tmpNum >= 10) {
  848. sum += tmpNum + 1;
  849. } else {
  850. sum += tmpNum;
  851. }
  852. } else {
  853. sum += tmpNum;
  854. }
  855. shouldDouble = !shouldDouble;
  856. }
  857. return parseInt(str.substr(str.length - 1), 10) === (10000 - sum) % 10;
  858. };
  859. validatorUtil.isISBN = function (str, version) {
  860. version = validatorUtil.toString(version);
  861. if (!version) {
  862. return validatorUtil.isISBN(str, 10) || validatorUtil.isISBN(str, 13);
  863. }
  864. let sanitized = str.replace(/[\s-]+/g, '')
  865. , checksum = 0, i;
  866. if (version === '10') {
  867. if (!isbn10Maybe.test(sanitized)) {
  868. return false;
  869. }
  870. for (i = 0; i < 9; i++) {
  871. checksum += (i + 1) * sanitized.charAt(i);
  872. }
  873. if (sanitized.charAt(9) === 'X') {
  874. checksum += 10 * 10;
  875. } else {
  876. checksum += 10 * sanitized.charAt(9);
  877. }
  878. if ((checksum % 11) === 0) {
  879. return !!sanitized;
  880. }
  881. } else if (version === '13') {
  882. if (!isbn13Maybe.test(sanitized)) {
  883. return false;
  884. }
  885. let factor = [ 1, 3 ];
  886. for (i = 0; i < 12; i++) {
  887. checksum += factor[i % 2] * sanitized.charAt(i);
  888. }
  889. if (sanitized.charAt(12) - ((10 - (checksum % 10)) % 10) === 0) {
  890. return !!sanitized;
  891. }
  892. }
  893. return false;
  894. };
  895. validatorUtil.isMobilePhone = function(str, locale) {
  896. if (locale in phones) {
  897. return phones[locale].test(str);
  898. }
  899. return false;
  900. };
  901. let default_currency_options = {
  902. symbol: '$'
  903. , require_symbol: false
  904. , allow_space_after_symbol: false
  905. , symbol_after_digits: false
  906. , allow_negatives: true
  907. , parens_for_negatives: false
  908. , negative_sign_before_digits: false
  909. , negative_sign_after_digits: false
  910. , allow_negative_sign_placeholder: false
  911. , thousands_separator: ','
  912. , decimal_separator: '.'
  913. , allow_space_after_digits: false
  914. };
  915. validatorUtil.isCurrency = function (str, options) {
  916. options = merge(options, default_currency_options);
  917. return currencyRegex(options).test(str);
  918. };
  919. validatorUtil.isJSON = function (str) {
  920. try {
  921. let obj = JSON.parse(str);
  922. return !!obj && typeof obj === 'object';
  923. } catch (e) {
  924. /* continue regardless of error */
  925. }
  926. return false;
  927. };
  928. validatorUtil.isMultibyte = function (str) {
  929. return multibyte.test(str);
  930. };
  931. validatorUtil.isAscii = function (str) {
  932. return ascii.test(str);
  933. };
  934. validatorUtil.isFullWidth = function (str) {
  935. return fullWidth.test(str);
  936. };
  937. validatorUtil.isHalfWidth = function (str) {
  938. return halfWidth.test(str);
  939. };
  940. validatorUtil.isVariableWidth = function (str) {
  941. return fullWidth.test(str) && halfWidth.test(str);
  942. };
  943. validatorUtil.isSurrogatePair = function (str) {
  944. return surrogatePair.test(str);
  945. };
  946. validatorUtil.isBase64 = function (str) {
  947. return base64.test(str);
  948. };
  949. validatorUtil.isMongoId = function (str) {
  950. return validatorUtil.isHexadecimal(str) && str.length === 24;
  951. };
  952. validatorUtil.isISO8601 = function (str) {
  953. return iso8601.test(str);
  954. };
  955. validatorUtil.ltrim = function (str, chars) {
  956. let pattern = chars ? new RegExp('^[' + chars + ']+', 'g') : /^\s+/g;
  957. return str.replace(pattern, '');
  958. };
  959. validatorUtil.rtrim = function (str, chars) {
  960. let pattern = chars ? new RegExp('[' + chars + ']+$', 'g') : /\s+$/g;
  961. return str.replace(pattern, '');
  962. };
  963. validatorUtil.trim = function (str, chars) {
  964. let pattern = chars ? new RegExp('^[' + chars + ']+|[' + chars + ']+$', 'g') : /^\s+|\s+$/g;
  965. return str.replace(pattern, '');
  966. };
  967. validatorUtil.escape = function (str) {
  968. return (str.replace(/&/g, '&amp;')
  969. .replace(/"/g, '&quot;')
  970. .replace(/'/g, '&#x27;')
  971. .replace(/</g, '&lt;')
  972. .replace(/>/g, '&gt;')
  973. .replace(/\//g, '&#x2F;')
  974. .replace(/\`/g, '&#96;'));
  975. };
  976. validatorUtil.stripLow = function (str, keep_new_lines) {
  977. let chars = keep_new_lines ? '\\x00-\\x09\\x0B\\x0C\\x0E-\\x1F\\x7F' : '\\x00-\\x1F\\x7F';
  978. return validatorUtil.blacklist(str, chars);
  979. };
  980. validatorUtil.whitelist = function (str, chars) {
  981. return str.replace(new RegExp('[^' + chars + ']+', 'g'), '');
  982. };
  983. validatorUtil.blacklist = function (str, chars) {
  984. return str.replace(new RegExp('[' + chars + ']+', 'g'), '');
  985. };
  986. let default_normalize_email_options = {
  987. lowercase: true,
  988. remove_dots: true,
  989. remove_extension: true
  990. };
  991. validatorUtil.normalizeEmail = function (email, options) {
  992. options = merge(options, default_normalize_email_options);
  993. if (!validatorUtil.isEmail(email)) {
  994. return false;
  995. }
  996. let parts = email.split('@', 2);
  997. parts[1] = parts[1].toLowerCase();
  998. if (parts[1] === 'gmail.com' || parts[1] === 'googlemail.com') {
  999. if (options.remove_extension) {
  1000. parts[0] = parts[0].split('+')[0];
  1001. }
  1002. if (options.remove_dots) {
  1003. parts[0] = parts[0].replace(/\./g, '');
  1004. }
  1005. if (!parts[0].length) {
  1006. return false;
  1007. }
  1008. parts[0] = parts[0].toLowerCase();
  1009. parts[1] = 'gmail.com';
  1010. } else if (options.lowercase) {
  1011. parts[0] = parts[0].toLowerCase();
  1012. }
  1013. return parts.join('@');
  1014. };
  1015. validatorUtil.getStrLength = function (str) {
  1016. str = str || '';
  1017. str = str.replace(/^\n+|\n+$/g, ""); //将富文本中\n过滤
  1018. var entryLen0 = str.length,
  1019. entryLen = 0;
  1020. var cnChar = str.match(/[^\x00-\x80]/g); //利用match方法检索出中文字符并返回一个存放中文的数组
  1021. if (!!cnChar && cnChar.length > 0)
  1022. entryLen = cnChar.length || 0; //算出实际的字符长度
  1023. return entryLen0 + entryLen;
  1024. }
  1025. validatorUtil.init();
  1026. module.exports = validatorUtil;