【问题标题】:How do I convert unicode codepoints to their character representation?如何将 unicode 代码点转换为它们的字符表示?
【发布时间】:2013-08-22 12:46:44
【问题描述】:

如何将表示代码点的字符串转换为适当的字符?

例如,我想要一个获取U+00E4 并返回ä 的函数。

我知道在字符类中我有一个函数toChars(int codePoint),它接受一个整数,但没有一个函数接受这种类型的字符串。

是否有内置函数,或者我必须对字符串进行一些转换以获得可以发送给函数的整数?

【问题讨论】:

    标签: java unicode


    【解决方案1】:

    代码点写成以U+为前缀的十六进制数字

    所以,你可以这样做

    int codepoint=Integer.parseInt(yourString.substring(2),16);
    char[] ch=Character.toChars(codepoint);
    

    【讨论】:

    • 你能得到一个 Java 字符而不是一个 char 数组吗?
    • @k-den 是的,类似于new StringBuilder().appendCodePoint(codepoint).toString().charAt(0),但请注意,高于 64k 的代码点将产生 两个 字符,即高低代理对。您可能更愿意放弃 .charAt(0) 并简单地将结果作为 String
    【解决方案2】:

    拨打this constructorString

    "\u00E4"
    
    new String(new int[] { 0x00E4 }, 0, 1);
    

    【讨论】:

    • 您将其视为 int 文字.. op 将其作为 U+00E4 形式的字符串。
    • @Anirudh 对,你处理得恰到好处。但我想知道 "\u00e4" 是否已知是等效的(即在 java 源代码中)。你收到了我的 +1。
    • 我猜它们是等价的..但我不确定这个..:)
    【解决方案3】:

    从 Kotlin 转换而来:

        public String codepointToString(int cp) {
            StringBuilder sb = new StringBuilder();
            if (Character.isBmpCodePoint(cp)) {
                sb.append((char) cp);
            } else if (Character.isValidCodePoint(cp)) {
                sb.append(Character.highSurrogate(cp));
                sb.append(Character.lowSurrogate(cp));
            } else {
                sb.append('?');
            }
            return sb.toString();
        }
    

    【讨论】:

    • 谢谢,但实际上是@tateisu 的代码通过转换器运行
    • 好吧,但是,我需要知道如何获取 /u 字符串而不是实际值
    • 注意 StringBuilder 有 .appendCodePoint()
    【解决方案4】:

    问题要求一个函数来转换表示 Unicode 代码点的字符串值(即"+Unnnn",而不是"\unnnn""0xnnnn 的Java 格式)。但是,较新版本的 Java 具有简化处理包含多个 Unicode 格式代码点的字符串的增强功能:

    这些增强功能允许采用不同的方法来解决 OP 中提出的问题。此方法在单个语句中将一组 Unicode 格式的代码点转换为可读的String

    void processUnicode() {
    
        // Create a test string containing "Hello World ?" with code points in Unicode format.
        // Include an invalid code point (+U0wxyz), and a code point outside the Unicode range (+U70FFFF).
        String data = "+U0048+U0065+U006c+U006c+U0wxyz+U006f+U0020+U0057+U70FFFF+U006f+U0072+U006c+U0000064+U20+U1f601";
    
        String text = Arrays.stream(data.split("\\+U"))
                .filter(s -> ! s.isEmpty()) // First element returned by split() is a zero length string.
                .map(s -> {
                    try {
                        return Integer.parseInt(s, 16);
                    } catch (NumberFormatException e) { 
                        System.out.println("Ignoring element [" + s + "]: NumberFormatException from parseInt(\"" + s + "\"}");
                    }
                    return null; // If the code point is not represented as a valid hex String.
                })
                .filter(v -> v != null) // Ignore syntactically invalid code points.
                .filter(i -> Character.isValidCodePoint(i)) // Ignore code points outside of Unicode range.
                .map(i -> Character.toString(i)) // Obtain the string value directly from the code point. (Requires JDK >= 11 )
                .collect(Collectors.joining());
    
        System.out.println(text); // Prints "Hello World ?"
    }
    

    这是输出:

    run:
    Ignoring element [0wxyz]: NumberFormatException from parseInt("0wxyz"}
    Hello World ?
    BUILD SUCCESSFUL (total time: 0 seconds)
    

    注意事项:

    • 使用这种方法,不再需要特定函数来转换 Unicode 格式的代码点。相反,这是通过Stream 处理中的多个中间操作分散的。当然,同样的代码仍可用于处理 Unicode 格式的单个代码点。
    • 很容易添加中间操作对Stream进行进一步的验证和处理,例如大小写转换、移除表情等。

    【讨论】:

      【解决方案5】:

      这个例子没有使用 char[]。

      // this code is Kotlin, but you can write same thing in Java
      val sb = StringBuilder()
      val cp :Int // codepoint
      when {
          Character.isBmpCodePoint(cp) -> sb.append(cp.toChar())
          Character.isValidCodePoint(cp) -> {
              sb.append(Character.highSurrogate(cp))
              sb.append(Character.lowSurrogate(cp))
          }
          else -> sb.append('?')
      }
      

      【讨论】:

      • 你可以用stringBuilder.appendCodePoint(cp)代替这个。
      • 我知道。我准备了这段代码来解释机制。
      【解决方案6】:

      从 Java 11 开始,您可以:

      jshell> Character.toString(Integer.parseInt("U+00E4".substring(2), 16))
      $1 ==> "ä"
      

      【讨论】:

        【解决方案7】:

        你可以打印出来

        s='\u0645\u0635\u0631\u064a'
        print(s)
        

        【讨论】:

          【解决方案8】:

          到目前为止,我发现的最简单的方法就是转换代码点;如果您只是希望每个代码点有一个字符,那么这对您来说可能没问题。:

          int codepoint = ...;
          char c = (char)codepoint;
          

          【讨论】:

          • 如果码位高于char的最大值,那么就会溢出,你会得到错误的码位。我认为这不是一个好主意。
          • char 类型在 Java 中已经过时多年(几十年?),甚至无法表示 Unicode 中定义的一半字符。
          猜你喜欢
          • 2015-05-30
          • 1970-01-01
          • 1970-01-01
          • 2016-06-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-02-09
          • 2013-04-29
          相关资源
          最近更新 更多