最近正好需要在 Windows 里显示 DOS 字符,特别是 ASCII 码 31 及以下 128 及以上的特殊字符。摸索了一下,找到了一个还算可以的解决方案。
重点提示
1. 采用 CP 437 转换 ASCII 码 128 及以上的字符;
2. ASCII 小于 32 的字符可以被解释为“控制字符”或“图像字符”;Windows 的代码转换选择前一种解释(例如,CR-LF 作为换行符);
3. 可以自己继承 Encoding 类,实现图像字符的转换。
背景
DOS 下面的特殊字符包括三个部分:CHR(0) - CHR(31), CHR(127), CHR(128-255)。
System.Text.Encoding 类有几个属性,可以返回常用的编码;但是 ASCII 编码只允许 7 位。
代码
下面为了方便,先帖上代码,以后再补上文字。
using System;
using System.Text;
namespace QuickHelp
{
public class Graphic437Encoding : Encoding
{
private static readonly Encoding CP437 = Encoding.GetEncoding(437);
private const string GraphicCharacters = "\0☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼";
public static bool IsControlCharacter(char c)
{
return (c < 32) || (c == 127);
}
public static bool ContainsControlCharacter(string s)
{
if (s == null)
throw new ArgumentNullException("s");
for (int i = 0; i < s.Length; i++)
{
if (IsControlCharacter(s[i]))
return true;
}
return false;
}
public static void SubstituteControlCharacters(char[] chars)
{
if (chars == null)
throw new ArgumentNullException("chars");
SubstituteControlCharacters(chars, 0, chars.Length);
}
public static void SubstituteControlCharacters(char[] chars, int index, int count)
{
if (chars == null)
throw new ArgumentNullException("chars");
if (index < 0 || index > chars.Length)
throw new ArgumentOutOfRangeException("index");
if (count < 0 || count > chars.Length - index)
throw new ArgumentOutOfRangeException("count");
for (int i = index; i < index + count; i++)
{
if (chars[i] < 32)
chars[i] = GraphicCharacters[chars[i]];
else if (chars[i] == 127)
chars[i] = '⌂';
}
}
public static string SubstituteControlCharacters(string s)
{
if (s == null)
return null;
if (!ContainsControlCharacter(s))
return s;
char[] chars = s.ToCharArray();
SubstituteControlCharacters(chars);
return new string(chars);
}
public override int GetByteCount(char[] chars, int index, int count)
{
return CP437.GetByteCount(chars, index, count);
}
public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex)
{
return CP437.GetBytes(chars, charIndex, charCount, bytes, byteIndex);
}
public override int GetCharCount(byte[] bytes, int index, int count)
{
return CP437.GetCharCount(bytes, index, count);
}
public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex)
{
int charCount = CP437.GetChars(bytes, byteIndex, byteCount, chars, charIndex);
SubstituteControlCharacters(chars, charIndex, charCount);
return charCount;
}
public override int GetMaxByteCount(int charCount)
{
return CP437.GetMaxByteCount(charCount);
}
public override int GetMaxCharCount(int byteCount)
{
return CP437.GetMaxCharCount(byteCount);
}
}
}
参考资料
Code page 437 (Wikipedia)