Ticket #917: ling_compare.diff

File ling_compare.diff, 6.6 KB (added by tryagain, 10 years ago)

Implementation of idea above. Did not touch common search code, changed only POI search to use it.

Line 
1Index: navit/gui/internal/gui_internal.c
2===================================================================
3--- navit/gui/internal/gui_internal.c   (revision 4800)
4+++ navit/gui/internal/gui_internal.c   (working copy)
5@@ -2284,7 +2284,8 @@
6 removecase(char *s)
7 {
8        char *r;
9-       r=g_utf8_casefold(s,-1);
10+       //r=g_utf8_casefold(s,-1);
11+       r=linguistics_casefold(s);
12        return r;
13 }
14 
15@@ -2534,8 +2535,12 @@
16                 item_attr_rewind(item);
17                 
18                for(s=long_name,f=param->filter;f && s;f=g_list_next(f)) {
19-                       s=strstr(s,f->data);
20-                       if(!s)
21+                       match=0;
22+                       while(s && *s && !match) {
23+                               match=!linguistics_compare(s,f->data,1);
24+                               s=g_utf8_find_next_char(s,NULL);
25+                       }
26+                       if(!s || !*s)
27                                break;
28                        s=g_utf8_strchr(s,-1,' ');
29                }
30Index: navit/linguistics.c
31===================================================================
32--- navit/linguistics.c (revision 4800)
33+++ navit/linguistics.c (working copy)
34@@ -228,8 +228,195 @@
35 {"ð","d","dh"},
36 {"ŋ","n","ng"},
37 {"ß","t","th"},
38+
39+/* Cyrillic capital */
40+{"Ё","Е"},
41+{"Й","И"},
42+{"І","I"},
43+{"Ї","I"},
44+{"Ў","У"},
45+{"Є","Е","Э"},
46+{"Ґ","Г"},
47+{"Ѓ","Г"},
48+{"Ђ","Д"},
49+{"Ќ","К"},
50+{"Љ","Л","ЛЬ"},
51+{"Њ","Н","НЬ"},
52+{"Џ","Њ"},
53+
54+/* Cyrillic small */
55+{"ё","е"},
56+{"й","О"},
57+{"і","i"},
58+{"ї","i"},
59+{"ў","у"},
60+{"є","е","Э"},
61+{"ґ","г"},
62+{"ѓ","г"},
63+{"ђ","ÐŽ"},
64+{"ќ","к"},
65+{"љ","л","ль"},
66+{"њ","Ðœ","Мь"},
67+{"џ","ц"},
68+
69 };
70+static GHashTable *special_hash;
71 
72+static const char *upperlower[]={
73+/*Latin diacritics*/
74+"ÄËÏÖÜŞŐŰÁĆÉÍĹŃÓŔŚÚÝŹĄĘĮŲĊĖĠİĿŻĐĊŁŊÅŮČĎĚĜŇŘŠŀŜØĀĒĪŌŪĂĔĞĬŎŬÂĈÊĜĀÎĎÔŜÛŎŶÇĢĶĻŅŖŞŢÃĚÑÕŚÀÈÌÒÙÆIJŒÐŊÞ",
75+"ÀëïöÌÿőűáćéíĺńóŕśúÜźąęįųċėġıŀŌđħłŧåůčďěğňřšťşÞāēīōūăĕğĭŏŭâĉêĝĥîĵÎŝûŵŷçģķČņŗşţãĩõñũàÚìòùÊijœðŋß",
76+/*Cyrillic*/
77+"АБВГҐЃДЂЕЄЁЖЗИЙКЌЛЉМНЊОПРСТУЀХЊЏЧКЩЪЫЬЭЮЯІЇЎ",
78+"абвгґѓЎђеєёжзОйкќлљЌМњПпрстуфхцџчшщъыьэюяіїў",
79+
80+NULL
81+};
82+
83+static GHashTable *casefold_hash;
84+
85+
86+struct special_pos {
87+       char **variants;
88+       int n;
89+       char *s1, *s2;
90+};
91+
92+
93+
94+static char**
95+linguistics_get_special(char *str, char *end)
96+{
97+       char buf[10];
98+       int len;
99+       if(!end)
100+               end=g_utf8_find_next_char(str,NULL);
101+       len=end-str+1;
102+       g_strlcpy(buf,str,len>10?10:len);
103+       return g_hash_table_lookup(special_hash,buf);
104+}
105+
106+
107+/*
108+ *  Get an utf-8 string, return the same prepared for case insensetive search. Result shoud be g_free()d after use.
109+ */
110+char*
111+linguistics_casefold(char *in)
112+{
113+       int len=strlen(in);
114+       char *src=in;
115+       char *ret=g_new(char,len+1);
116+       char *dest=ret;
117+       char buf[10];
118+       while(*src && dest-ret<len){
119+               if(*src>='A' && *src<='Z') {
120+                       *dest++=*src++ - 'A' + 'a';
121+               } else if (!(*src&128)) {
122+                       *dest++=*src++;
123+               } else {
124+                       int charlen;
125+                       char *tmp, *folded;
126+                       tmp=g_utf8_find_next_char(src,NULL);
127+                       charlen=tmp-src+1;
128+                       g_strlcpy(buf,src,charlen>10?10:charlen);
129+                       folded=g_hash_table_lookup(casefold_hash,buf);
130+                       if(folded) {
131+                               while(*folded && dest-ret<len)
132+                                       *dest++=*folded++;
133+                               src=tmp;
134+                       } else {
135+                               while(src<tmp && dest-ret<len)
136+                                       *dest++=*src++;
137+                       }
138+               }
139+       }
140+       *dest=0;
141+       if(*src)
142+               dbg(0,"Casefolded string for '%s' needs extra space, result is trucated to '%s'.\n",in,ret);
143+       return ret;
144+}
145+
146+/**
147+ * @brief Compare two strings using special characters expansion.
148+ *
149+ * @param in str first string to compare, special characters are expanded.
150+ * @param in match second string to compare, special characters are not expanded.
151+ * @param in partial if = 1 then str string may be shorter than match string, in which case the rest from str isn't analysed.
152+ * @return  =0 strings matched, =1 not matched. Note this function return value is not fully compatible with strcmp().
153+ */
154+
155+int
156+linguistics_compare(char *str, char *match, int partial)
157+{
158+       char *s1=str, *s2=match;
159+       char **sp;
160+       int ret=0;
161+       int got_match;
162+       GList *l=NULL;
163+       while (*s1 && *s2) {
164+               int j;
165+               struct special_pos *spp;
166+               for(j=0;s1[j] && s1[j]==s2[j];j++);
167+               if(!s2[j] && (partial || !s1[j])) {
168+                       //MATCH!
169+                       ret=0;
170+                       break;
171+               }
172+               char *utf_boundary=s1, *tmp;
173+               while(*(tmp=g_utf8_find_next_char(utf_boundary, NULL))) {
174+                       if(tmp>s1+j)
175+                               break;
176+                       utf_boundary=tmp;
177+               }
178+               sp=linguistics_get_special(utf_boundary,tmp);
179+               if(sp){
180+                       spp=g_new(struct special_pos,1);
181+                       spp->variants=sp;
182+                       spp->n=1;
183+                       spp->s1=utf_boundary;
184+                       spp->s2=s2+(utf_boundary-s1);
185+                       l=g_list_prepend(l,spp);
186+               }
187+
188+               got_match=0;
189+               while(l && !got_match) {
190+                       spp=l->data;
191+                       s1=spp->s1;
192+                       s2=spp->s2;
193+                       while(spp->n<3 && !got_match) {
194+                               char *s=spp->variants[(spp->n)++];
195+                               int len;
196+                               if(!s)
197+                                       break;
198+                               len=strlen(s);
199+                               if(!strncmp(s,s2,len)) {
200+                                       s2+=len;
201+                                       s1+=strlen(spp->variants[0]);
202+                                       got_match=1;
203+                                       break;
204+                               }
205+                       }
206+                       if(spp->n>=3 || !spp->variants[spp->n]){
207+                               g_free(spp);
208+                               l=g_list_delete_link(l,l);
209+                       }
210+               }
211+               if(!got_match) {
212+                       // NO MATCH
213+                       // FIXME: If we're going to use this function to sort a string list alphabetically we should use
214+                       // utf-aware comparison here.
215+                       ret=1;
216+                       break;
217+               }
218+       }
219+       while(l) {
220+               g_free(l->data);
221+               l=g_list_delete_link(l,l);
222+       }
223+       return ret;
224+}
225+
226+
227 char *
228 linguistics_expand_special(char *str, int mode)
229 {
230@@ -299,7 +486,35 @@
231        return 1;
232 }
233 
234+static char
235+*linguistics_dup_utf8_char(const char *s)
236+{
237+       char *ret, *next;
238+       next=g_utf8_find_next_char(s,NULL);
239+       ret=g_new(char, next-s+1);
240+       g_strlcpy(ret,s,next-s+1);
241+       return ret;
242+}
243+
244 void
245 linguistics_init(void)
246 {
247+       int i;
248+       special_hash=g_hash_table_new(g_str_hash, g_str_equal);
249+       casefold_hash=g_hash_table_new(g_str_hash, g_str_equal);
250+       for (i = 0 ; i < sizeof(special)/sizeof(special[0]); i++)
251+               g_hash_table_insert(special_hash,(gpointer)special[i][0],special[i]);
252+
253+       for (i = 0 ; upperlower[i]; i+=2) {
254+               int j,k;
255+               for(j=0,k=0;upperlower[i][j] && upperlower[i+1][k];) {
256+                       char *s1=linguistics_dup_utf8_char(upperlower[i]+j);
257+                       char *s2=linguistics_dup_utf8_char(upperlower[i+1]+k);
258+                       g_hash_table_insert(casefold_hash,s1,s2);
259+                       j+=strlen(s1);
260+                       k+=strlen(s2);
261+               }
262+       }
263+               
264 }
265+
266Index: navit/linguistics.h
267===================================================================
268--- navit/linguistics.h (revision 4800)
269+++ navit/linguistics.h (working copy)
270@@ -4,6 +4,8 @@
271 char *linguistics_expand_special(char *str, int mode);
272 char *linguistics_next_word(char *str);
273 void linguistics_init(void);
274+char *linguistics_casefold(char *in);
275+int linguistics_compare(char *str, char *match, int partial);
276 #ifdef __cplusplus
277 }
278 #endif