Кодирование декодированных URL-адресов в C++

Я хочу декодировать закодированные 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-адреса.

'ö' - это в основном '\x50\x102', так что у вас не будет его в символьном виде.
Jarod42 06.01.2019 10:52

@ Jarod42 Можно ли записать в строку?

sv90 06.01.2019 11:18
ö находится вне диапазона ASCII, поэтому в любом предварительно составленная или разложенная форма он займет более одного байта. Вы должны использовать широкий символ, например L'ö', или распечатать его как строку вместо символа
phuclv 06.01.2019 11:30

@ Jarod42 50102 - десятичное значение. Это 0xC3B6 в шестнадцатеричном формате, которое является UTF-8 представлением U + 00F6.

phuclv 06.01.2019 11:33

@phuclv: Действительно, я использую неправильные значения: - / Моя точка зрения заключалась в основном в том, что многобайтовый символ не помещается в один char.

Jarod42 06.01.2019 18:32

@ Jarod42 Есть ли способ рассчитать 0x00f6 из 0xc3b6? Я не смог найти связь между обоими представлениями Unicode. Если бы он был, я мог бы использовать классы в <codecvt> для печати ö из 0xc3b6.

sv90 06.01.2019 20:22

Лучше сделать так, чтобы у вас вообще не было этого многосимвольного литерала. Что вы пытаетесь сделать?

Lightness Races in Orbit 06.01.2019 20:30

@LightnessRacesinOrbit Я хочу декодировать закодированный URL-адрес, в котором есть строки типа% C3% B6, которые я хочу напечатать как ö

sv90 06.01.2019 20:38

@ sv90 Да, это гораздо интереснее и совсем не похоже на ваш текущий вопрос. Предлагаю вам отредактировать его, чтобы описать реальную проблему.

Lightness Races in Orbit 06.01.2019 20:39

@LightnessRacesinOrbit Спасибо за совет

sv90 06.01.2019 20:42
stackoverflow.com/q/21216307/560648
Lightness Races in Orbit 06.01.2019 21:00

@LightnessRacesinOrbit Спасибо, но UriHelper почему-то не работал для "% C3% B6"

sv90 06.01.2019 21:27

Ничего не могу поделать с информацией "не сработало"

Lightness Races in Orbit 06.01.2019 21:28

@LightnessRacesinOrbit Напечатал ? вместо ö

sv90 06.01.2019 21:30

Тот факт, что вы можете декодировать URL-адрес в строку UTF-8, не гарантирует, что ваша консоль может отображать его правильно. Кроме того, нет гарантии, что URL-адрес использует UTF-8 для кодирования символов. Кодировка URL-адреса зависит от сервера, которому принадлежит URL-адрес. Это недостаток, для устранения которого были разработаны IRI при замене URI / URL-адресов. Юникод - это запоздалая мысль в URL-адресах, но он является частью дизайна IRI.

Remy Lebeau 07.01.2019 17:54
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
15
253
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

В 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-адресов.

phuclv 07.01.2019 16:20

Сделал только для полноты и тестирования :)

sv90 07.01.2019 17:23

Ваша функция декодирования должна работать нормально. Но с функцией кодирования могут возникнуть проблемы. Например, ; / ? : @ = & - это зарезервированные символы. См. Предлагаемый ответ.

Barmak Shemirani 07.01.2019 19:49

Другие вопросы по теме