Ship internal tools in hours, not weeks. Real auth, users, jobs, audit logs, and cohesive UI included. Early access $249 $499 → [Get it now]

How to extract numbers from a string in JavaScript

Extracting numbers from strings is crucial for data parsing, form processing, text analysis, and implementing features like price extraction or numeric data validation in JavaScript applications. With over 25 years of experience in software development and as the creator of CoreUI, I’ve implemented number extraction in components like price calculators, data parsers, and validation systems where isolating numeric values from mixed text content is essential for processing. From my expertise, the most powerful and flexible solution is using the match() method with regular expressions to identify and extract numeric patterns. This approach handles various number formats and provides complete control over what constitutes a valid number in your context.

Use match() with a regular expression to extract all numbers from a string.

const text = 'Price: $25.99 and quantity: 3 items'
const numbers = text.match(/\d+(\.\d+)?/g)
// Result: ['25.99', '3']

The match() method with the regular expression /\d+(\.\d+)?/g finds all numeric patterns in the string. The regex breaks down as: \d+ matches one or more digits, (\.\d+)? optionally matches a decimal point followed by one or more digits, and the g flag finds all matches globally. In this example, it extracts both '25.99' and '3' from the mixed text. The result is an array of strings, which you can convert to actual numbers using map(Number): numbers.map(Number) gives [25.99, 3].

1. Extracting Integers Only

When you only need whole numbers, a simpler regex pattern suffices. This is common for extracting IDs, counts, or index values from text.

const text = 'Order #1234 has 5 items weighing 2.5kg'

// Extract only integers
const integers = text.match(/\d+/g)
// Result: ['1234', '5', '2', '5']
// Note: '2.5' becomes '2' and '5' separately

// Convert to actual numbers
const nums = text.match(/\d+/g)?.map(Number) ?? []
// Result: [1234, 5, 2, 5]

// Extract the first number only
const firstNumber = text.match(/\d+/)
console.log(firstNumber?.[0])
// Result: '1234'

console.log(Number(firstNumber?.[0]))
// Result: 1234

// Safe extraction with fallback
const extractFirst = (str, fallback = 0) => {
  const match = str.match(/\d+/)
  return match ? Number(match[0]) : fallback
}

console.log(extractFirst('Item #42'))    // 42
console.log(extractFirst('No numbers'))  // 0
console.log(extractFirst('', -1))        // -1

The ?.map(Number) ?? [] pattern safely handles the case where match() returns null (no numbers found). Without this, calling .map() on null would throw a TypeError. For more on handling empty strings, see how to check if a string is empty in JavaScript.

2. Extracting Decimal and Negative Numbers

Real-world data often includes decimals, negative values, and numbers starting with a decimal point. The regex needs to account for these patterns.

const text = 'Temperature: -5.3°C, wind: 12.7 mph, pressure: .98 atm'

// Extract decimals and negatives
const numbers = text.match(/-?\d*\.?\d+/g)?.map(Number) ?? []
// Result: [-5.3, 12.7, 0.98]

// Regex breakdown:
// -?       optional negative sign
// \d*      zero or more digits (handles .5 with no leading digit)
// \.?      optional decimal point
// \d+      one or more digits (at least some digits required)

// More examples
console.log('Score: -10.5 to +20.3'.match(/-?\d+(\.\d+)?/g)?.map(Number))
// Result: [-10.5, 20.3]

console.log('Coords: .5, -.75, 100'.match(/-?\d*\.?\d+/g)?.map(Number))
// Result: [0.5, -0.75, 100]

// Extract with sign preservation
const extractSigned = (text) => {
  return text.match(/[+-]?\d*\.?\d+/g)?.map(Number) ?? []
}

console.log(extractSigned('Change: +5.2% and -3.1%'))
// Result: [5.2, -3.1]

The pattern -?\d*\.?\d+ is the most versatile — it handles integers (42), decimals (3.14), negatives (-7), and numbers starting with a decimal (.5). It avoids the trailing-period bug by requiring at least one digit after the optional decimal point.

3. Extracting Currency and Formatted Numbers

Prices and formatted numbers contain commas, currency symbols, and specific decimal formats that need special handling.

// Extract prices from text
const priceText = 'Widget: $1,234.56, Gadget: €999.00, Tax: $12.50'

// Step 1: Match currency patterns
const pricePattern = /[\$€£¥][\d,]+\.?\d*/g
const prices = priceText.match(pricePattern)
// Result: ['$1,234.56', '€999.00', '$12.50']

// Step 2: Clean and convert to numbers
const cleanPrice = (str) => Number(str.replace(/[^0-9.]/g, ''))

const amounts = prices?.map(cleanPrice) ?? []
// Result: [1234.56, 999, 12.50]

// Extract formatted numbers (with commas)
const extractFormattedNumbers = (text) => {
  const pattern = /-?[\d,]+\.?\d*/g
  const matches = text.match(pattern) ?? []
  return matches.map(m => Number(m.replace(/,/g, '')))
}

console.log(extractFormattedNumbers('Population: 1,234,567 and area: 50,000.5 km²'))
// Result: [1234567, 50000.5]

// Extract with currency label
const extractPrices = (text) => {
  const pattern = /([\$€£¥])\s*([\d,]+\.?\d*)/g
  const results = []
  let match

  while ((match = pattern.exec(text)) !== null) {
    results.push({
      currency: match[1],
      amount: Number(match[2].replace(/,/g, ''))
    })
  }

  return results
}

console.log(extractPrices('Total: $1,250.00 + €45.99'))
// [{ currency: '$', amount: 1250 }, { currency: '€', amount: 45.99 }]

The exec() loop with capturing groups is more powerful than match() for structured extraction — it preserves the relationship between the currency symbol and the amount. For removing non-numeric characters, see how to remove special characters from a string in JavaScript.

4. Extracting Numbers with matchAll() and Named Groups

The matchAll() method with named capturing groups provides a modern, readable way to extract structured numeric data.

// Extract labeled numbers using named groups
const text = 'Width: 1920px, Height: 1080px, DPI: 96'
const pattern = /(?<label>\w+):\s*(?<value>\d+)/g

const entries = [...text.matchAll(pattern)].map(match => ({
  label: match.groups.label,
  value: Number(match.groups.value)
}))

console.log(entries)
// [
//   { label: 'Width', value: 1920 },
//   { label: 'Height', value: 1080 },
//   { label: 'DPI', value: 96 }
// ]

// Extract version numbers
const changelog = 'v2.1.3 released, fixing bug from v2.1.0'
const versionPattern = /v(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)/g

const versions = [...changelog.matchAll(versionPattern)].map(m => ({
  full: m[0],
  major: Number(m.groups.major),
  minor: Number(m.groups.minor),
  patch: Number(m.groups.patch)
}))

console.log(versions)
// [
//   { full: 'v2.1.3', major: 2, minor: 1, patch: 3 },
//   { full: 'v2.1.0', major: 2, minor: 1, patch: 0 }
// ]

// Extract dates as numbers
const dateText = 'Born: 1990-05-15, Joined: 2023-11-01'
const datePattern = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/g

const dates = [...dateText.matchAll(datePattern)].map(m => ({
  year: Number(m.groups.year),
  month: Number(m.groups.month),
  day: Number(m.groups.day)
}))

console.log(dates)
// [{ year: 1990, month: 5, day: 15 }, { year: 2023, month: 11, day: 1 }]

Named groups ((?<name>...)) make the regex self-documenting and the extracted data easier to work with. matchAll() returns an iterator of all matches with their groups, which spreads nicely into an array. This approach is supported in all modern browsers and Node.js 12+.

5. Extracting Numbers from Structured Text

Parsing structured formats like CSV lines, log entries, or configuration strings requires combining number extraction with string splitting.

// Extract numbers from CSV-like data
const csvLine = 'John,30,85000.50,4.5'
const values = csvLine.split(',')
const numericValues = values.filter(v => !isNaN(v) && v.trim() !== '').map(Number)
// Result: [30, 85000.5, 4.5]

// Extract from key-value pairs
const config = 'timeout=30s maxRetries=5 ratio=0.75 debug=true'
const extractConfigNumbers = (text) => {
  const pattern = /(\w+)=([\d.]+)/g
  const config = {}
  let match

  while ((match = pattern.exec(text)) !== null) {
    config[match[1]] = Number(match[2])
  }

  return config
}

console.log(extractConfigNumbers(config))
// { timeout: 30, maxRetries: 5, ratio: 0.75 }

// Extract from log entries
const logs = [
  '[2024-01-15 10:30:45] Response time: 234ms, Status: 200',
  '[2024-01-15 10:30:46] Response time: 1250ms, Status: 500',
  '[2024-01-15 10:30:47] Response time: 89ms, Status: 200'
]

const parseLog = (line) => {
  const time = line.match(/time:\s*(\d+)ms/)?.[1]
  const status = line.match(/Status:\s*(\d+)/)?.[1]
  return {
    responseTime: Number(time),
    status: Number(status)
  }
}

const parsed = logs.map(parseLog)
console.log(parsed)
// [{ responseTime: 234, status: 200 },
//  { responseTime: 1250, status: 500 },
//  { responseTime: 89, status: 200 }]

// Calculate average from extracted numbers
const avgResponseTime = parsed.reduce((sum, l) => sum + l.responseTime, 0) / parsed.length
console.log(Math.round(avgResponseTime))
// Result: 524

When parsing structured text, use targeted regex patterns for each field rather than a generic “find all numbers” approach. This prevents accidentally matching numbers from timestamps, IDs, or other fields you don’t want.

6. Using parseInt() and parseFloat() for Extraction

When you need to extract the first number from the beginning of a string, parseInt() and parseFloat() work without regex.

// parseInt extracts leading integer
console.log(parseInt('42px'))         // 42
console.log(parseInt('100%'))         // 100
console.log(parseInt('3.14'))         // 3 (truncates decimal)
console.log(parseInt('abc'))          // NaN
console.log(parseInt(''))             // NaN

// parseFloat extracts leading decimal
console.log(parseFloat('3.14rem'))    // 3.14
console.log(parseFloat('$99.99'))     // NaN (starts with $, not a digit)
console.log(parseFloat('.5em'))       // 0.5

// Extract CSS values
const extractCssValue = (cssString) => {
  const value = parseFloat(cssString)
  const unit = cssString.replace(String(value), '').trim()
  return { value, unit }
}

console.log(extractCssValue('16px'))     // { value: 16, unit: 'px' }
console.log(extractCssValue('1.5rem'))   // { value: 1.5, unit: 'rem' }
console.log(extractCssValue('100%'))     // { value: 100, unit: '%' }
console.log(extractCssValue('0.5em'))    // { value: 0.5, unit: 'em' }

// parseInt with radix for different bases
console.log(parseInt('ff', 16))   // 255 (hexadecimal)
console.log(parseInt('111', 2))   // 7 (binary)
console.log(parseInt('77', 8))    // 63 (octal)

// Safe number extraction
const toNumber = (value) => {
  const num = Number(value)
  return Number.isFinite(num) ? num : null
}

console.log(toNumber('42'))        // 42
console.log(toNumber(''))          // null (Number('') is 0, but we want null)
console.log(toNumber('abc'))       // null
console.log(toNumber('Infinity'))  // null

Use parseInt()/parseFloat() when the number is at the start of the string (like CSS values). Use match() with regex when numbers can appear anywhere in the text. Always use Number.isFinite() to validate the result — it catches NaN, Infinity, and -Infinity. This pattern is useful in CoreUI form validation for extracting and validating numeric input from form controls.

Best Practice Note:

Use /\d+(\.\d+)?/g for basic number extraction, -?\d*\.?\d+ for decimals and negatives, and matchAll() with named groups for structured data. Always convert extracted strings to numbers with Number() or map(Number)match() returns strings, not numbers. Handle the null case from match() with optional chaining (?.) and nullish coalescing (?? []). For replacing matched patterns, see how to replace all occurrences of a string in JavaScript.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author