Skip to content

Commit f735ce5

Browse files
Implement double pinyin
1 parent f2cc916 commit f735ce5

File tree

2 files changed

+195
-0
lines changed

2 files changed

+195
-0
lines changed
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
using System;
2+
using System.Collections.Concurrent;
3+
using System.Collections.Generic;
4+
using System.Collections.ObjectModel;
5+
using System.Diagnostics.CodeAnalysis;
6+
using System.Linq;
7+
using System.Text;
8+
using Flow.Launcher.Infrastructure.UserSettings;
9+
using ToolGood.Words.Pinyin;
10+
11+
namespace Flow.Launcher.Infrastructure
12+
{
13+
public class DoublePinAlphabet : IAlphabet
14+
{
15+
private ConcurrentDictionary<string, (string translation, TranslationMapping map)> _doublePinCache =
16+
new ConcurrentDictionary<string, (string translation, TranslationMapping map)>();
17+
18+
private Settings _settings;
19+
20+
public void Initialize([NotNull] Settings settings)
21+
{
22+
_settings = settings ?? throw new ArgumentNullException(nameof(settings));
23+
}
24+
25+
public bool CanBeTranslated(string stringToTranslate)
26+
{
27+
return WordsHelper.HasChinese(stringToTranslate);
28+
}
29+
30+
public (string translation, TranslationMapping map) Translate(string content)
31+
{
32+
if (_settings.ShouldUseDoublePin)
33+
{
34+
if (!_doublePinCache.ContainsKey(content))
35+
{
36+
return BuildCacheFromContent(content);
37+
}
38+
else
39+
{
40+
return _doublePinCache[content];
41+
}
42+
}
43+
return (content, null);
44+
}
45+
46+
private (string translation, TranslationMapping map) BuildCacheFromContent(string content)
47+
{
48+
if (WordsHelper.HasChinese(content))
49+
{
50+
var resultList = WordsHelper.GetPinyinList(content).Select(ToDoublePin).ToArray();
51+
StringBuilder resultBuilder = new StringBuilder();
52+
TranslationMapping map = new TranslationMapping();
53+
54+
bool pre = false;
55+
56+
for (int i = 0; i < resultList.Length; i++)
57+
{
58+
if (content[i] >= 0x3400 && content[i] <= 0x9FD5)
59+
{
60+
map.AddNewIndex(i, resultBuilder.Length, resultList[i].Length + 1);
61+
resultBuilder.Append(' ');
62+
resultBuilder.Append(resultList[i]);
63+
pre = true;
64+
}
65+
else
66+
{
67+
if (pre)
68+
{
69+
pre = false;
70+
resultBuilder.Append(' ');
71+
}
72+
73+
resultBuilder.Append(resultList[i]);
74+
}
75+
}
76+
77+
map.endConstruct();
78+
79+
var key = resultBuilder.ToString();
80+
map.setKey(key);
81+
82+
return _doublePinCache[content] = (key, map);
83+
}
84+
else
85+
{
86+
return (content, null);
87+
}
88+
}
89+
90+
private static readonly ReadOnlyDictionary<string, string> special = new(new Dictionary<string, string>(){
91+
{"a", "aa"},
92+
{"ai", "ai"},
93+
{"an", "an"},
94+
{"ang", "ah"},
95+
{"ao", "ao"},
96+
{"e", "ee"},
97+
{"ei", "ei"},
98+
{"en", "en"},
99+
{"er", "er"},
100+
{"o", "oo"},
101+
{"ou", "ou"}
102+
});
103+
104+
105+
private static readonly ReadOnlyDictionary<string, string> first = new(new Dictionary<string, string>(){
106+
{"ch", "i"},
107+
{"sh", "u"},
108+
{"zh", "v"}
109+
});
110+
111+
112+
private static readonly ReadOnlyDictionary<string, string> second = new(new Dictionary<string, string>()
113+
{
114+
{"ua", "x"},
115+
{"ei", "w"},
116+
{"e", "e"},
117+
{"ou", "z"},
118+
{"iu", "q"},
119+
{"ve", "t"},
120+
{"ue", "t"},
121+
{"u", "u"},
122+
{"i", "i"},
123+
{"o", "o"},
124+
{"uo", "o"},
125+
{"ie", "p"},
126+
{"a", "a"},
127+
{"ong", "s"},
128+
{"iong", "s"},
129+
{"ai", "d"},
130+
{"ing", "k"},
131+
{"uai", "k"},
132+
{"ang", "h"},
133+
{"uan", "r"},
134+
{"an", "j"},
135+
{"en", "f"},
136+
{"ia", "x"},
137+
{"iang", "l"},
138+
{"uang", "l"},
139+
{"eng", "g"},
140+
{"in", "b"},
141+
{"ao", "c"},
142+
{"v", "v"},
143+
{"ui", "v"},
144+
{"un", "y"},
145+
{"iao", "n"},
146+
{"ian", "m"}
147+
});
148+
149+
private static string ToDoublePin(string fullPinyin)
150+
{
151+
// Assuming s is valid
152+
StringBuilder doublePin = new StringBuilder();
153+
154+
if (fullPinyin.Length <= 3 && (fullPinyin[0] == 'a' || fullPinyin[0] == 'e' || fullPinyin[0] == 'o'))
155+
{
156+
if (special.ContainsKey(fullPinyin))
157+
{
158+
return special[fullPinyin];
159+
}
160+
}
161+
162+
// zh, ch, sh
163+
if (fullPinyin.Length >= 2 && first.ContainsKey(fullPinyin[..2]))
164+
{
165+
doublePin.Append(first[fullPinyin[..2]]);
166+
167+
if (second.TryGetValue(fullPinyin[2..], out string tmp))
168+
{
169+
doublePin.Append(tmp);
170+
}
171+
else
172+
{
173+
doublePin.Append(fullPinyin[2..]);
174+
}
175+
}
176+
else
177+
{
178+
doublePin.Append(fullPinyin[0]);
179+
180+
if (second.TryGetValue(fullPinyin[1..], out string tmp))
181+
{
182+
doublePin.Append(tmp);
183+
}
184+
else
185+
{
186+
doublePin.Append(fullPinyin[1..]);
187+
}
188+
}
189+
190+
return doublePin.ToString();
191+
}
192+
}
193+
}

Flow.Launcher.Infrastructure/UserSettings/Settings.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ public CustomBrowserViewModel CustomBrowser
159159
/// when false Alphabet static service will always return empty results
160160
/// </summary>
161161
public bool ShouldUsePinyin { get; set; } = false;
162+
163+
public bool ShouldUseDoublePin { get; set; } = false;
162164
public bool AlwaysPreview { get; set; } = false;
163165
public bool AlwaysStartEn { get; set; } = false;
164166

0 commit comments

Comments
 (0)