【问题标题】:Is this format: "U+043E;U+006F,U+004D" some sort of encoding standard and does java offer a standard library method to convert it to char?这种格式:“U+043E;U+006F,U+004D”是某种编码标准吗?java是否提供标准库方法将其转换为char?
【发布时间】:2021-02-01 00:32:58
【问题描述】:

我正在调查对我们的语言支持造成的一些混乱(它用于我们的 IDN 功能,如果这敲响了警钟的话)...

我使用 SQL GUI 客户端快速查看我们的语言定义的结构。因此,当我执行select charcodes from ourCharCodesTable where language = 'myLanguage'; 时,我会得到'myLanguage' 的某些值的结果,例如:

myLanguage = "ASCII":
result = "-0123456789abcdefghijklmnopqrstuvwxyz"

myLanguage = "Russian":
result = "-0123456789абвгдежзийклмнопрстуфхцчшщъьюяѐѝ"
(顺便说一句:如果你像我一样是多语种的话,这里已经可以看到语言错误了!)

我想:“好吧,我可以用这个!让我们编写一个 Java 程序并输入一些逻辑来查找错误......”
我需要我的逻辑一次从“结果”中接收一个字符,并根据当前表上下文应用我的逻辑来标记它是否应该存在...

但是!当我在:
myLanguage = "Belarusian":
有人会认为这种语言与俄语非常相似,但来自数据库的结果格式完全不同:result = "U+002D\nU+0030\nU+0030..."

而且,还有另一种格式! myLanguage = "Chinese" :
result = "#\nU+002D;U+002D;U+003D,U+004D,U+002D\nU+0030;U+0030;U+0030"

FWIW:charcodes 列是 CLOB 类型。

我知道U+002D 是'-' 而U+0030 是'0'...

我目前的想法是:
1] 检查整个响应是 'щ' 格式还是 'U+0449` 格式('U+****' 是否用 ';'、',' 或 '\n' 分隔 - 我只是将它们视为独立字符)
一种。如果它是“简单的”,只需将字符发送到我的测试方法
湾。如果是“hard one”,则获取十六进制部分(0449),转换为十进制(1097)并转换为char(щ)

所以,我的问题是:

  • 这是什么“U+043E;U+006F,U+004D”格式?
  • 如果它是一个广泛使用的标准,Java 是否提供任何方法来将它们的整个 String 转换为 char 数组?

【问题讨论】:

    标签: java character-encoding multilingual idn


    【解决方案1】:

    更新

    这个“U+043E;U+006F,U+004D”格式是什么?

    comment 中,OP 提供了指向https://www.iana.org/domains/idn-tables/tables/academy_zh_1.0.txt 的链接,其中包含以下文本:

    • 此表符合RFC 3743 中指定的格式

    RFC 3743 可以在https://www.rfc-editor.org/rfc/rfc3743找到


    如果它是一个广泛使用的标准,Java 是否提供任何方法将这些字符串的整个字符串转换为 char 数组?

    它不是一个广泛使用的标准,因此 Java 本身不提供该标准,但使用正则表达式很容易转换为常规字符串,因此您可以正常处理字符串。

    // Java 11+
    static String decodeUnicode(String input) {
        return Pattern.compile("U\\+[0-9A-F]{4,6}").matcher(input).replaceAll(mr ->
                Character.toString(Integer.parseInt(mr.group().substring(2), 16)));
    }
    
    // Java 9+
    static String decodeUnicode(String input) {
        return Pattern.compile("U\\+[0-9A-F]{4,6}").matcher(input).replaceAll(mr ->
                new String(new int[] { Integer.parseInt(mr.group().substring(2), 16) }, 0, 1));
    }
    
    // Java 1.5+
    static String decodeUnicode(String input) {
        StringBuffer buf = new StringBuffer();
        Matcher m = Pattern.compile("U\\+[0-9A-F]{4,6}").matcher(input);
        while (m.find()) {
            String hexString = m.group().substring(2);
            int codePoint = Integer.parseInt(hexString, 16);
            String unicodeCharacter = new String(new int[] { codePoint }, 0, 1);
            m.appendReplacement(buf, unicodeCharacter);
        }
        return m.appendTail(buf).toString();
    }
    

    测试

    System.out.println(decodeUnicode("#\nU+002D;U+002D;U+003D,U+004D,U+002D\nU+0030;U+0030;U+0030"));
    

    输出

    #
    -;-;=,M,-
    0;0;0
    

    【讨论】:

    • U+xxxx 是标准符号 - stackoverflow.com/questions/1273693。不知道其他东西(逗号、分号等)可能意味着什么。
    • @StephenC 其余的是ourCharCodesTable 表定义的列charcodes 的值,所以这将是一些专有规范。 --- 我知道 U+HHHH 是使用十六进制数字引用 Unicode 字符的标准符号,我以前从未见过带有该符号的字符串 encoded (“格式化”)。大多数编程语言使用\uHHHH。 JSON也是。 XML 使用&#xHHHH;
    • 不只是我们。在网上很容易找到这样的表格:(小心,大页面)iana.org/domains/idn-tables/tables/academy_zh_1.0.txt - IANA 但不是你可以问的那么酷的人......我问过我们的开发人员,他们首先填写了该表格,但他们的回答没有并不能真正激发信心。一个可能认识的人是 Patrick Mevzek,如果我幸运的话,他可能会看到这个问题!
    • @Andreas:很公平,我已经删除了我的 cmets。
    • 感谢您投入大量时间来提供帮助!我不想听起来贪婪或懒惰,但事实是我知道那个 RFC,但无法理解它。我找不到类似的东西:“分号是 UTF-16 编码的一部分,逗号意味着这些字符可以被认为是等效的,这只是一种简洁的方式来说明它们都是可以接受的(而不是将每个字符放在一个新行中) “ - 我意识到没有什么值得付钱让工程师做的事情这么容易理解,但 RFC 家伙肯定没有在这里放过棒!
    【解决方案2】:

    U+0000 是 Unicode 代码点的表示形式,格式定义为 in Apendix A of the Unicode Standard。这些数字只是表示代码点的十六进制编码数字。由于历史原因,0 总是用左填充到至少 4 位数字,但最长可达 6 位数字。

    它主要不是作为一种机器可读的编码,而是作为一种人类可读的 Unicode 代码点表示,用于运行文本(即这样的段落)。请特别注意,这种格式没有有办法区分后跟一些数字的四字符数字和 5 位或 6 位数字。所以U+123456 可以被解释为 3 种不同的是:U+1234 后跟文本 56U+12345 后跟文本 6U+123456。这使得它不适合自动替换和用作通用编码。

    因此,没有内置功能可以将其解析为等效的 String 或 Java 中的类似内容。

    以下代码可用于将单个 Unicode 代码点引用解析为String 中的适当代码点:

      public static String codePointToString(String input) {
        if (!input.startsWith("U+")) {
          throw new IllegalArgumentException("Malformed input, doesn't start with U+");
        }
        int codepoint = Integer.parseInt(input.substring(2), 16);
        if (codepoint < 0 || codepoint > Character.MAX_CODE_POINT) {
          throw new IllegalArgumentException("Malformed input, codepoint value out of valid range: " + codepoint);
        }
        return Character.toString(codepoint);
      }
    

    (在 Java 11 之前,返回行需要改用new String(new int[] { codepoint }, 0, 1))。

    如果您想用实际文本替换文本中表示的所有 Unicode 代码点(在某些情况下可能会使其不可读),您可以使用它(与上述方法一起使用):

      private static final Pattern PATTERN = Pattern.compile("U\\+[0-9A-Za-z]{4,6}");
      
      public static String decodeCodePoints(String input) {
        return PATTERN
            .matcher(input)
            .replaceAll(result -> codePointToString(result.group()));
      }
    

    【讨论】:

    【解决方案3】:

    实际上,我编写了一个名为 MgntUtils 的开源库,它有一个可以为您提供很大帮助的实用程序。您看到的代码是 unicode 序列,其中每个 U+XXXX 代表一个字符。库中的实用程序可以将任何语言的任何字符串(包括特殊字符)转换为 Unicode 序列,反之亦然。以下是它的工作原理示例:

    result = "Hello World";
    result = StringUnicodeEncoderDecoder.encodeStringToUnicodeSequence(result);
    System.out.println(result);
    result = StringUnicodeEncoderDecoder.decodeUnicodeSequenceToString(result);
    System.out.println(result);
    

    这段代码的输出是:

    \u0048\u0065\u006c\u006c\u006f\u0020\u0057\u006f\u0072\u006c\u0064
    Hello World
    

    该库可以在Maven CentralGithub 找到它作为 maven 工件并带有源代码和 javadoc

    这是StringUnicodeEncoderDecoder类的javadoc

    【讨论】:

    • \u0048 与 U+0048 的格式完全不同。
    • 是的,但它们确实表示相同的符号。对于测试或恢复数据,您可以复制粘贴您的代码 U+XXXX 并将“U+”替换为“\u”,然后您可以恢复数据。这个实用程序帮助了我很多次,这就是我将它作为开源库的一部分发布的原因。我认为这个答案不应该被否决,因为它为用户提供了诊断问题和恢复数据的选项。但是,我很感谢@Joachim Sauer,他给出了拒绝投票的理由
    • 它们也不太兼容:\uXXXX 符号始终为 4 个字符,并将非 BMP 代码点表示为两个代理项(即 \uXXXX\uXXXX 而不是 U+XXXXXX)。
    • “它们确实表示相同的符号” 无关紧要。 OP 需要处理U+HHHH,而不是\uHHHH,所以如果方法不这样做,那就没用了。 --- "you can copy-paste" OP 需要代码来执行此操作,而不是必须手动编辑的东西。 --- 投了反对票,因为答案没用,因为它无法帮助处理 OP 需要处理的输入。
    猜你喜欢
    • 1970-01-01
    • 2019-01-12
    • 1970-01-01
    • 2013-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-24
    相关资源
    最近更新 更多