Skip to content

Commit 818aac7

Browse files
Use lookup table to translate full pinyin to double pinyin
1 parent b31a740 commit 818aac7

File tree

4 files changed

+3805
-112
lines changed

4 files changed

+3805
-112
lines changed

Flow.Launcher.Infrastructure/PinyinAlphabet.cs

Lines changed: 54 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22
using System.Collections.Concurrent;
33
using System.Collections.Generic;
44
using System.Collections.ObjectModel;
5+
using System.IO;
56
using System.Text;
7+
using System.Text.Json;
68
using CommunityToolkit.Mvvm.DependencyInjection;
79
using Flow.Launcher.Infrastructure.UserSettings;
810
using ToolGood.Words.Pinyin;
11+
using Flow.Launcher.Infrastructure.Logger;
912

1013
namespace Flow.Launcher.Infrastructure
1114
{
@@ -16,9 +19,49 @@ public class PinyinAlphabet : IAlphabet
1619

1720
private readonly Settings _settings;
1821

22+
private ReadOnlyDictionary<string, string> currentDoublePinyinTable;
23+
1924
public PinyinAlphabet()
2025
{
2126
_settings = Ioc.Default.GetRequiredService<Settings>();
27+
LoadDoublePinyinTable();
28+
29+
_settings.PropertyChanged += (sender, e) =>
30+
{
31+
if (e.PropertyName == nameof(Settings.UseDoublePinyin) ||
32+
e.PropertyName == nameof(Settings.DoublePinyinSchema))
33+
{
34+
LoadDoublePinyinTable();
35+
_pinyinCache.Clear();
36+
}
37+
};
38+
}
39+
40+
private void LoadDoublePinyinTable()
41+
{
42+
if (_settings.UseDoublePinyin)
43+
{
44+
var tablePath = Path.Join(AppContext.BaseDirectory, "Resources", "double_pinyin.json");
45+
try
46+
{
47+
using var fs = File.OpenRead(tablePath);
48+
Dictionary<string, Dictionary<string, string>> table = JsonSerializer.Deserialize<Dictionary<string, Dictionary<string, string>>>(fs);
49+
if (!table.TryGetValue(_settings.DoublePinyinSchema, out var value))
50+
{
51+
throw new InvalidOperationException("DoublePinyinSchema is invalid.");
52+
}
53+
currentDoublePinyinTable = new ReadOnlyDictionary<string, string>(value);
54+
}
55+
catch (System.Exception e)
56+
{
57+
Log.Exception(nameof(PinyinAlphabet), "Failed to load double pinyin table from file: " + tablePath, e);
58+
currentDoublePinyinTable = new ReadOnlyDictionary<string, string>(new Dictionary<string, string>());
59+
}
60+
}
61+
else
62+
{
63+
currentDoublePinyinTable = new ReadOnlyDictionary<string, string>(new Dictionary<string, string>());
64+
}
2265
}
2366

2467
public bool ShouldTranslate(string stringToTranslate)
@@ -50,26 +93,27 @@ public bool ShouldTranslate(string stringToTranslate)
5093
var resultBuilder = new StringBuilder();
5194
var map = new TranslationMapping();
5295

53-
var pre = false;
96+
var previousIsChinese = false;
5497

5598
for (var i = 0; i < resultList.Length; i++)
5699
{
57100
if (content[i] >= 0x3400 && content[i] <= 0x9FD5)
58101
{
59102
string dp = _settings.UseDoublePinyin ? ToDoublePin(resultList[i]) : resultList[i];
60103
map.AddNewIndex(i, resultBuilder.Length, dp.Length + 1);
61-
resultBuilder.Append(' ');
104+
if (previousIsChinese)
105+
{
106+
resultBuilder.Append(' ');
107+
}
62108
resultBuilder.Append(dp);
63-
pre = true;
64109
}
65110
else
66111
{
67-
if (pre)
112+
if (previousIsChinese)
68113
{
69-
pre = false;
114+
previousIsChinese = false;
70115
resultBuilder.Append(' ');
71116
}
72-
73117
resultBuilder.Append(resultList[i]);
74118
}
75119
}
@@ -83,115 +127,13 @@ public bool ShouldTranslate(string stringToTranslate)
83127

84128
#region Double Pinyin
85129

86-
private static readonly ReadOnlyDictionary<string, string> special = new(new Dictionary<string, string>(){
87-
{"A", "aa"},
88-
{"Ai", "ai"},
89-
{"An", "an"},
90-
{"Ang", "ah"},
91-
{"Ao", "ao"},
92-
{"E", "ee"},
93-
{"Ei", "ei"},
94-
{"En", "en"},
95-
{"Er", "er"},
96-
{"O", "oo"},
97-
{"Ou", "ou"}
98-
});
99-
100-
private static readonly ReadOnlyDictionary<string, string> first = new(new Dictionary<string, string>(){
101-
{"Ch", "i"},
102-
{"Sh", "u"},
103-
{"Zh", "v"}
104-
});
105-
106-
private static readonly ReadOnlyDictionary<string, string> second = new(new Dictionary<string, string>()
130+
private string ToDoublePin(string fullPinyin)
107131
{
108-
{"ua", "x"},
109-
{"ei", "w"},
110-
{"e", "e"},
111-
{"ou", "z"},
112-
{"iu", "q"},
113-
{"ve", "t"},
114-
{"ue", "t"},
115-
{"u", "u"},
116-
{"i", "i"},
117-
{"o", "o"},
118-
{"uo", "o"},
119-
{"ie", "p"},
120-
{"a", "a"},
121-
{"ong", "s"},
122-
{"iong", "s"},
123-
{"ai", "d"},
124-
{"ing", "k"},
125-
{"uai", "k"},
126-
{"ang", "h"},
127-
{"uan", "r"},
128-
{"an", "j"},
129-
{"en", "f"},
130-
{"ia", "x"},
131-
{"iang", "l"},
132-
{"uang", "l"},
133-
{"eng", "g"},
134-
{"in", "b"},
135-
{"ao", "c"},
136-
{"v", "v"},
137-
{"ui", "v"},
138-
{"un", "y"},
139-
{"iao", "n"},
140-
{"ian", "m"}
141-
});
142-
143-
private static string ToDoublePin(string fullPinyin)
144-
{
145-
// Assuming s is valid
146-
var fullPinyinSpan = fullPinyin.AsSpan();
147-
var doublePin = new StringBuilder();
148-
149-
// Handle special cases (a, o, e)
150-
if (fullPinyin.Length <= 3 && (fullPinyinSpan[0] == 'a' || fullPinyinSpan[0] == 'e' || fullPinyinSpan[0] == 'o'))
132+
if (currentDoublePinyinTable.TryGetValue(fullPinyin, out var doublePinyinValue))
151133
{
152-
if (special.TryGetValue(fullPinyin, out var value))
153-
{
154-
return value;
155-
}
156-
}
157-
158-
// Check for initials that are two characters long (zh, ch, sh)
159-
if (fullPinyin.Length >= 2)
160-
{
161-
var firstTwoString = fullPinyinSpan[..2].ToString();
162-
if (first.TryGetValue(firstTwoString, out var firstTwoDoublePin))
163-
{
164-
doublePin.Append(firstTwoDoublePin);
165-
166-
var lastTwo = fullPinyinSpan[2..];
167-
var lastTwoString = lastTwo.ToString();
168-
if (second.TryGetValue(lastTwoString, out var tmp))
169-
{
170-
doublePin.Append(tmp);
171-
}
172-
else
173-
{
174-
doublePin.Append(lastTwo); // Todo: original pinyin, remove this line if not needed
175-
}
176-
}
177-
else
178-
{
179-
// Handle single-character initials
180-
doublePin.Append(fullPinyinSpan[0]);
181-
182-
var lastOne = fullPinyinSpan[1..];
183-
var lastOneString = lastOne.ToString();
184-
if (second.TryGetValue(lastOneString, out var tmp))
185-
{
186-
doublePin.Append(tmp);
187-
}
188-
else
189-
{
190-
doublePin.Append(lastOne);
191-
}
192-
}
134+
return doublePinyinValue;
193135
}
194-
return doublePin.ToString();
136+
return fullPinyin;
195137
}
196138

197139
#endregion

Flow.Launcher.Infrastructure/UserSettings/Settings.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,8 @@ public CustomBrowserViewModel CustomBrowser
292292

293293
public bool UseDoublePinyin { get; set; } = true; //For developing
294294

295+
public string DoublePinyinSchema { get; set; } = "XiaoHe"; //For developing
296+
295297
public bool AlwaysPreview { get; set; } = false;
296298

297299
public bool AlwaysStartEn { get; set; } = false;

Flow.Launcher/Flow.Launcher.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,9 @@
127127
<None Update="Resources\dev.ico">
128128
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
129129
</None>
130+
<None Update="Resources\double_pinyin.json">
131+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
132+
</None>
130133
</ItemGroup>
131134

132135
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">

0 commit comments

Comments
 (0)