【问题标题】:Is there a way in Java to convert an integer to its ordinal name?Java中有没有办法将整数转换为其序号?
【发布时间】:2011-07-24 23:01:31
【问题描述】:

我想取一个整数并得到它的序数,即:

1 -> "First"
2 -> "Second"
3 -> "Third"
...

【问题讨论】:

  • 如果它也能做前缀就好了……st,nd,rd
  • 请注意,如果您希望您的程序在您自己国家以外的地方使用,您应该小心使用可以本地化的解决方案。
  • 如果您需要本地化,请查看下面的@jfk 答案

标签: java


【解决方案1】:

如果您对1st2nd3rd 等感到满意,这里有一些可以正确处理任何整数的简单代码:

public static String ordinal(int i) {
    String[] suffixes = 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 + suffixes[i % 10];

    }
}

这里有一些针对极端情况的测试:

public static void main(String[] args) {
    int[] tests = {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, 1000};
    for (int test : tests) {
        System.out.println(ordinal(test));
    }
}

输出:

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
1000th

【讨论】:

  • 为什么这是公认的答案? OP用文字询问序数,答案不是那样。可能他拒绝了这个要求,但仍然是符合他要求的答案。
  • @desgraci 不确定是否是公认的答案,但我想这是最受欢迎的答案,因为它对其他人更普遍有用。
【解决方案2】:

使用优秀的ICU4J(还有一个优秀的 C 版本),您也可以这样做,并将序数作为简单的单词;

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

例如产生

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

【讨论】:

  • 我认为这应该被选为接受的答案,因为它直接回答了问题。
  • 请注意,对于某些语言,例如意大利语,%spellout-ordinal 不存在,必须在 %spellout-ordinal-masculine 和 %spellout-ordinal-feminine 之间进行选择,可能某些语言的体裁更多
  • 这很好,但是......我并不完全相信图书馆从语言环境的角度处理事情的方式。此答案中的示例代码表示它使用英国语言​​环境,但它提供(例如)one hundred one thousand three hundred eighty-second 用于数字 101,382。我希望它是one hundred and one thousand three hundred and eighty-second(添加了那些“和”)。这对英国来说(我认为)会更自然。这感觉更像是美国语言环境的写字方式。
  • 对于1st2nd3rd 等,请使用RuleBasedNumberFormat.ORDINAL,然后使用nf.format(x)
【解决方案3】:

另一种解决方案

public static String ordinal(int i) {
    int mod100 = i % 100;
    int mod10 = i % 10;
    if(mod10 == 1 && mod100 != 11) {
        return i + "st";
    } else if(mod10 == 2 && mod100 != 12) {
        return i + "nd";
    } else if(mod10 == 3 && mod100 != 13) {
        return i + "rd";
    } else {
        return i + "th";
    }
}

专业:不需要初始化数组(垃圾更少)
缺点:不是单线……

【讨论】:

    【解决方案4】:

    我已经想出了如何在 Android 中以一种非常简单的方式做到这一点。您需要做的就是将依赖项添加到您的appbuild.gradle 文件中:

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

    接下来,创建这个方法:

    科特林:

    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);
            }
        }
    

    然后,您可以像这样简单地使用它:

    科特林:

    val ordinal = 2.getOrdinal()
    

    Java:

    String ordinal = getNumberOrdinal(2)
    

    工作原理

    从 Android N (API 24) 开始,Android 使用 icu.text 而不是常规的 java.text (more info here),后者已经包含 ordinal numbers 的国际化实现。所以解决方案显然很简单——将icu4j库添加到项目中并在Nougat以下的版本上使用它

    【讨论】:

    • 重要提示:这不适用于较新版本的 ICU4J(至少 63.1);它将抛出 API 级别
    • 为这么简单的功能添加了太多的 apk 大小,+9mb。
    • 换句话说:android.icu.text.MessageFormat.format("{0,ordinal}", number)。请注意,改用 java.text.MessageFormat.format 会引发异常。 +1 国际化,这应该是公认的答案!
    【解决方案5】:

    在 1 行中:

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

    【讨论】:

    • 男孩将给垃圾收集器一个有趣的时间 XD
    • @Supuhstar,很容易证明该数组无法离开该方法的范围,因此编译器和运行时可以对此进行大量优化。即使以我最悲观的预测,这种方法在很短的时间内也不会产生任何垃圾。
    • @M.Prokhorov 我宁愿一个解决方案不依赖于可能在版本和环境之间改变的 JVM 实现细节,而是依赖于不依赖于严格定义的语言行为
    • @Supuhstar,任何关于 Java 垃圾的讨论都是依赖于 JVM 实现细节。 Java 只定义超出范围的对象被垃圾收集。它没有定义任何影响应用程序性能的垃圾对象的概念,也没有讨论因此而避免创建对象。
    • @M.Prokhorov 对,这就是为什么我认为将数组设为静态变量会更可靠地执行,保证在应用程序的整个生命周期内与任何 JVM 都在范围内,因此保证永远不会车库收集的
    【解决方案6】:

    波西米亚人的回答非常好,但我建议改进错误处理。如果您提供负整数,则使用原始版本的 ordinal 将引发 ArrayIndexOutOfBoundsException。我认为我下面的版本更清晰。我希望 junit 也有用,所以没有必要目视检查输出。

    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);
        }
    
    }
    

    【讨论】:

      【解决方案7】:

      在 Scala 中进行更改,

      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
      

      【讨论】:

      • Java 的问题?
      【解决方案8】:
      private static String getOrdinalIndicator(int number) {
              int mod = number;
              if (number > 13) {
                  mod = number % 10;
              }
              switch (mod) {
              case 1:
                  return "st";
              case 2:
                  return "nd";
              case 3:
                  return "rd";
              default:
                  return "th";
              }
          }
      

      【讨论】:

      • 问题是返回 First 为 1 等,如 Eleventh 为 11 等。你的答案没有实现。
      【解决方案9】:

      我有一个长而复杂但易于理解的概念

      private static void convertMe() {
      
          Scanner in = new Scanner(System.in);
          try {
              System.out.println("input a number to convert: ");
              int n = in.nextInt();
      
              String s = String.valueOf(n);
              //System.out.println(s);
      
              int len = s.length() - 1;
              if (len == 0){
                  char lastChar = s.charAt(len);
                  if (lastChar == '1'){
                      System.out.println(s + "st");
                  } else if (lastChar == '2') {
                      System.out.println(s + "nd");
                  } else if (lastChar == '3') {
                      System.out.println(s + "rd");
                  } else {
                      System.out.println(s + "th");
                  }
              } else if (len > 0){
                  char lastChar = s.charAt(len);
                  char preLastChar = s.charAt(len - 1);
                  if (lastChar == '1' && preLastChar != '1'){ //not ...11
                      System.out.println(s + "st");
                  } else if (lastChar == '2' && preLastChar != '1'){ //not ...12
                      System.out.println(s + "nd");
                  } else if (lastChar == '3' && preLastChar != '1'){ //not ...13
                      System.out.println(s + "rd");
                  } else {
                      System.out.println(s + "th");
                  }
              }
      
      
          } catch(InputMismatchException exception){
              System.out.println("invalid input");
          }
      
      
      }
      

      【讨论】:

        【解决方案10】:
        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";
            }
        }
        

        【讨论】:

          【解决方案11】:

          如果有人在寻找 Kotlin 扩展 版本:


          fun Int.toEnOrdinal(): String {
              val suffixes = arrayListOf("th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th")
              return when (this % 100) {
                  11, 12, 13 -> "{$this}th"
                  else -> "$this" + suffixes[this % 10]
              }
          }
          

          那么你需要做的就是在任何号码上调用这个函数

          5.toUKOrdinal() --> 5th

          21.toUKOrdinal() --> 21 日

          【讨论】:

            【解决方案12】:

            最好和最简单的方法,我们开始吧:

            import java.util.*;
            public class Numbers 
            {
                public final static String print(int num)
                {
                    num = num%10;
                    String str = "";
                    switch(num)
                    {
                    case 1:     
                        str = "st";
                        break;
                    case 2:     
                        str = "nd";
                        break;
                    case 3:     
                        str = "rd";
                        break;
                    default: 
                        str = "th";             
                    }
                    return str;
                }
            
                public static void main(String[] args) 
                {
                    Scanner sc = new Scanner(System.in);
                    System.out.print("Enter a number: ");
                    int number = sc.nextInt();
                    System.out.print(number + print(number));
                }
            }
            

            【讨论】:

            • 我没有看到这个处理数字 11、12 和 13?
            【解决方案13】:
            public static String getOrdinalFor(int value) {
                     int tenRemainder = value % 10;
                     switch (tenRemainder) {
                      case 1:
                       return value+"st";
                      case 2:
                       return value+"nd";
                      case 3:
                       return value+"rd";
                      default:
                       return value+"th";
                     }
                    }
            

            【讨论】:

            • 我没有看到这个处理数字 11、12 和 13?使用 if 来检查它们,例如 - if (number &gt;= 11 &amp;&amp; number &lt;= 13) { return number + "th"; }
            猜你喜欢
            • 2010-10-04
            • 2013-04-23
            • 1970-01-01
            • 2015-12-14
            • 2019-09-20
            • 2022-11-20
            • 2021-11-16
            • 1970-01-01
            相关资源
            最近更新 更多