1 #pragma once
2 
3 #include <string>
4 #include <wchar.h>
5 
6 #include <algorithm>
7 #include <memory>
8 
9 #pragma warning(push, 0)
10     #include <utf8/utf8.h>
11     #ifdef WIN32
12         #include <wcwidth.h>
13     #endif
14 #pragma warning(pop)
15 
16 #ifdef max
17 #undef max
18 #endif
19 
u8to16(const std::string & u8)20 inline std::wstring u8to16(const std::string& u8) {
21     std::wstring result;
22     utf8::utf8to16(u8.begin(), u8.end(), std::back_inserter(result));
23     return result;
24 }
25 
u16to8(const std::wstring & u16)26 inline std::string u16to8(const std::wstring& u16) {
27     std::string result;
28     utf8::utf16to8(u16.begin(), u16.end(), std::back_inserter(result));
29     return result;
30 }
31 
u8cols(const std::string & str)32 static inline size_t u8cols(const std::string& str) {
33     std::wstring wstr = u8to16(str);
34 #ifdef WIN32
35     int result = std::max(0, mk_wcswidth(wstr.c_str(), wstr.size()));
36 #else
37     int result = std::max(0, wcswidth(wstr.c_str(), wstr.size()));
38 #endif
39     return (result > 0) ? result : str.size();
40 }
41 
u8len(const std::string & str)42 inline static size_t u8len(const std::string& str) {
43     try {
44         return utf8::distance(str.begin(), str.end());
45     }
46     catch (...) {
47         return str.length();
48     }
49 }
50 
51 /* get the (raw) character index of the "nth" logical/display character */
u8offset(const std::string & str,int n)52 inline static size_t u8offset(const std::string& str, int n) {
53     if (str.size() == 0) {
54         return std::string::npos;
55     }
56 
57     std::string::const_iterator it = str.begin();
58 
59     int count = 0;
60     while (count < n && it != str.end()) {
61         utf8::unchecked::next(it);
62         ++count;
63     }
64 
65     return (size_t)(it - str.begin());
66 }
67 
u8substr(const std::string & in,int offset,int len)68 inline static std::string u8substr(const std::string& in, int offset, int len) {
69     std::string::const_iterator begin = in.begin() + offset;
70     std::string::const_iterator it = begin;
71 
72     int count = 0;
73     while (count < len && it != in.end()) {
74         utf8::unchecked::next(it);
75         ++count;
76     }
77 
78     return std::string(begin, it);
79 }
80 
81 template<typename... Args>
u8fmt(const std::string & format,Args...args)82 static std::string u8fmt(const std::string& format, Args ... args) {
83     /* https://stackoverflow.com/a/26221725 */
84     size_t size = std::snprintf(nullptr, 0, format.c_str(), args ...) + 1; /* extra space for '\0' */
85     std::unique_ptr<char[]> buf(new char[size]);
86     std::snprintf(buf.get(), size, format.c_str(), args ...);
87     return std::string(buf.get(), buf.get() + size - 1); /* omit the '\0' */
88 }
89 
u8replace(std::string & input,const std::string & find,const std::string & replace)90 static inline void u8replace(
91     std::string& input, const std::string& find, const std::string& replace)
92 {
93     size_t pos = input.find(find);
94     while (pos != std::string::npos) {
95         input.replace(pos, find.size(), replace);
96         pos = input.find(find, pos + replace.size());
97     }
98 }
99