|
6 | 6 |
|
7 | 7 | #include "pinyindata.h" |
8 | 8 | #include <algorithm> |
| 9 | +#include <array> |
| 10 | +#include <cassert> |
| 11 | +#include <cstddef> |
9 | 12 | #include <cstdint> |
10 | 13 | #include <iterator> |
11 | 14 | #include <optional> |
| 15 | +#include <ranges> |
12 | 16 | #include <string> |
13 | 17 | #include <unordered_map> |
14 | 18 | #include <unordered_set> |
|
21 | 25 |
|
22 | 26 | namespace libime { |
23 | 27 |
|
| 28 | +namespace { |
| 29 | + |
| 30 | +void applyPartialFinalFuzzy(PinyinMap &map) { |
| 31 | + // There are some finals won't generate any entries, just skip them from |
| 32 | + // map. |
| 33 | + const auto partialFinalFuzzyMap = |
| 34 | + std::to_array<std::pair<std::string, std::vector<PinyinFinal>>>({ |
| 35 | + {"a", |
| 36 | + {PinyinFinal::AN, PinyinFinal::AI, PinyinFinal::AO, |
| 37 | + PinyinFinal::ANG}}, |
| 38 | + {"e", |
| 39 | + {PinyinFinal::EI, PinyinFinal::EN, PinyinFinal::ENG, |
| 40 | + PinyinFinal::ER}}, |
| 41 | + {"i", |
| 42 | + {PinyinFinal::IA, PinyinFinal::IAN, PinyinFinal::IAO, |
| 43 | + PinyinFinal::IANG, PinyinFinal::IE, PinyinFinal::IN, |
| 44 | + PinyinFinal::ING, PinyinFinal::IONG, PinyinFinal::IU}}, |
| 45 | + {"ia", {PinyinFinal::IAN, PinyinFinal::IAO, PinyinFinal::IANG}}, |
| 46 | + {"ion", {PinyinFinal::IONG}}, |
| 47 | + {"o", {PinyinFinal::ONG, PinyinFinal::OU}}, |
| 48 | + {"on", {PinyinFinal::ONG}}, |
| 49 | + |
| 50 | +#if 0 |
| 51 | + // Item won't generate anything below. |
| 52 | + {"an", {PinyinFinal::ANG}}, |
| 53 | + {"en", {PinyinFinal::ENG}}, |
| 54 | + {"ian", {PinyinFinal::IANG}}, |
| 55 | + {"in", {PinyinFinal::ING}}, |
| 56 | + {"io", {PinyinFinal::IONG}}, |
| 57 | + |
| 58 | + {"u", |
| 59 | + {PinyinFinal::UA, PinyinFinal::UAI, PinyinFinal::UAN, |
| 60 | + PinyinFinal::UANG, PinyinFinal::UE, PinyinFinal::UI, |
| 61 | + PinyinFinal::UN, PinyinFinal::UO}}, |
| 62 | + {"ua", {PinyinFinal::UAI, PinyinFinal::UAN, PinyinFinal::UANG}}, |
| 63 | + {"uan", {PinyinFinal::UANG}}, |
| 64 | + {"v", {PinyinFinal::VE}}, |
| 65 | +#endif |
| 66 | + }); |
| 67 | + std::vector<PinyinEntry> newEntries; |
| 68 | + std::map<std::string, int> statistic; |
| 69 | + for (const auto initial : std::views::iota(PinyinEncoder::firstInitial, |
| 70 | + PinyinEncoder::lastInitial) | |
| 71 | + std::views::transform([](auto i) { |
| 72 | + return static_cast<PinyinInitial>(i); |
| 73 | + })) { |
| 74 | + if (initial == PinyinInitial::Zero) { |
| 75 | + continue; |
| 76 | + } |
| 77 | + for (const auto &[str, finals] : partialFinalFuzzyMap) { |
| 78 | + assert(std::ranges::all_of(finals, [&str](auto f) { |
| 79 | + const auto &finalString = PinyinEncoder::finalToString(f); |
| 80 | + return finalString.starts_with(str) && |
| 81 | + finalString.size() > str.size(); |
| 82 | + })); |
| 83 | + const auto &initialString = PinyinEncoder::initialToString(initial); |
| 84 | + const auto partialFinalString = initialString + str; |
| 85 | + bool ignore = false; |
| 86 | + for (size_t i = std::max<size_t>(initialString.size() + 1, |
| 87 | + partialFinalString.size() - 1); |
| 88 | + i <= partialFinalString.size(); i++) { |
| 89 | + if (map.contains(partialFinalString.substr(0, i))) { |
| 90 | + ignore = true; |
| 91 | + break; |
| 92 | + } |
| 93 | + } |
| 94 | + if (ignore) { |
| 95 | + continue; |
| 96 | + } |
| 97 | + for (auto final : finals) { |
| 98 | + auto pinyin = |
| 99 | + PinyinEncoder::initialFinalToPinyinString(initial, final); |
| 100 | + if (auto iter = map.find(pinyin); |
| 101 | + iter != map.end() && |
| 102 | + iter->flags() == PinyinFuzzyFlag::None) { |
| 103 | + newEntries.push_back( |
| 104 | + PinyinEntry(partialFinalString.data(), initial, final, |
| 105 | + PinyinFuzzyFlag::PartialFinal)); |
| 106 | + } |
| 107 | + } |
| 108 | + } |
| 109 | + } |
| 110 | + for (const auto &newEntry : newEntries) { |
| 111 | + FCITX_ASSERT(map.insert(newEntry).second); |
| 112 | + } |
| 113 | +} |
| 114 | + |
| 115 | +} // namespace |
| 116 | + |
24 | 117 | const std::vector<bool> &getEncodedInitialFinal() { |
25 | 118 | static const auto encodedInitialFinal = []() { |
26 | 119 | std::vector<bool> a; |
@@ -164,32 +257,46 @@ getInnerSegment() { |
164 | 257 |
|
165 | 258 | const InnerSegmentMap &getInnerSegmentV2() { |
166 | 259 | static const InnerSegmentMap innerSegment = []() { |
167 | | - InnerSegmentMap innerSegmentV2; |
168 | | - for (const auto &[key, value] : getInnerSegment()) { |
169 | | - innerSegmentV2[key].push_back(value); |
170 | | - } |
| 260 | + InnerSegmentMap innerSegmentV2Generate; |
| 261 | + const auto &pinyinMap = getPinyinMapV2(); |
| 262 | + for (const auto &entry : getPinyinMapV2()) { |
| 263 | + if (entry.pinyin().size() < 3) { |
| 264 | + continue; |
| 265 | + } |
| 266 | + if (innerSegmentV2Generate.contains(entry.pinyin())) { |
| 267 | + continue; |
| 268 | + } |
| 269 | + // We want to support 2 + 1, 2 + 2, 3 + 1, 2 + 3, 3 + 2, 3 + 3. |
| 270 | + for (size_t i = 2; i <= 3 && i < entry.pinyin().size(); i++) { |
| 271 | + if (entry.pinyin().size() <= i) { |
| 272 | + continue; |
| 273 | + } |
| 274 | + auto part1 = entry.pinyinView().substr(0, i); |
| 275 | + auto part2 = entry.pinyinView().substr(i); |
| 276 | + if (part2 == "ng") { |
| 277 | + continue; |
| 278 | + } |
| 279 | + auto range1 = pinyinMap.equal_range(part1); |
| 280 | + if (!std::any_of( |
| 281 | + range1.first, range1.second, [&](const auto &entry) { |
| 282 | + return entry.flags() == PinyinFuzzyFlag::None; |
| 283 | + })) { |
| 284 | + continue; |
| 285 | + } |
| 286 | + auto range2 = pinyinMap.equal_range(part2); |
| 287 | + if (!std::any_of( |
| 288 | + range2.first, range2.second, [&](const auto &entry) { |
| 289 | + return entry.flags() == PinyinFuzzyFlag::None; |
| 290 | + })) { |
| 291 | + continue; |
| 292 | + } |
171 | 293 |
|
172 | | - for (const auto &newItem : std::vector< |
173 | | - std::pair<std::string, std::pair<std::string, std::string>>>{ |
174 | | - {"qiao", {"qia", "o"}}, |
175 | | - {"niao", {"nia", "o"}}, |
176 | | - {"liao", {"lia", "o"}}, |
177 | | - {"zhuo", {"zhu", "o"}}, |
178 | | - {"diao", {"dia", "o"}}, |
179 | | - {"shao", {"sha", "o"}}, |
180 | | - {"xiao", {"xia", "o"}}, |
181 | | - {"zhua", {"zhu", "a"}}, |
182 | | - {"shuo", {"shu", "o"}}, |
183 | | - {"shua", {"shu", "a"}}, |
184 | | - {"zhao", {"zha", "o"}}, |
185 | | - {"jiao", {"jia", "o"}}, |
186 | | - {"chuo", {"chu", "o"}}, |
187 | | - {"chua", {"chu", "a"}}, |
188 | | - {"chao", {"cha", "o"}}, |
189 | | - }) { |
190 | | - innerSegmentV2[newItem.first].push_back(newItem.second); |
| 294 | + innerSegmentV2Generate[entry.pinyin()].push_back( |
| 295 | + {std::string(part1), std::string(part2)}); |
| 296 | + } |
191 | 297 | } |
192 | | - return innerSegmentV2; |
| 298 | + |
| 299 | + return innerSegmentV2Generate; |
193 | 300 | }(); |
194 | 301 |
|
195 | 302 | return innerSegment; |
@@ -1417,6 +1524,8 @@ const PinyinMap &getPinyinMapV2() { |
1417 | 1524 | } |
1418 | 1525 | } |
1419 | 1526 |
|
| 1527 | + applyPartialFinalFuzzy(filtered); |
| 1528 | + |
1420 | 1529 | for (auto fz : {PinyinFuzzyFlag::U_OU, PinyinFuzzyFlag::IN_ING, |
1421 | 1530 | PinyinFuzzyFlag::EN_ENG, PinyinFuzzyFlag::AN_ANG, |
1422 | 1531 | PinyinFuzzyFlag::UAN_UANG, PinyinFuzzyFlag::IAN_IANG, |
|
0 commit comments