Characters¶
utf8_char, utf16_char, and utf32_char are validated single-scalar value types.
They are useful when you want to store or pass one Unicode scalar value without dropping down to raw UTF-8 bytes or UTF-16 code units.
For the named unicode_ranges::characters catalog, include unicode_ranges_all.hpp or include unicode_ranges/characters.hpp directly. The lighter unicode_ranges_borrowed.hpp umbrella no longer pulls that catalog in automatically.
When the character is known at compile time, the literal operators such as _u8c, _u16c, and _u32c are usually the nicest entry point. from_scalar(...) is the runtime path when the scalar value arrives as data.
Unless a section explicitly narrows the discussion, the UTF-8, UTF-16, and UTF-32 character APIs are structurally parallel.
#include "unicode_ranges_all.hpp"
#include <print>
using namespace unicode_ranges;
using namespace unicode_ranges::literals;
int main()
{
const auto sparkle = "โจ"_u8c;
const auto smile = u"๐"_u16c;
const auto rocket = U"๐"_u32c;
std::println("{}", sparkle); // โจ
std::println("{}", sparkle.code_unit_count()); // 3
std::println("{}", smile); // ๐
std::println("{}", smile.code_unit_count()); // 2
std::println("{}", rocket); // ๐
std::println("{}", rocket.code_unit_count()); // 1
std::println("{}", "x"_u8c.ascii_uppercase()); // X
}
Constants And Default Construction¶
Synopsis¶
utf8_char() = default;
utf16_char() = default;
utf32_char() = default;
static const utf8_char replacement_character;
static const utf8_char null_terminator;
static const utf16_char replacement_character;
static const utf16_char null_terminator;
static const utf32_char replacement_character;
static const utf32_char null_terminator;
Behavior¶
- Value-initialized
utf8_char,utf16_char, andutf32_charhold U+0000. replacement_characteris U+FFFD.null_terminatoris U+0000.
Complexity¶
Constant.
Exceptions¶
None.
noexcept¶
Default construction is non-throwing.
Example¶
#include "unicode_ranges_all.hpp"
#include <print>
using namespace unicode_ranges;
int main()
{
utf8_char zero8{};
utf16_char zero16{};
utf32_char zero32{};
std::println("{}", zero8.as_scalar()); // 0
std::println("{}", zero16.as_scalar()); // 0
std::println("{}", zero32.as_scalar()); // 0
std::println("{}", utf8_char::replacement_character); // ๏ฟฝ
std::println("{}", utf16_char::null_terminator.as_scalar()); // 0
std::println("{}", utf32_char::null_terminator.as_scalar()); // 0
}
Checked Scalar Construction¶
Synopsis¶
static constexpr std::optional<utf8_char> from_scalar(std::uint32_t scalar) noexcept;
static constexpr std::optional<utf16_char> from_scalar(std::uint32_t scalar) noexcept;
static constexpr std::optional<utf32_char> from_scalar(std::uint32_t scalar) noexcept;
Behavior¶
Constructs a validated character from a Unicode scalar value and reports failure with std::optional.
Return value¶
- Returns the constructed character when
scalaris a valid Unicode scalar value. - Returns
std::nulloptfor invalid inputs such as surrogate code points or values above U+10FFFF.
Complexity¶
Constant.
Exceptions¶
None.
noexcept¶
Always noexcept.
Example¶
#include "unicode_ranges_all.hpp"
#include <print>
using namespace unicode_ranges;
int main()
{
const auto omega = utf8_char::from_scalar(U'ฮฉ').value();
const auto rocket = utf16_char::from_scalar(U'๐').value();
const auto invalid = utf8_char::from_scalar(0xD800u);
std::println("{}", omega); // ฮฉ
std::println("{}", rocket); // ๐
std::println("{}", invalid.has_value()); // false
}
Unchecked Construction¶
Synopsis¶
static constexpr utf8_char from_scalar_unchecked(std::uint32_t scalar) noexcept;
template<typename CharT>
static constexpr utf8_char from_utf8_bytes_unchecked(const CharT* bytes, std::size_t size) noexcept;
static constexpr utf16_char from_scalar_unchecked(std::uint32_t scalar) noexcept;
template<typename CharT>
static constexpr std::optional<utf16_char>
from_utf16_code_units(const CharT* code_units, std::size_t size) noexcept;
template<typename CharT>
static constexpr utf16_char
from_utf16_code_units_unchecked(const CharT* code_units, std::size_t size) noexcept;
static constexpr utf32_char from_scalar_unchecked(std::uint32_t scalar) noexcept;
template<typename CharT>
static constexpr std::optional<utf32_char>
from_utf32_code_points(const CharT* code_points, std::size_t size) noexcept;
template<typename CharT>
static constexpr utf32_char
from_utf32_code_points_unchecked(const CharT* code_points, std::size_t size) noexcept;
Behavior¶
from_scalar_uncheckedtrusts that the supplied scalar is valid.from_utf8_bytes_uncheckedtrusts thatbytes[0, size)encodes exactly one valid UTF-8 scalar.from_utf16_code_unitsvalidates that the range holds exactly one valid UTF-16 scalar.from_utf16_code_units_uncheckedtrusts that the supplied code units hold exactly one valid UTF-16 scalar.from_utf32_code_pointsvalidates that the range holds exactly one valid UTF-32 scalar.from_utf32_code_points_uncheckedtrusts that the supplied code points hold exactly one valid UTF-32 scalar.
Return value¶
- The checked UTF-16 constructor returns
std::nulloptwhen the range is not exactly one valid UTF-16 character. - The checked UTF-32 constructor returns
std::nulloptwhen the range is not exactly one valid UTF-32 character. - The unchecked constructors always return a value.
Complexity¶
Constant.
Exceptions¶
None.
noexcept¶
All listed overloads are noexcept.
Example¶
Prefer the checked constructors and literals in normal user code. The unchecked overloads are for already-trusted input.
#include "unicode_ranges_all.hpp"
#include <print>
using namespace unicode_ranges;
int main()
{
const auto trusted_utf8 = utf8_char::from_utf8_bytes_unchecked(u8"โจ", 3);
const auto trusted_scalar = utf16_char::from_scalar_unchecked(U'๐');
const auto checked_utf16 = utf16_char::from_utf16_code_units(u"๐", 2).value();
std::println("{}", trusted_utf8); // โจ
std::println("{}", trusted_scalar); // ๐
std::println("{}", checked_utf16); // ๐
}
Scalar Value, Encoding, And Cross-Encoding Conversion¶
Synopsis¶
constexpr std::uint32_t as_scalar() const noexcept;
constexpr operator utf16_char() const noexcept; // utf8_char only
constexpr operator utf32_char() const noexcept; // utf8_char and utf16_char
constexpr operator utf8_char() const noexcept; // utf16_char only
constexpr operator utf16_char() const noexcept; // utf32_char only
constexpr operator utf8_char() const noexcept; // utf32_char only
template <typename Allocator = std::allocator<char8_t>>
constexpr basic_utf8_string<Allocator> to_utf8(const Allocator& alloc = Allocator()) const;
template <typename Allocator = std::allocator<char16_t>>
constexpr basic_utf16_string<Allocator> to_utf16(const Allocator& alloc = Allocator()) const;
template <typename Allocator = std::allocator<char32_t>>
constexpr basic_utf32_string<Allocator> to_utf32(const Allocator& alloc = Allocator()) const;
constexpr std::size_t code_unit_count() const noexcept;
template<typename CharT, typename OutIt>
constexpr std::size_t encode_utf8(OutIt out) const noexcept;
template<typename CharT, typename OutIt>
constexpr std::size_t encode_utf16(OutIt out) const noexcept;
template<typename CharT, typename OutIt>
constexpr std::size_t encode_utf32(OutIt out) const noexcept;
Behavior¶
as_scalar()returns the Unicode scalar value represented by the object.- The conversion operators transcode a single scalar between the UTF-8, UTF-16, and UTF-32 character representations.
to_utf8(),to_utf16(), andto_utf32()materialize a one-character owning string in the corresponding encoding.code_unit_count()returns the number of code units used by this encoding:- UTF-8:
1to4 - UTF-16:
1or2 - UTF-32:
1 encode_utf8(),encode_utf16(), andencode_utf32()copy the character into an output iterator and return the number of code units written.
Return value¶
as_scalar()returns the scalar directly.encode_*()returns the number of output code units.to_*_owned()returns an owning validated string containing exactly one character.
Complexity¶
Constant.
Exceptions¶
as_scalar(), the conversion operators,code_unit_count(), andencode_*()do not throw.to_*_owned()may throw allocator or container exceptions.
noexcept¶
as_scalar(), conversion operators,code_unit_count(), andencode_*()arenoexcept.to_*_owned()is notnoexcept.
Example¶
#include "unicode_ranges_all.hpp"
#include <format>
#include <print>
#include <string>
using namespace unicode_ranges;
using namespace unicode_ranges::literals;
int main()
{
const auto sparkle = "โจ"_u8c;
const utf16_char sparkle16 = sparkle;
std::string encoded8;
sparkle.encode_utf8<char>(std::back_inserter(encoded8));
std::u16string encoded16;
sparkle.encode_utf16<char16_t>(std::back_inserter(encoded16));
std::println("{}", std::format("{:X}", sparkle.as_scalar())); // 2728
std::println("{}", sparkle16); // โจ
std::println("{}", sparkle.to_utf8()); // โจ
std::println("{}", sparkle16.to_utf16()); // โจ
std::println("{}", sparkle.code_unit_count()); // 3
std::println("{}", encoded8); // โจ
std::println("{}", utf16_string_view::from_code_units(encoded16).value()); // โจ
}
Scalar Iteration Helpers¶
Synopsis¶
constexpr utf8_char& operator++() noexcept;
constexpr utf8_char operator++(int) noexcept;
constexpr utf8_char& operator--() noexcept;
constexpr utf8_char operator--(int) noexcept;
constexpr utf16_char& operator++() noexcept;
constexpr utf16_char operator++(int) noexcept;
constexpr utf16_char& operator--() noexcept;
constexpr utf16_char operator--(int) noexcept;
constexpr utf32_char& operator++() noexcept;
constexpr utf32_char operator++(int) noexcept;
constexpr utf32_char& operator--() noexcept;
constexpr utf32_char operator--(int) noexcept;
Behavior¶
Advances or retreats across Unicode scalar values, skipping the surrogate range.
The operations wrap:
- decrementing U+0000 produces U+10FFFF
- incrementing U+10FFFF produces U+0000
Complexity¶
Constant.
Exceptions¶
None.
noexcept¶
All four operators are noexcept.
Example¶
#include "unicode_ranges_all.hpp"
#include <format>
#include <print>
using namespace unicode_ranges;
using namespace unicode_ranges::literals;
int main()
{
auto latin = "A"_u8c;
++latin;
auto before_surrogates = utf16_char::from_scalar(0xD7FFu).value();
++before_surrogates;
auto wrap = utf8_char::from_scalar(0x10FFFFu).value();
++wrap;
std::println("{}", latin); // B
std::println("{}", std::format("{:X}", before_surrogates.as_scalar())); // E000
std::println("{}", wrap.as_scalar()); // 0
}
Unicode Classification Predicates¶
Synopsis¶
constexpr bool is_ascii() const noexcept;
constexpr bool is_alphabetic() const noexcept;
constexpr bool is_alphanumeric() const noexcept;
constexpr bool is_control() const noexcept;
constexpr bool is_digit() const noexcept;
constexpr bool is_lowercase() const noexcept;
constexpr bool is_numeric() const noexcept;
constexpr bool is_uppercase() const noexcept;
constexpr bool is_whitespace() const noexcept;
Behavior¶
is_ascii()tests whether the scalar is in the ASCII range.- The remaining predicates use the Unicode property tables shipped with the library.
is_alphanumeric()is defined asis_alphabetic() || is_numeric().
Return value¶
Returns true when the scalar has the queried property.
Complexity¶
Constant, with table lookups for the Unicode property predicates.
Exceptions¶
None.
noexcept¶
All listed overloads are noexcept.
Example¶
#include "unicode_ranges_all.hpp"
#include <print>
using namespace unicode_ranges;
using namespace unicode_ranges::literals;
int main()
{
std::println("{}", "ฮฉ"_u8c.is_alphabetic()); // true
std::println("{}", "ฮฉ"_u8c.is_ascii()); // false
std::println("{}", "7"_u8c.is_digit()); // true
std::println("{}", " "_u8c.is_whitespace()); // true
}
Unicode Property Queries¶
Synopsis¶
constexpr unicode_general_category general_category() const noexcept;
constexpr std::uint8_t canonical_combining_class() const noexcept;
constexpr unicode_grapheme_break_property grapheme_break_property() const noexcept;
constexpr unicode_script script() const noexcept;
constexpr unicode_east_asian_width east_asian_width() const noexcept;
constexpr unicode_line_break_class line_break_class() const noexcept;
constexpr unicode_bidi_class bidi_class() const noexcept;
constexpr unicode_word_break_property word_break_property() const noexcept;
constexpr unicode_sentence_break_property sentence_break_property() const noexcept;
constexpr bool is_emoji() const noexcept;
constexpr bool is_emoji_presentation() const noexcept;
constexpr bool is_extended_pictographic() const noexcept;
Behavior¶
- All of these methods are locale-independent scalar-property queries.
general_category()returns the Unicode General_Category bucket for the scalar.canonical_combining_class()returns the canonical combining class used by normalization and canonical reordering.grapheme_break_property(),line_break_class(),word_break_property(), andsentence_break_property()expose the default Unicode segmentation and line-breaking properties for the scalar.script()returns the Unicode Script property. Punctuation and separators often come back ascommon, while combining marks are ofteninherited.east_asian_width()returns the Unicode East Asian Width class used by terminal and grid-width heuristics.bidi_class()returns the scalar's Unicode bidirectional class. This is a property lookup, not full bidi reordering.is_emoji()tests the UnicodeEmojiproperty.is_emoji_presentation()tests the UnicodeEmoji_Presentationproperty.is_extended_pictographic()tests the UnicodeExtended_Pictographicproperty used by segmentation algorithms.- These are scalar properties only. They do not inspect grapheme clusters or emoji ZWJ sequences.
Return value¶
- The enum-returning methods return the property value for the scalar.
canonical_combining_class()returns the canonical combining class number.- The boolean methods return
truewhen the scalar has the queried property.
Complexity¶
Constant, with table lookups.
Exceptions¶
None.
noexcept¶
All listed overloads are noexcept.
Example¶
#include "unicode_ranges_all.hpp"
#include <print>
using namespace unicode_ranges;
using namespace unicode_ranges::literals;
int main()
{
std::println("{}", "A"_u8c.general_category() == unicode_general_category::uppercase_letter); // true
std::println("{}", "ฬ"_u8c.canonical_combining_class() == 230); // true
std::println("{}", "ฬ"_u8c.grapheme_break_property() == unicode_grapheme_break_property::extend); // true
std::println("{}", "ฮฉ"_u8c.script() == unicode_script::greek); // true
std::println("{}", "็"_u8c.east_asian_width() == unicode_east_asian_width::wide); // true
std::println("{}", "A"_u8c.line_break_class() == unicode_line_break_class::alphabetic); // true
std::println("{}", "ุด"_u8c.bidi_class() == unicode_bidi_class::arabic_letter); // true
std::println("{}", "A"_u8c.word_break_property() == unicode_word_break_property::a_letter); // true
std::println("{}", "."_u8c.sentence_break_property() == unicode_sentence_break_property::a_term); // true
std::println("{}", "๐"_u8c.is_emoji()); // true
std::println("{}", "๐"_u8c.is_emoji_presentation()); // true
std::println("{}", "๐"_u8c.is_extended_pictographic()); // true
std::println("{}", U"ฮฉ"_u32c.script() == unicode_script::greek); // true
std::println("{}", U"๐"_u32c.is_emoji()); // true
}
ASCII Classification Predicates¶
Synopsis¶
constexpr bool is_ascii_alphabetic() const noexcept;
constexpr bool is_ascii_alphanumeric() const noexcept;
constexpr bool is_ascii_control() const noexcept;
constexpr bool is_ascii_digit() const noexcept;
constexpr bool is_ascii_graphic() const noexcept;
constexpr bool is_ascii_hexdigit() const noexcept;
constexpr bool is_ascii_lowercase() const noexcept;
constexpr bool is_ascii_octdigit() const noexcept;
constexpr bool is_ascii_punctuation() const noexcept;
constexpr bool is_ascii_uppercase() const noexcept;
constexpr bool is_ascii_whitespace() const noexcept;
Behavior¶
These methods first require the value to be ASCII and then apply the corresponding ASCII-only classification rule.
Return value¶
Returns false for all non-ASCII characters.
Complexity¶
Constant.
Exceptions¶
None.
noexcept¶
All listed overloads are noexcept.
Example¶
#include "unicode_ranges_all.hpp"
#include <print>
using namespace unicode_ranges;
using namespace unicode_ranges::literals;
int main()
{
std::println("{}", "A"_u8c.is_ascii_alphabetic()); // true
std::println("{}", "9"_u8c.is_ascii_hexdigit()); // true
std::println("{}", "รฉ"_u8c.is_ascii_alphabetic()); // false
}
ASCII Transforms And ASCII Comparison¶
Synopsis¶
constexpr utf8_char ascii_lowercase() const noexcept;
constexpr utf8_char ascii_uppercase() const noexcept;
constexpr bool eq_ignore_ascii_case(utf8_char other) const noexcept;
constexpr void swap(utf8_char& other) noexcept;
constexpr utf16_char ascii_lowercase() const noexcept;
constexpr utf16_char ascii_uppercase() const noexcept;
constexpr bool eq_ignore_ascii_case(utf16_char other) const noexcept;
constexpr void swap(utf16_char& other) noexcept;
constexpr utf32_char ascii_lowercase() const noexcept;
constexpr utf32_char ascii_uppercase() const noexcept;
constexpr bool eq_ignore_ascii_case(utf32_char other) const noexcept;
constexpr void swap(utf32_char& other) noexcept;
Behavior¶
ascii_lowercase()andascii_uppercase()only modify ASCII letters.- Non-ASCII characters are returned unchanged.
eq_ignore_ascii_case()lowercases both operands with the ASCII-only transform and compares the results.swap()exchanges the stored code units.
Complexity¶
Constant.
Exceptions¶
None.
noexcept¶
All listed overloads are noexcept.
Example¶
#include "unicode_ranges_all.hpp"
#include <print>
using namespace unicode_ranges;
using namespace unicode_ranges::literals;
int main()
{
auto left = "A"_u8c;
auto right = "Z"_u8c;
left.swap(right);
std::println("{}", "x"_u8c.ascii_uppercase()); // X
std::println("{}", "ร"_u8c.ascii_lowercase()); // ร
std::println("{}", "x"_u8c.eq_ignore_ascii_case("X"_u8c)); // true
std::println("{}", left); // Z
std::println("{}", right); // A
}
Comparison, Streaming, Hashing, And Formatting¶
Synopsis¶
friend constexpr bool operator==(const utf8_char&, const utf8_char&) = default;
friend constexpr auto operator<=>(const utf8_char&, const utf8_char&) = default;
friend constexpr bool operator==(const utf8_char& lhs, char rhs) noexcept;
friend constexpr bool operator==(const utf8_char& lhs, char8_t rhs) noexcept;
friend std::ostream& operator<<(std::ostream& os, const utf8_char& ch);
friend constexpr bool operator==(const utf16_char&, const utf16_char&) = default;
friend constexpr auto operator<=>(const utf16_char&, const utf16_char&) = default;
friend constexpr bool operator==(const utf16_char& lhs, char16_t rhs) noexcept;
friend std::ostream& operator<<(std::ostream& os, const utf16_char& ch);
friend constexpr bool operator==(const utf32_char&, const utf32_char&) = default;
friend constexpr auto operator<=>(const utf32_char&, const utf32_char&) = default;
friend constexpr bool operator==(const utf32_char& lhs, char32_t rhs) noexcept;
friend std::ostream& operator<<(std::ostream& os, const utf32_char& ch);
template<> struct std::hash<utf8_char>;
template<> struct std::hash<utf16_char>;
template<> struct std::hash<utf32_char>;
template<> struct std::formatter<utf8_char, char>;
template<> struct std::formatter<utf8_char, wchar_t>;
template<> struct std::formatter<utf16_char, char>;
template<> struct std::formatter<utf16_char, wchar_t>;
template<> struct std::formatter<utf32_char, char>;
template<> struct std::formatter<utf32_char, wchar_t>;
Behavior¶
- The defaulted comparisons compare the stored encoded value.
utf8_charcompares directly withcharandchar8_twhen the value is a single-byte ASCII code point.utf16_charcompares directly withchar16_twhen the value is a single UTF-16 code unit.utf32_charcompares directly withchar32_tbecause every UTF-32 character is one code point unit.- Stream insertion writes a textual representation:
utf8_charwrites its UTF-8 bytes directlyutf16_chartranscodes to UTF-8 forstd::ostreamutf32_chartranscodes to UTF-8 forstd::ostreamstd::hashhashes the encoded text representation.- The
std::formatterspecializations support: - normal textual formatting
'c'as a text presentation alias- numeric presentations
d,b,B,o,x,X, which formatas_scalar()
Complexity¶
Constant.
Exceptions¶
- The comparison overloads and hashers do not throw.
- Stream insertion may report stream errors through the stream object.
- Formatter parsing may throw
std::format_errorfor unsupported or malformed format specifiers.
noexcept¶
- The comparison overloads and hashers are non-throwing.
- Stream insertion and formatters are not
noexcept.
Example¶
#include "unicode_ranges_all.hpp"
#include <format>
#include <functional>
#include <print>
#include <sstream>
using namespace unicode_ranges;
using namespace unicode_ranges::literals;
int main()
{
const auto euro = "โฌ"_u8c;
const auto grin = u"๐"_u16c;
std::ostringstream out;
out << euro;
std::println("{}", euro == "โฌ"_u8c); // true
std::println("{}", std::hash<utf8_char>{}(euro) == std::hash<utf8_char>{}("โฌ"_u8c)); // true
std::println("{}", out.str()); // โฌ
std::println("{}", std::format("{:X}", euro)); // 20AC
std::println("{}", std::format("{}", grin)); // ๐
}
Character Literals¶
Synopsis¶
using namespace unicode_ranges::literals;
consteval utf8_char operator ""_u8c();
consteval utf16_char operator ""_u16c();
consteval utf32_char operator ""_u32c();
Behavior¶
The literal must encode exactly one valid UTF-8, UTF-16, or UTF-32 character in the corresponding encoding.
Return value¶
Returns the validated utf8_char, utf16_char, or utf32_char.
Exceptions¶
Because these are consteval literals, invalid input is rejected during compilation rather than at runtime.
Example¶
#include "unicode_ranges_all.hpp"
#include <print>
using namespace unicode_ranges;
using namespace unicode_ranges::literals;
int main()
{
constexpr auto sparkle = "โจ"_u8c;
constexpr auto grin = u"๐"_u16c;
constexpr auto rocket = U"๐"_u32c;
std::println("{}", sparkle); // โจ
std::println("{}", grin); // ๐
std::println("{}", rocket); // ๐
}
Curated Character Namespaces¶
Synopsis¶
namespace unicode_ranges::characters::utf8
{
namespace punctuation { inline constexpr utf8_char ...; }
namespace symbols { inline constexpr utf8_char ...; }
namespace currency { inline constexpr utf8_char ...; }
namespace math { inline constexpr utf8_char ...; }
namespace arrows { inline constexpr utf8_char ...; }
namespace emojis { inline constexpr utf8_char ...; }
}
namespace unicode_ranges::characters::utf16
{
namespace punctuation { inline constexpr utf16_char ...; }
namespace symbols { inline constexpr utf16_char ...; }
namespace currency { inline constexpr utf16_char ...; }
namespace math { inline constexpr utf16_char ...; }
namespace arrows { inline constexpr utf16_char ...; }
namespace emojis { inline constexpr utf16_char ...; }
}
namespace unicode_ranges::characters::utf32
{
namespace punctuation { inline constexpr utf32_char ...; }
namespace symbols { inline constexpr utf32_char ...; }
namespace currency { inline constexpr utf32_char ...; }
namespace math { inline constexpr utf32_char ...; }
namespace arrows { inline constexpr utf32_char ...; }
namespace emojis { inline constexpr utf32_char ...; }
}
Behavior¶
- These namespaces provide a curated convenience set of commonly used punctuation, symbols, currency signs, arrows, math symbols, and emoji.
characters::utf8::...constants areutf8_char.characters::utf16::...constants areutf16_char.characters::utf32::...constants areutf32_char.- Both trees expose the same names so you can choose the encoding that matches the surrounding API.
- This is intentionally not a complete Unicode catalog.
Complexity¶
Constant.
Exceptions¶
None.
noexcept¶
Accessing the constants is non-throwing.
Example¶
#include "unicode_ranges_all.hpp"
#include <print>
using namespace unicode_ranges;
int main()
{
std::println("{}", characters::utf8::currency::euro_sign); // โฌ
std::println("{}", characters::utf8::math::approximately_equal_to); // โ
std::println("{}", characters::utf8::emojis::clown_face); // ๐คก
std::println("{}", characters::utf8::emojis::party_popper); // ๐
std::println("{}", characters::utf16::currency::euro_sign); // โฌ
std::println("{}", characters::utf16::arrows::right_arrow); // โ
std::println("{}", characters::utf16::emojis::red_heart); // โค
std::println("{}", characters::utf16::emojis::rocket); // ๐
std::println("{}", characters::utf32::currency::euro_sign); // โฌ
std::println("{}", characters::utf32::symbols::section_sign); // ยง
std::println("{}", characters::utf32::emojis::sparkles); // โจ
std::println("{}", characters::utf32::emojis::rocket); // ๐
}