@@ -14,11 +14,8 @@ namespace Flow.Launcher.Infrastructure
1414{
1515 public class PinyinAlphabet : IAlphabet
1616 {
17- private ConcurrentDictionary < string , ( string translation , TranslationMapping map ) > _pinyinCache =
18- new ( ) ;
19-
17+ private readonly ConcurrentDictionary < string , ( string translation , TranslationMapping map ) > _pinyinCache = new ( ) ;
2018 private readonly Settings _settings ;
21-
2219 private ReadOnlyDictionary < string , string > currentDoublePinyinTable ;
2320
2421 public PinyinAlphabet ( )
@@ -28,10 +25,21 @@ public PinyinAlphabet()
2825
2926 _settings . PropertyChanged += ( sender , e ) =>
3027 {
31- if ( e . PropertyName == nameof ( Settings . UseDoublePinyin ) ||
32- e . PropertyName == nameof ( Settings . DoublePinyinSchema ) )
28+ switch ( e . PropertyName )
3329 {
34- Reload ( ) ;
30+ case nameof ( Settings . ShouldUsePinyin ) :
31+ if ( _settings . ShouldUsePinyin )
32+ {
33+ Reload ( ) ;
34+ }
35+ break ;
36+ case nameof ( Settings . UseDoublePinyin ) :
37+ case nameof ( Settings . DoublePinyinSchema ) :
38+ if ( _settings . UseDoublePinyin )
39+ {
40+ Reload ( ) ;
41+ }
42+ break ;
3543 }
3644 } ;
3745 }
@@ -44,105 +52,142 @@ public void Reload()
4452
4553 private void CreateDoublePinyinTableFromStream ( Stream jsonStream )
4654 {
47- Dictionary < string , Dictionary < string , string > > table = JsonSerializer . Deserialize < Dictionary < string , Dictionary < string , string > > > ( jsonStream ) ;
48- string schemaKey = _settings . DoublePinyinSchema . ToString ( ) ; // Convert enum to string
49- if ( ! table . TryGetValue ( schemaKey , out var value ) )
55+ var table = JsonSerializer . Deserialize < Dictionary < string , Dictionary < string , string > > > ( jsonStream ) ??
56+ throw new InvalidOperationException ( "Failed to deserialize double pinyin table: result is null" ) ;
57+
58+ var schemaKey = _settings . DoublePinyinSchema . ToString ( ) ;
59+ if ( ! table . TryGetValue ( schemaKey , out var schemaDict ) )
5060 {
51- throw new ArgumentException ( "DoublePinyinSchema is invalid or double pinyin table is broken." ) ;
61+ throw new ArgumentException ( $ "DoublePinyinSchema ' { schemaKey } ' is invalid or double pinyin table is broken.") ;
5262 }
53- currentDoublePinyinTable = new ReadOnlyDictionary < string , string > ( value ) ;
63+
64+ currentDoublePinyinTable = new ReadOnlyDictionary < string , string > ( schemaDict ) ;
5465 }
5566
5667 private void LoadDoublePinyinTable ( )
5768 {
58- if ( _settings . UseDoublePinyin )
69+ if ( ! _settings . UseDoublePinyin )
5970 {
60- var tablePath = Path . Join ( AppContext . BaseDirectory , "Resources" , "double_pinyin.json" ) ;
61- try
62- {
63- using var fs = File . OpenRead ( tablePath ) ;
64- CreateDoublePinyinTableFromStream ( fs ) ;
65- }
66- catch ( System . Exception e )
67- {
68- Log . Exception ( nameof ( PinyinAlphabet ) , "Failed to load double pinyin table from file: " + tablePath , e ) ;
69- currentDoublePinyinTable = new ReadOnlyDictionary < string , string > ( new Dictionary < string , string > ( ) ) ;
70- }
71+ currentDoublePinyinTable = new ReadOnlyDictionary < string , string > ( new Dictionary < string , string > ( ) ) ;
72+ return ;
73+ }
74+
75+ var tablePath = Path . Combine ( AppContext . BaseDirectory , "Resources" , "double_pinyin.json" ) ;
76+ try
77+ {
78+ using var fs = File . OpenRead ( tablePath ) ;
79+ CreateDoublePinyinTableFromStream ( fs ) ;
80+ }
81+ catch ( FileNotFoundException e )
82+ {
83+ Log . Exception ( nameof ( PinyinAlphabet ) , $ "Double pinyin table file not found: { tablePath } ", e ) ;
84+ currentDoublePinyinTable = new ReadOnlyDictionary < string , string > ( new Dictionary < string , string > ( ) ) ;
7185 }
72- else
86+ catch ( DirectoryNotFoundException e )
7387 {
88+ Log . Exception ( nameof ( PinyinAlphabet ) , $ "Directory not found for double pinyin table: { tablePath } ", e ) ;
89+ currentDoublePinyinTable = new ReadOnlyDictionary < string , string > ( new Dictionary < string , string > ( ) ) ;
90+ }
91+ catch ( UnauthorizedAccessException e )
92+ {
93+ Log . Exception ( nameof ( PinyinAlphabet ) , $ "Access denied to double pinyin table: { tablePath } ", e ) ;
94+ currentDoublePinyinTable = new ReadOnlyDictionary < string , string > ( new Dictionary < string , string > ( ) ) ;
95+ }
96+ catch ( System . Exception e )
97+ {
98+ Log . Exception ( nameof ( PinyinAlphabet ) , $ "Failed to load double pinyin table from file: { tablePath } ", e ) ;
7499 currentDoublePinyinTable = new ReadOnlyDictionary < string , string > ( new Dictionary < string , string > ( ) ) ;
75100 }
76101 }
77102
78103 public bool ShouldTranslate ( string stringToTranslate )
79104 {
80- // If a string has Chinese characters, we don't need to translate it to pinyin.
81- return _settings . ShouldUsePinyin && ! WordsHelper . HasChinese ( stringToTranslate ) ;
105+ // If the query (stringToTranslate) does NOT contain Chinese characters,
106+ // we should translate the target string to pinyin for matching
107+ return _settings . ShouldUsePinyin && ! ContainsChinese ( stringToTranslate ) ;
82108 }
83109
84110 public ( string translation , TranslationMapping map ) Translate ( string content )
85111 {
86- if ( ! _settings . ShouldUsePinyin || ! WordsHelper . HasChinese ( content ) )
112+ if ( ! _settings . ShouldUsePinyin || ! ContainsChinese ( content ) )
87113 return ( content , null ) ;
88114
89- return _pinyinCache . TryGetValue ( content , out var value )
90- ? value
91- : BuildCacheFromContent ( content ) ;
115+ return _pinyinCache . TryGetValue ( content , out var cached ) ? cached : BuildCacheFromContent ( content ) ;
92116 }
93117
94118 private ( string translation , TranslationMapping map ) BuildCacheFromContent ( string content )
95119 {
96120 var resultList = WordsHelper . GetPinyinList ( content ) ;
97-
98- var resultBuilder = new StringBuilder ( ) ;
121+ var resultBuilder = new StringBuilder ( _settings . UseDoublePinyin ? 3 : 4 ) ; // Pre-allocate with estimated capacity
99122 var map = new TranslationMapping ( ) ;
100123
101124 var previousIsChinese = false ;
102125
103126 for ( var i = 0 ; i < resultList . Length ; i ++ )
104127 {
105- if ( content [ i ] >= 0x3400 && content [ i ] <= 0x9FD5 )
128+ if ( IsChineseCharacter ( content [ i ] ) )
106129 {
107- string translated = _settings . UseDoublePinyin ? ToDoublePin ( resultList [ i ] ) : resultList [ i ] ;
130+ var translated = _settings . UseDoublePinyin ? ToDoublePinyin ( resultList [ i ] ) : resultList [ i ] ;
131+
108132 if ( i > 0 )
109133 {
110134 resultBuilder . Append ( ' ' ) ;
111135 }
136+
112137 map . AddNewIndex ( resultBuilder . Length , translated . Length ) ;
113138 resultBuilder . Append ( translated ) ;
114139 previousIsChinese = true ;
115140 }
116141 else
117142 {
143+ // Add space after Chinese characters before non-Chinese characters
118144 if ( previousIsChinese )
119145 {
120146 previousIsChinese = false ;
121147 resultBuilder . Append ( ' ' ) ;
122148 }
149+
123150 map . AddNewIndex ( resultBuilder . Length , resultList [ i ] . Length ) ;
124151 resultBuilder . Append ( resultList [ i ] ) ;
125152 }
126153 }
127154
128- map . endConstruct ( ) ;
155+ map . EndConstruct ( ) ;
129156
130- var key = resultBuilder . ToString ( ) ;
131-
132- return _pinyinCache [ content ] = ( key , map ) ;
157+ var translation = resultBuilder . ToString ( ) ;
158+ var result = ( translation , map ) ;
159+
160+ return _pinyinCache [ content ] = result ;
133161 }
134162
135- #region Double Pinyin
136-
137- private string ToDoublePin ( string fullPinyin )
163+ /// <summary>
164+ /// Optimized Chinese character detection using the comprehensive CJK Unicode ranges
165+ /// </summary>
166+ private static bool ContainsChinese ( ReadOnlySpan < char > text )
138167 {
139- if ( currentDoublePinyinTable . TryGetValue ( fullPinyin , out var doublePinyinValue ) )
168+ foreach ( var c in text )
140169 {
141- return doublePinyinValue ;
170+ if ( IsChineseCharacter ( c ) )
171+ return true ;
142172 }
143- return fullPinyin ;
173+ return false ;
144174 }
145175
146- #endregion
176+ /// <summary>
177+ /// Check if a character is a Chinese character using comprehensive Unicode ranges
178+ /// Covers CJK Unified Ideographs, Extension A
179+ /// </summary>
180+ private static bool IsChineseCharacter ( char c )
181+ {
182+ return ( c >= 0x4E00 && c <= 0x9FFF ) || // CJK Unified Ideographs
183+ ( c >= 0x3400 && c <= 0x4DBF ) ; // CJK Extension A
184+ }
185+
186+ private string ToDoublePinyin ( string fullPinyin )
187+ {
188+ return currentDoublePinyinTable . TryGetValue ( fullPinyin , out var doublePinyinValue )
189+ ? doublePinyinValue
190+ : fullPinyin ;
191+ }
147192 }
148193}
0 commit comments