C как узнать кодировку строки
Перейти к содержимому

C как узнать кодировку строки

  • автор:

Чем определяется кодировка строковых констант (литералов)

В сети и здесь, на 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
    Благодарности: 44

    EvgeniyQQQ, Не знаю, что есть 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
      Благодарности: 44

      EvgeniyQQQ, Не знаю, что есть 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 кодировкам. Если посмотреть на все темы, посвященные этому, то практически любой совет сводится к этому. Но я рекомендую этого не делать, это вредные советы. Ничего хорошего для профессионального развития они не несут, в лучшем случае это бег на месте.

      Похожие публикации:

      1. Как в сводной таблице добавить столбец с формулой
      2. Как открыть порты на модеме byfly
      3. Как разблокировать самсунг gt e1200m
      4. Как удалить python ubuntu

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *