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

indian-money

v1.0.0

Published

A tiny, dependency-free TypeScript library to parse Indian currency strings (₹/Rs with lakh/crore units) into numbers and to format numbers back using the Indian numbering system

Downloads

23

Readme

indian-money

A tiny, dependency-free TypeScript library to parse Indian currency strings (₹/Rs with lakh/crore units) into numbers and to format numbers back using the Indian numbering system, including compact L/Cr output.

npm version TypeScript Test Coverage

Features

  • Parsing: Convert messy real-world INR strings like "2.3 Cr", "45L", "Rs 1,50,000" to JavaScript numbers
  • Formatting: Format numbers with Indian digit grouping (1,23,45,678), optional currency symbols, and compact units (L/Cr)
  • Round-trip stability: format(parse(s)) produces normalized output for accepted inputs
  • Zero dependencies: No runtime dependencies, works in browsers and Node.js
  • TypeScript first: Fully typed API with excellent IntelliSense support
  • Tiny bundle: ~3-4 KB minified + gzipped
  • Comprehensive: Handles mixed units ("2 cr 30 lakh"), negatives, scientific notation, and edge cases

Installation

npm install indian-money

Quick Start

import { parseINR, formatINR } from 'indian-money';

// Parsing examples
parseINR('₹1,50,000');           // { kind: 'ok', value: 150000, ... }
parseINR('2.3 Cr');              // { kind: 'ok', value: 23000000, ... }
parseINR('2 crore 30 lakh');     // { kind: 'ok', value: 23000000, ... }
parseINR('-Rs 75,000');          // { kind: 'ok', value: -75000, negative: true, ... }
parseINR('INR 2,30,000.50');     // { kind: 'ok', value: 230000.5, ... }

// Formatting examples
formatINR(150000);                                    // "₹1,50,000.00"
formatINR(1250000, { style: 'compact-indian' });     // "₹12.5L"
formatINR(23000000, { style: 'compact-indian' });    // "₹2.3Cr"
formatINR(-1234.5, { sign: 'accounting' });          // "(₹1,234.50)"
formatINR(150000, { ascii: true });                  // "Rs 1,50,000.00"

API Reference

parseINR(input, options?)

Parses Indian currency strings into numbers with detailed metadata.

function parseINR(input: string, opts?: ParseOptions): ParseOutput

interface ParseOptions {
  allowMetricUnits?: boolean; // Allow k/m/b units (default: false)
  maxLen?: number;            // Max input length guard (default: 200)
}

type ParseOutput = ParseOk | ParseErr

interface ParseOk {
  kind: 'ok';
  value: number;              // Parsed rupees value (may have decimals for paise)
  negative: boolean;          // True if negative sign/parentheses detected
  detected: {
    currency?: 'INR';         // Present if ₹/Rs/INR markers found
    unit?: 'lakh' | 'crore' | null; // Highest unit detected
    raw: string;              // Original input
  };
}

interface ParseErr {
  kind: 'err';
  reason: 'empty' | 'invalid' | 'overflow' | 'nonfinite';
  at?: number;                // Optional character index where parsing failed
}

Supported formats:

  • Currency markers: , Rs, Rs., INR, रु (case-insensitive)
  • Units: cr/crs/crore/crores (1e7), l/lac/lacs/lakh/lakhs (1e5)
  • Mixed units: "2 cr 30 lakh", "1.5 crore 25 L"
  • Signs: Leading -, +, or accounting parentheses (₹1,234)
  • Separators: Commas, spaces, non-breaking spaces in any combination
  • Scientific notation: "1e6 L", "2.3e-2 Cr" (when units present)

formatINR(number, options?)

Formats numbers using Indian numbering system with various options.

function formatINR(n: number, opts?: FormatOptions): string

interface FormatOptions {
  currency?: 'INR' | null;     // Currency symbol (default: 'INR' = ₹)
  ascii?: boolean;             // Use "Rs" instead of "₹" (default: false)
  decimals?: number;           // Fraction digits (default: 2)
  style?: 'standard' | 'compact-indian' | 'compact-metric';
  minCompact?: number;         // Min value for compact style (default: 1e5)
  spaceBetween?: boolean;      // "2 Cr" vs "2Cr" (default: false)
  sign?: 'auto' | 'always' | 'accounting'; // Negative formatting
}

Style options:

  • standard: ₹1,23,45,678.90 (Indian grouping)
  • compact-indian: ₹12.3L, ₹2.3Cr (Indian units)
  • compact-metric: ₹1.2k, ₹3.4m (international units)

Helper Functions

toIndianCompact(number, options?)

function toIndianCompact(n: number, opts?: {
  decimals?: number;
  spaceBetween?: boolean;
}): string

toIndianCompact(1230000);     // "12.3L"
toIndianCompact(23000000);    // "2.3Cr"

fromIndianCompact(input)

function fromIndianCompact(input: string): ParseOutput

fromIndianCompact('2.3 Cr'); // { kind: 'ok', value: 23000000, ... }

Advanced Examples

Error Handling

const result = parseINR('invalid input');
if (result.kind === 'err') {
  console.log(`Parse error: ${result.reason}`);
  if (result.at !== undefined) {
    console.log(`Error at position: ${result.at}`);
  }
} else {
  console.log(`Parsed value: ${result.value}`);
}

Round-trip Processing

// Parse user input, then format for display
const userInput = "2 cr 30 lakh";
const parsed = parseINR(userInput);

if (parsed.kind === 'ok') {
  const formatted = formatINR(parsed.value, { 
    style: 'compact-indian',
    spaceBetween: true 
  });
  console.log(formatted); // "₹2.3 Cr"
}

Custom Formatting

// ASCII-friendly accounting format
formatINR(-150000, {
  ascii: true,
  sign: 'accounting',
  decimals: 0
}); // "(Rs 1,50,000)"

// Compact with custom threshold
formatINR(75000, {
  style: 'compact-indian',
  minCompact: 50000,
  spaceBetween: true
}); // "₹0.75 L"

Working with Mixed Units

// Parse complex mixed unit expressions
parseINR('₹2 crore 50 lakh 75 thousand'); // Not supported - use "2.505 cr"
parseINR('₹2.505 cr');                   // { kind: 'ok', value: 25050000, ... }

// Mixed units are limited to crore + lakh combinations
parseINR('1 cr 50 lakh');    // ✅ { kind: 'ok', value: 15000000, ... }
parseINR('50 lakh 25 thousand'); // ❌ { kind: 'err', reason: 'invalid' }

Use Cases

E-commerce & Fintech

// Parse user input in investment calculator
const userInput = "2.5 cr";
const investment = parseINR(userInput);
if (investment.kind === 'ok') {
  const returns = investment.value * 0.12; // 12% returns
  console.log(`Annual returns: ${formatINR(returns, { style: 'compact-indian' })}`);
}

Data Import/Export

// Normalize CSV data containing mixed INR formats
const csvData = ["Rs 1,50,000", "2.3Cr", "₹45L"];
const normalized = csvData
  .map(parseINR)
  .filter(result => result.kind === 'ok')
  .map(result => result.value);

Content Processing

// Clean scraped financial data
const scrapedText = "Property value: ₹2 crore 30 lakh";
const match = scrapedText.match(/₹[\d\s,cr lakh]+/i);
if (match) {
  const parsed = parseINR(match[0]);
  if (parsed.kind === 'ok') {
    console.log(`Standardized: ${formatINR(parsed.value)}`);
  }
}

Browser Support

Works in all modern browsers and Node.js 18+. Uses Intl.NumberFormat when available, with automatic fallback for environments without internationalization support.

Performance

  • Parsing: ~1M operations/second
  • Formatting: ~500K operations/second
  • Bundle size: ~3.4KB minified + gzipped
  • Memory: Zero-copy string parsing, minimal allocations

Comparison with Alternatives

| Feature | indian-money | Intl.NumberFormat | Other libraries | |---------|-------------|------------------|----------------| | Parse INR strings | ✅ | ❌ | Limited | | Indian formatting | ✅ | ✅ | Limited | | Lakh/Crore units | ✅ | ❌ | Some | | Mixed units ("2 cr 30 lakh") | ✅ | ❌ | ❌ | | TypeScript support | ✅ | ✅ | Varies | | Bundle size | 3.4KB | 0KB (built-in) | Varies | | Zero dependencies | ✅ | ✅ | ❌ |

Contributing

Contributions welcome! Please read our contributing guidelines and submit pull requests to our GitHub repository.

License

MIT License. See LICENSE for details.

Changelog

See CHANGELOG.md for version history and migration guides.