Кодировки в Windows
В данной статье пойдёт речь о кодировках в Windows. Все в жизни хоть раз использовали и писали консольные приложения как таковые. Нету разницы для какой причины. Будь-то выбивание процесса или же просто написать «Привет. Я не могу сделать кодировку нормальной, поэтому я смотрю эту статью!».
Тем, кто ещё не понимает, о чём проблема, то вот Вам:
А тут было написано:
Но никто ничего не понял.
В любом случае в Windows до 10 кодировка BAT и других языков, не использует кодировку поддерживающую Ваш язык, поэтому все русские символы будут писаться неправильно.
1. Настройка консоли в батнике
Сразу для тех, кто пишет chcp 1251 лучше написать это:
Первый способ устранения проблемы, это Notepad++. Для этого Вам нужно открыть Ваш батник таким способом:
Не бойтесь, у Вас откроется код Вашего батника, а затем Вам нужно будет сделать следующие действия:
Если Вам ничего не помогло, то преобразуйте в UTF-8 без BOM.
2. Написание консольных программ
Нередко люди пишут консольные программы(потому что на некоторых десктопные писать невозможно), а кодировка частая проблема.
Первый способ непосредственно Notepad++, но а если нужно сначала одну кодировку, а потом другую?
Сразу для использующих chcp 1251 пишите это:
Второй способ это написать десктопную программу, или же использовать Visual Studio. Если же не помогает, то есть первое: изменение кодировки вывода(Пример на C++).
Если же не сработает:
3. Изменение chcp 1251
Если же у Вас батник, то напишите в начало:
Теперь у Нас будет нормальный вывод в консоль. На других языках (С++):
4. Сделать жизнь мёдом
При использовании данного способа Вы не сможете:
- Разрабатывать приложения на Windows ниже 10
- Спасти мир от данной проблемы
- Думать о других людях
- Разрабатывать десктопные приложения, так как Вам жизнь покажется мёдом
- Сменить Windows на версию ниже 10
- Ну и понимать людей, у которых Windows ниже 10
Установить Windows 10. Там кодировка консоли специально подходит для языка страны, и Вам больше не нужно будет беспокоиться об этой проблеме. Но у Вас появится ещё 6 проблем, и вернуться к предыдущей лицензионной версии Windows Вы не сможете.
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.
Блог GunSmoker-а (переводы)
. when altering one’s mind becomes as easy as programming a computer, what does it mean to be human.
вторник, 5 октября 2010 г.
Почему ACP <> OEMCP (обычно)
Это перевод Why ACP != OEMCP (usually). Автор: Майкл Каплан.
Обычно при работе с консолью люди сразу же замечают такую вещь: страница по-умолчанию ANSI (ACP) не совпадает с кодовой страницей OEM (OEMCP) для большинства локалей.
Это идёт из времён MS-DOS (как и многие другие вещи!).
Когда у нас было время DOS, кодовые страницы контролировались IBM, а не Microsoft. Многие «оригинальные» кодовые страницы появились в это время — от интересных до очень странных (да, я говорю о кодовой странице №437!), хотя некоторые из них предшествуют даже IBM (насчёт этого я точно не уверен).
Затем вышла Windows с кодовыми страницами Windows, разработанными (если можно так сказать о данных), чтобы обрабатывать много языков одновременно. Смоделированными по серии ISO-8859, но с добавлением символов, полезных большинству языков, а не выбранным (типа базовой поддержки французского в арабской кодовой странице):
- 1250 — Central Europe
- 1251 — Cyrillic
- 1252 — Latin 1 (иногда называемая Western European)
- 1253 — Greek
- 1254 — Turkish
- 1255 — Hebrew
- 1256 — Arabic
- 1257 — Baltic
- 1258 — Vietnam
Идея была в том, что DOS-программы (в тот момент не рассматриваемые как «устаревшие» — потому что других программ практически не было) работали бы с теми же самыми старыми кодовыми страницами, а Windows приложения использовали бы новые кодовые страницы и работали бы с многими языками. Были даже добавлены API-функции, чтобы менять поведение базовых функций файловой системы, поскольку файловая система — это то место, где пересекаются эти приложения. Так были рождены функции AreFileApisANSI, SetFileApisToOEM и SetFileApisToANSI 1 .
Итак, эти кодовые страницы не равны по соображениям совместимости.
— Ага — скажете вы, — но почему же тогда ACP и OEMCP равны для всех локалей CJK? У нас есть:
- 932 — Japanese (Shift-JIS)
- 936 — Simplified Chinese (GBK)
- 949 — Korean
- 950 — Traditional Chinese (Big5)
И они работают и как кодовые страницы ANSI и как OEM в большинстве локалей восточной Азии.
Для этого есть много причин. Одна из самых очевидных — эти четыре кодовые страницы изначально создавались по стандартам (государственным или промышленным) и поэтому у них нет вопроса обратной совместимости. Никто не захотел просто так штамповать кодовые страницы.
Одна из архитектурных причин, которые влияют на NT — правила о кодовых страницах в режиме ядра. У функции API типа RtlUnicodeStringToOemString и RtlUnicodeStringToAnsiString есть неявное предположение, что размер строки при конвертации никогда не изменится (т.е. при конвертации ANSI OEM размер строки в байтах меняться не может). И для кодовых страниц не-CJK это не проблема: потому что либо символ находится в кодовой странице и занимает один байт, либо его там нет и он представлен вопросительным знаком (который тоже занимает один байт). Но кодовые страницы CJK могут иметь символы длиной в несколько байт. Поэтому будет плохой идеей заводить разные (для ANSI/OEM) кодовые страницы, одна из которых кодирует символ в один байт, а другая — в несколько.
(Эти функции также предполагают, что размер любого Unicode-символа равен двум байтам — что действительно так для символов из любых кодовых страниц ANSI и OEM. И для тех, кому интересно: функции в ntdll.dll не ставят вопрос об обработке precomposed или composite Unicode — они поддерживают только форму precomposed. И Джулия не несёт за эти функции никакой ответственности, хотя она когда-то исправляла в них баги!)
В любом случае, кодовые страницы восточной Азии избавлены от необходимости в двух кодовых страницах. Это хорошо, потому что у них есть и другие вещи, о которых нужно волноваться — функции типа IsDBCSLeadByte.
Ну, разве вы не рады, что вы используете Unicode и вам не нужно волноваться об этих проблемах? 🙂
1 — и даже не заикайтесь о системе наименования, в которой у одного акронима (API) не все буквы заглавные, а в других (ANSI, OEM) — все. Боже.
Почему-то не читается содержимое файла в OEM 866 на других компах, кроме моего
Я написал программку по считыванию файла в формате OEM 866 и выводе определенных строк в консоль. На моих компьютерах все работает отлично, однако на других компьютерах содержимое файла попросту не читается, но при этом сам файл открывается без проблем (добавил функцию проверки is_open). Разница между компьютерами в установленном GCC.
Подскажите, пожалуйста, какие библиотеки нужно добавить, дабы все читалось без проблем без установки GCC? На данный момент в проекте есть libgcc_s_dw2-1.dll и libstdc++-6.dll.
Заметка, программа читает нормально файлы в кодировке Windows 1251 на любых компах.
Программа не работает на всех компах кроме моего
Добрый день. Создал проект, программа работает нормально. Решил вытащить exe файл, чтобы скинуть.
В папке Сеть 11 других компьютеров кроме моего
Здраствуйте , на днях зашел в папку »Сеть» и обноружил там 11 других компьютеров кроме моего.
Вывод текста в кодировке Win-1251 из bat-файла, текст которого в кодировке OEM-866
примем за аксиому утверждение: «bat-скрипт следует создавать в кодировке DOS (OEM-866)» . пусть.
Кодировка OEM 866
Доброго времени суток. ђҐЈЁ®* — вот эту лабуду хотелось бы перевести в нормальный вид. Пробовал.
Там, где не работает, не прописана, и никогда не стоял ни этот mingw, ни другой?
Добавлено через 3 минуты
Чтобы время сократить, нужно заодно ещё такое проверить. Если будет выводить считанное, то значит не находит в считанном. Тогда нужно проверить, как выводится на консоль текст из кода, и как он выглядит на консоли после функции CharToOem().
Там где не работает, не прописан путь и никогда не стоял никакой компилятор это точно.
Добавлено через 7 минут
T.e.
Или что ты имеешь ввиду?
Ок, спасибо. Тот код тоже работал. Завтра напишу, как что вышло.
Еще я поставил версию Release и убрал все опции флаги, кроме: [-O2], [-s] во флагах компилятора.
Показывает только первую строчку.
Второй попросту нет.
Самое интересное, что у него кракозябры на месте русского.
У меня на компе первая строка кракозябры, остальное, что в OEM нормально отображается.
Еще одно. Проверил на еще одном компе, где опять же ничего не ставилось и проги никогда не было, и оно работает! Видимо, скорее всего, проблема в настройке системы или что-то типа того.
От чего это может зависеть?
Решение
GCC здесь вообще не при чем. CharToOemA конвертирует текст из системной кодировки в
кодировку консоли, совместимую с текстовым режимом (т.е. из ANSI в OEM, если простым языком).
Проблема в том, что в зависимости от локализации системы и ее региональных настроек эти
кодировки могут различаться. Например, на русских Виндах, а также там, где для программ,
не поддерживающих Unicode, установлен русский язык, системной кодировкой является CP-1251
(кириллица). Но на английских Виндах там уже CP-1252. OEM-кодировки тоже различаются,
для русского языка там OEM866, для английского другая (какая — сейчас не вспомню).
Когда ты запускаешь свою программу на английской, например, Винде, то CharToOemA
«думает», что на вход ей подают CP-1252, а на самом деле там CP-1251, вот и получаем
«кракозябры», не работающие функции поиска подстроки и т.п.
Проблема в том, что я проверял и компилировал на русской Windows 10 64. Там все без проблем. У меня на работе Windows 7 64 английская и данная функция работает. У коллеги точно такая же Винда и все работает. А у 2-ух других коллег опять же такая винда, но не работает.
Скрины сейчас скину.
Добавлено через 19 минут
Фото с компа, где не работает. Английская Windows 7 64 bit
Фото с работающего. Английская Windows 7 64 bit
Фото с работающего. Английская Windows 7 64 bit
Всем спасибо! С локализациями помогло. Оказалось, что на компах, где работало, для не Unicode программ стояла локализация Russian, а где не работало, стояло English. При смене на Russian все действительно работает.
Если не сложно, подскажите, пожалуйста, как в будущем можно этого избежать, работая с файлами в кодировке OEM 866?
Или же какую-нибудь статейку про работу с Unicode в C++.
Решение
Прежде всего, ты должен всегда знать, в какой кодировке у тебя текст и какая кодировка
требуется для той или иной функции. Есть такой принцип: если у тебя есть строка, но
ты не знаешь, в какой она кодировке, то можешь считать, что у тебя нет этой строки.
Это проблема очень многих компонентов и программных интерфейсов, которые работают с
текстом: они манипулируют так и сяк строками, но явно не оговаривают, в какой кодировке
должны быть эти строки; иногда «подразумевается» UTF-8, иногда системная кодировка
ANSI или еще какая-нибудь конкретная, но какая точно — никто не скажет. Отсюда и
рождаются ошибки, подобные этой. А вот если бы мы точно знали, что текст в исходном
файле в кодировке CP-1251, а для вывода нужна строго OEMCP, то можно было выполнить
соответствующее преобразование с помощью MultiByteToWideChar и WideCharToMultiByte
(сначала из CP-1251 в Unicode UTF-16, затем из него в OEMCP), либо одним из других
подходящих способов (ICU, iconv и т.п.) и это работало бы на любой системе и на
любых региональных настройках.
В Windows есть три основных кодировки:
Основная рабочая кодировка Windows, появилась в Windows 2000 и с тех пор она
используется практически всеми компонентами системы, включая ядро. Прелесть Unicode
объяснять не нужно: один и тот же текст, не зависимо от локализации и региональных
настроек системы, кодируется и выглядит везде одинаково. Кроме того, пространство
Unicode очень большое, оно включает в себя символы и специальные знаки подавляющего
большинства существующих алфавитов и письменностей, включая всякую для нас с вами
экзотику, такую как иероглифы, арабский язык с письмом справа-налево и т.п.
Только используя Unicode можно отобразить в одном предложении слова на разных языках
(например, сообщение на немецком языке, которое содержит имя файла с иероглифами).
* ANSI (системная кодировка)
Кодировка для поддержки программ, которые не работают с Unicode.
В зависимости от настроек и локализации системы, это может быть или CP-1251
(кириллица), или CP-1252 (латиница), или одна из множества других кодовых страниц.
Беда в том, что текст, подразумевающий дефолтную кодировку ANSI, может прекрасно
отображаться на одной системе и превращаться в «кракозябры» на другой.
Типичный пример — MessageBoxA с текстом на русском языке, который отображается
только на адаптированных под русский язык системах. У MessageBoxW такой проблемы
нет, потому что она использует Unicode (W — от «Wide Char» или «Wide String»,
т.е. «широкие» символы).
* OEM (системная кодировка консоли)
Эта кодировка предназначена для использования консольными приложениями.
Также, как и ANSI, конкретная кодировка зависит от локализации и региональных
настроек системы. Русский — OEM-866, французский — OEM-863, греческий — OEM-737, и т.д.
Минусы те же: текст в OEM-кодировке переносим только на те системы, которые умеют
работать с ней. Например, чтобы заставить английскую Windows показать в консоли
текст в OEM-866, потребуется целая серия очень хитрых «приседаний».
Если нет каких-то других особых причин, я рекомендую всегда стараться использовать
только Unicode, так как это на порядок снижает количество проблем, связанных с
интернационализацией приложения. Собственно, интернационализация — это и есть
переход на Unicode, его для того и придумали.
При этом использование Unicode не освобождает тебя от ответственности все равно
знать, в какой кодировке текст Потому что там может быть UTF-8, а может
UTF-16 или UTF-32, Big или Little Endian, с BOM или без.
Конкретно у консоли в Windows есть еще один очень большой недостаток — для
отображения текста в определенной кодировке нужно еще, чтобы был установлен
«правильный» шрифт. Документированные способы программно найти и установить для
консоли подходящий шрифт существуют только на последних версиях Windows и
там все равно очень легко запутаться. Если ты не знаешь на 100%, как это сделать,
то лучше всего использовать только символы латинского алфавита и работать с
текстом в консоли только латиницей. С отображением латиницы точно уж проблем
никаких не возникнет. Многие программы именно так и поступают.