日语的节省空间字符编码?

6
在我看来,一个常见的问题是字符编码与位图字体的结合。大多数多语言编码之间有很大的差距,并且甚至存在许多未使用的代码点。因此,如果我想使用它们,我会浪费很多内存(不仅为了保存多字节文本 - 我特别指位图字体中的空格),而VRAM通常非常宝贵...因此唯一合理的事情似乎是:在我的纹理上使用自定义映射,例如UTF-8字符(这样就不会浪费空间)。但是:这种努力似乎与使用自己的专有字符编码相同(因此也是纹理中字符的自己的顺序)。在我特殊的情况下,我有4096个不同字符的纹理空间,并需要显示拉丁语和日语字符(utf-8只支持通用CJK代码页,这很混乱)。是否有人遇到过类似的问题(如果没有,我真的很惊讶)?如果已经有任何方法,请告诉我!
编辑:在这里描述了同样的问题http://www.tonypottier.info/Unicode_And_Japanese_Kanji/,但它没有提供如何将这些位图字体映射保存到utf-8空间中的真正解决方案。因此,欢迎任何进一步的帮助!
编辑2:
非常感谢您的回答。很抱歉,我的问题没有描述清楚。
我真正想解决的问题是:CJK Unicode范围超过20000个字符。但只有大约2000个字符的子集是必要的,以正确显示日文文本。这些字符分布在U+4E00到U+9FA5的范围内。因此,我需要将这些Unicode代码点(仅适用于日语的2000个代码点)转换为我创建的纹理的坐标(在其中我也可以按照自己的意愿排序字符)。
即U+4E03是一个日本字符,但U+4E04、U+4E05、U+4E06不是。然后U+4E07也是一个日本字符。所以我能看到的最简单的解决方案是:在字符U+4E03之后,在我的纹理中留下三个空格(或在那里写下不必要的字符U+4E04、U+4E05、U+4E06),然后写下U+4E07。但这将浪费很多纹理空间(20000个字符,即使只有2000个是必要的)。所以我想能够在我的纹理中只放入:"...U+4E03,U+4E07..."。但我不知道如何编写我的displayText函数-因为我无法知道我想要显示的字形的纹理坐标在哪里。这将需要一个哈希表或类似的东西,但我不知道如何存储这些数据(为每个字符编写像...{U+4E03,128},{U+4E07,129}...这样的东西来填充哈希表会很混乱)。

以下是问题的回答: 1)没有特定的格式 - 所以我将自己编写displayText函数。 2)没有反对Unicode的理由 - 只是我的位图字体有CJK范围问题。 3)我认为,这通常是平台和语言无关的,但在我的情况下,我使用的是Mac OS X/iOS上的C++和OpenGL。

非常感谢您的帮助!如果您对此有任何进一步的想法,那真的会对我很有帮助!

6个回答

3

您想要解决的真正问题是什么?

是因为UTF-8编码的字符串每个字符占用三个字节吗?如果是,那就切换到UTF-16。否则不要责怪UTF-8。(解释:UTF-8只是一种将整数序列转换为字节序列的算法。它与代码页中字符的分组无关。这就是Unicode代码点的作用。)

是因为Unicode代码点分布在许多“代码页”上吗(其中“代码页”表示256个相邻的Unicode代码点块)?如果是,那就发明一种从Unicode代码点(0x000000-0x10FFFF)到较小整数集的映射。就内存而言,这应该不会比实际所需的字符数多花费4个字节。查找时间大约需要24次内存访问、24次整数比较和24条分支指令。(事实上,这将是一个树图中的二进制搜索。)如果这太昂贵了,您可以使用基于哈希表的映射。

还有其他问题吗?那请给我们一些示例,以更好地了解您的问题。

据我所知,您可能应该编写一个小型实用程序,该程序以您想要在应用程序中使用的Unicode代码点集作为输入,然后生成用于显示文本的代码和数据。这引发了以下问题:

  1. 您是否必须使用特定的位图字体格式,或者将自己编写displayText函数?
  2. 是否有任何原因不使用Unicode作为所有字符串,并在渲染文本时将其转换为您的位图优化编码?编码转换当然应该是内部的displayText方法,对普通应用程序代码不可见。
  3. 仅出于兴趣:问题是否特定于某种编程语言或环境?

更新:

我假设您的主要问题是像这样的某个函数:

Rectangle position(int codepoint)

如果我要做这件事,我会为每个字符准备一个位图。位图的文件名将是码点,这样“大图”可以很容易地重新生成,以防你需要更多的字符。准备工作包括以下步骤:
  1. 加载所有的位图并确定它们的尺寸。这一步的结果是从整数到(宽度、高度)对的映射。
  2. 计算一个好的布局来在大图中放置字符图像,并记住每个字符放置的位置。保存大图。将码点与(x、y、宽度、高度)的映射保存到另一个文件中。这可以是文本文件,或者如果你没有磁盘空间,也可以是二进制文件。细节并不重要。
displayText 函数将按如下方式工作:
void displayText(int x, int y, String s) {
  for (char c : s.toCharArray()) { // TODO: handle code points correctly
    int codepoint = c;
    Rectangle position = positions.get(codepoint);
    if (position != null) {
      // draw bitmap
      x += position.width;
    }
  }
}

Map<Integer, Rectangle> positions = loadPositionsFromFile();

现在唯一的问题是如何使用尽可能少的内存来表示这张地图,并且仍然足够快。当然,这取决于您使用的编程语言。
内存中的表示可以是包含x、y、宽度和高度的几个数组。对于每个元素,16位整数应该足够了。而且也许你只需要8位来表示宽度和高度。然后,另一个数组将代码点映射到positionData中的索引(如果代码点不可用,则映射到某个特殊值)。这将是一个由20000个16位整数组成的数组,因此总之你有:
- positionXpositionYpositionWidthpositionHeight共12000字节。 - 如果使用数组而不是映射,则codepointToIndexInPositionArrays占40000字节。
与位图本身的大小相比,这应该已经足够小了。并且由于这些数组不会改变,所以它们可以放在只读内存中。

非常感谢。我在我的第一篇帖子中添加了细节和答案(因为作为评论太长了)。如果您对此有任何进一步的想法,我会非常高兴! - Constantin

2
我相信对于编码这些数据来说,最有效(无损)的方法是使用Huffman编码来存储文档信息。这是一个经典的信息理论问题。你需要进行映射,以从压缩空间到字符空间。

这种技术将根据每个文档中的字符频率(或您选择应用它的任何领域/文档)尽可能高效地压缩您的文档。只有您使用的字符将被存储,并且它们将以直接与它们使用频率成比例的高效方式存储。

我认为解决这个问题的最佳方法是使用现有的实现(如UTF16、UTF8……)。这将比实现自己的Huffman编码少出错得多,以节省一点空间。磁盘空间和带宽很便宜,但使客户或经理生气的错误并不便宜。我的信念是,Huffman编码在理论上可能是最有效(无损)的编码,但不适用于此应用程序。不过看看链接,这可能有助于某些概念。

- Brian J. Stinar -


1

UTF-8通常是一种非常高效的编码方式。如果您的应用程序主要关注亚洲和其他使用多字节字符集的地区,那么使用UTF-16可能会更加有益。当然,您可以编写自己的编码方式,但它不会节省太多数据,并且会给您带来很多工作。

如果您真的需要压缩数据(我想知道为什么),最好使用一些算法来压缩您的UTF数据。大多数算法在处理较大的数据块时效率更高,但也有一些算法适用于压缩小块的文本。我认为,如果您探索这些算法而不是定义自己的编码方式,将会节省很多时间。


1

这篇文章已经过时了,现在不是1980年了,几乎所有的显示应用程序都不需要搜集位。例如,在开发iPhone应用程序时,您必须计划跨多种语言的本地化,因此仅为日语节省一些位有点无意义。

日本仍然使用Shift-JIS,因为像中国的GB18030、香港的BIG5等,他们已经锁定了大量稳定和高效的资源池。迁移到Unicode需要重新编写大量框架工具,并进行额外的测试。

如果您看一下iPod,它通过仅支持拉丁文、中文、日文和韩文来节省位数,跳过泰文和其他脚本。随着iPhone的存储价格下降和存储容量增加,苹果公司已经能够添加对更多脚本的支持。

UTF-8是节省空间的方法,使用UTF-8进行存储,并转换为UCS-2或更高版本以进行更方便的操作和显示。 Shift-JIS和Unicode之间的差异实际上非常小。


0

汉字单独就有超过4096个字符,我说的不是标点符号,而是用来组成词语的字符。根据维基百科

《康熙字典》中包含的汉字数量约为47,035个,尽管其中很多是历史上积累下来但很少使用的变体。

即使其中许多很少使用,即使90%都不需要,你仍然会用完你的配额。(我认为现代文本中实际使用的数字大约在10-20k左右。)

如果您事先知道将要使用哪些字符,您最好创建一个Unicode代码点到纹理索引的间接表。然后,您只需要在纹理中放置实际使用的字符数量即可。我相信Flash(和一些PDF文件)在内部做了类似的事情。


1
OP正在使用日语而不是中文。由于使用平假名书写,因此需要更少的字符。 - dan04
1
康熙字典的参考价值不高,因为它省略了名字,在现代使用中实际上有约154,000个汉字。 - Steve-o
@dan04 如果你看一下我回答时问题所说的内容,你会发现它并没有提到日语 - 它只是说“多语言”和“亚洲语言”。 - Laurence Gonsalves

0
你可以使用多个位图,并按需加载它们,而不是一个试图包含所有可能字符的单个位图。

但是,所有这些可能出现在单个文本中的字符都分布在Unicode代码页上 - 所以我仍然需要同时将所有这些位图存储在内存中... :| - Constantin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接