cdc105304557420bf446f30f4039af6112ff0fb6
[yaz-moved-to-github.git] / src / stemmer.c
1
2
3 #if HAVE_CONFIG_H
4 #include "config.h"
5 #endif
6
7 #if YAZ_HAVE_ICU
8
9 #include <yaz/yconfig.h>
10
11 #include <yaz/stemmer.h>
12
13 #include <yaz/xmalloc.h>
14
15 #include <libstemmer.h>
16
17 #include <unicode/ustring.h>  /* some more string fcns*/
18 #include <unicode/uchar.h>    /* char names           */
19
20 enum stemmer_implementation {
21     yaz_no_operation,
22     yaz_snowball
23 };
24 struct yaz_stemmer_t
25 {
26     int implementation;
27     // Required for cloning.
28     char *locale;
29     char *rule;
30     struct sb_stemmer *sb_stemmer;
31 };
32
33 const char* yaz_stemmer_lookup_charenc(const char *charenc, const char *rule) {
34     return "UTF_8";
35 }
36
37 const char* yaz_stemmer_lookup_algorithm(const char *locale, const char *rule) {
38     return locale;
39 }
40
41 yaz_stemmer_p yaz_stemmer_snowball_create(const char *locale, const char *rule, UErrorCode *status) {
42     const char *charenc = yaz_stemmer_lookup_charenc(locale, rule);
43     const char *algorithm = yaz_stemmer_lookup_algorithm(locale,rule);
44     struct sb_stemmer *stemmer = sb_stemmer_new(algorithm, charenc);
45     yaz_stemmer_p yaz_stemmer;
46     if (stemmer == 0) {
47         *status = U_ILLEGAL_ARGUMENT_ERROR;
48         yaz_log(YLOG_FATAL, "yaz_stemmer: Failed to create snowball stemmer from locale %srule %s. Showball: charenc %s algorithm %s ", 
49                 locale, rule, charenc, algorithm);
50         return 0;
51     }
52     yaz_log(YLOG_DEBUG, "created snowball stemmer: algoritm %s charenc %s ", algorithm, charenc);
53     yaz_stemmer = xmalloc(sizeof(*yaz_stemmer));
54     yaz_stemmer->implementation = yaz_snowball;
55       
56     yaz_stemmer->locale = xstrdup(locale);
57     yaz_stemmer->rule = xstrdup(rule);
58     yaz_stemmer->sb_stemmer = stemmer;
59     yaz_log(YLOG_DEBUG, "created snowball stemmer: algoritm %s charenc %s ", algorithm, charenc);
60     return yaz_stemmer;
61 }
62
63 yaz_stemmer_p yaz_stemmer_create(const char *locale, const char *rule, UErrorCode *status) {
64     *status = U_ZERO_ERROR;
65     // dispatch logic required if more algorithms is implemented.
66     yaz_log(YLOG_DEBUG, "create stemmer: locale %s rule %s ", locale, rule);
67     return yaz_stemmer_snowball_create(locale, rule, status);
68 }
69
70 yaz_stemmer_p yaz_stemmer_clone(yaz_stemmer_p stemmer) {
71     UErrorCode error = U_ZERO_ERROR;
72     if (stemmer == 0)
73       return 0;
74     return yaz_stemmer_create(stemmer->locale, stemmer->rule, &error);
75 }
76
77 void yaz_stemmer_stem(yaz_stemmer_p stemmer, struct icu_buf_utf16 *dst, struct icu_buf_utf16* src, UErrorCode *status)
78 {
79     switch(stemmer->implementation) {
80         case yaz_snowball: {
81             struct icu_buf_utf8 *utf8_buf = icu_buf_utf8_create(0);
82             icu_utf16_to_utf8(utf8_buf, src, status);
83             if (*status == U_ZERO_ERROR) {
84                 const sb_symbol *cstr = (const sb_symbol*) icu_buf_utf8_to_cstr(utf8_buf);
85                 const sb_symbol *sb_symbol = sb_stemmer_stem(stemmer->sb_stemmer, cstr, utf8_buf->utf8_len);
86                 if (sb_symbol == 0) {
87                     icu_buf_utf16_copy(dst, src);
88                 }
89                 else {
90                     const char *cstr = (const char *) sb_symbol;
91                     icu_utf16_from_utf8_cstr(dst, cstr , status);
92                 }
93             }
94             icu_buf_utf8_destroy(utf8_buf);
95             return ;
96             break;
97         }
98     case yaz_no_operation:
99       yaz_log(YLOG_DEBUG, "Stemmer (No operation) called");
100     default: {
101             // Default return the same as given.
102             icu_buf_utf16_copy(dst, src);
103         }
104     }
105 }
106
107 void yaz_stemmer_destroy(yaz_stemmer_p stemmer) 
108 {
109   /* Handle no stemmer correctly */
110   if (stemmer == 0)
111     return ;
112
113   switch (stemmer->implementation) {
114   case yaz_snowball:
115     sb_stemmer_delete(stemmer->sb_stemmer);
116     break;
117   }
118   xfree(stemmer->locale);
119   xfree(stemmer->rule);
120   xfree(stemmer);
121 }
122
123 #endif /* YAZ_HAVE_ICU */