strnum.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. const hexRegex = /^[-+]?0x[a-fA-F0-9]+$/;
  2. const numRegex = /^([\-\+])?(0*)([0-9]*(\.[0-9]*)?)$/;
  3. // const octRegex = /^0x[a-z0-9]+/;
  4. // const binRegex = /0x[a-z0-9]+/;
  5. const consider = {
  6. hex : true,
  7. // oct: false,
  8. leadingZeros: true,
  9. decimalPoint: "\.",
  10. eNotation: true,
  11. //skipLike: /regex/
  12. };
  13. export default function toNumber(str, options = {}){
  14. options = Object.assign({}, consider, options );
  15. if(!str || typeof str !== "string" ) return str;
  16. let trimmedStr = str.trim();
  17. if(options.skipLike !== undefined && options.skipLike.test(trimmedStr)) return str;
  18. else if(str==="0") return 0;
  19. else if (options.hex && hexRegex.test(trimmedStr)) {
  20. return parse_int(trimmedStr, 16);
  21. // }else if (options.oct && octRegex.test(str)) {
  22. // return Number.parseInt(val, 8);
  23. }else if (trimmedStr.search(/.+[eE].+/)!== -1) { //eNotation
  24. return resolveEnotation(str,trimmedStr,options);
  25. // }else if (options.parseBin && binRegex.test(str)) {
  26. // return Number.parseInt(val, 2);
  27. }else{
  28. //separate negative sign, leading zeros, and rest number
  29. const match = numRegex.exec(trimmedStr);
  30. // +00.123 => [ , '+', '00', '.123', ..
  31. if(match){
  32. const sign = match[1] || "";
  33. const leadingZeros = match[2];
  34. let numTrimmedByZeros = trimZeros(match[3]); //complete num without leading zeros
  35. const decimalAdjacentToLeadingZeros = sign ? // 0., -00., 000.
  36. str[leadingZeros.length+1] === "."
  37. : str[leadingZeros.length] === ".";
  38. //trim ending zeros for floating number
  39. if(!options.leadingZeros //leading zeros are not allowed
  40. && (leadingZeros.length > 1
  41. || (leadingZeros.length === 1 && !decimalAdjacentToLeadingZeros))){
  42. // 00, 00.3, +03.24, 03, 03.24
  43. return str;
  44. }
  45. else{//no leading zeros or leading zeros are allowed
  46. const num = Number(trimmedStr);
  47. const parsedStr = String(num);
  48. if( num === 0) return num;
  49. if(parsedStr.search(/[eE]/) !== -1){ //given number is long and parsed to eNotation
  50. if(options.eNotation) return num;
  51. else return str;
  52. }else if(trimmedStr.indexOf(".") !== -1){ //floating number
  53. if(parsedStr === "0") return num; //0.0
  54. else if(parsedStr === numTrimmedByZeros) return num; //0.456. 0.79000
  55. else if( parsedStr === `${sign}${numTrimmedByZeros}`) return num;
  56. else return str;
  57. }
  58. let n = leadingZeros? numTrimmedByZeros : trimmedStr;
  59. if(leadingZeros){
  60. // -009 => -9
  61. return (n === parsedStr) || (sign+n === parsedStr) ? num : str
  62. }else {
  63. // +9
  64. return (n === parsedStr) || (n === sign+parsedStr) ? num : str
  65. }
  66. }
  67. }else{ //non-numeric string
  68. return str;
  69. }
  70. }
  71. }
  72. const eNotationRegx = /^([-+])?(0*)(\d*(\.\d*)?[eE][-\+]?\d+)$/;
  73. function resolveEnotation(str,trimmedStr,options){
  74. if(!options.eNotation) return str;
  75. const notation = trimmedStr.match(eNotationRegx);
  76. if(notation){
  77. let sign = notation[1] || "";
  78. const eChar = notation[3].indexOf("e") === -1 ? "E" : "e";
  79. const leadingZeros = notation[2];
  80. const eAdjacentToLeadingZeros = sign ? // 0E.
  81. str[leadingZeros.length+1] === eChar
  82. : str[leadingZeros.length] === eChar;
  83. if(leadingZeros.length > 1 && eAdjacentToLeadingZeros) return str;
  84. else if(leadingZeros.length === 1
  85. && (notation[3].startsWith(`.${eChar}`) || notation[3][0] === eChar)){
  86. return Number(trimmedStr);
  87. }else if(options.leadingZeros && !eAdjacentToLeadingZeros){ //accept with leading zeros
  88. //remove leading 0s
  89. trimmedStr = (notation[1] || "") + notation[3];
  90. return Number(trimmedStr);
  91. }else return str;
  92. }else{
  93. return str;
  94. }
  95. }
  96. /**
  97. *
  98. * @param {string} numStr without leading zeros
  99. * @returns
  100. */
  101. function trimZeros(numStr){
  102. if(numStr && numStr.indexOf(".") !== -1){//float
  103. numStr = numStr.replace(/0+$/, ""); //remove ending zeros
  104. if(numStr === ".") numStr = "0";
  105. else if(numStr[0] === ".") numStr = "0"+numStr;
  106. else if(numStr[numStr.length-1] === ".") numStr = numStr.substring(0,numStr.length-1);
  107. return numStr;
  108. }
  109. return numStr;
  110. }
  111. function parse_int(numStr, base){
  112. //polyfill
  113. if(parseInt) return parseInt(numStr, base);
  114. else if(Number.parseInt) return Number.parseInt(numStr, base);
  115. else if(window && window.parseInt) return window.parseInt(numStr, base);
  116. else throw new Error("parseInt, Number.parseInt, window.parseInt are not supported")
  117. }