Skip to content

Commit 9feb266

Browse files
authored
Merge pull request #185 from taooceros/AcronymFuzzy
Add Acronym Support for Fuzzy Search
2 parents 16da1e2 + 2602cc0 commit 9feb266

File tree

11 files changed

+400
-132
lines changed

11 files changed

+400
-132
lines changed

Flow.Launcher.Infrastructure/PinyinAlphabet.cs

Lines changed: 110 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Concurrent;
3+
using System.Collections.Generic;
34
using System.Linq;
45
using System.Text;
56
using JetBrains.Annotations;
@@ -8,22 +9,117 @@
89

910
namespace Flow.Launcher.Infrastructure
1011
{
12+
public class TranslationMapping
13+
{
14+
private bool constructed;
15+
16+
private List<int> originalIndexs = new List<int>();
17+
private List<int> translatedIndexs = new List<int>();
18+
private int translaedLength = 0;
19+
20+
public string key { get; private set; }
21+
22+
public void setKey(string key)
23+
{
24+
this.key = key;
25+
}
26+
27+
public void AddNewIndex(int originalIndex, int translatedIndex, int length)
28+
{
29+
if (constructed)
30+
throw new InvalidOperationException("Mapping shouldn't be changed after constructed");
31+
32+
originalIndexs.Add(originalIndex);
33+
translatedIndexs.Add(translatedIndex);
34+
translatedIndexs.Add(translatedIndex + length);
35+
translaedLength += length - 1;
36+
}
37+
38+
public int MapToOriginalIndex(int translatedIndex)
39+
{
40+
if (translatedIndex > translatedIndexs.Last())
41+
return translatedIndex - translaedLength - 1;
42+
43+
int lowerBound = 0;
44+
int upperBound = originalIndexs.Count - 1;
45+
46+
int count = 0;
47+
48+
// Corner case handle
49+
if (translatedIndex < translatedIndexs[0])
50+
return translatedIndex;
51+
if (translatedIndex > translatedIndexs.Last())
52+
{
53+
int indexDef = 0;
54+
for (int k = 0; k < originalIndexs.Count; k++)
55+
{
56+
indexDef += translatedIndexs[k * 2 + 1] - translatedIndexs[k * 2];
57+
}
58+
59+
return translatedIndex - indexDef - 1;
60+
}
61+
62+
// Binary Search with Range
63+
for (int i = originalIndexs.Count / 2;; count++)
64+
{
65+
if (translatedIndex < translatedIndexs[i * 2])
66+
{
67+
// move to lower middle
68+
upperBound = i;
69+
i = (i + lowerBound) / 2;
70+
}
71+
else if (translatedIndex > translatedIndexs[i * 2 + 1] - 1)
72+
{
73+
lowerBound = i;
74+
// move to upper middle
75+
// due to floor of integer division, move one up on corner case
76+
i = (i + upperBound + 1) / 2;
77+
}
78+
else
79+
return originalIndexs[i];
80+
81+
if (upperBound - lowerBound <= 1 &&
82+
translatedIndex > translatedIndexs[lowerBound * 2 + 1] &&
83+
translatedIndex < translatedIndexs[upperBound * 2])
84+
{
85+
int indexDef = 0;
86+
87+
for (int j = 0; j < upperBound; j++)
88+
{
89+
indexDef += translatedIndexs[j * 2 + 1] - translatedIndexs[j * 2];
90+
}
91+
92+
return translatedIndex - indexDef - 1;
93+
}
94+
}
95+
}
96+
97+
public void endConstruct()
98+
{
99+
if (constructed)
100+
throw new InvalidOperationException("Mapping has already been constructed");
101+
constructed = true;
102+
}
103+
}
104+
11105
public interface IAlphabet
12106
{
13-
string Translate(string stringToTranslate);
107+
public (string translation, TranslationMapping map) Translate(string stringToTranslate);
14108
}
15109

16110
public class PinyinAlphabet : IAlphabet
17111
{
18-
private ConcurrentDictionary<string, string> _pinyinCache = new ConcurrentDictionary<string, string>();
112+
private ConcurrentDictionary<string, (string translation, TranslationMapping map)> _pinyinCache =
113+
new ConcurrentDictionary<string, (string translation, TranslationMapping map)>();
114+
19115
private Settings _settings;
20116

21117
public void Initialize([NotNull] Settings settings)
22118
{
23119
_settings = settings ?? throw new ArgumentNullException(nameof(settings));
24120
}
25121

26-
public string Translate(string content)
122+
public (string translation, TranslationMapping map) Translate(string content)
27123
{
28124
if (_settings.ShouldUsePinyin)
29125
{
@@ -34,21 +130,15 @@ public string Translate(string content)
34130
var resultList = WordsHelper.GetPinyinList(content);
35131

36132
StringBuilder resultBuilder = new StringBuilder();
37-
38-
for (int i = 0; i < resultList.Length; i++)
39-
{
40-
if (content[i] >= 0x3400 && content[i] <= 0x9FD5)
41-
resultBuilder.Append(resultList[i].First());
42-
}
43-
44-
resultBuilder.Append(' ');
133+
TranslationMapping map = new TranslationMapping();
45134

46135
bool pre = false;
47136

48137
for (int i = 0; i < resultList.Length; i++)
49138
{
50139
if (content[i] >= 0x3400 && content[i] <= 0x9FD5)
51140
{
141+
map.AddNewIndex(i, resultBuilder.Length, resultList[i].Length + 1);
52142
resultBuilder.Append(' ');
53143
resultBuilder.Append(resultList[i]);
54144
pre = true;
@@ -60,15 +150,21 @@ public string Translate(string content)
60150
pre = false;
61151
resultBuilder.Append(' ');
62152
}
153+
63154
resultBuilder.Append(resultList[i]);
64155
}
65156
}
66157

67-
return _pinyinCache[content] = resultBuilder.ToString();
158+
map.endConstruct();
159+
160+
var key = resultBuilder.ToString();
161+
map.setKey(key);
162+
163+
return _pinyinCache[content] = (key, map);
68164
}
69165
else
70166
{
71-
return content;
167+
return (content, null);
72168
}
73169
}
74170
else
@@ -78,7 +174,7 @@ public string Translate(string content)
78174
}
79175
else
80176
{
81-
return content;
177+
return (content, null);
82178
}
83179
}
84180
}

0 commit comments

Comments
 (0)