gpt4 book ai didi

c++ - 将 unicode sf::String 传递到 std::filesystem::u8path

转载 作者:行者123 更新时间:2023-12-02 09:59:53 25 4
gpt4 key购买 nike

我试图得到 sf::String进入 std::filesystem::u8path .我的第一种方法是将其转换为 std::string , (std::string)sfstringbar但它认为它是一个单字节字符,我也试过 auto x = sfstringbar.toUtf8() std::string(x.begin(), x.end())但一样。我的第二种方法是将它作为 char 传递。数组,希望可以使用 UTF 8 编码读取它,但仍然会发生同样的情况。
编辑:

char* makeutf8str(str string) {
std::basic_string<sf::Uint8> utf8 = string.toUtf8();
std::vector<char>* out = new std::vector<char>;
for (auto x = utf8.begin(); x != utf8.end(); x++) {
out->push_back(*x);
}
return &(out->at(0));
}

bool neaxfile::isfile(str file) {
std::cout << "\nThis: " << makeutf8str(file) << "\n";
return std::filesystem::is_regular_file(std::filesystem::u8path(makeutf8str(file)));
}
这是我尝试的第二个解决方案。我有一个名为 Яyes.txt 的文件举个例子,但是当我通过检查它是否存在时,它说它不存在。因为 makeutf8str()函数拆分 Я进入 Я .我似乎无法让编码器正常工作。
编辑2:
str neaxfile::getcwd() {
std::error_code ec;
str path = std::filesystem::current_path(ec).u8string();
if (ec.value() == 0) {
return path;
} else {
return '\0';
}
}

std::vector<str> neaxfile::listfiles() {
std::vector<str> res;
for (auto entry : std::filesystem::directory_iterator((std::string)neaxfile::getcwd())) {
if (neaxfile::isfile(entry.path().wstring())) res.push_back(entry.path().wstring());
}
return res;
}
我尝试了下面的第一个解决方案。它不再打印 Я .但它仍然不能确认这是一个文件。我尝试使用该 ^ 列出文件

最佳答案

std::filesystem::u8path() "从 p s [或 char s (C++20 起)] 的 UTF-8 编码序列构造路径 char8_t 作为 std::stringstd::string_view 提供,或者作为一个以空字符结尾的多字节字符串,或者作为一个 [first, last) 迭代器对。"
一个 std::string可以保存一个 UTF-8 编码的字符序列(最好在 C++20 中使用 std::u8string)。 sf::String::ToUtf8() 返回一个 UTF-8 编码的 std::basic_string<Uint8> .您可以简单地转换 UInt8数据到 char构建 std::string ,不需要你的makeutf8str()使用函数std::vector<char>或返回原始 char*完全没有(尤其是因为它无论如何都会泄漏std::vector)。
您可以使用 std::string采用 char* 的构造函数和 size_t作为输入,例如:

std::string makeutf8str(const str &string) {
auto utf8 = string.toUtf8();
return std::string(reinterpret_cast<const char*>(utf8.c_str()), utf8.size());
}
或者,您可以使用 std::string将一系列迭代器作为输入的构造函数(尽管您声称,这应该可以正常工作),例如:
std::string makeutf8str(const str &string) {
auto utf8 = string.toUtf8();
return std::string(utf8.begin(), utf8.end());
}
无论哪种方式都适用于 std::coutstd::filesystem::u8path() ,例如:
bool neaxfile::isfile(const str &file) {
auto utf8 = makeutf8str(file);
std::cout << "\nThis: " << utf8 << "\n";
return std::filesystem::is_regular_file(std::filesystem::u8path(utf8));
}
话虽如此,Unicode 字符 Я以 UTF-8 编码为字节 0xD0 0xAF ,当解释为 Latin-1 而不是 UTF-8 时,将显示为 Я .这意味着 std::string数据被正确地 UTF-8 编码,只是没有被正确处理。例如,如果您的控制台无法处理 UTF-8 输出,那么您将看到 Я而不是 Я .但是, u8path()应该处理 UTF-8 编码的 std::string很好,并根据需要将其转换为文件系统的 native 编码。但是,不能保证底层文件系统实际上会处理像 Яyes.txt 这样的 Unicode 文件名。正确,但这将是操作系统问题,而不是 C++ 问题。

更新 : 你的 listfiles()函数在使用 directory_iterator 时根本没有使用 UTF-8 .它是 sf::String 的类型转换来自 getcwd() ANSI 编码 std::string (这是有损转换),而不是 UTF-8 编码的 std::string .但更糟糕的是, sf::Stringgetcwd() build 来自 UTF-8 编码的 std::string但是 std::string sf::String 的构造函数默认情况下需要 ANSI,而不是 UTF-8(要解决这个问题,你必须给它一个 UTF-8 std::locale )。因此,您正在经历几次有损转换,试图从 std::filesystem::path returned from 获取字符串。 std::filesystem::current_path to std::filesystem::directory_iterator`。 sf::String可以转换到/从 std::wstring , 其中 std::filesystem::path也可以使用,所以不用经过UTF-8和 std::filesystem::u8path()至少在 std::wstring 的 Windows 上使用 UTF-16 和 Windows 底层文件系统 API 也使用 UTF-16。
试试这个:
bool neaxfile::isfile(const str &file) {
std::wstring wstr = file;
std::wcout << L"\nThis: " << wstr << L"\n";
return std::filesystem::is_regular_file(std::filesystem::path(wstr));
}

str neaxfile::getcwd() {
std::error_code ec;
str path = std::filesystem::current_path(ec).wstring();
if (ec.value() == 0) {
return path;
} else {
return L"";
}
}

std::vector<str> neaxfile::listfiles() {
std::vector<str> res;
std::filesystem::path cwdpath(neaxfile::getcwd().wstring());
for (auto entry : std::filesystem::directory_iterator(cwdpath) {
str filepath = entry.path().wstring();
if (neaxfile::isfile(filepath)) res.push_back(filepath);
}
return res;
}
如果您真的想使用 UTF-8 在 C++ 字符串和 SFML 字符串之间进行转换,请尝试这样做以避免任何数据丢失:
std::string makeutf8str(const str &string) {
auto utf8 = string.toUtf8();
return std::string(reinterpret_cast<const char*>(utf8.c_str()), utf8.size());
}

str fromutf8str(const std::string &string) {
return str::fromUtf8(utf8.begin(), utf8.end());
}

bool neaxfile::isfile(const str &file) {
auto utf8 = makeutf8str(file);
std::cout << "\nThis: " << utf8 << "\n";
return std::filesystem::is_regular_file(std::filesystem::u8path(utf8));
}

str neaxfile::getcwd() {
std::error_code ec;
auto path = std::filesystem::current_path(ec).u8string();
if (ec.value() == 0) {
return fromutf8str(path);
} else {
return "";
}
}

std::vector<str> neaxfile::listfiles() {
std::vector<str> res;
auto cwdpath = std::filesystem::u8path(makeutf8str(neaxfile::getcwd()));
for (auto entry : std::filesystem::directory_iterator(cwdpath)) {
str filepath = fromutf8str(entry.path().u8string());
if (neaxfile::isfile(filepath)) res.push_back(filepath);
}
return res;
}
话虽如此,您在 C++ 字符串和 SFML 字符串之间进行了大量不必要的转换。当您不直接与 SFML 的 API 交互时,您真的不应该使用 SFML 字符串。您确实应该尽可能多地使用 C++ 字符串,尤其是使用 <filesystem> API,例如:
bool neaxfile::isfile(const std::string &file) {
std::cout << L"\nThis: " << file << L"\n";
return std::filesystem::is_regular_file(std::filesystem::u8path(file));
}

std::string neaxfile::getcwd() {
std::error_code ec;
std::string path = std::filesystem::current_path(ec).u8string();
if (ec.value() == 0) {
return path;
} else {
return "";
}
}

std::vector<std::string> neaxfile::listfiles() {
std::vector<std::string> res;
auto cwdpath = std::filesystem::u8path(neaxfile::getcwd());
for (auto entry : std::filesystem::directory_iterator(cwdpath)) {
auto filepath = entry.path().u8string();
if (neaxfile::isfile(filepath)) res.push_back(filepath);
}
return res;
}
或者:
bool neaxfile::isfile(const std::wstring &file) {
std::wcout << L"\nThis: " << file << L"\n";
return std::filesystem::is_regular_file(std::filesystem::path(file));
}

std::wstring neaxfile::getcwd() {
std::error_code ec;
auto path = std::filesystem::current_path(ec).wstring();
if (ec.value() == 0) {
return path;
} else {
return L"";
}
}

std::vector<std::wstring> neaxfile::listfiles() {
std::vector<std::wstring> res;
std::filesystem::path cwdpath(neaxfile::getcwd());
for (auto entry : std::filesystem::directory_iterator(cwdpath)) {
auto filepath = entry.path().wstring();
if (neaxfile::isfile(filepath)) res.push_back(filepath);
}
return res;
}
更好的选择是根本不传递字符串。 std::filesystem::path是一种抽象,可以帮助您避免这种情况,例如:
bool neaxfile::isfile(const std::filesystem::path &file) {
std::wcout << L"\nThis: " << file.wstring() << L"\n";
return std::filesystem::is_regular_file(file);
}

std::filesystem::path neaxfile::getcwd() {
std::error_code ec;
auto path = std::filesystem::current_path(ec);
if (ec.value() == 0) {
return path;
} else {
return {};
}
}

std::vector<std::filesystem::path> neaxfile::listfiles() {
std::vector<std::filesystem::path> res;
for (auto entry : std::filesystem::directory_iterator(neaxfile::getcwd())) {
auto filepath = entry.path();
if (neaxfile::isfile(filepath)) res.push_back(filepath);
}
return res;
}

关于c++ - 将 unicode sf::String 传递到 std::filesystem::u8path,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63175473/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com