24 #include "gnc-unicode.h" 27 #include <unicode/stsearch.h> 28 #include <unicode/tblcoll.h> 29 #include <unicode/coll.h> 30 #include "gnc-locale-utils.h" 31 #include <glib-2.0/glib.h> 33 constexpr
const char *logdomain{
"gnc.locale"};
35 enum class CompareStrength {
44 collator_set_strength(icu::Collator* collator, CompareStrength strength)
48 case CompareStrength::PRIMARY:
49 collator->setStrength(icu::Collator::PRIMARY);
51 case CompareStrength::SECONDARY:
52 collator->setStrength(icu::Collator::SECONDARY);
54 case CompareStrength::TERTIARY:
55 collator->setStrength(icu::Collator::TERTIARY);
57 case CompareStrength::QUATERNARY:
58 collator->setStrength(icu::Collator::QUATERNARY);
60 case CompareStrength::IDENTICAL:
61 collator->setStrength(icu::Collator::IDENTICAL);
67 unicode_has_substring_internal(
const char* needle,
const char* haystack,
68 int* position,
int* length,
69 CompareStrength strength)
71 UErrorCode status{U_ZERO_ERROR};
72 auto locale{gnc_locale_name()};
73 auto u_needle{icu::UnicodeString::fromUTF8(needle)};
74 auto u_haystack{icu::UnicodeString::fromUTF8(haystack)};
75 icu::StringSearch search(u_needle, u_haystack, locale,
nullptr, status);
78 if (U_SUCCESS(status))
80 auto collator = search.getCollator();
81 collator_set_strength(collator, strength);
85 if (U_FAILURE(status))
87 g_log(logdomain, G_LOG_LEVEL_ERROR,
88 "StringSearch creation failed for %s", haystack);
92 auto pos{search.first(status)};
93 if (U_FAILURE(status))
95 g_log(logdomain, G_LOG_LEVEL_ERROR,
96 "StringSearch encountered an error finding %s in %s",
100 if (pos == USEARCH_DONE)
102 g_log(logdomain, G_LOG_LEVEL_DEBUG,
"%s not found in %s",
107 if (position && length)
110 *length = search.getMatchedLength();
113 g_log(logdomain, G_LOG_LEVEL_DEBUG,
"%s found in %s at index %d",
114 needle, haystack, pos);
119 gnc_unicode_has_substring_base_chars(
const char* needle,
120 const char* haystack,
124 return unicode_has_substring_internal(needle, haystack, position, length,
125 CompareStrength::PRIMARY);
129 gnc_unicode_has_substring_accented_chars(
const char* needle,
130 const char* haystack,
134 return unicode_has_substring_internal(needle, haystack, position, length,
135 CompareStrength::SECONDARY);
139 gnc_unicode_has_substring_accented_case_sensitive(
const char* needle,
140 const char* haystack,
144 return unicode_has_substring_internal(needle, haystack, position, length,
145 CompareStrength::TERTIARY);
149 gnc_unicode_has_substring_identical(
const char* needle,
154 auto location = strstr(haystack, needle);
155 if (location && location != haystack)
157 *position =
static_cast<int>(location - haystack);
158 *length = strlen(needle);
165 unicode_compare_internal(
const char* one,
const char* two,
166 CompareStrength strength)
168 UErrorCode status{U_ZERO_ERROR};
169 auto locale{gnc_locale_name()};
170 std::unique_ptr<icu::Collator> coll(
171 icu::Collator::createInstance(icu::Locale(locale), status));
173 if (U_SUCCESS(status))
174 collator_set_strength(coll.get(), strength);
176 if (U_FAILURE(status))
178 g_log(logdomain, G_LOG_LEVEL_ERROR,
179 "Failed to create collator for locale %s: %s",
180 locale, u_errorName(status));
185 auto result = coll->compare(one, two, status);
187 if (U_FAILURE(status))
189 g_log(logdomain, G_LOG_LEVEL_ERROR,
190 "Comparison of %s and %s in locale %s failed: %s",
191 one, two, locale, u_errorName(status));
197 return result == UCOL_LESS ? -1 : result == UCOL_EQUAL ? 0 : 1;
201 gnc_unicode_compare_base_chars(
const char* one,
const char* two)
203 return unicode_compare_internal(one, two, CompareStrength::PRIMARY);
207 gnc_unicode_compare_accented_chars(
const char* one,
const char* two)
209 return unicode_compare_internal(one, two, CompareStrength::SECONDARY);
213 gnc_unicode_compare_accented_case_sensitive(
const char* one,
const char* two)
215 return unicode_compare_internal(one, two, CompareStrength::TERTIARY);
219 gnc_unicode_compare_identical(
const char* one,
const char* two)
221 return unicode_compare_internal(one, two, CompareStrength::IDENTICAL);