1
1
using System ;
2
2
using System . Collections . Concurrent ;
3
+ using System . Collections . Generic ;
3
4
using System . Linq ;
4
5
using System . Text ;
5
6
using JetBrains . Annotations ;
8
9
9
10
namespace Flow . Launcher . Infrastructure
10
11
{
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
+
11
105
public interface IAlphabet
12
106
{
13
- string Translate ( string stringToTranslate ) ;
107
+ public ( string translation , TranslationMapping map ) Translate ( string stringToTranslate ) ;
14
108
}
15
109
16
110
public class PinyinAlphabet : IAlphabet
17
111
{
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
+
19
115
private Settings _settings ;
20
116
21
117
public void Initialize ( [ NotNull ] Settings settings )
22
118
{
23
119
_settings = settings ?? throw new ArgumentNullException ( nameof ( settings ) ) ;
24
120
}
25
121
26
- public string Translate ( string content )
122
+ public ( string translation , TranslationMapping map ) Translate ( string content )
27
123
{
28
124
if ( _settings . ShouldUsePinyin )
29
125
{
@@ -34,21 +130,15 @@ public string Translate(string content)
34
130
var resultList = WordsHelper . GetPinyinList ( content ) ;
35
131
36
132
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 ( ) ;
45
134
46
135
bool pre = false ;
47
136
48
137
for ( int i = 0 ; i < resultList . Length ; i ++ )
49
138
{
50
139
if ( content [ i ] >= 0x3400 && content [ i ] <= 0x9FD5 )
51
140
{
141
+ map . AddNewIndex ( i , resultBuilder . Length , resultList [ i ] . Length + 1 ) ;
52
142
resultBuilder . Append ( ' ' ) ;
53
143
resultBuilder . Append ( resultList [ i ] ) ;
54
144
pre = true ;
@@ -60,15 +150,21 @@ public string Translate(string content)
60
150
pre = false ;
61
151
resultBuilder . Append ( ' ' ) ;
62
152
}
153
+
63
154
resultBuilder . Append ( resultList [ i ] ) ;
64
155
}
65
156
}
66
157
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 ) ;
68
164
}
69
165
else
70
166
{
71
- return content ;
167
+ return ( content , null ) ;
72
168
}
73
169
}
74
170
else
@@ -78,7 +174,7 @@ public string Translate(string content)
78
174
}
79
175
else
80
176
{
81
- return content ;
177
+ return ( content , null ) ;
82
178
}
83
179
}
84
180
}
0 commit comments