На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
  
> С# Проблемы с кодировкой в консоли
    Делаю простую задачу: читаю в консоли клавишу с помощью метода ReadKey() и добавляю
    полученный символ в строковую переменную. Вот код:
    ExpandedWrap disabled
       ConsoleKeyInfo keyInfo = new ConsoleKeyInfo();
       string str = null;
       
       while (true)
       {
            keyInfo = Console.ReadKey();
            if (keyInfo.Key == ConsoleKey.Enter)
                  break;
            str += keyInfo.KeyChar;
       }
       Console.WriteLine("\n{0}",str);

    С латинскими символами проблем нет, а вместо русских - выдает знаки вопроса и при вводе и при выводе.
    В чем дело не могу понять.
    Попытки подключить кодовую страницу:

    Console.OutputEncoding = Encoding.GetEncoding(1251);

    или получить строку из набора байт, соответствующих введенным символам:

    string res = Encoding.GetEncoding(1251).GetString(Encoding.Default.GetBytes(str.ToCharArray()));

    ни к чему хорошему не приводят.

    Помогите, пожалуйста!
      Цитата avt @
      Делаю простую задачу: читаю в консоли клавишу с помощью метода ReadKey() и добавляю
      полученный символ в строковую переменную. Вот код:
      ExpandedWrap disabled
         ConsoleKeyInfo keyInfo = new ConsoleKeyInfo();
         string str = null;
         
         while (true)
         {
              keyInfo = Console.ReadKey();
              if (keyInfo.Key == ConsoleKey.Enter)
                    break;
              str += keyInfo.KeyChar;
         }
         Console.WriteLine("\n{0}",str);

      С латинскими символами проблем нет, а вместо русских - выдает знаки вопроса и при вводе и при выводе.
      В чем дело не могу понять.
      Попытки подключить кодовую страницу:

      Console.OutputEncoding = Encoding.GetEncoding(1251);

      или получить строку из набора байт, соответствующих введенным символам:

      string res = Encoding.GetEncoding(1251).GetString(Encoding.Default.GetBytes(str.ToCharArray()));

      ни к чему хорошему не приводят.

      Помогите, пожалуйста!

      У меня твой код работает отлично, попробуй использовать "Cyrillic (DOS)" 866 вместо 1251
        Что значит попробовать кириллицу Dos?

        Console.OutputEncoding = Encoding.GetEncoding(866);
        не помогает

        Напиши, какой должен быть код!
          Цитата avt @
          Попытки подключить кодовую страницу:

          Console.OutputEncoding = Encoding.GetEncoding(1251);


          У твоей консоли просто нет такой кодировочной страницы наверное. Посмотри какие есть варианты кодировок командой chcp с командной строки.
            Цитата avt @
            Что значит попробовать кириллицу Dos?

            Console.OutputEncoding = Encoding.GetEncoding(866);
            не помогает

            Напиши, какой должен быть код!

            Твой код работает! Сделай то что посоветовал Vladimir
            У меня в консоли пишет
            ExpandedWrap disabled
              C:\>chcp
              Текущая кодовая страница: 866
              C:\>


            Добавлено
            И с русскими буквами проблем нет.
              Еще консольные фонты можно попробовать поменять, у меня например получилось русскую UTF8 строку вывести только в Lucida Console В кодировке UTF8 вроде хорошо видно

              ExpandedWrap disabled
                string cyrillic = "У твоей консоли просто нет такой кодировочной страницы наверное. ";
                string utf8 = Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(cyrillic));        
                Console.OutputEncoding = Encoding.UTF8;
                Console.WriteLine(utf8);
                Console.Read();


              При условии что в консоле выбраны Lucida Console получается вроде нормально.

              Добавлено
              Ну как, вывелась строка? :huh:

              Добавлено
              Цитата Coffee @
              У меня твой код работает отлично, попробуй использовать "Cyrillic (DOS)" 866 вместо 1251


              У тебя Default кодировка наверное сразу на кириллице стоит, а у avt на какой-то другой. Гляди, байты беруться с Default кодировкой, а строка потом читается с 1251. Могут быть проблемы.

              ExpandedWrap disabled
                string res = Encoding.GetEncoding(1251).GetString(Encoding.Default.GetBytes(str.ToCharArray()));
              Сообщение отредактировано: Vladimir -
                  Так тоже должно работать:

                  ExpandedWrap disabled
                    string res = Encoding.GetEncoding(1251).GetString(Encoding.GetEncoding(1251).GetBytes(cyrillic.ToCharArray()));
                    На команду чеккодпэйдж командная строка выдала ..866.
                    строки типа Console.WriteLine("Привет") работают нормально.
                    метод ReadLine() тоже работает прекрасно.

                    А строка с методом GetString не идет...

                    Отробатывая пошагово, смотрю за переменными _key и _keyChar (они в keyInfo).
                    Если, например, нажать в русской раскладке клавишу G(П),
                    то в _key попадает символ G а в _keyChar - какой-то непонятный
                    символ, напоминающий Y с кодом 1199. Таким образом,
                    Метод ReadKey() уже при чтении клавиши выдаёт знак вопроса вместо русского символа
                    (т.е. дает ошибку на входе).

                    И вот еще что: если в моем коде вместо строки
                    str += keyInfo.KeyChar;
                    написать строку
                    str += keyInfo.Key;
                    то и с латиницей начинаются проблемы: ввожу строку в нижнем регистре,
                    а выводятся - те же символы, но напечатанные заглавными буквами.
                    Т.е. свойство Key дает ошибку на выходе.

                    Я пробовал: мой код на другом компьютере (Visual C# 2010 Express) работает
                    замечательно без всяких кодировок. Но как только вместо KeyChar взять Char,
                    начинаются чудеса.

                    Добавлено
                    Ошибка в предыдущем сообщении:
                    "Но как только вместо KeyChar взять Char Key"
                      Цитата avt @
                      А строка с методом GetString не идет...


                      Там у тебя в исходной строке по ходу уже не кириллица а неизвестные знаки. :(

                      Добавлено
                      Цитата avt @
                      Т.е. свойство Key дает ошибку на выходе.


                      Не, он же представляет клавишу. Она называется G. Если б у тебя было ДВЕ клавиши - одна для G, а другая для g, тогда б они по разному бы обозначались.

                      Добавлено
                      Цитата avt @
                      в _keyChar - какой-то непонятный
                      символ, напоминающий Y с кодом 1199. Таким образом,
                      Метод ReadKey() уже при чтении клавиши выдаёт знак вопроса вместо русского символа
                      (т.е. дает ошибку на входе).


                      Какие-то проблемы с чтением кодировки unicode
                        Я согласен, в keyInfo.Key читаются клавиши а не символы, и никакой ошибки на выходе не существует!

                        Остается понять, что с Unicode-ом
                          Пробую смотреть, какие коды соответствуют введенным символам.
                          После цикла while добавляю следующий код:
                          ExpandedWrap disabled
                            int cp = 65001;
                            // 65001 это юникод utf-8
                            char[] ch = str.ToCharArray();
                            byte[] b = Encoding.GetEncoding(cp).GetBytes(ch);
                            for (int i = 0; i < b.Length; i++)
                                Console.Write(b[i] + " ");

                          Ввожу 'абв' - на выходе должно быть 208 176 208 177 и 208 178, а у меня 210 160 210 161 210 162.
                          Если брать cp=1200 (utf-16), то должно быть 48 4 49 4 50 4, а у меня 160 4 161 4 162 4, что соответствует
                          последовательности 'абв' в кодировке 866, если брать 0, 2 и 4 элементы массива b.
                          Того же эффекта можно добиться и при cp = 65001, если брать 1, 3 и 6 элементы этого массива.
                          ExpandedWrap disabled
                            char[] ch = str.ToCharArray();
                            byte[] b = Encoding.GetEncoding(1200).GetBytes(ch);
                            for (int i = 0; i < b.Length; i++)
                                Console.Write(b[i] + " ");
                            byte[] b1 = new byte[b.Length / 2];
                            for (int i = 0; i < b1.Length; i++)
                                b1[i] = b[i * 2];
                            Console.WriteLine("\n{0}",Encoding.GetEncoding(866).GetString(b1));

                          Те, у кого такая проблема, это поймут...

                          Но это не решение вопроса. Остается непонятным, почему в VS Team System 2008 имеется такая
                          чехорда с кодировками.

                          Может быть, это глюк Net framework 3.5 и его просто надо заменить на новый?..

                          Вопрос остается открытым!
                            Цитата avt @
                            Если брать cp=1200 (utf-16), то должно быть 48 4 49 4 50 4, а у меня 160 4 161 4 162 4, что соответствует

                            Что то вы путаете. У юникода нулевая страница содержит символы ASCII. потому совершенно ожиданно, что UTF16 переведёт "abc" в "61 00 62 00 63 00".
                            Данный код у меня так и работает:
                            ExpandedWrap disabled
                              var enc = System.Text.Encoding.GetEncoding(1200);
                              var txt = "abc";
                              var b1 = enc.GetBytes(txt);
                              var b2 = Encoding.Unicode.GetBytes(txt);


                            Whhops! язык перепутал. у вас же абв. щас... :)

                            Добавлено
                            для "абв" данный код даёт так же ожиданный результат "30 04 31 04 32 04" (HEX), что соответствует, например, этой информации: http://ru.wikipedia.org/wiki/Windows-1251 - там в табличке подписаны номера юникода для символов этой кодировки.

                            Добавлено
                            Если у вас не такой результат - вероятно у вас в системе почему то неверно получается кодировка по её коду. Наведите в дебаге на полученую кодировку по коду 1200 и убедитесь что её имя - EncodingName = "Unicode" или WebName = "utf-16".
                            Сообщение отредактировано: Alexus -
                              Программное решение исходного вопроса следующее:
                              ExpandedWrap disabled
                                ConsoleKeyInfo keyInfo = new ConsoleKeyInfo();
                                string str = null;
                                while (true)
                                {
                                    keyInfo = Console.ReadKey();
                                    if (keyInfo.Key == ConsoleKey.Enter)
                                        break;
                                    str += keyInfo.KeyChar;                
                                }
                                char[] ch = str.ToCharArray();
                                byte[] b = Encoding.GetEncoding(1200).GetBytes(ch);
                                byte[] b1 = new byte[b.Length / 2];
                                for (int i = 0; i < b1.Length; i++)
                                    b1[i] = b[i * 2];
                                string str2 = Encoding.GetEncoding(866).GetString(b1);

                              и в str2 попадают корректные символы, которые можно анализировать
                              на предмет совпадения с эталоном. Тот факт, что при вводе остаются
                              знаки вопроса, для меня не важно, так как я их маскирую звездочками
                              (изначально решается задача входа в некую среду по паролю).

                              Другой вопрос, почему у одних все работает нормально (например, в
                              2010-ом экспрессе), а у других (в 2005 и 2008-ой студии) - нет, и как
                              данную проблему решить не программно, а системно (чтобы всё у всех
                              работало правильно). Я пробовал переустановить net framework на более
                              позднюю версию, - не помогает.
                              0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                              0 пользователей:


                              Рейтинг@Mail.ru
                              [ Script execution time: 0,0523 ]   [ 16 queries used ]   [ Generated: 29.06.25, 18:38 GMT ]