Чем определяется кодировка строковых констант (литералов)
В сети и здесь, на SO, довольно много материала о работе с кодировками и локалями. Но почему-то нет вразумительной информации о кодировке строковых констант (литералов).
const char * text = "Какая ваша кодировка?";
Чем определяется кодировка строковых литералов: кодировкой файла с исходником, опциями компилятора или чем-то еще? Что на эту тему говорит стандарт? Как достоверно узнать кодировку строковых литералов на этапе компиляции (может макросы какие есть)? А в рантайме?
Отслеживать
задан 25 окт 2015 в 22:08
6,853 2 2 золотых знака 23 23 серебряных знака 43 43 бронзовых знака
3 ответа 3
Сортировка: Сброс на вариант по умолчанию
Данный ответ посвящён практике применения Microsoft Visual Studio.
Хорошего кроссплатформенного решения я, к сожалению, не знаю.
- Для файлов-исходников в неюникодных кодировках, строка интерпретируется как строка в ANSI-кодировке. Для русскоязычных систем это CP 1251. Это выполняется даже если для файла исходника задекларирована другая кодировка! При компиляции на системе с другой ANSI-кодировкой результат будет отличаться.
- Для файлов-исходников в юникодных кодировках, кодировка строки также Unicode.
- Если при этом строка «узкая» (то есть, типа char[] ), то строка будет сконвертирована в ANSI-кодировку с теми же последствиями.
- Если при этом строка «широкая» (то есть, типа wchar_t[] ), то строка останется как есть, то есть, правильной.
Это означает, что нужно использовать
- либо юникодную кодировку исходников + широкие строки,
- либо узкие строки в ANSI-кодировке с потерей компилируемости под нерусскими системами,
- либо кодировать литералы числовыми константами.
Как выяснилось в результате длительной дискуссии с @ixSci и @Abyx, Visual Studio 2015 ведёт себя немного по-другому: в случае кодировки файла utf-8 и узкой строки, в строке таки окажется utf-8. Но в случае кодировки файла utf-16 (ucs-2), результат прежний: попытка сконвертировать в ANSI (которая может и провалиться).
Обновление:
Visual Studio 2015 и старше конвертирует строки во внутренний формат. Конвертация определяется набором символов исходного файла (source character set), из которого символы конвертируются во внутренний формат (на текущий момент это utf-8). Набор символов, т. е., по сути, кодировка исходного файла определяется следующим образом
- Если файл содержит BOM, этим самым однозначно определяется его кодировка.
- В противном случае, если файл выглядит как файл в utf-16 (Visual Studio производит прикидку этого по первым восьми байтам) big/little endian, то это считается его кодировкой.
- В противном случае, если при компиляции (или в настройках проекта) указан ключ /source-charset , указанная в этом ключе кодировка и считается кодировкой входного файла.
- В противном случае, кодировкой входного файла считается системная кодовая страница (т. е., ANSI). Обратите внимание, что это не самый лучший вариант, т. к. одни и те же байты исходников при этом могут по-разному интерпретироваться на разных системах.
Следующая важная вещь — это набор символов времени выполнения (execution character set). Это, по сути, кодировка, в которую будут сконвертированы узкие строковые/символьные литералы (объявленные без префикса) при записи в выполняемый файл, и которые программа «увидит», если просканирует строки по байтам. Если при компиляции указан ключ /execution-charset , это и будет искомым набором символов. Если нет, в качестве набора символов используется текущая кодовая страница.
Обратите внимание, что вы можете указать ключ /utf-8 , который установит одним махом оба набора символов в utf-8.
Ещё один набор символов — широкий набор символов времени выполнения (wide execution character set) — используется для конвертации широких символьных/строковых литералов. Он в MS Visual Studio неизменен и совпадает с utf-16.
C как узнать кодировку строки
Ну, почему-же. Можно. Набрать статистику распределения символов.
Для русского языка часто встречающиеся символы ОТЕНАР.Участник клуба
Регистрация: 12.10.2007
Сообщений: 1,204Вот схема:
объявляем два массива
WinCounts : array [char] of integer; // Количество символов в кодировке Win
DosCounts : array [char] of integer; // Количество сисволов в кодировке DOSОчередную строку файла обработываем:
if length(S) = 0 then exit;
SetLength(S2, length(S));
OEMToChar(PChar(S), PChar(S2)); /// DOWtoWIN
S1 := Upper(S);
S2 := Upper(S2);
for i:=1 to length(S1) do begin
Inc(WinCounts[S1[i]]);
Inc(DosCounts[S2[i]]);
end;т.е. увеличиваем количество символов в обеих кодировках.
Чем больше строк обработано, тем лучше, но достаточно даже одной строки.После обработки части файла:
M := (WinCounts[‘О’] + WinCounts[‘Т’] + WinCounts[‘Е’] + WinCounts[‘H’] + WinCounts[‘А’]);
if (DosCounts[‘О’] + DosCounts[‘Т’] + DosCounts[‘Е’] + DosCounts[‘H’] + DosCounts[‘А’]) > M
then CodePage := cpDOS;Форумчанин
Регистрация: 25.09.2007
Сообщений: 189
это не 100% вариант, думаю (хотя спорить не хочется)
Пользователь
Регистрация: 01.11.2007
Сообщений: 33[b]alexBlack[b] видите ли в чем дело, мне нужно переводить из DOS кодировки в Win но я не знаю в какой кодировке пребывает файл в данный момент. Функция OEMToChar переводит (и непереводит если это не надо, хотя не уверен не тестировал ) например считав строку из файла прогоняю ее через OEMToChar и она меняется если эта строка в DOS кодировке и не меняется если в WIN кодировке! Я хочу добиться именно такого эффекта, я написал свою функцию OEMToChar, но если строка уже в Win код-ке она искажает символы входящие в диапазон от ‘р’до ‘я’
Участник клуба
Регистрация: 12.10.2007
Сообщений: 1,204
Сообщение от PuzzleC[b]alexBlack[b] видите ли в чем дело, мне нужно переводить из DOS кодировки в Win но я не знаю в какой кодировке пребывает файл в данный момент. Функция OEMToChar переводит (и непереводит если это не надо, хотя не уверен не тестировал ) например считав строку из файла прогоняю ее через OEMToChar и она меняется если эта строка в DOS кодировке и не меняется если в WIN кодировке! Я хочу добиться именно такого эффекта, я написал свою функцию OEMToChar, но если строка уже в Win код-ке она искажает символы входящие в диапазон от ‘р’до ‘я’
То есть я не достаточно подорбно объяснил. Итак. Сначала нужно узнать в какой кодировке файл. Для этого его нужно просканировать (или хотя-бы несколько строк). Для каждой строки файла S
S1 = upper(S) — исходная строка
S2 = upper(OEMtoChar(S)) — та же строка в другой кодировкеМы используем только верхний регистр символов, т.к. нас интересует частота встречаемости.
Увеличиваем количество символов
for i:=1 to length(S1) do begin
Inc(WinCounts[S1[i]]);
Inc(DosCounts[S2[i]]);
end;Когда все строки проанализированы, проверяем частоты встречаемости символов ОТЕНАР в обеих кодировках
M := (WinCounts[‘О’] + WinCounts[‘Т’] + WinCounts[‘Е’] + WinCounts[‘H’] + WinCounts[‘А’]);
if (DosCounts[‘О’] + DosCounts[‘Т’] + DosCounts[‘Е’] + DosCounts[‘H’] + DosCounts[‘А’]) > M
then CodePage := cpDOS;
else CodePage := cpWIN;И уже теперь, если cpDOS, то переводим строку в кодировку WIN.
Как уже было замечено, 100% определения не достигнуть. Но, по моим наблюдениям такой алгоритм правильно срабатывал по одной строке.
Надеюсь, я достаточно понятно объяснил.
C как узнать кодировку строки
Для отключения данного рекламного блока вам необходимо зарегистрироваться или войти с учетной записью социальной сети.
Сообщения: 1696
Благодарности: 44EvgeniyQQQ, Не знаю, что есть ANSI. Но в ASCII не может быть символов с кодом > 127 (это 7-итная кодировка). Если же используется «расширенный» ASCII (Latin-1 или любая другая национальная кодировка), то можно просто проверить, что исходная строка содержит символы с кодом > 127 и является корректной utf-8 строкой (т.е. удовлетворяет этим требованиям: http://tools.ietf.org/html/rfc3629#section-3). Если строка достаточно большая и не в utf-8, то где-нибудь обязательно будет неправильна закодирована, и следовательно не utf-8, иначе «произвольная однобайтовая кодировка».
Это сообщение посчитали полезным следующие участники:
Сообщения: 14
Благодарности: 4Текст, состоящий только из символов с номером меньше 128, при записи в UTF-8 превращается в обычный текст ASCII. И наоборот, в тексте UTF-8 любой байт со значением меньше 128 изображает символ ASCII с тем же кодом. Остальные символы Юникода изображаются последовательностями длиной от 2 до 6 байтов, в которых первый байт всегда имеет вид 11xxxxxx, а остальные — 10xxxxxx. Более подробно о UTF-8 посмотрите http://ru.wikipedia.org/wiki/UTF-8. Что же касается ANSI — то насколько я понимаю, это то же, что и кодировка Windows-1251, т.е. 8-битная и содержит русские символы.
Это сообщение посчитали полезным следующие участники:
Сообщения: 4
Благодарности: 1Конфигурация компьютера
Процессор: c2d E8200 Материнская плата: p5e Память: 2gb Видеокарта: gf 8800gt ОС: 2008r2 Потребовалось мне автоопределение кодировки в текстовом файле; нашёл (не претендуя на универсальность) такой выход (builder xe3):
String tst= al+af+am+bt+sn; // несколько тэгов, выделенных из fb2 файла
if( tst[1]>0x007F && UTF8Decode(tst)[1]!=0xfffd ) al=UTF8Decode(al);// нет, это не ansi!суть в том, что UTF8Decode от русского ansi-текста возвращает строку, забитую 0xFFFD
а от английского ansi-текста или любого utf8-текста возвращает читабельный ansi-текст.ps для fb2, понятно, надо каждый тег проверять (т.к. в utf файле могут быть смешаны и русские и английские тэги), но принцип проверки понятен.
C как узнать кодировку строки
Как определить кодировку строки и преобразовать в utf8?
Через imap подключаюсь к серверу и получаю список сообщений. Проблема в кодировке тела письма — в гугле оно одно, в яндексе другое. Хочу чтобы система автоматом определяла кодировку и преобразовывала его в utf8
import cchardet def convert_encoding(data, new_coding = 'UTF-8'): encoding = cchardet.detect(data)['encoding'] if new_coding.upper() != encoding.upper(): data = data.decode(encoding, data).encode(new_coding) return data def get_mails(login, password): print("Connecting to <>. ".format(server)) imap = imaplib.IMAP4_SSL(server) print("Connected! Logging in as <>. ".format(login)); imap.login(login, password) print("Logged in! Listing messages. "); status, select_data = imap.select('INBOX') nmessages = select_data[0].decode('utf-8') status, search_data = imap.search(None, 'ALL') for msg_id in search_data[0].split(): status, msg_data = imap.fetch(msg_id, '(RFC822)') msg_raw = msg_data[0][1].decode("utf8") mail = mailparser.parse_from_string(msg_raw) telo = convert_encoding(mail.body.encode()) # Вот тут траблыДля примера — mail.body содержит следующий текст
'\\u041f\\u0440\\u043e\\u0432\\u0435\\u0440\\u043a\\u0430 \\u0441'Выдаёт ошибку
TypeError: decode() argument 2 must be str, not bytes- Вопрос задан более трёх лет назад
- 1640 просмотров
5 комментариев
Средний 5 комментариев
Чем определяется кодировка строковых констант (литералов)
В сети и здесь, на SO, довольно много материала о работе с кодировками и локалями. Но почему-то нет вразумительной информации о кодировке строковых констант (литералов).
const char * text = "Какая ваша кодировка?";Чем определяется кодировка строковых литералов: кодировкой файла с исходником, опциями компилятора или чем-то еще? Что на эту тему говорит стандарт? Как достоверно узнать кодировку строковых литералов на этапе компиляции (может макросы какие есть)? А в рантайме?
Отслеживать
задан 25 окт 2015 в 22:08
6,853 2 2 золотых знака 23 23 серебряных знака 43 43 бронзовых знака3 ответа 3
Сортировка: Сброс на вариант по умолчанию
Данный ответ посвящён практике применения Microsoft Visual Studio.
Хорошего кроссплатформенного решения я, к сожалению, не знаю.
- Для файлов-исходников в неюникодных кодировках, строка интерпретируется как строка в ANSI-кодировке. Для русскоязычных систем это CP 1251. Это выполняется даже если для файла исходника задекларирована другая кодировка! При компиляции на системе с другой ANSI-кодировкой результат будет отличаться.
- Для файлов-исходников в юникодных кодировках, кодировка строки также Unicode.
- Если при этом строка «узкая» (то есть, типа char[] ), то строка будет сконвертирована в ANSI-кодировку с теми же последствиями.
- Если при этом строка «широкая» (то есть, типа wchar_t[] ), то строка останется как есть, то есть, правильной.
Это означает, что нужно использовать
- либо юникодную кодировку исходников + широкие строки,
- либо узкие строки в ANSI-кодировке с потерей компилируемости под нерусскими системами,
- либо кодировать литералы числовыми константами.
Как выяснилось в результате длительной дискуссии с @ixSci и @Abyx, Visual Studio 2015 ведёт себя немного по-другому: в случае кодировки файла utf-8 и узкой строки, в строке таки окажется utf-8. Но в случае кодировки файла utf-16 (ucs-2), результат прежний: попытка сконвертировать в ANSI (которая может и провалиться).
Обновление:
Visual Studio 2015 и старше конвертирует строки во внутренний формат. Конвертация определяется набором символов исходного файла (source character set), из которого символы конвертируются во внутренний формат (на текущий момент это utf-8). Набор символов, т. е., по сути, кодировка исходного файла определяется следующим образом
- Если файл содержит BOM, этим самым однозначно определяется его кодировка.
- В противном случае, если файл выглядит как файл в utf-16 (Visual Studio производит прикидку этого по первым восьми байтам) big/little endian, то это считается его кодировкой.
- В противном случае, если при компиляции (или в настройках проекта) указан ключ /source-charset , указанная в этом ключе кодировка и считается кодировкой входного файла.
- В противном случае, кодировкой входного файла считается системная кодовая страница (т. е., ANSI). Обратите внимание, что это не самый лучший вариант, т. к. одни и те же байты исходников при этом могут по-разному интерпретироваться на разных системах.
Следующая важная вещь — это набор символов времени выполнения (execution character set). Это, по сути, кодировка, в которую будут сконвертированы узкие строковые/символьные литералы (объявленные без префикса) при записи в выполняемый файл, и которые программа «увидит», если просканирует строки по байтам. Если при компиляции указан ключ /execution-charset , это и будет искомым набором символов. Если нет, в качестве набора символов используется текущая кодовая страница.
Обратите внимание, что вы можете указать ключ /utf-8 , который установит одним махом оба набора символов в utf-8.
Ещё один набор символов — широкий набор символов времени выполнения (wide execution character set) — используется для конвертации широких символьных/строковых литералов. Он в MS Visual Studio неизменен и совпадает с utf-16.
C как узнать кодировку строки
Сообщения: 133
Благодарности: 21Имеется массив символов типа char (язык С++). Необходимо определить кодировку этих символов (UTF8 или ANSI). Возможно ли это?
——-
«Не соглашайся ни на что, кроме совершенства!» — Анонимный автор.
«Совершенство достигается только к моменту полного краха.» — К.Н.Паркинсон.Сообщения: 1180
Благодарности: 279если имеется какой-нить словарик с типичными фразами, то наверное можно. Если на ascii может быть написана какая-то любая фигня, то однозначно нельзя
Для отключения данного рекламного блока вам необходимо зарегистрироваться или войти с учетной записью социальной сети.
Сообщения: 1696
Благодарности: 44EvgeniyQQQ, Не знаю, что есть ANSI. Но в ASCII не может быть символов с кодом > 127 (это 7-итная кодировка). Если же используется «расширенный» ASCII (Latin-1 или любая другая национальная кодировка), то можно просто проверить, что исходная строка содержит символы с кодом > 127 и является корректной utf-8 строкой (т.е. удовлетворяет этим требованиям: http://tools.ietf.org/html/rfc3629#section-3). Если строка достаточно большая и не в utf-8, то где-нибудь обязательно будет неправильна закодирована, и следовательно не utf-8, иначе «произвольная однобайтовая кодировка».
Сообщения: 14
Благодарности: 4Текст, состоящий только из символов с номером меньше 128, при записи в UTF-8 превращается в обычный текст ASCII. И наоборот, в тексте UTF-8 любой байт со значением меньше 128 изображает символ ASCII с тем же кодом. Остальные символы Юникода изображаются последовательностями длиной от 2 до 6 байтов, в которых первый байт всегда имеет вид 11xxxxxx, а остальные — 10xxxxxx. Более подробно о UTF-8 посмотрите http://ru.wikipedia.org/wiki/UTF-8. Что же касается ANSI — то насколько я понимаю, это то же, что и кодировка Windows-1251, т.е. 8-битная и содержит русские символы.
Сообщения: 4
Благодарности: 1Конфигурация компьютера 
Процессор: c2d E8200 Материнская плата: p5e Память: 2gb Видеокарта: gf 8800gt ОС: 2008r2 Потребовалось мне автоопределение кодировки в текстовом файле; нашёл (не претендуя на универсальность) такой выход (builder xe3):
String tst= al+af+am+bt+sn; // несколько тэгов, выделенных из fb2 файла
if( tst[1]>0x007F && UTF8Decode(tst)[1]!=0xfffd ) al=UTF8Decode(al);// нет, это не ansi!суть в том, что UTF8Decode от русского ansi-текста возвращает строку, забитую 0xFFFD
а от английского ansi-текста или любого utf8-текста возвращает читабельный ansi-текст.ps для fb2, понятно, надо каждый тег проверять (т.к. в utf файле могут быть смешаны и русские и английские тэги), но принцип проверки понятен.
Как узнать кодировку полученной строки аргумента main?
В main отправляется аргумент-строка на русском из IDE CLion v 2016.2.3.
Вывести этот аргумент на русском не получается, какую кодировку где не устанавливай: 1251 или 866. То ли в исходнике, то ли в консоли.Знаю лишь, что первые символы моей строки — какие-то отрицательные коды. Как по ним определить кодовую страницу, которая их формировала?
Кликните здесь для просмотра всего текста
1 2 3 4 5 6 7 8 9 10 11 12
int main(int argC, char* argV[]) char a[] = "Тестовый файл 2.txt"; for(int i = 0; i 10; ++i) cout (int) argV[1][i] ' '; > cout ; for(int i = 0; i 10; ++i) cout (int) a[i] ' '; > cout ; >
Прошу помощи. Тема кодировок вымораживает мой мозг чуть ли не полностью.
Скрин:
• Исходник: 866
• Консоль: 866Лучшие ответы ( 1 )
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
Ответы с готовыми решениями:Как узнать текущую кодировку строки
Допустим у меня имеется строковая переменная ,Как узнать текущую кодировку строки.
Написать функцию, которая удаляет начальные и конечные пробелы из строки, полученной в качестве аргумента
Написать функцию, которая удаляет начальные и конечные пробелы из строки, полученной в качестве.Написать функцию, которая удаляет начальные и конечные пробелы из строки, полученной в качестве аргумента
Написать функцию, которая удаляет начальные и конечные пробелы из строки, полученной в качестве.18429 / 9594 / 2347
Регистрация: 30.01.2014
Сообщений: 16,778
Сообщение от Lyosha12 
Вывести этот аргумент на русском не получается
Это юникод, UTF-8.
41 / 41 / 11
Регистрация: 02.04.2016
Сообщений: 308
Сообщение от DrOffset 
Это юникод, UTF-8.
Значит, мой русский текст кодируется двумя байтами, а не одним. И, при записи в один байт, второй просто обрезается, поэтому-то я и не смог определить выводимый текст ни в одном онлайн-конвертере.
Как тогда нужно правильно принимать символы UTF-8?
18429 / 9594 / 2347
Регистрация: 30.01.2014
Сообщений: 16,778
Сообщение от Lyosha12 
Как тогда нужно правильно принимать символы UTF-8?
В windows лучше всего работать в UTF-16. Использовать wstring для хранения строк. Локальные кодировки сильно ограничивают, тем более, что UTF-16 нативная кодировка windows.
Поэтому здесь нужно написать функцию преобразования из UTF-8 в UTF-16, а дальше работать с UTF-16 строкой.Да, я вижу, что многие этого стараются избегать, и приколачивают свою программу то к 1251, то 866 кодировкам. Если посмотреть на все темы, посвященные этому, то практически любой совет сводится к этому. Но я рекомендую этого не делать, это вредные советы. Ничего хорошего для профессионального развития они не несут, в лучшем случае это бег на месте.
Похожие публикации:
- Как в сводной таблице добавить столбец с формулой
- Как открыть порты на модеме byfly
- Как разблокировать самсунг gt e1200m
- Как удалить python ubuntu