LocalCellAddressParser { public LocalCellRef parse(final String address) throws ParseException { int status = 0; int col = 0; int row = 0; int state = BEGIN_COL; for (int i = 0; i < address.length(); i++) { final char c = address.charAt(i); switch (state) { case BEGIN_COL: if (c == LocalCellRef.ABS_SIGN) { status |= LocalCellRef.ABSOLUTE_COL; } else if ('A' <= c && c <= 'Z') { col = c - 'A' + 1; state = LocalCellAddressParser.OPT_LETTER; } else { throw this.parseException("Expected letter or $", address, i, c); } break; case BEGIN_ROW: if (c == LocalCellRef.ABS_SIGN) { status |= LocalCellRef.ABSOLUTE_ROW; } else if ('1' <= c && c <= '9') { row = c - '0'; state = LocalCellAddressParser.OPT_DIGIT; } else { throw this.parseException("Expected digit (not 0) or $", address, i, c); } break; case OPT_LETTER: if ('A' <= c && c <= 'Z') { col = col * PositionUtil.ALPHABET_SIZE + c - PositionUtil.ORD_A + 1; } else { state = LocalCellAddressParser.BEGIN_ROW; i--; continue; } break; case OPT_DIGIT: if ('0' <= c && c <= '9') { row = row * 10 + c - '0'; } else { throw this.parseException("Expected digit", address, i, c); } break; default: throw this.parseException("Unexpected error", address, i, c); } } if (state != OPT_DIGIT) { throw new ParseException( String.format("Address too short, expected digit: %s[]", address), address.length()); } return new LocalCellRef(row - 1, col - 1, status); }  LocalCellRef parse(final String address);  }
@Test public void testA2() throws ParseException { Assert.assertEquals(new LocalCellRef(1, 0, 0), this.parser.parse("A2")); }
@Test public void testdB3() throws ParseException { Assert.assertEquals(new LocalCellRef(2, 1, 1), this.parser.parse("$B3")); }
@Test public void testCd4() throws ParseException { Assert.assertEquals(new LocalCellRef(3, 2, 2), this.parser.parse("C$4")); }
@Test public void testdDd5() throws ParseException { Assert.assertEquals(new LocalCellRef(4, 3, 3), this.parser.parse("$D$5")); }
@Test public void testA0() throws ParseException { this.exception.expect(ParseException.class); this.exception.expectMessage("Expected digit (not 0) or $: A[0]"); this.parser.parse("A0"); }
@Test public void test0A() throws ParseException { this.exception.expect(ParseException.class); this.exception.expectMessage("Expected letter or $: [0]A"); this.parser.parse("0A"); }
@Test public void testA1A() throws ParseException { this.exception.expect(ParseException.class); this.exception.expectMessage("Expected digit: A1[A]"); this.parser.parse("A1A"); }
@Test public void testShort() throws ParseException { this.exception.expect(ParseException.class); this.exception.expectMessage("Address too short, expected digit: $D$[]"); this.parser.parse("$D$"); }
@Test public void testWrongChar() throws ParseException { this.exception.expect(ParseException.class); this.exception.expectMessage("Expected digit (not 0) or $: $D[.]$5"); this.parser.parse("$D.$5"); }