]> source.dussan.org Git - poi.git/commitdiff
translate almost any number to english and roman letters
authorSergey Vladimirov <sergey@apache.org>
Wed, 17 Aug 2011 13:47:51 +0000 (13:47 +0000)
committerSergey Vladimirov <sergey@apache.org>
Wed, 17 Aug 2011 13:47:51 +0000 (13:47 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1158701 13f79535-47bb-0310-9956-ffa450edef68

src/scratchpad/src/org/apache/poi/hwpf/converter/NumberFormatter.java
src/scratchpad/testcases/org/apache/poi/hwpf/converter/TestNumberFormatter.java [new file with mode: 0644]

index e5c7b32f087c541c9f5f1d0538826a9e9ffa0035..42a72a9d945b0e998527e6f30cc320163637302f 100644 (file)
@@ -22,49 +22,117 @@ package org.apache.poi.hwpf.converter;
 import org.apache.poi.util.Beta;
 
 /**
- * Comment me
+ * Utility class to translate numbers in letters, usually for lists.
  * 
- * @author Ryan Ackley
+ * @author Sergey Vladimirov (vlsergey {at} gmail {dot} com)
  */
 @Beta
 public final class NumberFormatter
 {
 
-    private static String[] C_LETTERS = new String[] { "a", "b", "c", "d", "e",
-            "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r",
-            "s", "t", "u", "v", "x", "y", "z" };
-
-    private static String[] C_ROMAN = new String[] { "i", "ii", "iii", "iv",
-            "v", "vi", "vii", "viii", "ix", "x", "xi", "xii", "xiii", "xiv",
-            "xv", "xvi", "xvii", "xviii", "xix", "xx", "xxi", "xxii", "xxiii",
-            "xxiv", "xxv", "xxvi", "xxvii", "xxviii", "xxix", "xxx", "xxxi",
-            "xxxii", "xxxiii", "xxxiv", "xxxv", "xxxvi", "xxxvii", "xxxvii",
-            "xxxviii", "xxxix", "xl", "xli", "xlii", "xliii", "xliv", "xlv",
-            "xlvi", "xlvii", "xlviii", "xlix", "l" };
-
-    private final static int T_ARABIC = 0;
-    private final static int T_LOWER_LETTER = 4;
-    private final static int T_LOWER_ROMAN = 2;
-    private final static int T_ORDINAL = 5;
-    private final static int T_UPPER_LETTER = 3;
-    private final static int T_UPPER_ROMAN = 1;
+    private static final String[] ENGLISH_LETTERS = new String[] { "a", "b",
+            "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o",
+            "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" };
+
+    private static final String[] ROMAN_LETTERS = { "m", "cm", "d", "cd", "c",
+            "xc", "l", "xl", "x", "ix", "v", "iv", "i" };
+
+    private static final int[] ROMAN_VALUES = { 1000, 900, 500, 400, 100, 90,
+            50, 40, 10, 9, 5, 4, 1 };
+
+    private static final int T_ARABIC = 0;
+    private static final int T_LOWER_LETTER = 4;
+    private static final int T_LOWER_ROMAN = 2;
+    private static final int T_ORDINAL = 5;
+    private static final int T_UPPER_LETTER = 3;
+    private static final int T_UPPER_ROMAN = 1;
 
     public static String getNumber( int num, int style )
     {
         switch ( style )
         {
         case T_UPPER_ROMAN:
-            return C_ROMAN[num - 1].toUpperCase();
+            return toRoman( num ).toUpperCase();
         case T_LOWER_ROMAN:
-            return C_ROMAN[num - 1];
+            return toRoman( num );
         case T_UPPER_LETTER:
-            return C_LETTERS[num - 1].toUpperCase();
+            return toLetters( num ).toUpperCase();
         case T_LOWER_LETTER:
-            return C_LETTERS[num - 1];
+            return toLetters( num );
         case T_ARABIC:
         case T_ORDINAL:
         default:
             return String.valueOf( num );
         }
     }
+
+    private static String toLetters( int number )
+    {
+        final int base = 26;
+
+        if ( number <= 0 )
+            throw new IllegalArgumentException( "Unsupported number: " + number );
+
+        if ( number < base + 1 )
+            return ENGLISH_LETTERS[number - 1];
+
+        long toProcess = number;
+
+        StringBuilder stringBuilder = new StringBuilder();
+        int maxPower = 0;
+        {
+            int boundary = 0;
+            while ( toProcess > boundary )
+            {
+                maxPower++;
+                boundary = boundary * base + base;
+
+                if ( boundary > Integer.MAX_VALUE )
+                    throw new IllegalArgumentException( "Unsupported number: "
+                            + toProcess );
+            }
+        }
+        maxPower--;
+
+        for ( int p = maxPower; p > 0; p-- )
+        {
+            long boundary = 0;
+            long shift = 1;
+            for ( int i = 0; i < p; i++ )
+            {
+                shift *= base;
+                boundary = boundary * base + base;
+            }
+
+            int count = 0;
+            while ( toProcess > boundary )
+            {
+                count++;
+                toProcess -= shift;
+            }
+            stringBuilder.append( ENGLISH_LETTERS[count - 1] );
+        }
+        stringBuilder.append( ENGLISH_LETTERS[(int) toProcess - 1] );
+        return stringBuilder.toString();
+    }
+
+    private static String toRoman( int number )
+    {
+        if ( number <= 0 )
+            throw new IllegalArgumentException( "Unsupported number: " + number );
+
+        StringBuilder result = new StringBuilder();
+
+        for ( int i = 0; i < ROMAN_LETTERS.length; i++ )
+        {
+            String letter = ROMAN_LETTERS[i];
+            int value = ROMAN_VALUES[i];
+            while ( number >= value )
+            {
+                number -= value;
+                result.append( letter );
+            }
+        }
+        return result.toString();
+    }
 }
diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/converter/TestNumberFormatter.java b/src/scratchpad/testcases/org/apache/poi/hwpf/converter/TestNumberFormatter.java
new file mode 100644 (file)
index 0000000..5cd60bf
--- /dev/null
@@ -0,0 +1,75 @@
+package org.apache.poi.hwpf.converter;
+
+import junit.framework.TestCase;
+
+public class TestNumberFormatter extends TestCase
+{
+
+    public void testRoman()
+    {
+        assertEquals( "i", NumberFormatter.getNumber( 1, 2 ) );
+        assertEquals( "ii", NumberFormatter.getNumber( 2, 2 ) );
+        assertEquals( "iii", NumberFormatter.getNumber( 3, 2 ) );
+        assertEquals( "iv", NumberFormatter.getNumber( 4, 2 ) );
+        assertEquals( "v", NumberFormatter.getNumber( 5, 2 ) );
+        assertEquals( "vi", NumberFormatter.getNumber( 6, 2 ) );
+        assertEquals( "vii", NumberFormatter.getNumber( 7, 2 ) );
+        assertEquals( "viii", NumberFormatter.getNumber( 8, 2 ) );
+        assertEquals( "ix", NumberFormatter.getNumber( 9, 2 ) );
+        assertEquals( "x", NumberFormatter.getNumber( 10, 2 ) );
+
+        assertEquals( "mdcvi", NumberFormatter.getNumber( 1606, 2 ) );
+        assertEquals( "mcmx", NumberFormatter.getNumber( 1910, 2 ) );
+        assertEquals( "mcmliv", NumberFormatter.getNumber( 1954, 2 ) );
+    }
+
+    public void testEnglish()
+    {
+        assertEquals( "a", NumberFormatter.getNumber( 1, 4 ) );
+        assertEquals( "z", NumberFormatter.getNumber( 26, 4 ) );
+
+        assertEquals( "aa", NumberFormatter.getNumber( 1 * 26 + 1, 4 ) );
+        assertEquals( "az", NumberFormatter.getNumber( 1 * 26 + 26, 4 ) );
+
+        assertEquals( "za", NumberFormatter.getNumber( 26 * 26 + 1, 4 ) );
+        assertEquals( "zz", NumberFormatter.getNumber( 26 * 26 + 26, 4 ) );
+
+        assertEquals( "aaa",
+                NumberFormatter.getNumber( 26 * 26 + 1 * 26 + 1, 4 ) );
+        assertEquals( "aaz",
+                NumberFormatter.getNumber( 26 * 26 + 1 * 26 + 26, 4 ) );
+
+        assertEquals( "aba",
+                NumberFormatter.getNumber( 1 * 26 * 26 + 2 * 26 + 1, 4 ) );
+        assertEquals( "aza",
+                NumberFormatter.getNumber( 1 * 26 * 26 + 26 * 26 + 1, 4 ) );
+
+        assertEquals( "azz",
+                NumberFormatter.getNumber( 26 * 26 + 26 * 26 + 26, 4 ) );
+        assertEquals( "baa",
+                NumberFormatter.getNumber( 2 * 26 * 26 + 1 * 26 + 1, 4 ) );
+        assertEquals( "zaa",
+                NumberFormatter.getNumber( 26 * 26 * 26 + 1 * 26 + 1, 4 ) );
+        assertEquals( "zzz",
+                NumberFormatter.getNumber( 26 * 26 * 26 + 26 * 26 + 26, 4 ) );
+
+        assertEquals(
+                "aaaa",
+                NumberFormatter.getNumber( 1 * 26 * 26 * 26 + 1 * 26 * 26 + 1
+                        * 26 + 1, 4 ) );
+        assertEquals(
+                "azzz",
+                NumberFormatter.getNumber( 1 * 26 * 26 * 26 + 26 * 26 * 26 + 26
+                        * 26 + 26, 4 ) );
+        assertEquals(
+                "zzzz",
+                NumberFormatter.getNumber( 26 * 26 * 26 * 26 + 26 * 26 * 26
+                        + 26 * 26 + 26, 4 ) );
+
+        for ( int i = 1; i < 1000000; i++ )
+        {
+            // make sure there is no exceptions
+            NumberFormatter.getNumber( i, 4 );
+        }
+    }
+}