11using System ;
22using System . Collections . Concurrent ;
3+ using System . Collections . Generic ;
34using System . Linq ;
45using System . Text ;
56using JetBrains . Annotations ;
89
910namespace 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