代码之家  ›  专栏  ›  技术社区  ›  Nyerguds

以字体显示0x00-0x1F字符

  •  1
  • Nyerguds  · 技术社区  · 6 年前

    我正在开发一个工具,可以编辑一些旧的dos游戏的可翻译字符串文件。

    这显示了我得到的(左)和我想要的(右)。显示的四个条目分别包含字节0x11、0x10、0x1e和0x1f。

    the problem

    (顶部是 DataGridView ,底部是 TextBox )

    有没有简单的方法来展示它们?我试过了 new Font("Terminal", 8) 但那不起作用,字体恢复为微软无衬线。lucida控制台和courier新字体都不包含这些字符。我也试过了 new Font(FontFamily.GenericMonospace, 8) (不确定到底是哪种字体)但也没有。

    另外一个问题是,我正在处理多个基于dos的特殊字符文本编码(ui上有一个下拉列表,可以立即切换并从备份字节中重新转换),所以即使我能够切换到控制台字体,很多这些特殊的(西里尔文、希腊文)k,阿拉伯语等)字符可能不可用。示例条目在一个字符串中只显示一个特殊字符,但实际上可能有组合。

    顶部的一个可能的替代方案,因为它只用于显示,将使用对应于旧DOS字体的Unicode字符进行替换(我已经用U240D->“”替换换行符),但即使如此,我仍想知道是否有任何自动方法可以实现这一点。

    1 回复  |  直到 6 年前
        1
  •  0
  •   Nyerguds    6 年前

    好吧,使用查找表 " ☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼" 解决了我问题的第一部分;在 DataGridView 现在看来是对的。(谢谢, Reza Aghaei )

    • , ¶ § )我不能在0x00-0x1f范围内同时使用这些字符,也不能支持在其>127范围内包含其中一些字符的编码。

    所以,相反,对于可编辑的 TextBox ,我选择将Unicode字符用于 C0 ASCII control codes .

    这种变化纯粹是视觉上的;因为我已经过滤了 文本框 ,我最终控制并覆盖了所有的输入方法:键盘输入、通过快捷键的剪贴板和通过上下文菜单的剪贴板。考虑到动态编码交换系统,我直接用自己的系统替换了整个undo/redo系统,并由原始字节数组支持。

    在预览和编辑中使用不同的字符可能有点奇怪,但是从模型中可以看到,字符串文件清楚地使用符号–151;_、–戥、–戥、–戥来表示左、右、上、下。如果我也在那里使用控制代码字符,那将丢失。

    不过,一个重要的兼容性注意事项是:我最初使用默认的ms sans-serif字体,它似乎可以在我的win10笔记本上使用,但是 它在我的win7电脑上不起作用 ,并给出了所有控制代码的替换字符矩形。最后,我不得不把所有的东西 数据表格控件 , the 文本框 ,及其上下文菜单)到 卢西达无Unicode 让它工作。


    两个功能 FilterText FlattenText 是系统的核心。他们使用这三个侧面数据:

    ASCII_CONTROL 是一个 const String 包含ASCII控制代码字符: "␀␁␂␃␄␅␆␇␈␉␊␋␌␍␎␏␐␑␒␓␔␕␖␗␘␙␚␛␜␝␞␟";

    _validCharactersLowRange 是一个 Char[] 包含转换为选定文本编码的原始00-1f字节范围。每当编码发生更改时,都会更新它,尽管它似乎总是与unicode字符00-1f对应,所以不确定它是否需要更新。(正如我所说,整个问题或多或少是因为字体没有适合该范围的符号。)

    _validCharacters 是另一个 字符[] 其中包含此编码的转换字符范围的其余部分,其中00-1f范围由 ascii_控件 ,以获取编辑中实际允许的字符的完整范围。 文本框 .

    功能:

    过滤器文本 将筛选出要在 文本框 . 这包括用ascii控制代码字符替换00-1f范围。它的设计使得过滤后的文本可以再次通过同一个过滤器,而不会出现任何问题。

    注意使用 \r 因为换行符是我正在编辑的文件格式规范的一部分。

    /// <summary>
    /// Filters illegal characters out of the given text, and converts
    /// any characters in the 0x00-0x1F range to control code symbols.
    /// Used for filtering file, keyboard and clipboard input.
    /// </summary>
    /// <param name="text">Input text</param>
    /// <returns>Text containing only normal ASCII characters, special > 127 characters of the chosen encoding, or control code characters for the 0x00-0x1F range</returns>
    private String FilterText(String text)
    {
        // Filter out null characters; they're completely illegal.
        Char[] inputch = text.Replace(Environment.NewLine, "\r").Where(x => x != '\0').ToArray();
        // Make string for easy IndexOf lookup
        String validCharsLowRange = new String(_validCharactersLowRange);
        for (Int32 i = 0; i < inputch.Length; i++)
        {
            Char inputChar = inputch[i];
            // Ignore line breaks
            if (inputChar == '\r')
                continue;
            // Check for low range characters to replace
            Int32 index = validCharsLowRange.IndexOf(inputChar);
            if (index == -1)
                continue;
            inputch[i] = ASCII_CONTROL[index];
        }
        // Filter out illegal characters
        return new String(inputch.Where((x => x == '\r' || this._validCharacters.Contains(x))).ToArray()).Replace("\r", Environment.NewLine);
    }
    

    扁平文本 文本框 并将其转换为该文本编码中预期的裸字符,这意味着输入已准备好转换回字节或复制到剪贴板,它将用ascii控制代码字符还原00-1f范围的替换。

    /// <summary>
    /// Convert text from the input textBox to actual chars correpsonding to the chosen encoding.
    /// This can be used for converting back to bytes; or for clipboard copy.
    /// </summary>
    /// <param name="text">Text from the TextBox.</param>
    /// <returns>The normalized string.</returns>
    private Char[] FlattenText(String text)
    {
        Char[] preparedOutput = text.Replace(Environment.NewLine, "\r").ToCharArray();
        for (Int32 i = 0; i < preparedOutput.Length; i++)
        {
            Int32 index = ASCII_CONTROL.IndexOf(preparedOutput[i]);
            if (index != -1)
                preparedOutput[i] = this._validCharactersLowRange[index];
        }
        return preparedOutput;
    }
    

    然后,为了更好地测量,我为 文本框 ,因为那些控制代码字符实在是太小了…并添加了一种插入它们的简单方法。

    final project
    (忽略事实 0x0F 丢失了;这是我后来修复的一个小错误)

    不管怎样,谢谢你的帮助;我希望这个错综复杂的混乱能对其他人有用。完整的代码可以找到 here 。可能对其他试图编写处理这些00-1f字符的内容的人有用。(或者,见鬼,有人在编写自己的撤消/重做历史系统;其中有一个相当漂亮的系统。)