| |
| |
| |
| |
| |
| |
| |
| |
| |
| #pragma once |
|
|
| #include <string> |
| #include <regex> |
| #include <string_view> |
| #include <algorithm> |
| #include <cctype> |
| #include <unordered_map> |
| #include <cstdint> |
|
|
|
|
| class TextCleaner { |
| public: |
| TextCleaner() = default; |
| ~TextCleaner() = default; |
|
|
| std::string run(const std::string& input_text) { |
| if (input_text.empty()) return ""; |
| |
| |
| std::string text = _fullwidth_to_halfwidth(input_text); |
| |
| |
| std::regex ws_re(R"(\s+)"); |
| text = std::regex_replace(text, ws_re, " "); |
| |
| |
| auto not_whitespace = [](unsigned char ch) { |
| return !std::isspace(ch); |
| }; |
| |
| |
| auto begin = std::find_if(text.begin(), text.end(), not_whitespace); |
| if (begin == text.end()) { |
| return ""; |
| } |
| auto end = std::find_if(text.rbegin(), text.rend(), not_whitespace).base(); |
| |
| |
| std::string trimmed(begin, end); |
| |
| |
| std::string filtered; |
| filtered.reserve(trimmed.length()); |
| |
| |
| |
| |
| |
| |
| |
| |
| for (unsigned char ch : trimmed) { |
| if (ch >= 32 || ch == '\n' || ch == '\r' || ch == '\t') { |
| filtered.push_back(static_cast<char>(ch)); |
| } |
| } |
|
|
| return filtered; |
| } |
|
|
|
|
| private: |
| |
| std::string _fullwidth_to_halfwidth(const std::string& input) { |
| std::string result; |
| result.reserve(input.length()); |
| |
| |
| |
| static const std::unordered_map<std::string, std::string> full_to_half = { |
| |
| {"。", "."}, |
| {"!", "!"}, |
| {"?", "?"}, |
| {";", ";"}, |
| {",", ","}, |
| {"、", ","}, |
| {":", ":"}, |
| {""", "\""}, |
| {"'", "'"}, |
| {"(", "("}, |
| {")", ")"}, |
| {"【", "["}, |
| {"】", "]"}, |
| {"《", "<"}, |
| {"》", ">"}, |
| |
| |
| {" ", " "}, |
| |
| |
| {"A", "A"}, {"B", "B"}, {"C", "C"}, {"D", "D"}, {"E", "E"}, |
| {"F", "F"}, {"G", "G"}, {"H", "H"}, {"I", "I"}, {"J", "J"}, |
| {"K", "K"}, {"L", "L"}, {"M", "M"}, {"N", "N"}, {"O", "O"}, |
| {"P", "P"}, {"Q", "Q"}, {"R", "R"}, {"S", "S"}, {"T", "T"}, |
| {"U", "U"}, {"V", "V"}, {"W", "W"}, {"X", "X"}, {"Y", "Y"}, |
| {"Z", "Z"}, |
| {"a", "a"}, {"b", "b"}, {"c", "c"}, {"d", "d"}, {"e", "e"}, |
| {"f", "f"}, {"g", "g"}, {"h", "h"}, {"i", "i"}, {"j", "j"}, |
| {"k", "k"}, {"l", "l"}, {"m", "m"}, {"n", "n"}, {"o", "o"}, |
| {"p", "p"}, {"q", "q"}, {"r", "r"}, {"s", "s"}, {"t", "t"}, |
| {"u", "u"}, {"v", "v"}, {"w", "w"}, {"x", "x"}, {"y", "y"}, |
| {"z", "z"}, |
| {"0", "0"}, {"1", "1"}, {"2", "2"}, {"3", "3"}, {"4", "4"}, |
| {"5", "5"}, {"6", "6"}, {"7", "7"}, {"8", "8"}, {"9", "9"}, |
| |
| |
| {""", "\""}, |
| {"'", "'"}, |
| {""", "\""}, |
| {"'", "'"}, |
| {"~", "~"}, |
| {"@", "@"}, |
| {"#", "#"}, |
| {"$", "$"}, |
| {"%", "%"}, |
| {"&", "&"}, |
| {"*", "*"}, |
| {"+", "+"}, |
| {"-", "-"}, |
| {"=", "="}, |
| {"\", "\\"}, |
| {"|", "|"}, |
| {"{", "{"}, |
| {"}", "}"}, |
| {"^", "^"}, |
| {"_", "_"}, |
| {"`", "`"}, |
| {"<", "<"}, |
| {">", ">"}, |
| }; |
| |
| size_t i = 0; |
| while (i < input.length()) { |
| |
| unsigned char ch = static_cast<unsigned char>(input[i]); |
| |
| if (ch < 128) { |
| |
| result.push_back(input[i]); |
| i++; |
| } else { |
| |
| bool matched = false; |
| |
| |
| if (i + 2 < input.length()) { |
| std::string utf8_char = input.substr(i, 3); |
| auto it = full_to_half.find(utf8_char); |
| if (it != full_to_half.end()) { |
| result += it->second; |
| i += 3; |
| matched = true; |
| } |
| } |
| |
| |
| if (!matched) { |
| |
| int char_len = 0; |
| if ((ch & 0xF0) == 0xF0) char_len = 4; |
| else if ((ch & 0xE0) == 0xE0) char_len = 3; |
| else if ((ch & 0xC0) == 0xC0) char_len = 2; |
| else char_len = 1; |
| |
| result += input.substr(i, char_len); |
| i += char_len; |
| } |
| } |
| } |
| |
| return result; |
| } |
| }; |