├── .gitignore ├── .nvmrc ├── CHANGELOG.md ├── LICENSE ├── README.md ├── index.js ├── package.json └── test ├── fixtures.json └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 5.7.0 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 1.0.0 / 2016-02-23 2 | ------------------ 3 | - initial release 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright © 2022 Exodus Movement, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the “Software”), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | parse-num 2 | ========== 3 | 4 | JavaScript component to parse, clean, remove formatting (unformat) numbers in strings. 5 | 6 | 7 | Install 8 | ------- 9 | 10 | npm install --save parse-num 11 | 12 | 13 | Usage 14 | ----- 15 | 16 | ### parseNum 17 | 18 | **Signature:** `parseNum(value, [decimalSep])` 19 | 20 | **Parameters:** 21 | 22 | - `value`: Any value to parse a number from. If it's `null` or `undefined`, it will return `NaN`. If it's 23 | a `number`, it will just return the `number`. Otherwise, it will coerce the input `value` to a `string` using 24 | `toString()`. 25 | - `decimalSep`: *optional* `string` parameter to specify a decimal separator. Defaults to `"."`. 26 | 27 | **Returns:** 28 | 29 | The parsed `number`. 30 | 31 | **Example:** 32 | 33 | ```js 34 | const parseNum = require('parse-num') 35 | // import parseNum from 'parse-num' // if using ES6 36 | 37 | parseNum('$ 123,456.78') // => 123456.78 38 | parseNum('$ 123,456') // => 123456 39 | parseNum('&*()$ 123,456') // => 123456 40 | parseNum(';$@#$%^&123,456.78') // => 123456.78 41 | parseNum('$ -123,456') // => -123456 42 | parseNum('$ -123,456.78') // => -123456.78 43 | parseNum('&*()$ -123,456') // => -123456 44 | parseNum(';$@#$%^&-123,456.78') // => -123456.78 45 | parseNum('$ 123,456', ')') // => 123.456 46 | parseNum('$ 123456|78', '|') // => 123456.78 47 | parseNum('&*()$ 123>456', '>') // => 123.456 48 | parseNum(';$@#$%^&123,456\'78', '\'') // => 123456.78 49 | ``` 50 | 51 | ### Don't want `NaN`? 52 | 53 | Don't ever want to deal with NaN? Do this: 54 | 55 | ```js 56 | var num = parseNum(null) 57 | if (isNaN(num)) num = 0 58 | 59 | // could also coerce to integer <=== BE careful, 'INTEGER', not 'FLOAT' 60 | var num = ~~parseNum(null) 61 | console.log(num) // => 0 62 | ``` 63 | 64 | 65 | Credits 66 | ------- 67 | 68 | The basis of this code came from [accounting.js](https://github.com/openexchangerates/accounting.js). 69 | 70 | 71 | License 72 | ------- 73 | 74 | MIT 75 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | // modified from accounting.js 4 | function parseNum (value, decimalSep) { 5 | if (value == null) return NaN 6 | decimalSep = decimalSep || '.' 7 | 8 | // Return the value as-is if it's already a number: 9 | if (typeof value === 'number') return value 10 | 11 | // build regex to strip out everything except digits, decimal point and minus sign: 12 | var regex = new RegExp('[^0-9-' + decimalSep + ']', ['g']) 13 | var unformatted = value.toString() // explicitly convert to string 14 | unformatted = unformatted 15 | // .replace(/\((.*)\)/, '-$1') // replace bracketed values with negatives 16 | .replace(regex, '') // strip out any cruft 17 | .replace(decimalSep, '.') // make sure decimal point is standard 18 | 19 | unformatted = parseFloat(unformatted) 20 | 21 | return unformatted 22 | } 23 | 24 | module.exports = parseNum 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "parse-num", 3 | "version": "1.0.0", 4 | "description": "Parse, clean, remove formatting (unformat) numbers in strings.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "standard && ava --verbose" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/exodusmovement/parse-num.git" 12 | }, 13 | "keywords": [ 14 | "parse", 15 | "clean", 16 | "unformat", 17 | "numbers", 18 | "format", 19 | "number", 20 | "string", 21 | "money", 22 | "currency" 23 | ], 24 | "author": "Exodus Movement, Inc.", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/exodusmovement/parse-num/issues" 28 | }, 29 | "files": [ 30 | "index.js" 31 | ], 32 | "homepage": "https://github.com/exodusmovement/parse-num#readme", 33 | "devDependencies": { 34 | "ava": "0.12.x", 35 | "standard": "6.x" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/fixtures.json: -------------------------------------------------------------------------------- 1 | { 2 | "valid": [ 3 | ["$ 123,456.78", 123456.78], 4 | ["$ 123,456", 123456], 5 | ["&*()$ 123,456", 123456], 6 | [";$@#$%^&123,456.78", 123456.78], 7 | ["$ -123,456", -123456], 8 | ["$ -123,456.78", -123456.78], 9 | ["&*()$ -123,456", -123456], 10 | [";$@#$%^&-123,456.78", -123456.78], 11 | ["$ 123,456", ",", 123.456], 12 | ["$ 123456|78", "|", 123456.78], 13 | ["&*()$ 123>456", ">", 123.456], 14 | [";$@#$%^&123,456\"78", "\"", 123456.78] 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | import _test from 'ava' 2 | import fixtures from './fixtures' 3 | import parseNum from '../' 4 | 5 | const test = _test.cb 6 | 7 | test('parse strings to numbers', function (t) { 8 | fixtures.valid.forEach((f) => { 9 | if (f.length === 2) { 10 | const desc = `${f[0]} => ${f[1]}` 11 | t.is(parseNum(f[0]), f[1], desc) 12 | } else if (f.length === 3) { 13 | const desc = `${f[0]} => ${f[2]}` 14 | t.is(parseNum(f[0], f[1]), f[2], desc) 15 | } 16 | }) 17 | 18 | t.end() 19 | }) 20 | 21 | test('NaN results', function (t) { 22 | t.true(Number.isNaN(parseNum()), 'undefined => NaN') 23 | t.true(Number.isNaN(parseNum(null)), 'null => NaN') 24 | t.true(Number.isNaN(parseNum({})), '{} => NaN') 25 | t.true(Number.isNaN(parseNum([])), '[] => NaN') 26 | t.true(Number.isNaN(parseNum(true)), 'true => NaN') 27 | t.true(Number.isNaN(parseNum(false)), 'false => NaN') 28 | t.end() 29 | }) 30 | 31 | test('toString() conversions', function (t) { 32 | t.is(parseNum([3, 4]), 34) 33 | t.is(parseNum({ toString: () => '22' }), 22) 34 | t.is(parseNum(new Date(1452027142877)), 52016145222) 35 | t.end() 36 | }) 37 | --------------------------------------------------------------------------------