diff --git a/resources/default_tweaks.py b/resources/default_tweaks.py index 1aa820819c..6b351ed18c 100644 --- a/resources/default_tweaks.py +++ b/resources/default_tweaks.py @@ -517,3 +517,11 @@ default_tweak_format = None # your library and your personal editing style. preselect_first_completion = False +#: Recognize numbers inside text when sorting +# This means that when sorting on text fields like title the text "Book 2" +# will sort before the text "Book 100". This is how humans usually expect +# things to sort. If you prefer the computer sort (which is a little faster, +# but will cause Book 100 to sort before Book 2), then set numeric_collation +# to False. +numeric_collation = True + diff --git a/src/calibre/utils/icu.c b/src/calibre/utils/icu.c index 3c133418b1..f1e8fce299 100644 --- a/src/calibre/utils/icu.c +++ b/src/calibre/utils/icu.c @@ -59,6 +59,7 @@ icu_Collator_new(PyTypeObject *type, PyObject *args, PyObject *kwds) PyErr_SetString(PyExc_Exception, "Failed to create collator."); return NULL; } + ucol_setAttribute(collator, UCOL_NUMERIC_COLLATION, UCOL_ON, &status); self = (icu_Collator *)type->tp_alloc(type, 0); if (self != NULL) { @@ -110,6 +111,21 @@ icu_Collator_set_strength(icu_Collator *self, PyObject *val, void *closure) { } // }}} +// Collator.numeric {{{ +static PyObject * +icu_Collator_get_numeric(icu_Collator *self, void *closure) { + UErrorCode status = U_ZERO_ERROR; + return Py_BuildValue("O", (ucol_getAttribute(self->collator, UCOL_NUMERIC_COLLATION, &status) == UCOL_ON) ? Py_True : Py_False); +} + +static int +icu_Collator_set_numeric(icu_Collator *self, PyObject *val, void *closure) { + UErrorCode status = U_ZERO_ERROR; + ucol_setAttribute(self->collator, UCOL_NUMERIC_COLLATION, (PyObject_IsTrue(val)) ? UCOL_ON : UCOL_OFF, &status); + return 0; +} +// }}} + // Collator.actual_locale {{{ static PyObject * icu_Collator_actual_locale(icu_Collator *self, void *closure) { @@ -415,6 +431,10 @@ static PyGetSetDef icu_Collator_getsetters[] = { (char *)"The strength of this collator.", NULL}, + {(char *)"numeric", + (getter)icu_Collator_get_numeric, (setter)icu_Collator_set_numeric, + (char *)"If True the collator sorts contiguous digits as numbers rather than strings, so 2 will sort before 10.", + NULL}, {NULL} /* Sentinel */ }; diff --git a/src/calibre/utils/icu.py b/src/calibre/utils/icu.py index 66ee8fd59f..aa08f293fa 100644 --- a/src/calibre/utils/icu.py +++ b/src/calibre/utils/icu.py @@ -46,6 +46,8 @@ def load_collator(): icu = load_icu() if icu is not None: _collator = icu.Collator(get_locale()) + if not tweaks['numeric_collation']: + _collator.numeric = False return _collator def primary_collator():