| // © 2016 and later: Unicode, Inc. and others. |
| // License & terms of use: http://www.unicode.org/copyright.html |
| /* |
| ****************************************************************************** |
| * Copyright (C) 2007-2012, International Business Machines Corporation and * |
| * others. All Rights Reserved. * |
| ****************************************************************************** |
| */ |
| |
| package com.ibm.icu.impl.duration.impl; |
| |
| import java.util.Locale; |
| |
| public class Utils { |
| public static final Locale localeFromString(String s) { |
| String language = s; |
| String region = ""; |
| String variant = ""; |
| |
| int x = language.indexOf("_"); |
| if (x != -1) { |
| region = language.substring(x+1); |
| language = language.substring(0, x); |
| } |
| x = region.indexOf("_"); |
| if (x != -1) { |
| variant = region.substring(x+1); |
| region = region.substring(0, x); |
| } |
| return new Locale(language, region, variant); |
| } |
| /* |
| public static <T> T[] arraycopy(T[] src) { |
| T[] result = (T[])Array.newInstance(src.getClass().getComponentType(), src.length); // can we do this without casting? |
| for (int i = 0; i < src.length; ++i) { |
| result[i] = src[i]; |
| } |
| return result; |
| } |
| */ |
| |
| /** |
| * Interesting features of chinese numbers: |
| * - Each digit is followed by a unit symbol (10's, 100's, 1000's). |
| * - Units repeat in levels of 10,000, there are symbols for each level too (except 1's). |
| * - The digit 2 has a special form before the 10 symbol and at the end of the number. |
| * - If the first digit in the number is 1 and its unit is 10, the 1 is omitted. |
| * - Sequences of 0 digits and their units are replaced by a single 0 and no unit. |
| * - If there are two such sequences of 0 digits in a level (1000's and 10's), the 1000's 0 is also omitted. |
| * - The 1000's 0 is also omitted in alternating levels, such that it is omitted in the rightmost |
| * level with a 10's 0, or if none, in the rightmost level. |
| * - Level symbols are omitted if all of their units are omitted |
| */ |
| public static String chineseNumber(long n, ChineseDigits zh) { |
| if (n < 0) { |
| n = -n; |
| } |
| if (n <= 10) { |
| if (n == 2) { |
| return String.valueOf(zh.liang); |
| } |
| return String.valueOf(zh.digits[(int)n]); |
| } |
| |
| // 9223372036854775807 |
| char[] buf = new char[40]; // as long as we get, and actually we can't get this high, no units past zhao |
| char[] digits = String.valueOf(n).toCharArray(); |
| |
| // first, generate all the digits in place |
| // convert runs of zeros into a single zero, but keep places |
| // |
| boolean inZero = true; // true if we should zap zeros in this block, resets at start of block |
| boolean forcedZero = false; // true if we have a 0 in tens's place |
| int x = buf.length; |
| for (int i = digits.length, u = -1, l = -1; --i >= 0;) { |
| if (u == -1) { |
| if (l != -1) { |
| buf[--x] = zh.levels[l]; |
| inZero = true; |
| forcedZero = false; |
| } |
| ++u; |
| } else { |
| buf[--x] = zh.units[u++]; |
| if (u == 3) { |
| u = -1; |
| ++l; |
| } |
| } |
| int d = digits[i] - '0'; |
| if (d == 0) { |
| if (x < buf.length-1 && u != 0) { |
| buf[x] = '*'; |
| } |
| if (inZero || forcedZero) { |
| buf[--x] = '*'; |
| } else { |
| buf[--x] = zh.digits[0]; |
| inZero = true; |
| forcedZero = u == 1; |
| } |
| } else { |
| inZero = false; |
| buf[--x] = zh.digits[d]; |
| } |
| } |
| |
| // scanning from right, find first required 'ling' |
| // we only care if n > 101,0000 as this is the first case where |
| // it might shift. remove optional lings in alternating blocks. |
| if (n > 1000000) { |
| boolean last = true; |
| int i = buf.length - 3; |
| do { |
| if (buf[i] == '0') { |
| break; |
| } |
| i -= 8; |
| last = !last; |
| } while (i > x); |
| |
| i = buf.length - 7; |
| do { |
| if (buf[i] == zh.digits[0] && !last) { |
| buf[i] = '*'; |
| } |
| i -= 8; |
| last = !last; |
| } while (i > x); |
| |
| // remove levels for empty blocks |
| if (n >= 100000000) { |
| i = buf.length - 8; |
| do { |
| boolean empty = true; |
| for (int j = i-1, e = Math.max(x-1, i-8); j > e; --j) { |
| if (buf[j] != '*') { |
| empty = false; |
| break; |
| } |
| } |
| if (empty) { |
| if (buf[i+1] != '*' && buf[i+1] != zh.digits[0]) { |
| buf[i] = zh.digits[0]; |
| } else { |
| buf[i] = '*'; |
| } |
| } |
| i -= 8; |
| } while (i > x); |
| } |
| } |
| |
| // replace er by liang except before or after shi or after ling |
| for (int i = x; i < buf.length; ++i) { |
| if (buf[i] != zh.digits[2]) continue; |
| if (i < buf.length - 1 && buf[i+1] == zh.units[0]) continue; |
| if (i > x && (buf[i-1] == zh.units[0] || buf[i-1] == zh.digits[0] || buf[i-1] == '*')) continue; |
| |
| buf[i] = zh.liang; |
| } |
| |
| // eliminate leading 1 if following unit is shi |
| if (buf[x] == zh.digits[1] && (zh.ko || buf[x+1] == zh.units[0])) { |
| ++x; |
| } |
| |
| // now, compress out the '*' |
| int w = x; |
| for (int r = x; r < buf.length; ++r) { |
| if (buf[r] != '*') { |
| buf[w++] = buf[r]; |
| } |
| } |
| return new String(buf, x, w-x); |
| } |
| |
| // public static void main(String[] args) { |
| // for (int i = 0; i < args.length; ++i) { |
| // String arg = args[i]; |
| // System.out.print(arg); |
| // System.out.print(" > "); |
| // long n = Long.parseLong(arg); |
| // System.out.println(chineseNumber(n, ChineseDigits.DEBUG)); |
| // } |
| // } |
| |
| public static class ChineseDigits { |
| final char[] digits; |
| final char[] units; |
| final char[] levels; |
| final char liang; |
| final boolean ko; |
| |
| ChineseDigits(String digits, String units, String levels, char liang, boolean ko) { |
| this.digits = digits.toCharArray(); |
| this.units = units.toCharArray(); |
| this.levels = levels.toCharArray(); |
| this.liang = liang; |
| this.ko = ko; |
| } |
| |
| public static final ChineseDigits DEBUG = |
| new ChineseDigits("0123456789s", "sbq", "WYZ", 'L', false); |
| |
| public static final ChineseDigits TRADITIONAL = |
| new ChineseDigits("\u96f6\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341", // to shi |
| "\u5341\u767e\u5343", // shi, bai, qian |
| "\u842c\u5104\u5146", // wan, yi, zhao |
| '\u5169', false); // liang |
| |
| public static final ChineseDigits SIMPLIFIED = |
| new ChineseDigits("\u96f6\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341", // to shi |
| "\u5341\u767e\u5343", // shi, bai, qian |
| "\u4e07\u4ebf\u5146", // wan, yi, zhao |
| '\u4e24', false); // liang |
| |
| // no 1 before first unit no matter what it is |
| // not sure if there are 'ling' units |
| public static final ChineseDigits KOREAN = |
| new ChineseDigits("\uc601\uc77c\uc774\uc0bc\uc0ac\uc624\uc721\uce60\ud314\uad6c\uc2ed", // to ten |
| "\uc2ed\ubc31\ucc9c", // 10, 100, 1000 |
| "\ub9cc\uc5b5?", // 10^4, 10^8, 10^12 |
| '\uc774', true); |
| } |
| } |