エクセルなんて大嫌いだ!

えーと、お久しぶりです。タイトルは某吾朗さん*1の映画のヒロインの如く読んでください。

こちらにあったお題を解いてみました。
大体テスト、リファクタリング込みで1時間弱くらいだったような気がします。

でもPerlじゃなくてJavaなんだな。これが。*2


出来上がったもの

package org.excel;

import java.util.HashMap;
import java.util.Map;

public class RowCalc {
	private static final Map<Character, Integer>	m1	= new HashMap<>();
	private static final Map<Integer, Character>	m2	= new HashMap<>();
	private static final int						LEN	= 26;
	static {
		char c = 'A';
		for (int i = 1; i < LEN + 1; i++) {
			m1.put(c, i);
			m2.put(i, c);
			c++;
		}
	}

	public int AlphabetToNum(String alphabet) {
		int ret = 0;
		final String _alphabet = new StringBuilder(alphabet).reverse().toString();
		for (int i = 0; i < _alphabet.length(); i++) {
			ret += m1.get(_alphabet.charAt(i)) * Math.pow(LEN, i);
		}
		return ret;
	}

	public String NumToAlphabet(int num) {
		final StringBuilder sb = new StringBuilder();
		int key = 0;
		while (num > 0) {
			key = num % LEN;
			num = num / LEN;
			if (key == 0) {
				key = LEN;
				num--;
			}
			sb.append(m2.get(key));
		}
		return sb.reverse().toString();
	}
}


テストコード

package org.excel;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

import org.junit.Test;

public class RowCalcTest {
	@Test
	public final void アルファベットから数字() {
		final RowCalc rc = new RowCalc();
		assertThat(rc.AlphabetToNum("A"), is(1));
		assertThat(rc.AlphabetToNum("Z"), is(26));
		assertThat(rc.AlphabetToNum("AA"), is(27));
		assertThat(rc.AlphabetToNum("IV"), is(256));
		assertThat(rc.AlphabetToNum("DW"), is(127));
		assertThat(rc.AlphabetToNum("XFD"), is(16384));
		assertThat(rc.AlphabetToNum("ZZ"), is(702));
	}

	@Test
	public final void 数字からアルファベット() {
		final RowCalc rc = new RowCalc();
		assertThat(rc.NumToAlphabet(1), is("A"));
		assertThat(rc.NumToAlphabet(27), is("AA"));
		assertThat(rc.NumToAlphabet(256), is("IV"));
		assertThat(rc.NumToAlphabet(16384), is("XFD"));
		assertThat(rc.NumToAlphabet(127), is("DW"));
		assertThat(rc.NumToAlphabet(26), is("Z"));
		assertThat(rc.NumToAlphabet(702), is("ZZ"));
	}

	public final void 相互でやってみた() {
		final RowCalc rc = new RowCalc();
		assertThat(rc.NumToAlphabet(rc.AlphabetToNum("A")), is("A"));
		assertThat(rc.NumToAlphabet(rc.AlphabetToNum("AZ")), is("AZ"));
		assertThat(rc.NumToAlphabet(rc.AlphabetToNum("BA")), is("BA"));
		assertThat(rc.NumToAlphabet(rc.AlphabetToNum("Z")), is("Z"));
		assertThat(rc.NumToAlphabet(rc.AlphabetToNum("AA")), is("AA"));
		assertThat(rc.NumToAlphabet(rc.AlphabetToNum("ZZ")), is("ZZ"));
		assertThat(rc.NumToAlphabet(rc.AlphabetToNum("ZAZ")), is("ZAZ"));
	}
}

この問題の最大のポイントは基数変換かなと。
要は26番目のZが出てきたときに繰り上がりがないのでどうするの?ってお話。
なので自分はこうしてみました。

key = num % LEN;
num = num / LEN;
if (key == 0) {
	key = LEN;
	num--;
}


要は繰り上がるところを繰り上げないで処理してるみたいな感じにしてます。*3
あと、「ただし、問題1で作ったプログラムを拡張すること。」って条件は恐らく満たしてない時点で色々アレ。

*1:TMAじゃないよ!

*2:なんていうか不勉強でゴメンナサイ。

*3:すごくローテクでゴメンナサイ…。