Chapter 9: Strings and Character Processing
9.07Beginner / Intermediate5 topics16 min5 interactive animations

String-to-number parsing

Turning text into numbers safely: integer parsing, negative numbers, base conversion, overflow checks and tokenization. Real parsers must handle signs, bad characters and values outside the int range.

Learning goals

  • Parse integers manually with correct sign handling
  • Detect overflow while parsing
  • Convert numbers between bases
  • Tokenize input into numbers

Prerequisites

Core operationsNumeric correctness
9.07.1

Integer parsing

Parsing an integer reads digits left to right, updating value = value * 10 + digit, where the digit is c - '0'. Reject empty input, a sign with no digits and any non-digit character. Integer.parseInt throws NumberFormatException for all of these, and for leading or trailing spaces.

Parse your own text in the animation and watch the value build up.

Java
1int a = Integer.parseInt("1204"); // 1204
2int b = Integer.parseInt("+45"); // 45: a plus sign is accepted
3int c = Integer.parseInt("007"); // 7: leading zeros are fine
4// Integer.parseInt(" 7") and Integer.parseInt("") throw NumberFormatException

Parsing an int by hand (sign, digits, overflow)

Interactive · edit the input

Your input

Try

char[] s · length 5

-
1
2
0
4
01234
ReadingConsumedRejected
Setup

Read an optional sign, then digits left to right: value = value * 10 + digit. Accumulate in a long so overflow can be detected.

Step 1 / 7
Java
1static int parseInt(String s) {
2 int i = 0, sign = 1;
3 if (s.charAt(0) == '-' || s.charAt(0) == '+') { if (s.charAt(0) == '-') sign = -1; i = 1; }
4 if (i == s.length()) throw new NumberFormatException(s); // a sign alone
5 long value = 0;
6 for (; i < s.length(); i++) {
7 int d = s.charAt(i) - '0';
8 if (d < 0 || d > 9) throw new NumberFormatException(s); // not a digit
9 value = value * 10 + d;
10 if (sign * value > Integer.MAX_VALUE || sign * value < Integer.MIN_VALUE) throw new NumberFormatException(s); // overflow
11 }
12 return (int) (sign * value);
13}

Live state

i

0

sign

1

value

0

No condition evaluated on this step
Execution trace (dry run table)Show 7 steps
StepLineStateWhat happens
1L2i=0 sign=1 value=0Read an optional sign, then digits left to right: value = value * 10 + digit. Accumulate in a long so overflow can be detected.
2L3i=1 sign=-1'-' is a sign: sign = -1. Digits start at index 1.
3L10i=1 digit=1 value=1 sign * value=-1value = previous * 10 + 1 = 1.
4L10i=2 digit=2 value=12 sign * value=-12value = previous * 10 + 2 = 12.
5L10i=3 digit=0 value=120 sign * value=-120value = previous * 10 + 0 = 120.
6L10i=4 digit=4 value=1204 sign * value=-1204value = previous * 10 + 4 = 1204.
7L12return=-1204Parsed -1204. Note the smallest int works because the magnitude 2147483648 is compared after applying the sign.
9.07.2

Negative numbers

Handle an optional leading '-' (or '+') before the digits and apply the sign at the end: the sign is a separate variable, not part of the digit loop. The most negative int, -2147483648, has no positive counterpart, so a parser that parses the magnitude into an int fails on it; accumulate in a long or in negative form.

Try the smallest-int preset: the magnitude 2147483648 does not fit, but the signed value does.

Java
1int min = Integer.parseInt("-2147483648"); // fine: Integer.MIN_VALUE
2int abs = Math.abs(Integer.MIN_VALUE); // still -2147483648: no positive counterpart

Parsing an int by hand (sign, digits, overflow)

Interactive · edit the input

Your input

Try

char[] s · length 5

-
1
2
0
4
01234
ReadingConsumedRejected
Setup

Read an optional sign, then digits left to right: value = value * 10 + digit. Accumulate in a long so overflow can be detected.

Step 1 / 7
Java
1static int parseInt(String s) {
2 int i = 0, sign = 1;
3 if (s.charAt(0) == '-' || s.charAt(0) == '+') { if (s.charAt(0) == '-') sign = -1; i = 1; }
4 if (i == s.length()) throw new NumberFormatException(s); // a sign alone
5 long value = 0;
6 for (; i < s.length(); i++) {
7 int d = s.charAt(i) - '0';
8 if (d < 0 || d > 9) throw new NumberFormatException(s); // not a digit
9 value = value * 10 + d;
10 if (sign * value > Integer.MAX_VALUE || sign * value < Integer.MIN_VALUE) throw new NumberFormatException(s); // overflow
11 }
12 return (int) (sign * value);
13}

Live state

i

0

sign

1

value

0

No condition evaluated on this step
Execution trace (dry run table)Show 7 steps
StepLineStateWhat happens
1L2i=0 sign=1 value=0Read an optional sign, then digits left to right: value = value * 10 + digit. Accumulate in a long so overflow can be detected.
2L3i=1 sign=-1'-' is a sign: sign = -1. Digits start at index 1.
3L10i=1 digit=1 value=1 sign * value=-1value = previous * 10 + 1 = 1.
4L10i=2 digit=2 value=12 sign * value=-12value = previous * 10 + 2 = 12.
5L10i=3 digit=0 value=120 sign * value=-120value = previous * 10 + 0 = 120.
6L10i=4 digit=4 value=1204 sign * value=-1204value = previous * 10 + 4 = 1204.
7L12return=-1204Parsed -1204. Note the smallest int works because the magnitude 2147483648 is compared after applying the sign.
9.07.3

Base conversion

To write n in base b, repeatedly take the remainder n % b as the next digit (least significant first) and divide by b until n is 0, then reverse the digits. To read a string in base b use value = value * b + digit. Java provides Integer.toString(n, radix), Integer.toBinaryString, toHexString and Integer.parseInt(s, radix).

Convert a number in the animation; the digits come out in reverse order.

Java
1static String toBase(int n, int base) {
2 if (n == 0) return "0";
3 StringBuilder sb = new StringBuilder();
4 while (n > 0) { sb.append(Character.forDigit(n % base, base)); n /= base; }
5 return sb.reverse().toString();
6}
7String bin = Integer.toBinaryString(156); // "10011100"
8int hex = Integer.parseInt("ff", 16); // 255

Converting a number to another base

Interactive · edit the input

Your input

Try

digits so far (least significant first)

none yet
Setup

Repeatedly divide by 2: the remainders are the digits, starting from the least significant.

Step 1 / 10
Java
1static String toBase(int n, int base) { // n >= 0
2 if (n == 0) return "0";
3 StringBuilder sb = new StringBuilder();
4 while (n > 0) {
5 int digit = n % base;
6 sb.append(Character.forDigit(digit, base));
7 n /= base;
8 }
9 return sb.reverse().toString(); // digits come out least significant first
10}

Live state

n

156

base

2

No condition evaluated on this step
Execution trace (dry run table)Show 10 steps
StepLineStateWhat happens
1L3n=156 base=2Repeatedly divide by 2: the remainders are the digits, starting from the least significant.
2L6n=156 n % base=0 digit=0156 % 2 = 0; 156 / 2 = 78.
3L6n=78 n % base=0 digit=078 % 2 = 0; 78 / 2 = 39.
4L6n=39 n % base=1 digit=139 % 2 = 1; 39 / 2 = 19.
5L6n=19 n % base=1 digit=119 % 2 = 1; 19 / 2 = 9.
6L6n=9 n % base=1 digit=19 % 2 = 1; 9 / 2 = 4.
7L6n=4 n % base=0 digit=04 % 2 = 0; 4 / 2 = 2.
8L6n=2 n % base=0 digit=02 % 2 = 0; 2 / 2 = 1.
9L6n=1 n % base=1 digit=11 % 2 = 1; 1 / 2 = 0.
10L9return="10011100"Reverse the collected digits: 156 in base 2 is "10011100". Integer.toString(156, 2) does the same.
9.07.4

Overflow checks

Multiplying by 10 can overflow an int silently. Check before or after each step: accumulate in a long and compare with Integer.MAX_VALUE and MIN_VALUE, or test value > (Integer.MAX_VALUE - digit) / 10 before updating. Math.multiplyExact and Math.addExact throw ArithmeticException on overflow.

Parse 2147483648 in the animation: the check fires on the last digit.

Java
1static int parsePositive(String s) {
2 int value = 0;
3 for (char c : s.toCharArray()) {
4 int d = c - '0';
5 if (value > (Integer.MAX_VALUE - d) / 10) throw new ArithmeticException("overflow");
6 value = value * 10 + d;
7 }
8 return value;
9}

Parsing an int by hand (sign, digits, overflow)

Interactive · edit the input

Your input

Try

char[] s · length 5

-
1
2
0
4
01234
ReadingConsumedRejected
Setup

Read an optional sign, then digits left to right: value = value * 10 + digit. Accumulate in a long so overflow can be detected.

Step 1 / 7
Java
1static int parseInt(String s) {
2 int i = 0, sign = 1;
3 if (s.charAt(0) == '-' || s.charAt(0) == '+') { if (s.charAt(0) == '-') sign = -1; i = 1; }
4 if (i == s.length()) throw new NumberFormatException(s); // a sign alone
5 long value = 0;
6 for (; i < s.length(); i++) {
7 int d = s.charAt(i) - '0';
8 if (d < 0 || d > 9) throw new NumberFormatException(s); // not a digit
9 value = value * 10 + d;
10 if (sign * value > Integer.MAX_VALUE || sign * value < Integer.MIN_VALUE) throw new NumberFormatException(s); // overflow
11 }
12 return (int) (sign * value);
13}

Live state

i

0

sign

1

value

0

No condition evaluated on this step
Execution trace (dry run table)Show 7 steps
StepLineStateWhat happens
1L2i=0 sign=1 value=0Read an optional sign, then digits left to right: value = value * 10 + digit. Accumulate in a long so overflow can be detected.
2L3i=1 sign=-1'-' is a sign: sign = -1. Digits start at index 1.
3L10i=1 digit=1 value=1 sign * value=-1value = previous * 10 + 1 = 1.
4L10i=2 digit=2 value=12 sign * value=-12value = previous * 10 + 2 = 12.
5L10i=3 digit=0 value=120 sign * value=-120value = previous * 10 + 0 = 120.
6L10i=4 digit=4 value=1204 sign * value=-1204value = previous * 10 + 4 = 1204.
7L12return=-1204Parsed -1204. Note the smallest int works because the magnitude 2147483648 is compared after applying the sign.
9.07.5

Tokenization

Tokenization splits input into meaningful pieces. For numbers separated by whitespace use split("\\s+") (after trim()), StringTokenizer, or Scanner. Handle empty tokens: a leading delimiter yields an empty first token, and consecutive delimiters give empty tokens unless the regex absorbs runs.

Try the whitespace-run preset.

Java
1String line = " 12 -7 30 ";
2String[] parts = line.trim().split("\\s+"); // [12, -7, 30]
3int[] nums = Arrays.stream(parts).mapToInt(Integer::parseInt).toArray();
4long sum = Arrays.stream(nums).asLongStream().sum(); // 35

split: how a string becomes tokens

Interactive · edit the input

Your input

Try

char[] s · length 8

a
,
b
,
,
c
,
,
01234567
ReadingDelimiterPart of a token

tokens

none yet
Setup

Every comma ends a token. Two commas in a row make an empty token.

Step 1 / 11
Java
1static List<String> split(String s, char delim) {
2 List<String> out = new ArrayList<>();
3 StringBuilder cur = new StringBuilder();
4 for (char c : s.toCharArray()) {
5 if (c == delim) { out.add(cur.toString()); cur.setLength(0); } // delimiter: close the token
6 else cur.append(c);
7 }
8 out.add(cur.toString()); // the last token, possibly empty
9 return out; // String.split(regex) then drops trailing empty tokens
10}

Live state

No condition evaluated on this step
Execution trace (dry run table)Show 11 steps
StepLineStateWhat happens
1L2Every comma ends a token. Two commas in a row make an empty token.
2L6i=0 current="a"Append 'a' to the current token.
3L5i=1 token="a"Delimiter: close the token "a".
4L6i=2 current="b"Append 'b' to the current token.
5L5i=3 token="b"Delimiter: close the token "b".
6L5i=4 token=""Delimiter with nothing before it: an empty token is added.
7L6i=5 current="c"Append 'c' to the current token.
8L5i=6 token="c"Delimiter: close the token "c".
9L5i=7 token=""Delimiter with nothing before it: an empty token is added.
10L8token=""End of input: add the last token "" (empty).
11L9return=["a", "b", "", "c"] length=4Java's split removes trailing empty tokens (but keeps leading and inner ones): 4 tokens.

Practice ladder

Now try it yourself

Easy

  • Parse "-1204" by hand with value = value * 10 + digit
  • Convert 255 to hexadecimal and binary

Medium

  • Why does parsing the magnitude of -2147483648 into an int fail?
  • Write parsePositive that rejects overflow

Advanced

  • Implement atoi with whitespace, sign and clamping on overflow

Key takeaways

  • Digits are c - '0'; accumulate value * 10 + digit and apply the sign separately.
  • Accumulate in long or check before multiplying to catch overflow.
  • Base conversion uses repeated remainders; split with a regex handles whitespace runs.