Как обрабатывать несколько локалей для ifstream, cout и т. Д. В C++
Я пытаюсь прочитать и обработать несколько файлов, которые находятся в другой кодировке. Я должен использовать только STL для этого. Предположим, что у нас есть файлы iso-8859-15 и UTF-8.
В этом так ответе говорится:
В двух словах, более интересная часть для вас:
std::stream
(stringstream
,fstream
,cin
,cout
) имеет внутренний объект locale, который соответствует значению глобальной локали C++ в момент создания объекта потока. Какstd::in
создается задолго до того, как ваш код в main вызывается, он, скорее всего, имеет классическую локаль C, независимо от того, что вы делаете потом.- Вы можете убедиться, что объект std::stream имеет желаемую локаль, вызвав
std::stream::imbue(std::locale(your_favorite_locale))
,
Проблема состоит в том, что из двух типов только файлы, которые соответствуют языку, который был создан первым, обрабатываются правильно. Например, если locale_DE_ISO885915
предшествует locale_DE_UTF8
затем файлы, которые находятся в UTF-8
неправильно добавлены в string s
и когда я cout
их я вижу только пару строк из файла.
void processFiles() {
//setup locales for file decoding
std::locale locale_DE_ISO885915("de_DE.iso885915@euro");
std::locale locale_DE_UTF8("de_DE.UTF-8");
//std::locale::global(locale_DE_ISO885915);
//std::cout.imbue(std::locale());
const std::ctype<wchar_t>& facet_DE_ISO885915 = std::use_facet<std::ctype<wchar_t>>(locale_DE_ISO885915);
//std::locale::global(locale_DE_UTF8);
//std::cout.imbue(std::locale());
const std::ctype<wchar_t>& facet_DE_UTF8 = std::use_facet<std::ctype<wchar_t>>(locale_DE_UTF8);
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
std::string currFile, fileStr;
std::wifstream inFile;
std::wstring s;
for (std::vector<std::string>::const_iterator fci = files.begin(); fci != files.end(); ++fci) {
currFile = *fci;
//check file and set locale
if (currFile.find("-8.txt") != std::string::npos) {
std::locale::global(locale_DE_ISO885915);
std::cout.imbue(locale_DE_ISO885915);
}
else {
std::locale::global(locale_DE_UTF8);
std::cout.imbue(locale_DE_UTF8);
}
inFile.open(path + currFile, std::ios_base::binary);
if (!inFile) {
//TODO specific file report
std::cerr << "Failed to open file " << *fci << std::endl;
exit(1);
}
s.clear();
//read file content
std::wstring line;
while( (inFile.good()) && std::getline(inFile, line) ) {
s.append(line + L"\n");
}
inFile.close();
//remove punctuation, numbers, tolower...
for (unsigned int i = 0; i < s.length(); ++i) {
if (ispunct(s[i]) || isdigit(s[i]))
s[i] = L' ';
}
if (currFile.find("-8.txt") != std::string::npos) {
facet_DE_ISO885915.tolower(&s[0], &s[0] + s.size());
}
else {
facet_DE_UTF8.tolower(&s[0], &s[0] + s.size());
}
fileStr = converter.to_bytes(s);
std::cout << fileStr << std::endl;
std::cout << currFile << std::endl;
std::cout << fileStr.size() << std::endl;
std::cout << std::setlocale(LC_ALL, NULL) << std::endl;
std::cout << "========================================================================================" << std::endl;
// Process...
}
return;
}
Как вы можете видеть в коде, я пытался с global
а также locale local variables
но безрезультатно.
Кроме того, в Как я могу использовать std::imbue, чтобы установить локаль для std::wcout? ТАК ответь, говорится:
Таким образом, похоже, что существует базовый механизм библиотеки C, который должен быть сначала включен с помощью setlocale, чтобы преобразование imbue работало правильно.
Является ли этот "неясный" механизм проблемой здесь?
Можно ли чередовать эти две локали при обработке файлов? Что я должен наполнить ( cout
, ifstream
, getline
?) и как?
Какие-либо предложения?
PS: Почему все, что связано с языком, так хаотично? : |
1 ответ
Это работает для меня, как и ожидалось, на моей машине с Linux, но не на моей машине с Windows под Cygwin (набор доступных локалей, по-видимому, одинаков на обеих машинах, но std::locale::locale
просто терпит неудачу с каждой мыслимой строкой локали).
#include <iostream>
#include <fstream>
#include <locale>
#include <string>
void printFile(const char* name, const char* loc)
{
try {
std::wifstream inFile;
inFile.imbue(std::locale(loc));
inFile.open(name);
std::wstring line;
while (getline(inFile, line))
std::wcout << line << '\n';
} catch (std::exception& e) {
std::cerr << e.what() << std::endl;
}
}
int main()
{
std::locale::global(std::locale("en_US.utf8"));
printFile ("gtext-u8.txt", "de_DE.utf8"); // utf-8 text: grüßen
printFile ("gtext-legacy.txt", "de_DE@euro"); // iso8859-15 text: grüßen
}
Выход:
grüßen
grüßen