File size: 7,647 Bytes
71e354e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/**************************************************************************************************
 *
 * Copyright (c) 2019-2026 Axera Semiconductor (Ningbo) Co., Ltd. All Rights Reserved.
 *
 * This source file is the property of Axera Semiconductor (Ningbo) Co., Ltd. and
 * may not be copied or distributed in any isomorphic form without the prior
 * written consent of Axera Semiconductor (Ningbo) Co., Ltd.
 *
 **************************************************************************************************/
#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);
        
        // 1. 替换连续空白字符
        std::regex ws_re(R"(\s+)");
        text = std::regex_replace(text, ws_re, " ");
        
        // 2. 去除首尾空白
        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);
        
        // 3. 过滤字符
        std::string filtered;
        filtered.reserve(trimmed.length());
        
        // 遍历每个字符,只保留满足条件的字符:
        // 条件1:ord(char) >= 32  # ASCII值大于等于32(可打印字符和常见标点)
        //        - ASCII 0-31是控制字符(如换行符、回车符、制表符等)
        //        - ASCII 32是空格
        //        - ASCII 33-126是可打印字符
        // 条件2:or char in '\n\r\t'  # 或者字符是换行符、回车符、制表符
        //        虽然这些字符的ASCII值<32,但我们特别允许它们通过
        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());  // 预分配内存
        
        // 全角到半角的映射表(UTF-8编码)
        // 注意:全角字符通常是3字节的UTF-8编码
        static const std::unordered_map<std::string, std::string> full_to_half = {
            // 中文标点
            {"。", "."},    // 全角句号
            {"!", "!"},    // 全角感叹号
            {"?", "?"},    // 全角问号
            {";", ";"},    // 全角分号
            {",", ","},    // 全角逗号
            {"、", ","},    // 全角顿号(转换为逗号)
            {":", ":"},    // 全角冒号
            {""", "\""},   // 全角双引号
            {"'", "'"},    // 全角单引号
            {"(", "("},    // 全角左括号
            {")", ")"},    // 全角右括号
            {"【", "["},    // 全角左方括号
            {"】", "]"},    // 全角右方括号
            {"《", "<"},    // 全角左书名号
            {"》", ">"},    // 全角右书名号
            
            // 全角空格(通常用于中文排版)
            {" ", " "},    // 全角空格转半角空格
            
            // 全角字母和数字(A-Z, a-z, 0-9)
            {"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()) {
            // 检查是否是UTF-8多字节字符
            unsigned char ch = static_cast<unsigned char>(input[i]);
            
            if (ch < 128) {
                // ASCII字符,直接保留
                result.push_back(input[i]);
                i++;
            } else {
                // 可能是UTF-8字符,尝试匹配
                bool matched = false;
                
                // 检查最常见的3字节UTF-8字符(中文标点通常是3字节)
                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) {
                    // 复制整个UTF-8字符(可能是2-4字节)
                    int char_len = 0;
                    if ((ch & 0xF0) == 0xF0) char_len = 4;      // 4字节字符
                    else if ((ch & 0xE0) == 0xE0) char_len = 3; // 3字节字符
                    else if ((ch & 0xC0) == 0xC0) char_len = 2; // 2字节字符
                    else char_len = 1;                          // 不应该发生
                    
                    result += input.substr(i, char_len);
                    i += char_len;
                }
            }
        }
        
        return result;
    }
};