Читать многоязычный файл

Содержание:

Remarks

If /Zc:wchar_t is on, is a keyword for a built-in integral type in code compiled as C++. If /Zc:wchar_t- (with a minus sign) is specified, or in code compiled as C, is not a built-in type. Instead, is defined as a for in the canonical header stddef.h. (The Microsoft implementation defines it in another header that is included by stddef.h and other standard headers.)

We do not recommend /Zc:wchar_t- because the C++ standard requires that be a built-in type. Using the version can cause portability problems. If you upgrade from earlier versions of Visual Studio and encounter compiler error C2664 because the code is trying to implicitly convert a to , we recommend that you change the code to fix the error, instead of setting /Zc:wchar_t-.

The /Zc:wchar_t option is on by default in C++ compilations, and is ignored in C compilations. The /permissive- option does not affect /Zc:wchar_t.

Microsoft implements as a two-byte unsigned value. It maps to the Microsoft-specific native type . For more information about , see Data Type Ranges and Fundamental Types.

If you write new code that has to interoperate with older code that still uses the version of , you can provide overloads for both the and variations of , so that your code can be linked with code compiled with /Zc:wchar_t or code compiled without it. Otherwise, you would have to provide two different builds of the library, one with and one without /Zc:wchar_t enabled. Even in this case, we recommend that you build the older code by using the same compiler that you use to compile the new code. Never mix binaries compiled with different compilers.

When /Zc:wchar_t is specified, _WCHAR_T_DEFINED and _NATIVE_WCHAR_T_DEFINED symbols are defined. For more information, see Predefined Macros.

If your code uses the compiler COM global functions, because /Zc:wchar_t is now on by default, we recommend that you change explicit references to comsupp.lib (either from the comment pragma or on the command line) to either comsuppw.lib or comsuppwd.lib. (If you must compile with /Zc:wchar_t-, use comsupp.lib.) If you include the comdef.h header file, the correct library is specified for you. For information about compiler COM support, see Compiler COM Support.

The built-in type is not supported when you compile C code. For more information about conformance issues with Visual C++, see Nonstandard Behavior.

To set this compiler option in the Visual Studio development environment

  1. Open the project’s Property Pages dialog box. For details, see Set C++ compiler and build properties in Visual Studio.

  2. Select the Configuration Properties > C/C++ > Language page.

  3. Modify the Treat wchar_t as Built-in Type property.

Другие решения

К сожалению, стандартный c ++ не имеет реальной поддержки вашей ситуации. (например. Unicode в C ++ — 11)

Вам нужно будет использовать библиотеку обработки текста, которая его поддерживает. Что-то вроде этот

2

И вот второй ответ — о (отсутствии) соответствия стандартов Microsoft в отношении — потому что, благодаря комитету по стандартам, хеджирующему свои ставки, ситуация с этим более запутанная, чем должна быть.

Просто быть чистым, в Windows ширина всего 16 бит, и, как мы все знаем, в наши дни символов Unicode намного больше, чем в наши дни, поэтому, на первый взгляд, Windows несовместима (хотя, как мы все снова знаем, они делают то, что они делают по причине).

Итак, двигаясь дальше, я обязан Бо Перссону за то, что он выкопал это (выделение мое):

Стандарт говорит в :

Хммм. «Среди поддерживаемых локалей». О чем это все?

Ну, я, например, не знаю, и, я подозреваю, это не тот человек, который это написал. Это было просто сделано, чтобы позволить Microsoft сорваться с крючка, просто так. Это просто двойной разговор.

Как уже отмечали другие (по сути), стандарт — это беспорядок. Кто-то должен поместить что-то об этом там, чтобы другие люди могли понять.

1

Стандарт c ++ определяет wchar_t как тип, который будет поддерживать любую кодовую точку. На Linux это правда. MSVC нарушает стандарт и определяет его как 16-разрядное целое число, которое слишком мало.

Поэтому единственный переносимый способ обработки строк — это преобразование их из собственных строк в utf-8 на входе и из utf-8 в собственные строки в точке вывода.

Вам, конечно, нужно будет использовать магию #ifdef для выбора правильного преобразования и вызовов ввода / вывода в зависимости от ОС.

Несоблюдение стандартов является причиной того, что у нас не может быть хороших вещей.

Шаг 57 — OLECHAR в CHAR и обратно

Странный это тип OLECHAR, на самом деле это WCHAR:

#if defined(_WIN32) && !defined(OLE2ANSI)
typedef WCHAR OLECHAR;

А WCHAR занимает два байта:

typedef unsigned short WCHAR;

Глобально у нас есть два типа кодировки. ANSI — ASCII и UNICODE. Несмотря на то, что ANSI и ASCII разные кодировки суть у них одна. Для кодирования используется один байт. А вот в UNICODE используются два байта.

Это все нормально и идея хорошея. Конечно надо поддерживать все символы в одном шрифте. Только плохо, что часть систем Windows работает так, а часть по другому. Вообще меня честно это раздражает. Нет, чтобы перейти сразу на один и все. И кстати надо придумать OLECHAR, а я должен знать, что это WCHAR и так далее. Слов нет прям. Надо нас программистов измучить как только можно. Ну да ладно. OLE работает с широкими символами WCHAR. Нам надо научиться переводить эти символы из одной кодировки в другую. Давайте объявим строку:

#include "stdafx.h"
#include "windows.h"
#include "ole2.h"
#include "iostream.h"


void main()
{
	OLECHAR olechar;
	wcscpy(olechar,L"1.xls");
}

Как вы думаете зачем перед строкой L ?? И думать нечего, наш текст это CHAR, а скомпилироваться должен как WCHAR вот мы и объясняем компилятору, что это WCHAR будь он не ладен. Дальше строку надо заполнить. Это делается функцией wcscpy(), которая аналог strcpy().

strcpy --> wcscpy

Такое преобразование произошло практически со всеми строковыми функциями. То есть не преобразование, а просто функции добавились. Все они описаны в WCHAR.H. Развивая дальше мысль скажу, что есть функция wprintf(), которая умеет выводить нам на экран все-таки эти WCHAR символы.

Для копирования из CHAR в WCHAR применяется функция mbstowcs:

size_t mbstowcs( wchar_t *wcstr, const char *mbstr, size_t count );

Смотрим:

#include "stdafx.h"
#include "windows.h"
#include "ole2.h"
#include "iostream.h"

void main()
{
	OLECHAR olechar;
	char chars;
	strcpy(chars,"Hello");
	mbstowcs((OLECHAR*)&olechar,(CHAR*)&chars,sizeof(chars));
	wprintf(olechar);
}

Для обратного процесса WCHAR -> CHAR -> wcstombs:

size_t wcstombs( char *mbstr, const wchar_t *wcstr, size_t count );

Смотрим:

#include "stdafx.h"
#include "windows.h"
#include "ole2.h"
#include "iostream.h"

void main()
{
	OLECHAR olechar;
	wcscpy(olechar,L"Hello OLE");
	char chars;
	wcstombs((CHAR*)&chars,(OLECHAR*)&olechar,sizeof(chars));
	cout << chars << endl;
}


Предыдущий Шаг | Следующий Шаг | ОглавлениеАвтор Каев Артем.

RemarksRemarks

Тип был исходным типом символа в C и C++.The type was the original character type in C and C++. Тип часто используется для представления байта, который не является встроенным типом в C++.The type is often used to represent a byte, which is not a built-in type in C++. Этот тип можно использовать для хранения символов из кодировки ASCII или любой из КОДИРОВОК ISO-8859, а также для отдельных байтов многобайтовых символов, таких как Shift-JIS или кодировка UTF-8 для набора символов Юникода.The type can be used to store characters from the ASCII character set or any of the ISO-8859 character sets, and individual bytes of multi-byte characters such as Shift-JIS or the UTF-8 encoding of the Unicode character set. Строки типа называются узкими строками даже при использовании для кодирования многобайтовых символов.Strings of type are referred to as narrow strings, even when used to encode multi-byte characters. В компиляторе Microsoft — это 8-разрядный тип.In the Microsoft compiler, is an 8-bit type.

Тип является определяемым реализацией типом расширенных символов.The type is an implementation-defined wide character type. В компиляторе Майкрософт он представляет 16-разрядный символ, используемый для хранения Юникода в кодировке UTF-16LE, собственный тип символов в операционных системах Windows.In the Microsoft compiler, it represents a 16-bit wide character used to store Unicode encoded as UTF-16LE, the native character type on Windows operating systems. Версии расширенных символов функций библиотеки универсальной среды выполнения C (UCRT) используют и его указатели и типы массивов в качестве параметров и возвращаемых значений, как и версии расширенных символов собственного API Windows.The wide character versions of the Universal C Runtime (UCRT) library functions use and its pointer and array types as parameters and return values, as do the wide character versions of the native Windows API.

Типы и представляют 16-разрядные и 32-разрядные символы, соответственно.The and types represent 16-bit and 32-bit wide characters, respectively. Юникод в кодировке UTF-16 может храниться в типе, а Юникод в кодировке UTF-32 может храниться в типе.Unicode encoded as UTF-16 can be stored in the type, and Unicode encoded as UTF-32 can be stored in the type. Строки этих типов и все они называются расширенными строками, хотя термин часто относится к строкам типа.Strings of these types and are all referred to as wide strings, though the term often refers specifically to strings of type.

Ввод символов

Следующая программа просит пользователя ввести символ. Затем она выводит этот символ и его ASCII-код:

#include <iostream>

int main()
{
std::cout << «Input a keyboard character: «;

char ch;
std::cin >> ch;
std::cout << ch << » has ASCII code » << static_cast<int>(ch) << std::endl;

return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12

#include <iostream>

intmain()

{

std::cout<<«Input a keyboard character: «;

charch;

std::cin>>ch;

std::cout<<ch<<» has ASCII code «<<static_cast<int>(ch)<<std::endl;

return;

}

Результат выполнения программы:

Обратите внимание, даже если cin позволит вам ввести несколько символов, переменная будет хранить только первый символ (именно он и помещается в переменную). Остальная часть пользовательского ввода останется во входном буфере, который использует cin, и будет доступна для использования последующим вызовам cin

Рассмотрим это всё на практике:

#include

int main()
{
std::cout > ch; // ch = ‘a’, «bcd» останется во входном буфере
std::cout (ch) > ch; // ch = ‘b’, «cd» останется в буфере
std::cout (ch)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

#include

intmain()

{

std::cout>ch;// ch = ‘a’, «bcd» останется во входном буфере

std::cout(ch)>ch;// ch = ‘b’, «cd» останется в буфере

std::cout(ch)

Результат выполнения программы:

Оператор static_cast

Если вы хотите вывести символы в виде цифр, а не в виде букв, то вам нужно сообщить cout выводить переменные типа char в виде целочисленных значений. Не очень хороший способ это сделать — присвоить переменной типа int переменную типа char и вывести её:

#include <iostream>

int main()
{
char ch(97);
int i(ch); // присваиваем значение переменной ch переменной типа int
std::cout << i << std::endl; // выводим значение переменной типа int
return 0;
}

1
2
3
4
5
6
7
8
9

#include <iostream>

intmain()

{

charch(97);

inti(ch);// присваиваем значение переменной ch переменной типа int

std::cout<<i<<std::endl;// выводим значение переменной типа int

return;

}

Результат:

Лучшим способом является конвертация переменной из одного типа данных в другой с помощью оператора static_cast.

Синтаксис выглядит следующим образом:

принимает значение из в качестве входных данных и конвертирует его в указанный вами .

Пример использования оператора для конвертации типа char в тип int:

#include <iostream>

int main()
{
char ch(97);
std::cout << ch << std::endl;
std::cout << static_cast<int>(ch) << std::endl;
std::cout << ch << std::endl;
return 0;
}

1
2
3
4
5
6
7
8
9
10

#include <iostream>

intmain()

{

charch(97);

std::cout<<ch<<std::endl;

std::cout<<static_cast<int>(ch)<<std::endl;

std::cout<<ch<<std::endl;

return;

}

Результат выполнения программы:

Запомните, принимает в качестве входных данных. Если мы используем переменную в , то эта переменная изменяет свой тип только в стейтменте с оператором . Процесс конвертации никак не влияет на исходную переменную с её значением! В вышеприведенном примере, переменная остается переменной типа char с прежним значением, чему является подтверждением последний стейтмент с cout.

Также в static_cast нет никакой проверки по диапазону, так что если вы попытаетесь использовать числа, которые будут слишком большие или слишком маленькие для конвертируемого типа, то произойдет .

Более подробно о мы ещё поговорим на соответствующем уроке.

Диапазоны значений и знак целочисленных типов данных

Как вы уже знаете из предыдущего урока, переменная с n-ным количеством бит может хранить 2n возможных значений. Но что это за значения? Это значения, которые находятся в диапазоне. Диапазон — это значения от и до, которые может хранить определенный тип данных. Диапазон целочисленной переменной определяется двумя факторами: её размером (измеряется в битах) и её знаком (который может быть signed или unsigned).

Целочисленный тип signed (со знаком) означает, что переменная может содержать как положительные, так и отрицательные числа. Чтобы объявить переменную как signed, используйте ключевое слово :

signed char c;
signed short s;
signed int i;
signed long l;
signed long long ll;

1
2
3
4
5

signedcharc;

signedshorts;

signedinti;

signedlongl;

signedlonglongll;

По умолчанию, ключевое слово пишется перед типом данных.

1-байтовая целочисленная переменная со знаком (signed) имеет диапазон значений от -128 до 127, т.е. любое значение от -128 до 127 (включительно) может храниться в ней безопасно.

В некоторых случаях мы можем заранее знать, что отрицательные числа в программе использоваться не будут. Это очень часто встречается при использовании переменных для хранения количества или размера чего-либо (например, ваш рост или вес не может быть отрицательным).

Целочисленный тип unsigned (без знака) может содержать только положительные числа. Чтобы объявить переменную как unsigned, используйте ключевое слово :

unsigned char c;
unsigned short s;
unsigned int i;
unsigned long l;
unsigned long long ll;

1
2
3
4
5

unsignedcharc;

unsignedshorts;

unsignedinti;

unsignedlongl;

unsignedlonglongll;

1-байтовая целочисленная переменная без знака (unsigned) имеет диапазон значений от 0 до 255.

Обратите внимание, объявление переменной как unsigned означает, что она не сможет содержать отрицательные числа (только положительные). Теперь, когда вы поняли разницу между signed и unsigned, давайте рассмотрим диапазоны значений разных типов данных:

Теперь, когда вы поняли разницу между signed и unsigned, давайте рассмотрим диапазоны значений разных типов данных:

Размер/Тип Диапазон значений
1 байт signed от -128 до 127
1 байт unsigned от 0 до 255
2 байта signed от -32 768 до 32 767
2 байта unsigned от 0 до 65 535
4 байта signed от -2 147 483 648 до 2 147 483 647
4 байта unsigned от 0 до 4 294 967 295
8 байтов signed от -9 223 372 036 854 775 808 до 9 223 372 036 854 775 807
8 байтов unsigned от 0 до 18 446 744 073 709 551 615

Для математиков: Переменная signed с n-ным количеством бит имеет диапазон от -(2n-1) до 2n-1-1. Переменная unsigned с n-ным количеством бит имеет диапазон от 0 до (2n)-1.

Для нематематиков: Используем таблицу

Начинающие программисты иногда путаются между signed и unsigned переменными. Но есть простой способ запомнить их различия. Чем отличается отрицательное число от положительного? Правильно! Минусом спереди. Если минуса нет, значит число — положительное. Следовательно, целочисленный тип со знаком (signed) означает, что минус может присутствовать, т.е. числа могут быть как положительными, так и отрицательными. Целочисленный тип без знака (unsigned) означает, что минус спереди отсутствует, т.е. числа могут быть только положительными.

Решение

Привет, давайте сделаем это. Давайте предоставим практическое решение конкретной проблемы чтения текста из файла в кодировке UTF-8 и передачи его в широкую строку без потери какой-либо информации.

Как только мы сможем это сделать, у нас все будет в порядке, потому что представленные здесь служебные функции будут обрабатывать все преобразования UTF-8 в широкополосные (и наоборот) в целом, и это ключевая вещь, которую вы упускаете.

Итак, во-первых, как бы вы прочитали в ваших данных? Ну, это легко. Потому что на одном уровне строки UTF-8 — это просто последовательность Вы можете, во многих целях, просто относиться к ним таким образом. Так что вам просто нужно сделать то, что вы сделали бы для любой текстовый файл, например:

Все идет нормально. Это все выглядит достаточно просто.

Но теперь, чтобы упростить обработку строки, которую мы только что прочитали (потому что обработка многобайтовых строк в коде — большая проблема), нам нужно преобразовать ее в так называемую широкая строка прежде чем мы попытаемся что-то с этим сделать. На самом деле есть несколько их разновидностей (из-за неопределенности, связанной с тем, насколько «широко» на самом деле на любой конкретной платформе), но сейчас я буду придерживаться чтобы все было просто, и сделать это преобразование на самом деле проще, чем вы думаете.

Итак, без лишних слов, вот ваши функции преобразования (для чего вы купили билет):

Боже, это было легко, почему эти билеты так дорого стоили?

Я думаю, это все, что мне действительно нужно сказать. Из того, что вы говорите в своем вопросе, я думаю, что у вас уже было четкое представление о том, что вы хотели бы сделать, вы просто не знали, как этого добиться (и, возможно, не совсем объединили все точки пока) но на всякий случай есть какая-то затянувшаяся путаница, как только вы делать иметь широкую строку, которую вы можете свободно использовать все методы std :: basic_string, и все будет «просто работать». И если вам нужно преобразовать обратно в строку UTF-8, чтобы (скажем) записать ее в файл, то теперь это тривиально.

Примечания (добавлено как редактирование):

  • устарел в C ++ 17 (не знаю почему), но если вы ограничите его использование только этими двумя функциями, то на самом деле беспокоиться не о чем. Всегда можно переписать их, если и когда придет что-то лучшее (подсказка, подсказка, уважаемые люди по стандартам).
  • я могу, я полагаю, справиться с другими кодировками символов, но, насколько мне известно, кого это волнует?
  • если (который основан на ) не подходит для вас на вашей конкретной платформе, тогда вы всегда можете использовать или же ,

2

Решение

Принципиально, использовать когда кодировка имеет больше символов, чем может содержать.

Фон Тип имеет достаточную емкость для хранения любого символа (кодировки) в наборе символов ASCII.

Проблема в том, что для многих языков требуется больше кодировок, чем для ASCII. Таким образом, вместо 127 возможных кодировок требуется больше. Некоторые языки имеют более 256 возможных кодировок. Тип не гарантирует диапазон больше 256. Таким образом, требуется новый тип данных.

, широкие символы a.k.a, предоставляют больше места для кодировок.

Резюме
использование тип данных, когда диапазон кодировок составляет 256 или менее, например, ASCII. использование когда вам нужна емкость более 256.

Предпочитаю Unicode для обработки больших наборов символов (например, смайликов).

4

Другие символьные типы: wchar_t, char16_t и char32_t

wchar_t следует избегать практически во всех случаях (кроме тех, когда происходит взаимодействие с Windows API).

Так же, как и стандарт ASCII использует целые числа для представления символов английского языка, так и другие кодировки используют целые числа для представления символов других языков. Наиболее известный стандарт (после ASCII) — Unicode, который имеет в запасе более 110 000 целых чисел для представления символов из разных языков.

Существуют следующие кодировки Unicode:

   UTF-32: требует 32 бита для представления символа.

   UTF-16: требует 16 бит для представления символа.

   UTF-8: требует 8 бит для представления символа.

char16_t и char32_t были добавлены в C++11 для поддержки 16-битных и 32-битных символов Unicode (8-битные символы и так поддерживаются типом char).

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

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