Отображать символы 0x00-0x1F в шрифте - PullRequest
0 голосов
/ 31 мая 2018

Я работаю над инструментом, который может редактировать файл переводимых строк для некоторых старых игр для DOS.

Проблема, с которой я сталкиваюсь, заключается в том, что я сталкиваюсь с символами ASCII в этих строках, которые находятся в диапазоне от 0x00 доДиапазон 0x1F (перед пробелом).Эти символы имеют символы в шрифте консоли DOS, но ни один из них, кажется, не присутствует ни в каком современном шрифте.

Это показывает, что я получаю (слева) и что я хочу (справа).Четыре показанные записи содержат соответственно байты 0x11, 0x10, 0x1E и 0x1F.

the problem

(верхняя часть - DataGridView, нижняя часть - TextBox)

Есть ли простой способ их отобразить?Я попытался new Font("Terminal", 8), но это не сработало, и шрифт вернулся к Microsoft Sans Serif.И ни шрифты Lucida Console, ни Courier New не содержат этих символов.Я также попробовал new Font(FontFamily.GenericMonospace, 8) (точно не знаю, какой именно это шрифт), но у него его тоже не было.

Дополнительная проблема заключается в том, что я имею дело с несколькими региональными кодировками на основе DOS со специальнымисимволы (в пользовательском интерфейсе есть выпадающий список для мгновенного переключения и преобразования из вспомогательных байтов), поэтому, даже если бы я смог переключиться на консольный шрифт, многие из этих специальных символов (кириллица, греческий, арабский и т. д.), вероятно,быть недоступнымЗаписи примера показывают только один специальный символ в одной строке, но на самом деле могут быть комбинации.

Возможной альтернативой для верхней части, поскольку она предназначена только для отображения, будет замена с символами Юникода, соответствующимина старый шрифт DOS (я уже заменяю разрывы строк на U240D -> "␍"), но даже тогда мне интересно, есть ли какой-нибудь автоматизированный способ это осуществить.

1 Ответ

0 голосов
/ 02 июня 2018

Что ж, использование таблицы поиска с " ☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼" решило первую часть моей проблемы;предварительный просмотр в 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, потому что эти элементы управлениясимволы кода на самом деле чертовски крошечные ... и добавил простой способ их вставки.

final project
(игнорируйте тот факт, что 0x0F отсутствует; это небольшая ошибка, которую я исправил позже)

В любом случае, спасибо за помощь;Я надеюсь, что этот запутанный беспорядок может быть полезным для кого-то еще.Полный код можно найти здесь .Может быть полезно всем, кто пытается написать что-то для обработки этих символов 00-1F.(Или, чёрт возьми, кто-то пишет свою собственную систему истории отмен / повторов; там есть довольно изящная система.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...