Я хочу декодировать закодированные URL-адреса. Например, буква ö закодирована как "%C3%B6", что соответствует ее шестнадцатеричной кодировке utf-8 0xc3b6 (50102).
Теперь вам нужно знать, как напечатать это значение как ö на консоли или в строковом буфере.
Простое преобразование в char, wchar_t, char16_t или char32_t и печать в cout или wcout не сработали.
Самое близкое, что я получил, было использование его представления utf-16 0x00f6. Следующий фрагмент кода выводит ö
#include <codecvt>
#include <iostream>
#include <locale>
int main() {
std::wstring_convert<std::codecvt_utf8<char16_t>, char16_t> convert;
std::cout << convert.to_bytes(0x00f6) << '\n';
}
Теперь мне нужен способ вычисления 0x00f6 из 0xc3b6 или другой подход для декодирования URL-адреса.
@ Jarod42 Можно ли записать в строку?
ö находится вне диапазона ASCII, поэтому в любом предварительно составленная или разложенная форма он займет более одного байта. Вы должны использовать широкий символ, например L'ö', или распечатать его как строку вместо символа
@ Jarod42 50102 - десятичное значение. Это 0xC3B6 в шестнадцатеричном формате, которое является UTF-8 представлением U + 00F6.
@phuclv: Действительно, я использую неправильные значения: - / Моя точка зрения заключалась в основном в том, что многобайтовый символ не помещается в один char.
@ Jarod42 Есть ли способ рассчитать 0x00f6 из 0xc3b6? Я не смог найти связь между обоими представлениями Unicode. Если бы он был, я мог бы использовать классы в <codecvt> для печати ö из 0xc3b6.
Лучше сделать так, чтобы у вас вообще не было этого многосимвольного литерала. Что вы пытаетесь сделать?
@LightnessRacesinOrbit Я хочу декодировать закодированный URL-адрес, в котором есть строки типа% C3% B6, которые я хочу напечатать как ö
@ sv90 Да, это гораздо интереснее и совсем не похоже на ваш текущий вопрос. Предлагаю вам отредактировать его, чтобы описать реальную проблему.
@LightnessRacesinOrbit Спасибо за совет
@LightnessRacesinOrbit Спасибо, но UriHelper почему-то не работал для "% C3% B6"
Ничего не могу поделать с информацией "не сработало"
@LightnessRacesinOrbit Напечатал ? вместо ö
Тот факт, что вы можете декодировать URL-адрес в строку UTF-8, не гарантирует, что ваша консоль может отображать его правильно. Кроме того, нет гарантии, что URL-адрес использует UTF-8 для кодирования символов. Кодировка URL-адреса зависит от сервера, которому принадлежит URL-адрес. Это недостаток, для устранения которого были разработаны IRI при замене URI / URL-адресов. Юникод - это запоздалая мысль в URL-адресах, но он является частью дизайна IRI.





В POSIX вы можете напрямую распечатать строку UTF8:
std::string utf8 = "\xc3\xb6"; // or just u8"ö"
printf(utf8);
В Windows вам нужно преобразовать в UTF16. Используйте wchar_t вместо char16_t, даже если char16_t должен быть правильным. В Windows они оба имеют размер по 2 байта на символ.
Вы хотите, чтобы convert.from_bytes конвертировал из UTF8, а не convert.to_bytes, который конвертируется в UTF8.
Печать Unicode в консоли Windows - еще одна головная боль. См. Соответствующие темы.
Обратите внимание, что std::wstring_convert устарел и на данный момент не имеет замены.
#include <iostream>
#include <string>
#include <codecvt>
#include <windows.h>
int main()
{
std::string utf8 = "\xc3\xb6";
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> convert;
std::wstring utf16 = convert.from_bytes(utf8);
MessageBox(0, utf16.c_str(), 0, 0);
DWORD count;
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), utf16.c_str(), utf16.size(), &count, 0);
return 0;
}
Кодирование / декодирование URL
«Безопасные для URL-адресов символы» не нуждаются в кодировке. Все остальные символы, включая символы, отличные от ASCII, должны быть закодированы. Пример:
std::string encode_url(const std::string& s)
{
const std::string safe_characters =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
std::ostringstream oss;
for(auto c : s) {
if (safe_characters.find(c) != std::string::npos)
oss << c;
else
oss << '%' << std::setfill('0') << std::setw(2) <<
std::uppercase << std::hex << (0xff & c);
}
return oss.str();
}
std::string decode_url(const std::string& s)
{
std::string result;
for(std::size_t i = 0; i < s.size(); i++) {
if (s[i] == '%') {
try {
auto v = std::stoi(s.substr(i + 1, 2), nullptr, 16);
result.push_back(0xff & v);
} catch(...) { } //handle error
i += 2;
}
else {
result.push_back(s[i]);
}
}
return result;
}
Спасибо за помощь. Вот что я придумал. Может быть, это поможет кому-то другому
#include <iomanip>
#include <iostream>
#include <sstream>
#include <cstdint>
std::string encode_url(const std::string& s) {
std::ostringstream oss;
for (std::uint16_t c : s) {
if (c > 0 && c < 128) {
oss << static_cast<char>(c);
}
else {
oss << '%' << std::uppercase << std::hex << (0x00ff & c);
}
}
return std::move(oss).str();
}
int parse_hex(const std::string& s) {
std::istringstream iss(s);
int n;
iss >> std::uppercase >> std::hex >> n;
return n;
}
std::string decode_url(const std::string& s) {
std::string result;
result.reserve(s.size());
for (std::size_t i = 0; i < s.size();) {
if (s[i] != '%') {
result.push_back(s[i]);
++i;
}
else {
result.push_back(parse_hex(s.substr(i + 1, 2)));
i += 3;
}
}
return result;
}
Еще есть возможности для оптимизации, но это работает :)
нет необходимости кодировать URL, если вы просто хотите распечатать. Кодирование URL-адресов почти не используется за пределами URL-адресов.
Сделал только для полноты и тестирования :)
Ваша функция декодирования должна работать нормально. Но с функцией кодирования могут возникнуть проблемы. Например, ; / ? : @ = & - это зарезервированные символы. См. Предлагаемый ответ.
'ö'- это в основном'\x50\x102', так что у вас не будет его в символьном виде.