diff --git a/src/Handler/Utils/Exam.hs b/src/Handler/Utils/Exam.hs index 6dc50e878..e9cad7130 100644 --- a/src/Handler/Utils/Exam.hs +++ b/src/Handler/Utils/Exam.hs @@ -583,14 +583,33 @@ examAutoOccurrence (hash -> seed) rule ExamAutoOccurrenceConfig{..} occurrences specialMapping = [ExamOccurrenceMappingSpecial $ transformTag borderLength tag | tag <- specialTags] alphabetTags, specialTags :: [[CI Char]] - (alphabetTags, specialTags) = partition (all (`elem` alphabet) . take (length start)) userTags + (alphabetTags, specialTags) = partition (all (`elem` alphabet) . transformTag borderLength) userTags -- | pre/suffix of largest user tag + -- special (i.e. non-ascii) tags use the largest smaller ascii-char according to RFC5051.compareUnicode maybeEnd :: Maybe [CI Char] maybeEnd = case t of - -- TODO account for special tags - -- e.g. don't stop at T if Ù is in the special prefix set [] -> Just $ replicate borderLength $ last alphabet - _nonEmpty -> transformTag borderLength . maximum <$> fromNullable alphabetTags + _nonEmpty -> max alphabetEnd specialEnd + where + alphabetEnd :: Maybe [CI Char] + alphabetEnd = transformTag borderLength . maximum <$> fromNullable alphabetTags + specialEnd :: Maybe [CI Char] + specialEnd + = withAlphabetChars + . transformTag borderLength + . maximumBy (\a b -> RFC5051.compareUnicode (pack $ map CI.foldedCase a) (pack $ map CI.foldedCase b)) + <$> fromNullable specialTags + withAlphabetChars :: [CI Char] -> [CI Char] + withAlphabetChars [] = [] + withAlphabetChars (c:cs) + | elem c alphabet = c : withAlphabetChars cs + | otherwise= case previousAlphabetChar c of + Nothing -> [] + (Just c') -> c' : withAlphabetChars cs + previousAlphabetChar :: CI Char -> Maybe (CI Char) + previousAlphabetChar c = fmap last $ fromNullable $ nfilter ((== GT) . compareChars c) alphabet + compareChars :: CI Char -> CI Char -> Ordering + compareChars a b = RFC5051.compareUnicode (pack [CI.foldedCase a]) (pack [CI.foldedCase b]) nextStart :: NonNull [CI Char] -- end is guaranteed nonNull, all empty tags are filtered out in users' nextStart