漢数字を数値に変換する(DSLっぽく)
d:id:terazzo:20101212:1292147950のやつ、実は先にJavaで書いてみてた。
メソッドとかは一つずつ定義している。実装の方はProxy使えば少しだけ短くなるかもしれない。
使い方
本当に使うんならちゃんとPOJOクラスにしよう。あと修飾子もちゃんと付けて。
import static sample.janumber.JaNumberTest.*; ... long result = 三.億().四().千().九().百().万().二().百().三().longValue(); assertEquals("三億四千九百万二百三 == 349000203", 349000203L, result); // true!
ソースコードの簡単な説明
- 見やすくする為にアクセス指定はなるべく消している
- 見やすさのためなので、パッケージプライベートにしている意図は無い
- メソッドは数字ひとつずつ定義している。
- 最初の一文字は定数になっているので、import staticして使えるなど
- 位によって続けられる文字が違うので、その辺はインタフェースで表現している。
- 一応「三五」とか「億万」とかはコンパイル時にエラーになる
- 「百二千」とかは書けてしまう。「二千百」と同じになる。
- インタフェース細分化すれば型チェックではじけそうではある。
- Rubyではクロージャっぽく書いたところもJavaではクラスを分けてコンストラクタの引数で渡している
- Javaでも匿名内部クラスで無理に書けなくはない。
ソースコード
例によって1ファイルで動かしやすくする為にJUnitのテスト内部で作成。
package sample.janumber; import junit.framework.TestCase; public class JaNumberTest extends TestCase { /**一〜九が続けられる位置 */ public interface DigitAcceptable { DigitResult 一(); DigitResult 二(); DigitResult 三(); DigitResult 四(); DigitResult 五(); DigitResult 六(); DigitResult 七(); DigitResult 八(); DigitResult 九(); } /** 十、百、千が続けられる位置 */ public interface ClassAcceptable { ClassResult 十(); ClassResult 百(); ClassResult 千(); } /** 万、億、兆、...が続けられる位置 */ public interface UnitAcceptable { UnitResult 万(); UnitResult 億(); UnitResult 兆(); } /** 基本的にLongに変換可能 */ public interface JaNumber { long longValue(); } /** 一から九の後は 十、百、千 or 万、億、兆が続く */ public interface DigitResult extends JaNumber, ClassAcceptable, UnitAcceptable { } /** 十、百、千の後は 何が来ても良い */ public interface ClassResult extends JaNumber, DigitAcceptable, ClassAcceptable, UnitAcceptable { } /** 万、億、兆の後は 一から九 or 十、百、千が続く */ public interface UnitResult extends JaNumber, DigitAcceptable, ClassAcceptable { } /** 漢数字の抽象スーパークラス */ abstract static class Base { /** 一つ前の数字を保持してリストを作る */ private Base previous; /** コンストラクタ */ Base(Base previous) { super(); this.previous = previous; } Base getPrevious() { return previous; } /** 万、億、兆、...単位の合計値を戻す */ abstract long unitValue(); /** 十、百、千単位の合計値を戻す */ abstract int classValue(); /** 一〜九単位の合計値を戻す */ abstract int digitValue(); /** long値として取り出す */ public long longValue() { return unitValue() + classValue() + digitValue(); } /** * 仮にbase(「万」=10000, 「十」10など)が続いた場合のclassValue。 * 桁の値が二でbaseが10だとすると二十になる。 * 桁の値が千でbaseが10だとすると千十になる。 * @param base 呼び出し側の数字の単位(例: 千なら1000) */ abstract int classValueWith(int base); /* これ以下は各漢数字用のメソッドの定義 */ public DigitResult 一() { return new DigitResultImpl(1, this); } public DigitResult 二() { return new DigitResultImpl(2, this); } public DigitResult 三() { return new DigitResultImpl(3, this); } public DigitResult 四() { return new DigitResultImpl(4, this); } public DigitResult 五() { return new DigitResultImpl(5, this); } public DigitResult 六() { return new DigitResultImpl(6, this); } public DigitResult 七() { return new DigitResultImpl(7, this); } public DigitResult 八() { return new DigitResultImpl(8, this); } public DigitResult 九() { return new DigitResultImpl(9, this); } public ClassResult 十() { return new ClassResultImpl(10, this); } public ClassResult 百() { return new ClassResultImpl(100, this); } public ClassResult 千() { return new ClassResultImpl(1000, this); } public UnitResult 万() { return new UnitResultImpl(10000, this); } public UnitResult 億() { return new UnitResultImpl(10000 * 10000, this); } public UnitResult 兆() { return new UnitResultImpl(10000 * 10000 * 10000, this); } } /** 一から九用のクラス */ static class DigitResultImpl extends Base implements DigitResult { private int digit; /** コンストラクタ。 */ DigitResultImpl(int digit, Base previous) { super(previous); this.digit = digit; } long unitValue() { return getPrevious().unitValue(); } int classValue() { return getPrevious().classValue(); } int digitValue() { return digit; } int classValueWith(int base) { return getPrevious().classValue() + base * digitValue(); } } /** 十、百、千用のクラス */ static class ClassResultImpl extends Base implements ClassResult { private int base; ClassResultImpl(int base, Base previous) { super(previous); this.base = base; } long unitValue() { return getPrevious().unitValue(); } int classValue() { return getPrevious().classValueWith(base); } int digitValue() { return 0; } int classValueWith(int base) { return classValue() + base; } } static class UnitResultImpl extends Base implements UnitResult { private long base; UnitResultImpl(long base, Base previous) { super(previous); this.base = base; } long unitValue() { return getPrevious().unitValue() + base * (getPrevious().classValue() + getPrevious().digitValue()); } int classValue() { return 0; } int digitValue() { return 0; } int classValueWith(int base) { return base; } } /** 最初の一文字用のオブジェクト。 */ private static final UnitResult BASE = new UnitResultImpl(0, null) { long unitValue() { return 0; } }; /** 最初の一文字は定数で用意しておく */ public static final DigitResult 一 = BASE.一(); public static final DigitResult 二 = BASE.二(); public static final DigitResult 三 = BASE.三(); public static final DigitResult 四 = BASE.四(); public static final DigitResult 五 = BASE.五(); public static final DigitResult 六 = BASE.六(); public static final DigitResult 七 = BASE.七(); public static final DigitResult 八 = BASE.八(); public static final DigitResult 九 = BASE.九(); public static final ClassResult 十 = BASE.十(); public static final ClassResult 百 = BASE.百(); public static final ClassResult 千 = BASE.千();
テスト
上の続きで
public void test3() { long result = 三.longValue(); assertEquals("三==3", 3, result); } public void test10() { long result = 十.longValue(); assertEquals("十==10", 10, result); } public void test30() { long result = 三.十().longValue(); assertEquals("三十==30", 30, result); } public void test13() { long result = 十.三().longValue(); assertEquals("十三==13", 13, result); } public void test33() { long result = 三.十().三().longValue(); assertEquals("三十三==33", 33, result); } public void test100() { long result = 百.longValue(); assertEquals("百==100", 100, result); } public void test103() { long result = 百.三().longValue(); assertEquals("百三==103", 103, result); } public void test113() { long result = 百.十().三().longValue(); assertEquals("百十三==113", 113, result); } public void test130() { long result = 百.三().十().longValue(); assertEquals("百三十==130", 130, result); } public void test133() { long result = 百.三().十().三().longValue(); assertEquals("百三十三==133", 133, result); } public void test1000() { long result = 千.longValue(); assertEquals("千==1000", 1000, result); } public void test1003() { long result = 千.三().longValue(); assertEquals("千三==1003", 1003, result); } public void test1013() { long result = 千.十().三().longValue(); assertEquals("千十三==1013", 1013, result); } public void test1033() { long result = 千.三().十().三().longValue(); assertEquals("千三十三==1033", 1033, result); } public void test3013() { long result = 三.千().十().三().longValue(); assertEquals("三千十三==3013", 3013, result); } public void test3033() { long result = 三.千().三().十().三().longValue(); assertEquals("三千三十三==3033", 3033, result); } public void test3303() { long result = 三.千().三().百().三().longValue(); assertEquals("三千三百三==3303", 3303, result); } public void test3300() { long result = 三.千().三().百().longValue(); assertEquals("三千三百==3300", 3300, result); } public void test3333() { long result = 三.千().三().百().三().十().三().longValue(); assertEquals("三千三百三十三==3333", 3333, result); } public void test10000() { long result = 三.万().longValue(); assertEquals("三万==30000", 30000, result); } public void test10003() { long result = 三.万().三().longValue(); assertEquals("三万三==30003", 30003, result); } public void test10013() { long result = 三.万().十().三().longValue(); assertEquals("三万十三==300013", 30013, result); } public void test10030() { long result = 三.万().三().十().longValue(); assertEquals("三万三十==30030", 30030, result); } public void test10033() { long result = 三.万().三().十().三().longValue(); assertEquals("三万三十三==30033", 30033, result); } public void test349000203() { long result = 三.億().四().千().九().百().万().二().百().三().longValue(); assertEquals("三億四千九百万二百三==349000203", 349000203L, result); } }