diff --git a/crowd_anki/config/config_settings.py b/crowd_anki/config/config_settings.py index 2e81190..38e105e 100644 --- a/crowd_anki/config/config_settings.py +++ b/crowd_anki/config/config_settings.py @@ -9,11 +9,16 @@ class NoteSortingMethods(Enum): FIELD1 = "field1" + FIELD1_N = "field1_numeric" FIELD2 = "field2" + FIELD_LAST = "field_last" + BROWSER_SORT_FIELD = "browser_sort_field" NO_SORTING = "none" GUID = "guid" FLAG = "flag" TAG = "tag" + TAG_N = "tag_numeric" + NOTE_ID = "note_id" NOTE_MODEL_NAME = "note_model_name" NOTE_MODEL_ID = "note_model_id" diff --git a/crowd_anki/export/note_sorter.py b/crowd_anki/export/note_sorter.py index 001f455..fd1583e 100644 --- a/crowd_anki/export/note_sorter.py +++ b/crowd_anki/export/note_sorter.py @@ -1,5 +1,6 @@ from ..config.config_settings import ConfigSettings, NoteSortingMethods +import re class NoteSorter: sorting_definitions = { @@ -11,10 +12,15 @@ class NoteSorter: NoteSortingMethods.GUID: lambda i: i.anki_object.guid, NoteSortingMethods.FLAG: lambda i: i.anki_object.flags, NoteSortingMethods.TAG: lambda i: i.anki_object.tags, + NoteSortingMethods.TAG_N: lambda i: NoteSorter.numeric_list(i.anki_object.tags), + NoteSortingMethods.NOTE_ID: lambda i: i.anki_object.id, NoteSortingMethods.NOTE_MODEL_NAME: lambda i: i.anki_object._model["name"], NoteSortingMethods.NOTE_MODEL_ID: lambda i: i.anki_object._model["crowdanki_uuid"], NoteSortingMethods.FIELD1: lambda i: i.anki_object.fields[0], - NoteSortingMethods.FIELD2: lambda i: i.anki_object.fields[1] + NoteSortingMethods.FIELD1_N: lambda i: NoteSorter.numeric_list(i.anki_object.fields[0]), + NoteSortingMethods.FIELD2: lambda i: i.anki_object.fields[1], + NoteSortingMethods.FIELD_LAST: lambda i: i.anki_object.fields[-1], + NoteSortingMethods.BROWSER_SORT_FIELD: lambda i: i.anki_object.fields[i.anki_object._model['sortf']] } def __init__(self, config: ConfigSettings): @@ -41,3 +47,30 @@ def get_sort_key(self, note): for method_name in self.sort_methods ) ) + + # premature optimisation? + numeric_list_regex = re.compile(r'^([^0-9]*)([0-9]*)(.*)$') + + @staticmethod + def numeric_list(s): + """Split string into a list of alternating strings and integers. + + The listed strings do not contain any numeric characters. The + integers are non-negative. + + For example, 'section1.42' will return ['section', 1, '.', 42]. + + This function is used to allow sorting strings containing numerals + more "naturally". + + """ + m = NoteSorter.numeric_list_regex.match(s) + (prefix, integer, suffix) = m.groups() + if integer: + l = [prefix, int(integer)] + if suffix: + return l + NoteSorter.numeric_list(suffix) + else: + return l + else: + return [prefix] diff --git a/test/export/note_sorter_spec.py b/test/export/note_sorter_spec.py index 5992e0d..e52e632 100644 --- a/test/export/note_sorter_spec.py +++ b/test/export/note_sorter_spec.py @@ -10,19 +10,29 @@ test_guids = ["abc", "bcd", "cde", "def", "efg", "fgh"] test_flags = [0, 1, 2, 3, 4, 5] -test_tags = ["adjectives", "directions", "interesting", "nouns", "verbs", "zzzzFinal"] +test_tags = ["adjectives", "directions10", "directions2", "nouns", "verbs", "zzzzFinal"] +test_tags_numeric = [["adjectives"], ["directions", 2], ["directions", 10], ["nouns"], + ["verbs"], ["zzzzFinal"]] +test_note_ids = test_flags test_notemodels = ["Default", "LL Noun", "LL Sentence", "LL Verb", "LL Word", "Zulu"] test_notemodelids = test_guids test_fields = test_tags +test_fields_numeric = test_tags_numeric +test_sortf = [0] * 6 note_sorting_single_result_pairs = [ (NoteSortingMethods.GUID, test_guids), (NoteSortingMethods.FLAG, test_flags), (NoteSortingMethods.TAG, test_tags), + (NoteSortingMethods.TAG_N, test_tags_numeric), + (NoteSortingMethods.NOTE_ID, test_note_ids), (NoteSortingMethods.NOTE_MODEL_NAME, test_notemodels), (NoteSortingMethods.NOTE_MODEL_ID, test_notemodelids), (NoteSortingMethods.FIELD1, test_fields), - (NoteSortingMethods.FIELD2, test_fields) + (NoteSortingMethods.FIELD1_N, test_fields_numeric), + (NoteSortingMethods.FIELD2, test_fields), + (NoteSortingMethods.FIELD_LAST, test_fields), + (NoteSortingMethods.BROWSER_SORT_FIELD, test_fields) ] test_multikey_notemodel_guid = [(notemodel, guid) for notemodel in test_notemodels for guid in test_guids] @@ -43,10 +53,12 @@ def get_single_note_mock(i): note.anki_object.guid = test_guids[i] note.anki_object.flags = test_flags[i] note.anki_object.tags = test_tags[i] + note.anki_object.id = test_note_ids[i] note.anki_object._model = { "name": test_notemodels[i], - "crowdanki_uuid": test_notemodelids[i] + "crowdanki_uuid": test_notemodelids[i], + "sortf": test_sortf[i] } note.anki_object.fields = [test_fields[i], test_fields[i]]