Is there a way in Java to convert an integer to its ordinal name?

后端 未结 12 1310
生来不讨喜
生来不讨喜 2020-11-27 15:12

I want to take an integer and get its ordinal, i.e.:

1 -> \"First\"
2 -> \"Second\"
3 -> \"Third\"
...
相关标签:
12条回答
  • 2020-11-27 15:45

    Bohemians answer is very good but I recommend improving the error handling. With the original version of ordinal if you supply a negative integer an ArrayIndexOutOfBoundsException will be thrown. I think my version below is clearer. I hope the junit is also useful so it is not necessary to visually check the output.

    public class FormattingUtils {
    
        /**
         * Return the ordinal of a cardinal number (positive integer) (as per common usage rather than set theory).
         * {@link http://stackoverflow.com/questions/6810336/is-there-a-library-or-utility-in-java-to-convert-an-integer-to-its-ordinal}
         * 
         * @param i
         * @return
         * @throws {@code IllegalArgumentException}
         */
        public static String ordinal(int i) {
            if (i < 0) {
                throw new IllegalArgumentException("Only +ve integers (cardinals) have an ordinal but " + i + " was supplied");
            }
    
            String[] sufixes = new String[] { "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th" };
            switch (i % 100) {
            case 11:
            case 12:
            case 13:
                return i + "th";
            default:
                return i + sufixes[i % 10];
            }
        }
    }
    
    
    import org.junit.Test;
    import static org.assertj.core.api.Assertions.assertThat;
    
    public class WhenWeCallFormattingUtils_Ordinal {
    
        @Test
        public void theEdgeCasesAreCovered() {
            int[] edgeCases = { 0, 1, 2, 3, 4, 5, 10, 11, 12, 13, 14, 20, 21, 22, 23, 24, 100, 101, 102, 103, 104, 111, 112,
                    113, 114 };
            String[] expectedResults = { "0th", "1st", "2nd", "3rd", "4th", "5th", "10th", "11th", "12th", "13th", "14th",
                    "20th", "21st", "22nd", "23rd", "24th", "100th", "101st", "102nd", "103rd", "104th", "111th", "112th",
                    "113th", "114th" };
    
            for (int i = 0; i < edgeCases.length; i++) {
                assertThat(FormattingUtils.ordinal(edgeCases[i])).isEqualTo(expectedResults[i]);
            }
        }
    
        @Test(expected = IllegalArgumentException.class)
        public void supplyingANegativeNumberCausesAnIllegalArgumentException() {
            FormattingUtils.ordinal(-1);
        }
    
    }
    
    0 讨论(0)
  • 2020-11-27 15:47
    static String getOrdinal(int input) {
        if(input<=0) {
            throw new IllegalArgumentException("Number must be > 0");
        }
        int lastDigit = input % 10;
        int lastTwoDigit = input % 100;
        if(lastTwoDigit >= 10 && lastTwoDigit <= 20) {
            return input+"th";
        }
        switch (lastDigit) {
        case 1:
            return input+"st";
        case 2:
            return input+"nd";
        case 3:
            return input+"rd";
    
        default:
            return input+"th";
        }
    }
    
    0 讨论(0)
  • 2020-11-27 15:48

    In Scala for a change,

    List(1, 2, 3, 4, 5, 10, 11, 12, 13, 14 , 19, 20, 23, 33, 100, 113, 123, 101, 1001, 1011, 1013, 10011) map {
        case a if (a % 10) == 1 && (a % 100) != 11 => a + "-st"
        case b if (b % 10) == 2 && (b % 100) != 12 => b + "-nd"
        case c if (c % 10) == 3 && (c % 100) != 13 => c + "-rd"
        case e                                     => e + "-th"
      }  foreach println
    
    0 讨论(0)
  • 2020-11-27 15:49

    Using the excellent ICU4J (there's also an excellent C version) you can also do this and get the Ordinals as plain words;

    RuleBasedNumberFormat nf = new RuleBasedNumberFormat(Locale.UK, RuleBasedNumberFormat.SPELLOUT);
    for(int i = 0; i <= 30; i++)
    {
        System.out.println(i + " -> "+nf.format(i, "%spellout-ordinal"));
    }
    

    for example produces

    0 -> zeroth
    1 -> first
    2 -> second
    3 -> third
    4 -> fourth
    5 -> fifth
    6 -> sixth
    7 -> seventh
    8 -> eighth
    9 -> ninth
    10 -> tenth
    11 -> eleventh
    12 -> twelfth
    13 -> thirteenth
    14 -> fourteenth
    15 -> fifteenth
    16 -> sixteenth
    17 -> seventeenth
    18 -> eighteenth
    19 -> nineteenth
    20 -> twentieth
    21 -> twenty-first
    22 -> twenty-second
    23 -> twenty-third
    24 -> twenty-fourth
    25 -> twenty-fifth
    26 -> twenty-sixth
    27 -> twenty-seventh
    28 -> twenty-eighth
    29 -> twenty-ninth
    30 -> thirtieth
    
    0 讨论(0)
  • 2020-11-27 16:01

    If you're OK with "1st", "2nd", "3rd" etc, here's some simple code that will correctly handle any integer:

    public static String ordinal(int i) {
        String[] sufixes = new String[] { "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th" };
        switch (i % 100) {
        case 11:
        case 12:
        case 13:
            return i + "th";
        default:
            return i + sufixes[i % 10];
    
        }
    }
    

    Here's some tests for edge cases:

    public static void main(String[] args) {
        int[] edgeCases = { 0, 1, 2, 3, 4, 5, 10, 11, 12, 13, 14, 20, 21, 22, 23, 24, 100, 101, 102, 103, 104, 111, 112, 113, 114 };
        for (int edgeCase : edgeCases) {
            System.out.println(ordinal(edgeCase));
        }
    }
    

    Output:

    0th
    1st
    2nd
    3rd
    4th
    5th
    10th
    11th
    12th
    13th
    14th
    20th
    21st
    22nd
    23rd
    24th
    100th
    101st
    102nd
    103rd
    104th
    111th
    112th
    113th
    114th
    
    0 讨论(0)
  • 2020-11-27 16:04

    I've figured out how to do this in Android in a pretty simple way. All you need to do is to add the dependency to your app's build.gradle file:

    implementation "com.ibm.icu:icu4j:53.1"
    

    Next, create this method:

    Kotlin:

    fun Number?.getOrdinal(): String? {
        if (this == null) {
            return null
        }
    
        val format = "{0,ordinal}"
    
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            android.icu.text.MessageFormat.format(format, this)
        } else {
            com.ibm.icu.text.MessageFormat.format(format, this)
        }
    }
    

    Java:

    public static String getNumberOrdinal(Number number) {
            if (number == null) {
                return null;
            }
    
            String format = "{0,ordinal}";
    
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                return android.icu.text.MessageFormat.format(format, number);
            } else {
                return com.ibm.icu.text.MessageFormat.format(format, number);
            }
        }
    

    Then, you can simply use it like this:

    Kotlin:

    val ordinal = 2.getOrdinal()
    

    Java:

    String ordinal = getNumberOrdinal(2)
    

    How it works

    Starting from Android N (API 24) Android uses icu.text instead of regular java.text (more info here), which already contains internationalized implementation for ordinal numbers. So the solution is obviously simple - to add the icu4j library to the project and use it on versions below the Nougat

    0 讨论(0)
提交回复
热议问题