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