Lisp vs. Java???

via http://www.kmonos.net/alang/d/2.0/lisp-java-d.html
なんだか、LispJavaC++ より優れた結果を残しているようなので、自分も挑戦してみました。
とりあえず問題を見て入力をみたり出力を確認したりしながら、1時間半ほどで以下のコードが書けました。空行やコメント、unittest、(Lispと合わせて) 末尾の閉じ括弧 } を除くと、77行でした。Link先のDで書いたほうが短くなってますね。やっていることは単純に、前のほうから一致する単語を探索していくだけです。気をつけるのは、数字は1文字だけならそのまま使っても良い、と言うところくらいですかね?
Javaでもこれくらいはできるぞ、と誰かに言いたくなったのでEntryを起こしちゃいました。

package ch.jpn.taoe.challenge;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;

import org.junit.Test;

public class PhoneToWord {
	/////                                ABCDEFGHIJKLMNOPQRSTUVWXYZ
	private static final char[] TABLE = "57630499617851881234762239".toCharArray();

	private final Map<String, List<String>> dictionary_ = new HashMap<String, List<String>>();

	public PhoneToWord() {
	}

	public void addWord(String word) {
		String key = wordToNumber(word);
		List<String> list = dictionary_.get(key);
		if (list == null) {
			list = new ArrayList<String>();
			dictionary_.put(key, list);
		}
		list.add(word);
	}

	public String[] convertToWords(String input) {
		List<String> search = new ArrayList<String>();
		search.add("");
		matchWords(wordToNumber(input), 0, false, search);

		String[] result = new String[search.size()];
		for (int index = 0; index < result.length; index++) {
			result[index] = String.format("%s:%s", input, search.get(index));
		}
		return result;
	}
	private boolean matchWords(String input, int offset, boolean useNumber, List<String> result) {
//System.out.println("matchWords:" + input + ", offset=" + offset + ", useNum=" + useNumber + ", " + result);
		if (offset >= input.length()) return true;
		boolean matched = false;
		List<String> matchedResult = new ArrayList<String>();
		for (String key: dictionary_.keySet()) {
			if (!input.startsWith(key, offset)) {
				continue;
			}

			List<String> work = new ArrayList<String>();
			for (String word: result) {
				for (String add: dictionary_.get(key)) {
					work.add(word + " " + add);
				}
			}
			boolean res = matchWords(input, offset + key.length(), false, work);
			if (res) {
				matched = true;
				matchedResult.addAll(work);
			}
		}
		if (!matched && !useNumber) {
			char c = input.charAt(offset);
			List<String> work = new ArrayList<String>();
			for (String word: result) {
				work.add(word + " " + c);
			}
			boolean res = matchWords(input, offset + 1, true, work);
			if (res) {
				matched = true;
				matchedResult.addAll(work);
			}
		}
//System.out.println(matched + ", " + matchedResult);
		result.clear();
		result.addAll(matchedResult);
		return matched;
	}

	private String wordToNumber(String word) {
		StringBuilder builder = new StringBuilder();
		for (int index = 0, length = word.length(); index < length; index++) {
			char c = word.charAt(index);
			if ('0' <= c && c <= '9') {
				builder.append(c);
			} else if ('a' <= c && c <= 'z') {
				builder.append(TABLE[c - 'a']);
			} else if ('A' <= c && c <= 'Z') {
				builder.append(TABLE[c - 'A']);
			}
		}
		return builder.toString();
	}


	@Test
	public void testCheckLetter() {
		assertEquals("", wordToNumber(""));
		assertEquals("01112223334455666777888999", wordToNumber("e | j n q | r w x | d s y | f t | a m | c i v | b k u | l o p | g h z"));
		assertEquals("01112223334455666777888999", wordToNumber("E | J N Q | R W X | D S Y | F T | A M | C I V | B K U | L O P | G H Z"));
		assertEquals("0123456789",                 wordToNumber("0 |   1   |   2   |   3   |  4  |  5  |   6   |   7   |   8   |   9"));
	}

	@Test
	public void testAddData() {
		PhoneToWord test = new PhoneToWord();
		for (String word: new String[] {"an", "blau", "Bo\"", "Boot", "bo\"s", "da", "Fee", "fern", "Fest", "fort", "je", "jemand", "mir", "Mix", "Mixer", "Name", "neu", "o\"d", "Ort", "so", "Tor", "Torf", "Wasser"}) {
			test.addWord(word);
		}
		List<String> list = test.dictionary_.get("51");
		assertNotNull(list);
		assertEquals(1, list.size());
		assertEquals("an", list.get(0));

		list = test.dictionary_.get("562");
		assertEquals(2, list.size());
		assertEquals("mir", list.get(0));
		assertEquals("Mix", list.get(1));
	}

	@Test
	public void testConvertToWords() {
		PhoneToWord test = new PhoneToWord();
		for (String word: new String[] {"an", "blau", "Bo\"", "Boot", "bo\"s", "da", "Fee", "fern", "Fest", "fort", "je", "jemand", "mir", "Mix", "Mixer", "Name", "neu", "o\"d", "Ort", "so", "Tor", "Torf", "Wasser"}) {
			test.addWord(word);
		}

		assertArrayEquals(new String[] {
		}, test.convertToWords("112"));

		assertArrayEquals(new String[] {
				"5624-82: mir Tor",
				"5624-82: Mix Tor"
		}, test.convertToWords("5624-82"));

		assertArrayEquals(new String[] {
				"4824: fort",
				"4824: Torf",
				"4824: Tor 4",
		}, test.convertToWords("4824"));

		assertArrayEquals(new String[] {
		}, test.convertToWords("0721/608-4067"));

		assertArrayEquals(new String[] {
				"10/783--5: je Bo\" da",
				"10/783--5: je bo\"s 5",
				"10/783--5: neu o\"d 5",
		}, test.convertToWords("10/783--5"));

		assertArrayEquals(new String[] {
		}, test.convertToWords("1078-913-5"));

		assertArrayEquals(new String[] {
				"381482: so 1 Tor"
		}, test.convertToWords("381482"));

		assertArrayEquals(new String[] {
				"04824: 0 fort",
				"04824: 0 Torf",
				"04824: 0 Tor 4",
		}, test.convertToWords("04824"));
	}


	public static void main(String[] args) throws Exception {
		PhoneToWord test = new PhoneToWord();
		Scanner dict = new Scanner(new File("dictionary.txt"));
		while (dict.hasNext()) {
			test.addWord(dict.nextLine());
		}

		Scanner input = new Scanner(new File("input.txt"));
		while (input.hasNext()) {
			String[] result = test.convertToWords(input.nextLine());
			for (String s: result) {
				System.out.println(s);
			}
		}
	}
}