2

客户端打印标签并一直使用一组符号 (?) 字体来执行此操作。该应用程序使用单字节数据库(Oracle with Latin-1)。我要替换的旧应用程序不支持 Unicode。它以某种方式做得很好。我正在编写的替换应用程序应该处理旧数据。

从charmap 应用程序中挑选的符号通常映射到特定的Unicode 字符,但有时它们不会。例如,使用 LAB3 字体看起来像月亮的东西实际上是 U+2014 (EM DASH)。当用户将此字符粘贴到 Swing 文本字段中时,该字符的代码点为 8212。它被“移动”到私人使用区域(Windows?Java?)。当将此字符保存到数据库时,Oracle 认为它不能被安全地编码并用可怕的 ¿ 代替它。因此,我开始将字符移动 8000:保存时 -= 8000,显示字段时 += 8000。不幸的是,我发现其他字符没有移动相同的数量。例如,在一种特定的字体中,ž 的代码点为 382,因此我将其移动了 +/-256 以“修复”它。

到现在为止,我害怕发现更多奇怪的偏移量,我想知道:我可以使用 Java 进行这种映射吗?也许 TTF 字体有一个它编码的 255 个字形的列表以及它们对应的 Unicode 字符,我可以“正确”地做到这一点?

现在我正在使用以下kludge:

static String fromDatabase(String str, String fontFamily) {

  if (str != null && fontFamily != null) {
    Font font = new Font(fontFamily, Font.PLAIN, 1);

    boolean changed = false;
    char[] chars = str.toCharArray();
    for (int i = 0; i < chars.length; i++) {
      if (font.canDisplay(chars[i] + 0xF000)) {
        // WE8MSWIN1252 + WinXP
        chars[i] += 0xF000;
        changed = true;
      }
      else if (chars[i] >= 128 && font.canDisplay(chars[i] + 8000)) {
        // WE8ISO8859P1 + WinXP
        chars[i] += 8000;
        changed = true;
      }
      else if (font.canDisplay(chars[i] + 256)) {
        // ž in LAB1 Eastern = 382
        chars[i] += 256;
        changed = true;
      }
    }
    if (changed) str = new String(chars);
  }
  return str;
}

static String toDatabase(String str, String fontFamily) {

  if (str != null && fontFamily != null) {
    boolean changed = false;
    char[] chars = str.toCharArray();
    for (int i = 0; i < chars.length; i++) {
      int chr = chars[i];
      if (chars[i] > 0xF000) {
        // WE8MSWIN1252 + WinXP
        chars[i] -= 0xF000;
        changed = true;
      }
      else if (chars[i] > 8000) {
        // WE8ISO8859P1 + WinXP
        chars[i] = (char) (chars[i] - 8000);
        changed = true;
      }
      else if (chars[i] > 256) {
        // ž in LAB1 Eastern = 382
        chars[i] = (char) (chars[i] - 256);
        changed = true;
      }
    }
    if (changed) return new String(chars);
  }

  return str;
}
4

2 回答 2

3

字体文件当然有从 Unicode 到字形的映射。不幸的是,字形是完全任意的,不需要与它映射到的角色有任何关系,就像你在 Moon/Em-Dash 中发现的那样。从单字节字符到 Unicode 代码点的映射可能可以在Windows Code Page 1252中找到,但这不是您想要的 - 您希望字符 0x97 等同于月亮字形,例如☽ FIRST QUARTER MOON U+263D而不是比— EM DASH U+2014。不幸的是,除了查看字体中的每个字符并将其与可用的 Unicode 字符进行比较之外,我无法提出任何建议。

于 2012-10-09T16:20:05.973 回答
0

只是为了提供关闭,这似乎是有效的:

static String fromDatabase(String str, String fontFamily) {
  if (str != null && fontFamily != null) {
    try {
      byte[] bytes = str.getBytes("ISO-8859-1"); // database encoding
      if (fontFamily.startsWith("LAB")) {
        str = new String(bytes, "Windows-1252");
      }
    }
    catch (UnsupportedEncodingException e) {
      e.printStackTrace();
    }
  }
  return str;
}

static String toDatabase(String str, String fontFamily) {
  if (str != null && fontFamily != null) {
    try {
      if (fontFamily.startsWith("LAB")) {
        str = new String(str.getBytes("Windows-1252"), "ISO-8859-1");
      }
    }
    catch (UnsupportedEncodingException e) {
      e.printStackTrace();
    }
  }
  return str;
}

public void exportFormData(EigentumsbezeichnungInformationFormData formData) throws ProcessingException {
  super.exportFormData(formData);
  formData.getWert().setValue(toDatabase(formData.getWert().getValue(), formData.getSchrift().getValue()));
}

public void importFormData(EigentumsbezeichnungInformationFormData formData) throws ProcessingException {
  super.importFormData(formData);
  getWertField().setValue(fromDatabase(formData.getWert().getValue(), formData.getSchrift().getValue()));
}

这是我的解释:数据库使用 ISO 8859-1(又名拉丁语 1)。十年前,客户委托了一堆特殊字体,故意说是Latin-1编码,但实际上显示的是不同的字符。注意这个例子中的 Omega 是如何代替 Ù 的!

用于说明映射的charmap 屏幕截图

此外,还使用了一些 Latin-1 未使用的字符。最简单的解决方案似乎假设正在使用相应的 Windows 代码页。这允许 Java 将“假 Windows-1252”数据库中的字节转码为 Unicode 并返回。翻译后,Swing 应用程序将使用显示 Omega 字形的字体显示一个 Ù。问题解决了。”

于 2012-11-22T10:13:40.780 回答