Что ж, использование таблицы поиска с " ☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼"
решило первую часть моей проблемы;предварительный просмотр в DataGridView
выглядит правильно.(спасибо, Реза Агаи ).
Что касается поля редактирования, в конце я понял, что мой вариант использования был противоречивым;некоторые из расширенных кодировок ascii на самом деле содержат символы из этой таблицы поиска (в основном •
, ¶
и §
).Я не могу одновременно использовать эти символы для диапазона 0x00-0x1F, а также поддерживать кодировки, которые содержат некоторые из них в диапазоне> 127.
Так что вместо этого для редактируемого TextBox
я выбралиспользуйте символы Юникода для управляющих кодов C0 ASCII .
Изменение чисто визуальное;так как я уже фильтровал содержимое TextBox
, я закончил контролировать и переопределять все методы ввода;ввод с клавиатуры, буфер обмена с помощью ярлыков и буфер обмена с помощью контекстного меню.И, учитывая систему переключения кодирования «на лету», я пошел дальше и заменил всю систему отмены / восстановления на собственную, подкрепленную оригинальными байтовыми массивами.
Может быть немного странно использовать разныесимволы для предварительного просмотра и редактирования, но, как видно из макета, в файле строк четко используются символы ◄, ►, ▲, ▼ для обозначения влево, вправо, вверх, вниз.Это было бы потеряно, если бы я использовал там и символы управляющего кода.
Одно важное замечание о совместимости, хотя: я изначально использовал для этого шрифт MS Sans Serif по умолчанию, который, похоже, работал на моем ноутбуке Win10, но он не работал на моем ПК с Win7 и давал замену символьных прямоугольников для всех управляющих кодов.В конце концов мне пришлось специально переключить все (DataGridView
, TextBox
и его контекстные меню) на Lucida Sans Unicode , чтобы заставить его работать.
две функции FilterText
и FlattenText
являются ядром системы.Они используют эти три части побочных данных:
ASCII_CONTROL
- это const String
, содержащий символы кода управления ASCII: "␀␁␂␃␄␅␆␇␈␉␊␋␌␍␎␏␐␑␒␓␔␕␖␗␘␙␚␛␜␝␞␟";
_validCharactersLowRange
- это Char[]
, содержащий оригинал00-1F диапазон байтов, преобразованных в выбранную кодировку текста.Это обновляется всякий раз, когда изменяется кодировка, хотя кажется, что она всегда просто соответствует символам Юникода 00-1F, поэтому не уверен, нужно ли ее вообще обновлять.(Как я уже сказал, вся эта проблема в большей или меньшей степени состоит в том, что шрифты не имеют надлежащих символов для этого диапазона.)
_validCharacters
- это еще один Char[]
, который содержит остаток преобразованной кодировкидиапазон символов, с диапазоном 00-1F, замененным содержимым ASCII_CONTROL
, чтобы получить полный диапазон действительных разрешенных символов при редактировании TextBox
.
Функции:
FilterText
отфильтрует любой ввод символов для отображения в TextBox
.Это включает в себя замену диапазона 00-1F на символы кода управления ASCII.Он спроектирован так, что отфильтрованный текст можно без проблем пропустить через тот же фильтр.
Обратите внимание, что использование \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
и преобразует его в символы, ожидаемые в этой кодировке текста, то есть ввод подготовлен для преобразования обратно в байты или для копирования в буфер обмена, Он отменяет замену диапазона 00-1F на символы кода управления ASCII.
/// <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
отсутствует; это небольшая ошибка, которую я исправил позже)
В любом случае, спасибо за помощь;Я надеюсь, что этот запутанный беспорядок может быть полезным для кого-то еще.Полный код можно найти здесь .Может быть полезно всем, кто пытается написать что-то для обработки этих символов 00-1F.(Или, чёрт возьми, кто-то пишет свою собственную систему истории отмен / повторов; там есть довольно изящная система.)