Я играл с std::wstring
а также std::wfstream
, когда я столкнулся со странным поведением. А именно, похоже, что std::basic_string<wchar_t>::find
не может найти определенные символы. Рассмотрим следующий код:
int main()
{
std::wifstream input("input.txt");
std::wofstream output("output.txt");
if(!(input && output)){
std::cerr << "file(s) not opened";
return -1;
}
std::wstring buf;
std::getline(input, buf);
output << buf;
std::cout << buf.find(L'ć');
}
Здесь я просто читаю первую строку input
файл и запись его в output
файл. Перед запуском программы содержимое первого файла aąbcćd
и выходной файл пуст. После выполнения кода входной файл успешно копируется в выходной файл.
Что меня удивляет, так это то, что я пытался найти ć
письмо в buf
и столкнулся с упомянутым странным поведением. После выполнения программы я подтвердил, что выходной файл содержит точно aąbcćd
который, очевидно, содержит упомянутый символ ć
,
Тем не менее, линия std::cout << buf.find(L'ć')
вел себя не так, как ожидалось. Я не ожидал получить вывод 4
, учитывая расположение памяти std::wstring
но я тоже определенно не ожидал получить std::string::npos
. Стоит отметить, что поиск обычных символов ASCII с помощью этого метода завершается успешно.
Подводя итог, упомянутый код правильно копирует первую строку входного файла в выходной файл, но ему не удается найти символ в строке (возвращающий npos), который отвечает за хранение данных, которые должны быть скопированы. Почему это так? Что вызывает find
потерпеть неудачу здесь?
Примечание: оба файла имеют кодировку UTF-8 в Windows.
к несчастью wchar_t
это не UTF-8, его UTF-16 (в Windows), и при чтении файла UTF-8 не происходит никакого волшебного преобразования. Если вы отладите свою программу, вы увидите поврежденные символы в вашем buf
переменная.
Вам либо нужно прочитать вашу строку как std::string
затем конвертировать из UTF-8 в whar_t
или работать в UTF-8 и конвертировать вашу литеральную строку из whcar_t
в std::string
из UTF-8 символов.
Если вы используете недавний компилятор, вы можете использовать следующее для создания строкового литерала UTF-8:
u8"ć"
Следующее должно работать:
int main()
{
std::ifstream input("input.txt");
std::ofstream output("output.txt");
if(!(input && output)){
std::cerr << "file(s) not opened";
return -1;
}
std::string buf;
std::getline(input, buf);
output << buf;
std::cout << buf.find(u8"ć");
}
Других решений пока нет …