Проблема с преобразованием std::filesystem::path в std::string в C++C++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Проблема с преобразованием std::filesystem::path в std::string в C++

Сообщение Anonymous »

Я столкнулся с проблемой при попытке получить все имена файлов из каталога. Проблема возникает при обработке определенных строк, что приводит к ошибкам. Ниже приведен фрагмент кода:

Код: Выделить всё

#include 

int main()
{
const char* dir = "D:\\Music";
std::vector musicList;

for (const auto& entry : std::filesystem::recursive_directory_iterator(dir))
{
if (entry.is_regular_file())
{
musicList.emplace_back(entry.path().string());
}
}
}
Проблема возникает в входе.path().string() при обработке строк типа L"D:\\Music\\suki\\Angel Note - 月明かりは優しく・・・.mp3". Программа завершает работу с ошибкой, указывающей на:

Код: Выделить всё

_STD_BEGIN
// We would really love to use the proper way of building error_code by specializing
// is_error_code_enum and make_error_code for __std_win_error, but because:
//   1. We would like to keep the definition of __std_win_error in xfilesystem_abi.h
//   2. and xfilesystem_abi.h cannot include 
//   3. and specialization of is_error_code_enum and overload of make_error_code
//      need to be kept together with the enum (see limerick in N4950 [temp.expl.spec]/8)
// we resort to using this _Make_ec helper.
_NODISCARD inline error_code _Make_ec(__std_win_error _Errno) noexcept { // make an error_code
return { static_cast(_Errno), _STD system_category() };
}

[[noreturn]] inline void _Throw_system_error_from_std_win_error(const __std_win_error _Errno) {
_THROW(system_error{ _Make_ec(_Errno) });  // Here occur error!
}
_STD_END
Я скомпилировал код в Visual Studio 2022, а стандарт C++ — C++17.
После исследования я упростил проблему следующим образом:

Код: Выделить всё

#include 

int main()
{
std::filesystem::path path = L"・";
auto str = path.string();
}
Аналогичные проблемы возникли в path.string(). После дальнейшего упрощения с помощью L"\u30FB" я обнаружил, что символ ・ представлен как "\u30FB".
В то время как path.wstring (), path.u8string() и другие преобразования строк работают хорошо, мне нужен char* для таких API, как ImGui::Text(str) или FMOD API. Попытки преобразовать wstring в строку с помощью codecvt, Win32 API или ICU привели к искажению текста, например «ãƒ»:

Код: Выделить всё

#include 
#include 

std::string ws2s(const std::wstring& wstr)
{
int len = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr);
std::string str;
str.reserve(len);
WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, str.data(), len, nullptr, nullptr);
return str;
}

int main()
{
std::filesystem::path path = L"\u30FB";
auto str = ws2s(path.wstring());
}
Результирующая строка была «ãƒ» вместо «\u30FB».
Есть ли надежный метод эффективно справиться с этой ситуацией?

Хорошо, я нашел проблему. Это кодировка, используемая в интерфейсе отладки VS. Он неправильно отображает UTF-8. Например, содержимое моего вектора имеет кодировку UTF-8, но интерфейс отладки отображает искаженный текст, как и содержимое vec[0]. Все, что мне нужно сделать, это добавить ,s8 к vec[0] в окне просмотра. Это заставляет дисплей отладки правильно отображать содержимое UTF-8.

О, Microsoft, почему вы настаиваете на UTF-16? Разве UTF-8 недостаточно хорош?

Подробнее здесь: https://stackoverflow.com/questions/787 ... tring-in-c
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»