我正在研究一种可以编辑某些旧DOS游戏的可翻译字符串文件的工具。
我遇到的问题是我在这些字符串中遇到的ASCII字符位于0x00到0x1F范围内(空格之前)。这些字符在DOS控制台字体中有符号,但它们似乎都不存在于任何现代字体中。
这显示了我得到的(左)和我想要的(右)。显示的四个条目分别包含字节0x11,0x10,0x1E和0x1F。
(上半部分是TextBox
,下半部分是new Font("Terminal", 8)
)
有没有简单的方法来显示它们?我尝试了new Font(FontFamily.GenericMonospace, 8)
但是没有用,字体还原为Microsoft Sans Serif。 Lucida Console和Courier New字体都不包含这些字符。我也试过<link href="{{ asset('vendor/bootstrap/dist/css/bootstrap.min.css') }}" rel="stylesheet" />
(不确定究竟是哪种字体),但也没有。
另一个问题是我处理多个基于DOS的区域文本编码与特殊字符(在UI上有一个下拉列表可以立即切换并从后备字节重新转换),所以即使我将能够切换到控制台字体,很多这些特殊(西里尔,希腊,阿拉伯等)字符可能无法使用。示例条目在一个字符串中只显示一个特殊字符,但实际上可能有组合。
顶部的一个可能的替代方案,因为它仅用于显示,将用对应于旧DOS字体的unicode字符进行替换(我已经用U240D替换了换行符 - &gt;&#34;␍&#34;),但即便如此,我也想知道是否有任何自动解决方法。
答案 0 :(得分:0)
好吧,使用" ☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼"
的查找表解决了我的问题的第一部分; DataGridView
中的预览现在看起来正确。 (谢谢,Reza Aghaei)。
至于编辑框,最后我意识到我的用例是矛盾的;一些扩展的ascii编码实际上包含该查找表中的字符(主要是•
,¶
和§
)。我不能将这些字符用于0x00-0x1F范围,并且还支持在其&gt;中包含其中一些字符的编码。 127范围。
相反,对于可编辑的TextBox
,我选择使用C0 ASCII control codes的unicode字符。
这种变化纯粹是视觉上的;因为我已经过滤了TextBox
的内容,所以我最终控制并覆盖了所有输入法;键盘输入,通过快捷方式剪贴板和通过上下文菜单的剪贴板。鉴于即时编码交换系统,我一直在前进,用我自己的系统替换整个undo / redo系统,并以原始字节数组为后盾。
使用不同的字符进行预览和编辑可能有点奇怪,但正如您从模型中看到的那样,字符串文件清楚地使用符号◄,►,▲,▼来表示左,右,上, 下。如果我在那里使用控制代码字符,那将会丢失。
一个重要的兼容性说明:我最初使用默认的MS Sans Serif字体,这似乎适用于我的Win10笔记本电脑,但它在我的Win7 PC上无效,为所有控制代码提供了替换字符矩形。最后,我必须专门将所有内容(DataGridView
,TextBox
及其上下文菜单)切换为 Lucida Sans Unicode 以使其正常工作。
两个函数FilterText
和FlattenText
是系统的核心。他们使用这三个边数据:
ASCII_CONTROL
是const String
,其中包含ASCII控制代码字符:"␀␁␂␃␄␅␆␇␈␉␊␋␌␍␎␏␐␑␒␓␔␕␖␗␘␙␚␛␜␝␞␟";
_validCharactersLowRange
是Char[]
,包含转换为所选文本编码的原始00-1F字节范围。每当编码改变时,这都会更新,尽管它似乎总是只对应于unicode字符00-1F,因此不确定它是否需要更新。 (正如我所说,整个问题或多或少只是字体没有适合该范围的符号。)
_validCharacters
是另一个Char[]
,其中包含此编码的其余转换字符范围,其中00-1F范围由ASCII_CONTROL
的内容替换,以获得全部范围编辑TextBox
中的实际允许字符。
功能:
FilterText
会过滤掉TextBox
中要显示的字符输入。这包括用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);
}
FlattenText
从TextBox
获取文本并将其转换为该文本编码中预期的裸字符,这意味着输入准备好转换回字节,或者复制到剪贴板,它用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;
}
然后,为了更好的衡量,我为TextBox
内置了字体大小控件,因为那些控制代码字符真的很小......并添加了一种简单的方法来插入它们。
(忽略0x0F
缺失的事实;这是我后来修复的一个小错误)
无论如何,谢谢你的帮助;我希望这个令人费解的混乱可能对其他人有用。完整代码可以找到here。对于试图写一些东西来处理这些00-1F字符的其他人可能会有用。 (或者,有人写了他们自己的撤销/重做历史系统;在那里得到了一个非常漂亮的。)