| |
| |
| |
| |
| |
| |
| |
| |
| |
| #include "utils/string_utils.hpp" |
| #include "utils/logger.h" |
|
|
| #include <sstream> |
| #include <algorithm> |
|
|
| namespace utils { |
|
|
| std::vector<std::string> split_utf8(const std::string& utf8_text) { |
| std::vector<std::string> chars; |
| for (size_t i = 0; i < utf8_text.length();) { |
| unsigned char c = static_cast<unsigned char>(utf8_text[i]); |
| size_t char_len = 0; |
| if (c < 0x80) char_len = 1; |
| else if ((c & 0xE0) == 0xC0) char_len = 2; |
| else if ((c & 0xF0) == 0xE0) char_len = 3; |
| else if ((c & 0xF8) == 0xF0) char_len = 4; |
| else char_len = 1; |
|
|
| if (i + char_len > utf8_text.length()) char_len = utf8_text.length() - i; |
| |
| chars.push_back(utf8_text.substr(i, char_len)); |
| i += char_len; |
| } |
| return chars; |
| } |
|
|
| |
| std::vector<std::string> str2list(const std::string& text, char delimiter) { |
| std::vector<std::string> tokens; |
| std::string token; |
| std::istringstream tokenStream(text); |
| |
| |
| |
| while (std::getline(tokenStream, token, delimiter)) { |
| if (!token.empty()) |
| tokens.push_back(token); |
| } |
|
|
| if (tokens.empty()) { |
| return std::vector<std::string>{text}; |
| } |
|
|
| return tokens; |
| } |
|
|
| void replace_inplace(std::string& str, const std::string& from, const std::string& to) { |
| if(from.empty()) |
| return; |
| |
| size_t start_pos = 0; |
| while((start_pos = str.find(from, start_pos)) != std::string::npos) { |
| str.replace(start_pos, from.length(), to); |
| start_pos += to.length(); |
| } |
| } |
|
|
| std::string strip(const std::string& s) { |
| auto begin = |
| std::find_if_not(s.begin(), s.end(), ::isspace); |
| auto end = |
| std::find_if_not(s.rbegin(), s.rend(), ::isspace).base(); |
| return (begin < end) ? std::string(begin, end) : ""; |
| } |
|
|
| |
| |
| void u8tou16(const char* src, size_t len, std::u16string& dst) { |
| if (len == 0) { dst = u""; return; } |
| try { |
| std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> converter; |
| dst = converter.from_bytes(src, src + len); |
| } catch (...) { |
| dst = u""; |
| } |
| } |
|
|
| void u16tou8(const char16_t* src, size_t len, std::string& dst) { |
| if (len == 0) { dst = ""; return; } |
| try { |
| std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> converter; |
| dst = converter.to_bytes(src, src + len); |
| } catch (...) { |
| dst = ""; |
| } |
| } |
|
|
| void SplitString(const std::string& str, char delimiter, std::vector<std::string>* result) { |
| std::stringstream ss(str); |
| std::string item; |
| while (std::getline(ss, item, delimiter)) { |
| if (!item.empty()) { |
| result->push_back(item); |
| } |
| } |
| } |
|
|
| void SplitString(const char* str, size_t len, char delimiter, std::vector<std::string>* result) { |
| std::string s(str, len); |
| SplitString(s, delimiter, result); |
| } |
|
|
| std::string DigitToChinese(char c) { |
| switch(c) { |
| case '0': return "零"; |
| case '1': return "一"; |
| case '2': return "二"; |
| case '3': return "三"; |
| case '4': return "四"; |
| case '5': return "五"; |
| case '6': return "六"; |
| case '7': return "七"; |
| case '8': return "八"; |
| case '9': return "九"; |
| default: return ""; |
| } |
| } |
|
|
| std::string NumberToChinese(const std::string& num_str) { |
| if (num_str.empty()) return ""; |
| |
| |
| int dot_count = 0; |
| for (char c : num_str) { |
| if (c == '.') dot_count++; |
| } |
| |
| if (dot_count > 1) { |
| std::string res; |
| for (char c : num_str) { |
| if (c == '.') { |
| res += "点"; |
| } else if (isdigit(c)) { |
| res += DigitToChinese(c); |
| } else { |
| |
| res += c; |
| } |
| } |
| return res; |
| } |
| |
| std::string res; |
| size_t start = 0; |
| if (num_str[0] == '-') { |
| res += "负"; |
| start = 1; |
| } else if (num_str[0] == '+') { |
| start = 1; |
| } |
|
|
| size_t dot_pos = num_str.find('.'); |
| std::string integer_part = num_str.substr(start, dot_pos - start); |
| std::string decimal_part; |
| if (dot_pos != std::string::npos) { |
| decimal_part = num_str.substr(dot_pos + 1); |
| } |
|
|
| |
| if (integer_part.empty()) { |
| res += "零"; |
| } else { |
| |
| |
| |
| |
| |
| |
| if (integer_part.length() > 12) { |
| for (char c : integer_part) { |
| res += DigitToChinese(c); |
| } |
| } else { |
| |
| const char* units[] = {"", "十", "百", "千"}; |
| const char* big_units[] = {"", "万", "亿", "兆"}; |
| |
| |
| size_t first_nonzero = integer_part.find_first_not_of('0'); |
| if (first_nonzero == std::string::npos) { |
| res += "零"; |
| } else { |
| std::string s = integer_part.substr(first_nonzero); |
| int len = s.length(); |
| |
| |
| int group_count = (len + 3) / 4; |
| |
| bool zero_flag = false; |
| |
| for (int i = 0; i < group_count; ++i) { |
| int group_idx = group_count - 1 - i; |
| int start_idx = std::max(0, len - (i + 1) * 4); |
| int end_idx = len - i * 4; |
| std::string group_str = s.substr(start_idx, end_idx - start_idx); |
| |
| std::string group_res; |
| bool group_has_value = false; |
| bool last_is_zero = false; |
| |
| int g_len = group_str.length(); |
| for (int j = 0; j < g_len; ++j) { |
| char digit = group_str[j]; |
| int unit_idx = g_len - 1 - j; |
| |
| if (digit == '0') { |
| last_is_zero = true; |
| } else { |
| if (last_is_zero) { |
| group_res += "零"; |
| last_is_zero = false; |
| } |
| |
| |
| |
| |
| if (digit == '1' && unit_idx == 1 && group_res.empty() && zero_flag == false && i == 0 && g_len == 2) { |
| |
| } else { |
| group_res += DigitToChinese(digit); |
| } |
| group_res += units[unit_idx]; |
| group_has_value = true; |
| } |
| } |
| |
| if (group_has_value) { |
| if (zero_flag && group_res.find("零") != 0) { |
| |
| |
| |
| |
| } |
| |
| |
| |
| |
| |
| |
| if (!res.empty() && group_str[0] == '0') { |
| |
| |
| |
| if (res.substr(res.length() - 3) != "零") |
| res += "零"; |
| } |
| |
| res += group_res; |
| res += big_units[i]; |
| |
| |
| |
| } |
| } |
| |
| |
| res = ""; |
| if (num_str[0] == '-') res += "负"; |
| |
| int remaining = len; |
| bool need_zero = false; |
| |
| for (int i = 0; i < len; ++i) { |
| int digit = s[i] - '0'; |
| int pos = len - 1 - i; |
| int unit_idx = pos % 4; |
| int big_unit_idx = pos / 4; |
| |
| if (digit == 0) { |
| if (unit_idx == 0 && big_unit_idx > 0 && (need_zero || (i > 0 && (s[i-1]-'0')!=0) )) { |
| |
| |
| |
| |
| } |
| need_zero = true; |
| } else { |
| if (need_zero) { |
| res += "零"; |
| need_zero = false; |
| } |
| |
| |
| if (digit == 1 && unit_idx == 1 && len == 2 && i == 0) { |
| |
| } else { |
| res += DigitToChinese(s[i]); |
| } |
| res += units[unit_idx]; |
| } |
| |
| if (unit_idx == 0 && big_unit_idx > 0) { |
| |
| |
| bool group_has_value = false; |
| int start_chk = std::max(0, i - 3); |
| for(int k=start_chk; k<=i; ++k) if(s[k] != '0') group_has_value = true; |
| |
| if (group_has_value) { |
| res += big_units[big_unit_idx]; |
| need_zero = false; |
| |
| |
| } |
| } |
| } |
| } |
| } |
| } |
|
|
| |
| if (!decimal_part.empty()) { |
| res += "点"; |
| for (char c : decimal_part) { |
| res += DigitToChinese(c); |
| } |
| } |
| |
| return res; |
| } |
|
|
| bool is_chinese(const std::string& str) { |
| |
| for (unsigned char c : str) { |
| if (c >= 0xE4 && c <= 0xE9) return true; |
| } |
| return false; |
| } |
|
|
| std::string trim(const std::string& str) { |
| size_t first = str.find_first_not_of(" \t\n\r"); |
| if (std::string::npos == first) return ""; |
| size_t last = str.find_last_not_of(" \t\n\r"); |
| return str.substr(first, (last - first + 1)); |
| } |
|
|
| std::string replace_all(std::string str, const std::string& from, const std::string& to) { |
| if (from.empty()) return str; |
| size_t start_pos = 0; |
| while((start_pos = str.find(from, start_pos)) != std::string::npos) { |
| str.replace(start_pos, from.length(), to); |
| start_pos += to.length(); |
| } |
| return str; |
| } |
|
|
| std::string join(const std::vector<std::string>& vec, const std::string& delim) { |
| std::string res; |
| for (size_t i = 0; i < vec.size(); ++i) { |
| if (i > 0) res += delim; |
| res += vec[i]; |
| } |
| return res; |
| } |
|
|
| } |