none
Как массив байт показать в textBox? RRS feed

  • Вопрос

  • Задача: массив байт от 0 до 255 выводить в текстовое поле (в виде символов), потом копировать эти символы в другое текстовое поле. После чего обратно преобразовывать их в массив байт.

    Использую кодировку "windows-1251"
    В этой кодировке один байт описывает один символ.
    Нужно ВСЕ символы выводить в textBox

    Возникло ряд проблем.
    1. После символа ‘\0’ обрубается вся строка. Т.е.
    textBox2.Text = win_1251String;
    отобразит символы которые идут до ‘\0’, но не после него.

    Сделал такой вариант:
    for (int i = 0; i < win_1251String.Length; i++)
    {
    textBox1.AppendText(win_1251String[i].ToString());
    }
    Но, тут возникла еще одна проблема:

    Последние символы немножко не совпадают.

    Вот весь текст программы:

    private void Form1_Load(object sender, EventArgs e)
            {
                Encoding win_1251 = Encoding.GetEncoding("windows-1251");
    
                byte[] asciiBytes = new byte[256];
    
                //Вариант 1 (символ '\0' последний)
                for (int i = 0; i < asciiBytes.Length; i++)
                {
                    asciiBytes[255-i] = (byte) i;
                }
                //Вариант 2 (символ '\0' первый)
                /*for (int i = 0; i < asciiBytes.Length; i++)
                {
                    asciiBytes[i] = (byte)i;
                }*/
    
                char[] win_1251Chars = new char[win_1251.GetCharCount(asciiBytes, 0, asciiBytes.Length)];
                win_1251.GetChars(asciiBytes, 0, asciiBytes.Length, win_1251Chars, 0);
                string win_1251String = new string(win_1251Chars);
                textBox2.Text = win_1251String;
    
                for (int i = 0; i < win_1251String.Length; i++)
                {
                    textBox1.AppendText(win_1251String[i].ToString());
                }
            }
    
    private void textBox1_TextChanged(object sender, EventArgs e)
            {
                button1.Text = textBox1.Text.Length.ToString();
            }

    Подскажите, пожалуйста, как обеспечить вывод в текстовое поле служебных символов?

    17 июля 2012 г. 15:01

Ответы

  • Тогда прогоняйте текст (со спецсиволвами) перед отображением в текстбоксе через кастомный енкодер, превращая спецсимволы во что-то вроде "(22)". А перед отправкой - прогоняйте через обратный декодер, превращая "(22)" в символ с кодом 22. Что-то вроде:

        class Program
        {
            static void Main(string[] args)
            {
                Encoding win_1251 = Encoding.GetEncoding("windows-1251");
    
                byte[] asciiBytes = new byte[256];
    
                //Вариант 1 (символ '\0' последний)
                for (int i = 0; i < asciiBytes.Length; i++)
                {
                    asciiBytes[255 - i] = (byte)i;
                }
                //Вариант 2 (символ '\0' первый)
                /*for (int i = 0; i < asciiBytes.Length; i++)
                {
                    asciiBytes[i] = (byte)i;
                }*/
    
                char[] win_1251Chars = new char[win_1251.GetCharCount(asciiBytes, 0, asciiBytes.Length)];
                win_1251.GetChars(asciiBytes, 0, asciiBytes.Length, win_1251Chars, 0);
    
                string raw = new string(win_1251Chars);
    
                string encoded = Encode(raw);
                Console.WriteLine(encoded); // ..... (1)(0)
    
                string decoded = Decode(encoded);
                Console.WriteLine(raw == decoded); // true
            }
    
            static string Encode(string raw)
            {
                return String.Concat(raw.Select(c => 
                    Char.IsControl(c) 
                    ? String.Format("({0})", (byte)c) 
                    : c.ToString())
                    .ToArray());
            }
    
            static string Decode(string encoded)
            {
                return Regex.Replace(
                    encoded, 
                    @"\((?<code>\d*)\)",
                    match => ((char)Byte.Parse(match.Groups["code"].Value)).ToString());
            }
        }
    

    • Помечено в качестве ответа sg6336 19 июля 2012 г. 6:18
    18 июля 2012 г. 16:28

Все ответы

  • В кодировке ASCIII и ее производных первые 32-символа - непечатные. Т.е. у них по определению нет представления в виде символов.

    Например, символ с кодом 8 - это backspace. Технически, вывод в текстбокс бэкспейса должен просто удалить предыдущий символ. В каком виде вы хотите получить этот символ в текстбоксе?

    17 июля 2012 г. 15:27
  • В том виде, который допускает создание нового массива байт.
    Немного более подробно опишу задачу:
    Есть интерфейс на ПК (написал на C#) в котором два текстовый поля и кнопка.
    Этот интерфейс через СОМ порт связывается с Bluetooth и отправляет данные на другое устройство (собранное на микроконтроллере МК, с прошивкой написанной на С). Устройство обрабатывает (шифрует) полученные данные и через Bluetooth отправляет их обратно на компьютер.
    В первом текстовом поле отображается, то что мы посылаем на МК. А во втором текстовом поле, то что принимаем с МК.
    Если бы мы отправляли файл. То было бы проще. В файл можно сохранить любые байты.
    Но, для демонстрации макета хотят пользоваться текстбоксами. А ряд символов (пару штук, как видно на рисунке) не отображаются.

    Что посоветуете в данной ситуации?

    P.S. Можно, конечно, поизварщатся и для непечатаемых символов использовать другую кодировку (в которой они отображаются). Но, пока что это звучит жутко (для меня).
    P.P.S. Поэтому и начал использовать не ASCII, а windows-1251 кодировку (в ней больше отображаемых символов).

    17 июля 2012 г. 16:44
  • Если там абракадабра должна показываться, то почему бы не использовать base64?
    18 июля 2012 г. 7:13
    Отвечающий
  • Идея хорошая, но с одним «Но».
    Символов всего 64, а не 256.
    Как отображать остальные значения?

    18 июля 2012 г. 9:39
  • Вы, по-моему, не дочитали статью на википедии. Никто же не говорит о том, что исходная и результирующая последовательности будут занимать одинаковое кол-во байт. Суть base64-кодирования - получить на выходе печатную последовательность символов.
    18 июля 2012 г. 10:58
  • Да, что-то ступил

    Когда сделаю, отпишусь. И проставлю «ответы»

    Base64

    18 июля 2012 г. 12:21
  • Обычно непечатаемые символы заменяют на точку, в таких программах, как HEX-viewer'ы и т. п.

    18 июля 2012 г. 12:46
  • Вся сложность в том, что мне нужно будет брать этот текст из textbox и преобразовывать опять в массив байт. Если заменить на точки, то информация будет утеряна.

    Сейчас рассматриваю два варианта:

    1. Использование Base64 для отображения      этого текста. В принципе, все работает. Но, «наглядность» макета страдает.      Т.к. отображаются не 256 символов, а 64 символа.
    2. Добавил еще по одному textbox. В одном textbox вывожу HEX представление      массива байт, а в другом textbox      строку с пропусками непечатных символов. Но, тогда длинна строки      получается короче, чем массив байт (из которых она образуется). А в      программе работаю только с массивами байт, а не строками.

    Пока ищу компромисс.

    18 июля 2012 г. 13:19
  • > Вся сложность в том, что мне нужно будет брать этот текст из textbox и преобразовывать опять в массив байт.

    Оригинальный текст пусть хранится в строке. Его и брать для преобразования. И лишь при выводе на текстбокс заменять непечатемые символы на точки.

    18 июля 2012 г. 13:22
  • Так для демонстрации надо чтобы отправленные и принятые данные визуально совпали или что? Не совсем понятно откуда берется изначальная байтовая последовательность. Кто ее вводит и как?
    18 июля 2012 г. 13:30
  • Еще раз.
    Изначально оператор ПК вводит текст.
    Потом этот текст отправляется в шифратор.
    Из шифратора возвращается шифрограмма (на уровне байт и бит все символы были заменены).
    Т.к. шифратор симметричный, то нужно шифрограмму отправить опять на шифратор. И тогда вернется исходный текст (который оператор набрал).
    Проблема в том, что служебные символы не могут быть отображены в textbox. Поэтому когда делаю команду textbox1.Text = textbox2.Text. То копируются не все символы. Т.к. textbox2 не смог отобразить все байты в виде символов.
    Весь затык, что их как-то нужно отобразить.
    Вариант с Base64 «начальство» отвергло. Т.к. «не слишком запутано выглядит» текст после шифровки.
    Сейчас думаю делать в Unicode с надеждой, что во время демонстрации в шифрограмме не попадутся символы U+0000 до U+001F. А саму шифрограмму хранить в статическом массиве байт. И копировать в textbox1 не из textbox2, а из этого массива байт.

    Мне не известно, баг это или нет, но textbox не может отображать какие либо символы, после символа '\0'. Т.е. обрубается все остальное после этого символа.
    И без разницы, копирую строкой или из массива байт в textbox.

    18 июля 2012 г. 15:39
  • Тогда прогоняйте текст (со спецсиволвами) перед отображением в текстбоксе через кастомный енкодер, превращая спецсимволы во что-то вроде "(22)". А перед отправкой - прогоняйте через обратный декодер, превращая "(22)" в символ с кодом 22. Что-то вроде:

        class Program
        {
            static void Main(string[] args)
            {
                Encoding win_1251 = Encoding.GetEncoding("windows-1251");
    
                byte[] asciiBytes = new byte[256];
    
                //Вариант 1 (символ '\0' последний)
                for (int i = 0; i < asciiBytes.Length; i++)
                {
                    asciiBytes[255 - i] = (byte)i;
                }
                //Вариант 2 (символ '\0' первый)
                /*for (int i = 0; i < asciiBytes.Length; i++)
                {
                    asciiBytes[i] = (byte)i;
                }*/
    
                char[] win_1251Chars = new char[win_1251.GetCharCount(asciiBytes, 0, asciiBytes.Length)];
                win_1251.GetChars(asciiBytes, 0, asciiBytes.Length, win_1251Chars, 0);
    
                string raw = new string(win_1251Chars);
    
                string encoded = Encode(raw);
                Console.WriteLine(encoded); // ..... (1)(0)
    
                string decoded = Decode(encoded);
                Console.WriteLine(raw == decoded); // true
            }
    
            static string Encode(string raw)
            {
                return String.Concat(raw.Select(c => 
                    Char.IsControl(c) 
                    ? String.Format("({0})", (byte)c) 
                    : c.ToString())
                    .ToArray());
            }
    
            static string Decode(string encoded)
            {
                return Regex.Replace(
                    encoded, 
                    @"\((?<code>\d*)\)",
                    match => ((char)Byte.Parse(match.Groups["code"].Value)).ToString());
            }
        }
    

    • Помечено в качестве ответа sg6336 19 июля 2012 г. 6:18
    18 июля 2012 г. 16:28
  • Спасибо.

    С делегатами слабоват. Пошел медитировать на код до просветления.

    Завтра помечу как ответ Ваш код, если больше вопросов не возникнет.

    18 июля 2012 г. 17:12