diff --git a/src/calibre/utils/icu.c b/src/calibre/utils/icu.c index ec9a778b58..158e79dbc4 100644 --- a/src/calibre/utils/icu.c +++ b/src/calibre/utils/icu.c @@ -804,6 +804,40 @@ end: } // }}} +// swap_case {{{ + +static PyObject* icu_swap_case(PyObject *self, PyObject *args) { + PyObject *input = NULL, *result = NULL; + UErrorCode status = U_ZERO_ERROR; + UChar *input_buf = NULL, *output_buf = NULL; + UChar32 *buf = NULL; + int32_t sz = 0, sz32 = 0, i = 0; + + if (!PyArg_ParseTuple(args, "O", &input)) return NULL; + + input_buf = python_to_icu(input, &sz, 1); + if (input_buf == NULL) goto end; + output_buf = (UChar*) calloc(3 * sz, sizeof(UChar)); + buf = (UChar32*) calloc(2 * sz, sizeof(UChar32)); + if (output_buf == NULL || buf == NULL) { PyErr_NoMemory(); goto end; } + u_strToUTF32(buf, 2 * sz, &sz32, input_buf, sz, &status); + + for (i = 0; i < sz32; i++) { + if (u_islower(buf[i])) buf[i] = u_toupper(buf[i]); + else if (u_isupper(buf[i])) buf[i] = u_tolower(buf[i]); + } + u_strFromUTF32(output_buf, 3*sz, &sz, buf, sz32, &status); + if (U_FAILURE(status)) { PyErr_SetString(PyExc_ValueError, u_errorName(status)); goto end; } + result = icu_to_python(output_buf, sz); + +end: + if (input_buf != NULL) free(input_buf); + if (output_buf != NULL) free(output_buf); + if (buf != NULL) free(buf); + return result; + +} // }}} + // set_default_encoding {{{ static PyObject * icu_set_default_encoding(PyObject *self, PyObject *args) { @@ -1058,6 +1092,10 @@ static PyMethodDef icu_methods[] = { "change_case(unicode object, which, locale) -> change case to one of UPPER_CASE, LOWER_CASE, TITLE_CASE" }, + {"swap_case", icu_swap_case, METH_VARARGS, + "swap_case(unicode object) -> swaps the case using the simple, locale independent unicode algorithm" + }, + {"set_default_encoding", icu_set_default_encoding, METH_VARARGS, "set_default_encoding(encoding) -> Set the default encoding for the python unicode implementation." }, diff --git a/src/calibre/utils/icu.py b/src/calibre/utils/icu.py index 584ae8ad45..0001d1521a 100644 --- a/src/calibre/utils/icu.py +++ b/src/calibre/utils/icu.py @@ -212,6 +212,11 @@ def capitalize(x): except (IndexError, TypeError, AttributeError): return x +try: + swapcase = _icu.swap_case +except AttributeError: # For people running from source + swapcase = lambda x:x.swapcase() + find = _make_func(_strcmp_template, 'find', collator='_collator', collator_func='collator', func='find') primary_find = _make_func(_strcmp_template, 'primary_find', collator='_primary_collator', collator_func='primary_collator', func='find') diff --git a/src/calibre/utils/icu_test.py b/src/calibre/utils/icu_test.py index 5ddd0bc345..c35612ae5e 100644 --- a/src/calibre/utils/icu_test.py +++ b/src/calibre/utils/icu_test.py @@ -90,6 +90,7 @@ class TestICU(unittest.TestCase): # capitals inside words self.ae(icu.title_case(x), titlecase(x).replace('machIne', 'Machine')) self.ae(icu.capitalize(x), x[0].upper() + x[1:].lower()) + self.ae(icu.swapcase(x), x.swapcase()) def test_find(self): ' Test searching for substrings '