npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@norbulcz/num-parse

v0.1.0

Published

Strict, locale-tolerant number parser (US/EU/CH) with validated grouping & currency stripping. Zero deps.

Readme

@norbulcz/num-parse

Strict, locale-tolerant number parser (US/EU/CH) with validated grouping. Zero dependencies.

npm version Performance Bundle Size Zero Dependencies

A robust TypeScript library for parsing numbers from strings with support for multiple international formats including US, European, and Swiss number formatting conventions.

Features

  • 🌍 Multi-locale support: US, EU, and Swiss number formats
  • 🔒 Strict validation: Validates proper thousands separators and decimal points
  • 🚫 Zero dependencies: Lightweight with no external dependencies
  • 📦 TypeScript: Full TypeScript support with type definitions
  • 🧪 Well tested: Comprehensive test suite with 300+ test cases
  • 📱 Modern: ES modules and CommonJS support
  • High Performance: 4.4M+ parses per second

Why Choose @norbulcz/num-parse?

  • Smaller (1.2KB gzipped, zero deps)
  • Stricter (rejects invalid groupings)
  • Locale-flexible (US, EU, Swiss, plain, space grouping, with currency symbols)
  • Safer (never silently misparses into wrong numbers)
  • Simple (no Intl dependency, no polyfills, no moment.js or numeral.js — just a single function)
  • Predictable (invalid input → returns null, never throws)

Performance

The library is highly optimized for performance:

  • 4.4M+ parses per second on modern hardware
  • 0.0002ms average parse time per operation
  • Pre-compiled regex patterns for maximum efficiency
  • Zero dependencies for minimal bundle impact

Bundle Size

  • ESM: ~1.2KB gzipped
  • CJS: ~1.6KB gzipped
  • Types: ~1.4KB

Installation

npm install @norbulcz/num-parse

Quickstart

import { parseNumber } from '@norbulcz/num-parse';

// US format
parseNumber("1,234.56"); // → 1234.56

// European format  
parseNumber("1.234,56"); // → 1234.56

// Swiss format (both apostrophe types)
parseNumber("1'234.56"); // → 1234.56
parseNumber("1'234.56"); // → 1234.56 (curly apostrophe)

// Currency symbols (automatically removed)
parseNumber("₪1,234.56"); // → 1234.56
parseNumber("1,234.56$"); // → 1234.56

// Plain numbers (no separators)
parseNumber("1234.56"); // → 1234.56
parseNumber("1234"); // → 1234

// Space grouping
parseNumber("1 234.56"); // → 1234.56
parseNumber("1 234 567.89"); // → 1234567.89

Usage

import { parseNumber } from '@norbulcz/num-parse';

// US format
parseNumber('1,234.56');     // → 1234.56
parseNumber('12,345.67');    // → 12345.67

// European format
parseNumber('1.234,56');     // → 1234.56
parseNumber('12.345,67');    // → 12345.67

// Swiss format (apostrophe as thousands separator)
parseNumber("1'234.56");     // → 1234.56
parseNumber("1'234,56");      // → 1234.56

// Negative numbers
parseNumber('-1,234.56');    // → -1234.56
parseNumber('-1.234,56');    // → -1234.56

// Edge cases
parseNumber('.5');           // → 0.5
parseNumber(',5');           // → 0.5
parseNumber('1,000');        // → 1000
parseNumber('1.000');        // → 1000

// Currency symbols (automatically removed)
parseNumber('₪1,234.56');   // → 1234.56 (Israeli Shekel)
parseNumber('₿0.001');      // → 0.001 (Bitcoin)
parseNumber('₩1,234.56');   // → 1234.56 (Korean Won)
parseNumber('₹1,234.56');   // → 1234.56 (Indian Rupee)
parseNumber('1,234.56$');   // → 1234.56 (US Dollar at end)
parseNumber('1.234,56€');   // → 1234.56 (Euro at end)

// Scientific notation (disabled by default)
parseNumber('1.5e3');        // → null (disabled by default)
parseNumber('1.5e3', { allowScientific: true }); // → 1500

// Plain inputs & spaces
parseNumber('3333');         // → 3333
parseNumber('12345.67');     // → 12345.67
parseNumber('12345,67');     // → 12345.67
parseNumber('1 123.34');     // → 1123.34
parseNumber('2 276,00');     // → 2276 (NBSP)

// Invalid inputs return null
parseNumber('invalid');      // → null
parseNumber('1,23,456');     // → null (invalid grouping)
parseNumber("12'34");        // → null (invalid apostrophe grouping)
parseNumber('123.');         // → null (trailing decimal)
parseNumber('');             // → null

Supported Formats

US Format

  • Thousands separator: comma (,)
  • Decimal separator: period (.)
  • Examples: 1,234.56, 12,345.67

European Format

  • Thousands separator: period (.)
  • Decimal separator: comma (,)
  • Examples: 1.234,56, 12.345,67

Swiss Format

  • Thousands separator: apostrophe (')
  • Decimal separator: period (.) or comma (,)
  • Examples: 1'234.56, 1'234,56

Currency Symbol Support

  • Automatically removes all Unicode currency symbols using the \p{Sc} class
  • Supports: $, , £, ¥, , , ¢, , , , , , , , and many more
  • Examples: ₪1,234.561234.56, ₿0.0010.001

API

parseNumber(value: string, options?: ParseOptions): number | null

Parses a string and returns a number or null if the input is invalid.

Parameters:

  • value (string): The string to parse
  • options (ParseOptions, optional): Configuration options

Returns:

  • number: The parsed number
  • null: If the input is invalid or empty

ParseOptions

interface ParseOptions {
  /** Strip any Unicode currency symbol (e.g. $, €, ₪, ₿). Default: true */
  stripCurrency?: boolean;
  /** Allow Swiss-style apostrophe grouping (both ' and '). Default: true */
  allowApostrophe?: boolean;
  /** Allow scientific notation like 1.5e3. Default: false */
  allowScientific?: boolean;
}

Options Examples

// Default behavior
parseNumber(input, {
  stripCurrency: true,   // \p{Sc} removed by default
  allowApostrophe: true, // Swiss ' and ' grouping
  allowScientific: false // opt-in
});

// Disable currency stripping
parseNumber('$1,234.56', { stripCurrency: false }); // → null
parseNumber('1,234.56', { stripCurrency: false });  // → 1234.56

// Disable Swiss apostrophe format
parseNumber("1'234.56", { allowApostrophe: false }); // → null
parseNumber('1,234.56', { allowApostrophe: false }); // → 1234.56

// Enable scientific notation
parseNumber('1.5e3', { allowScientific: true });     // → 1500
parseNumber('1.5e-3', { allowScientific: true });     // → 0.0015

// Combine options
parseNumber('₪1'234.56', { 
  stripCurrency: true, 
  allowApostrophe: true, 
  allowScientific: false 
}); // → 1234.56

Validation Rules

The parser enforces strict validation rules:

  1. Thousands separators must be in groups of exactly 3 digits
  2. Decimal points can only appear once
  3. Signs (+/-) can only appear at the beginning
  4. Swiss apostrophes must follow proper 3-digit grouping
  5. Mixed separators are disambiguated by the last separator (decimal point)

Examples

// Valid inputs
parseNumber('1,234.56');        // ✅ 1234.56
parseNumber('1.234,56');        // ✅ 1234.56
parseNumber("1'234.56");        // ✅ 1234.56
parseNumber('1,000');           // ✅ 1000
parseNumber('1.000');           // ✅ 1000
parseNumber("1'000");           // ✅ 1000
parseNumber('-1,234.56');       // ✅ -1234.56
parseNumber('.5');              // ✅ 0.5
parseNumber(',5');              // ✅ 0.5

// Invalid inputs
parseNumber('1,23,456');        // ❌ null (invalid grouping)
parseNumber('1.23.456');        // ❌ null (invalid grouping)
parseNumber('1,234.56.78');     // ❌ null (multiple decimal points)
parseNumber('1-234.56');        // ❌ null (sign in middle)
parseNumber('1,234,56');        // ❌ null (ambiguous - could be 1,234,56 or 1,234.56)
parseNumber('');                // ❌ null (empty)
parseNumber('invalid');         // ❌ null (non-numeric)

Performance Benchmarks

Real-world Performance

Running performance benchmark...
Total time: 1170.28ms
Average time per parse: 0.0002ms
Parses per second: 4,443,387
Total operations: 5,200,000

Test Cases Covered

  • US format: 1,234.56
  • EU format: 1.234,56
  • Swiss format: 1'234.56
  • Scientific notation: 1.5e3
  • Currency symbols: ₪1,234.56, 1,234.56$
  • Large numbers: 999,999,999.99
  • Small decimals: 0.001

Optimization Features

  • Pre-compiled regex patterns - No regex compilation overhead
  • Method extraction - Clean, maintainable code structure
  • Early returns - Minimal processing for invalid inputs
  • Unicode optimization - Efficient \p{Sc} class usage

Development

# Install dependencies
npm install

# Run tests
npm test

# Run tests in watch mode
npm run test:watch

# Build the library
npm run build

# Development mode with watch
npm run dev

Contributing

Contributions are welcome! Please open issues or pull requests on GitHub.

License

MIT © Norbert Lorincz