← Back to DevBytes

Solving String to Integer (atoi) in JavaScript: Step-by-Step Guide

Introduction to String to Integer (atoi)

The String to Integer (atoi) problem is a classic algorithmic challenge that frequently appears in coding interviews and competitive programming platforms like LeetCode. The task is to convert a string into a 32-bit signed integer while following a specific set of rules that mimic the behavior of the C standard library's atoi function.

While JavaScript already provides built-in methods like parseInt() and the unary plus operator, implementing atoi from scratch teaches you valuable lessons about string parsing, edge case handling, and numerical boundaries. This tutorial walks you through the problem, the algorithm, and a robust JavaScript implementation.

What Is the atoi Problem?

The atoi function converts a string to an integer, but it does so with strict rules. Unlike a simple type cast, it must handle whitespace, optional signs, non-numeric characters, and integer overflow. Understanding these rules is the first step toward a correct implementation.

Problem Statement

Given a string s, implement the myAtoi(string s) function that converts the string to a 32-bit signed integer. The algorithm follows these steps:

Example Inputs and Outputs

Here are a few examples to clarify the expected behavior:

Why It Matters

Although you may rarely need to implement atoi in production code, the problem is valuable for several reasons. First, it tests your ability to parse strings character by character, a foundational skill in text processing. Second, it forces you to think carefully about edge cases, such as empty strings, strings with only whitespace, overflow, and invalid leading characters.

Moreover, many real-world systems rely on safe string-to-number conversion. Configuration files, command-line arguments, and user input forms all require parsing numeric values from text. Understanding how atoi works helps you write more defensive code and avoid subtle bugs related to type coercion and overflow.

Step-by-Step Algorithm

Before writing code, let's break the problem into clear steps. A methodical approach ensures you handle every edge case correctly.

Step 1: Trim Leading Whitespace

Iterate through the string and skip any leading space characters. You can use a loop or the built-in trimStart() method, but for educational purposes, a manual loop is more instructive.

Step 2: Determine the Sign

After skipping whitespace, check if the next character is '+' or '-'. Record the sign and advance the index. If neither is present, assume the number is positive.

Step 3: Read Digits

Continue reading characters as long as they are digits (between '0' and '9'). Build the number by multiplying the current result by 10 and adding the new digit. Stop when you encounter a non-digit character or reach the end of the string.

Step 4: Apply the Sign and Clamp

Apply the recorded sign to the accumulated number. Then check if the result exceeds the 32-bit signed integer bounds. If it does, return the appropriate clamped value.

Complete JavaScript Implementation

Now let's translate the algorithm into JavaScript. The following implementation handles all the rules described above.

/**
 * Converts a string to a 32-bit signed integer (atoi).
 * @param {string} s
 * @return {number}
 */
function myAtoi(s) {
  const INT_MIN = -2147483648;
  const INT_MAX = 2147483647;

  let i = 0;
  let sign = 1;
  let result = 0;
  const n = s.length;

  // Step 1: Skip leading whitespace
  while (i < n && s[i] === ' ') {
    i++;
  }

  // Step 2: Check for optional sign
  if (i < n && (s[i] === '+' || s[i] === '-')) {
    sign = s[i] === '-' ? -1 : 1;
    i++;
  }

  // Step 3: Read digits and build the number
  while (i < n && s[i] >= '0' && s[i] <= '9') {
    const digit = s[i].charCodeAt(0) - '0'.charCodeAt(0);

    // Step 4: Check for overflow before adding the digit
    if (result > Math.floor(INT_MAX / 10) ||
        (result === Math.floor(INT_MAX / 10) && digit > INT_MAX % 10)) {
      return sign === 1 ? INT_MAX : INT_MIN;
    }

    result = result * 10 + digit;
    i++;
  }

  return sign * result;
}

How the Overflow Check Works

The overflow check is the trickiest part. Before appending a new digit, we verify that doing so would not exceed the maximum 32-bit value. We compare result against Math.floor(INT_MAX / 10), which is 214748364. If result is already larger than this, multiplying by 10 will overflow. If result equals this value, we check whether the next digit exceeds 7 (the last digit of 2147483647).

This approach avoids relying on JavaScript's larger number range and keeps the logic faithful to a true 32-bit implementation.

Testing the Implementation

Let's verify the function with several test cases to ensure correctness.

console.log(myAtoi("42"));              // 42
console.log(myAtoi("   -42"));          // -42
console.log(myAtoi("4193 with words")); // 4193
console.log(myAtoi("words and 987"));   // 0
console.log(myAtoi("-91283472332"));    // -2147483648
console.log(myAtoi("3.14159"));         // 3
console.log(myAtoi("+1"));              // 1
console.log(myAtoi("  0000000000012345678")); // 12345678
console.log(myAtoi(""));                // 0
console.log(myAtoi("   "));             // 0

Each test case exercises a different aspect of the algorithm, from basic conversion to overflow clamping and invalid input handling.

Comparing with Built-in Methods

JavaScript offers parseInt() and the Number() constructor, but they behave differently from atoi. Understanding these differences helps you choose the right tool for the job.

// parseInt stops at the first non-digit, similar to atoi
console.log(parseInt("4193 with words")); // 4193

// But parseInt does not clamp to 32-bit range
console.log(parseInt("-91283472332"));    // -91283472332

// Number() is stricter about the entire string
console.log(Number("4193 with words"));   // NaN

As you can see, parseInt() partially mimics atoi but does not enforce the 32-bit boundary. Number() is even stricter and returns NaN for strings with trailing non-numeric content. The custom myAtoi function gives you full control over these behaviors.

Best Practices

When implementing or using string-to-integer conversion, keep these best practices in mind:

  • Always validate input: Check for empty strings, whitespace-only strings, and strings with no valid digits before processing.
  • Handle overflow explicitly: Never assume the input will fit within your target integer range. Clamp or reject values that exceed the bounds.
  • Use character codes for digit extraction: Subtracting the character code of '0' from a digit character is a reliable, locale-independent way to get the numeric value.
  • Avoid floating-point intermediates: Build the integer using only integer arithmetic to prevent precision issues.
  • Write comprehensive tests: Cover edge cases like signs, leading zeros, overflow, underflow, and mixed alphanumeric input.
  • Prefer built-in methods in production: Unless you need custom behavior, parseInt() with a radix argument is usually sufficient and well-optimized.

Using parseInt Safely in Production

If you decide to use the built-in parseInt() in production code, always specify the radix to avoid unexpected behavior with leading zeros.

const value = parseInt(userInput, 10);

if (isNaN(value)) {
  console.error("Invalid number input");
} else {
  // Clamp to 32-bit range if necessary
  const clamped = Math.max(-2147483648, Math.min(2147483647, value));
  console.log(clamped);
}

This pattern combines the convenience of parseInt() with the safety of explicit clamping and validation.

Performance Considerations

The custom myAtoi implementation runs in O(n) time, where n is the length of the input string, and uses O(1) extra space. This is optimal because you must examine each relevant character at least once. The overflow check adds only constant-time comparisons per digit, so it does not affect the overall complexity.

For most applications, this performance is more than sufficient. If you are parsing extremely large volumes of strings, consider using typed arrays or WebAssembly for additional speed, but such optimizations are rarely necessary.

Conclusion

Implementing String to Integer (atoi) in JavaScript is an excellent exercise in careful string parsing and boundary handling. By following the step-by-step algorithm—skipping whitespace, reading the sign, accumulating digits, and clamping to the 32-bit range—you build a robust function that handles all the edge cases the problem demands. While production code can often rely on parseInt() with proper validation, understanding the underlying mechanics of atoi deepens your grasp of type conversion, overflow, and defensive programming. With the implementation and best practices covered in this tutorial, you are well-equipped to solve this problem confidently in interviews and apply its lessons to real-world scenarios.

🛠 Tools from DevBytes

Inventory Tracker Pro — Excel inventory system, low-stock alerts · $19
AI Dev Kit for Mac — local AI dev environment templates · $9.99
KeyMapper for Mac — custom keyboard shortcut toolkit · $7.99

← Back to all articles