Sonnex 0.1.0.2 → 0.1.0.3
raw patch · 4 files changed
+214/−49 lines, 4 filesdep +QuickCheckPVP ok
version bump matches the API change (PVP)
Dependencies added: QuickCheck
API changes (from Hackage documentation)
Files
- README.md +1/−1
- Sonnex.cabal +8/−1
- src/Text/Sonnex.hs +83/−47
- test/test-sonnex.hs +122/−0
README.md view
@@ -14,7 +14,7 @@ - C ← ch - d ← d, dd - e ← e, eu-- é ← ê, é, è, ai, ei+- E ← ê, é, è, ai, ei - f ← f, ff, ph - g ← gu - i ← î, i, ille
Sonnex.cabal view
@@ -1,5 +1,5 @@ name: Sonnex-version: 0.1.0.2+version: 0.1.0.3 synopsis: Sonnex is an alternative to Soundex for french language description: @@ -29,6 +29,13 @@ hs-source-dirs: src ghc-options: -Wall default-language: Haskell2010++test-suite testMain+ build-depends: QuickCheck -any, base >=4.7 && <4.8+ type: exitcode-stdio-1.0+ main-is: test-sonnex.hs+ buildable: True+ hs-source-dirs: src test source-repository head type: git
src/Text/Sonnex.hs view
@@ -22,7 +22,7 @@ - C ← ch - d ← d, dd - e ← e, eu-- é ← ê, é, è, ai, ei+- E ← ê, é, è, ai, ei - f ← f, ff, ph - g ← gu - i ← î, i, ille@@ -92,22 +92,23 @@ -- Apostroph is ignored/silent sonx ('\'':cs) = sonx cs+sonx ('’':cs) = sonx cs -- Starting with 'a' sonx "a" = "a"-sonx "aient" = "é"+sonx "aient" = "E" sonx "ain" = "1" sonx ('a':'i':'n':v:cs)- | isVowel v = 'é':sonx (v:cs)+ | isVowel v = 'E':sonx (v:cs) | otherwise = '1':sonx (v:cs)-sonx "ais" = "é"+sonx "ais" = "E" sonx ('a':'i':'s':v:cs)- | v == 's' = 'é':'s':sonx cs- | isVowel v = 'é':'z':sonx (v:cs)- | otherwise = 'é':'s':sonx (v:cs)+ | v == 's' = 'E':'s':sonx cs+ | isVowel v = 'E':'z':sonx (v:cs)+ | otherwise = 'E':'s':sonx (v:cs) sonx "ail" = "ai" sonx ('a':'i':'l':'l':cs) = 'a':'i':sonx cs-sonx ('a':'i':cs) = 'é':sonx cs+sonx ('a':'i':cs) = 'E':sonx cs sonx ('a':'m':'m':cs) = 'a':'m':sonx cs sonx ('a':'m':c:cs) | c == 'm' = 'a':'m':sonx cs@@ -118,16 +119,19 @@ | c == 'n' = 'a':'n':sonx cs | isVowel c = 'a':'n':sonx (c:cs) | otherwise = '2':sonx (c:cs)+sonx "assent" = "as" sonx ('a':'s':c:cs) | c == 's' = 'a':'s':sonx cs | isConson c = 'a':'s':sonx (c:cs) | otherwise = 'a':'z':sonx (c:cs) sonx ('a':'u':cs) = 'o':sonx cs-sonx "ay" = "é"-sonx "ays" = "é"+sonx "ay" = "E"+sonx "ays" = "E" sonx ('à':cs) = 'a':sonx cs-sonx ('â':cs) = 'a':sonx cs+sonx ('â':c:cs)+ | c == 't' = 'a':sonx ('t':cs)+ | otherwise = 'a':sonx(c:cs) -- Starting with 'b' sonx "b" = ""@@ -168,48 +172,50 @@ -- Starting with 'e' sonx "e" = ""-sonx "ec" = "éc"-sonx "ef" = "éf"+sonx "ec" = "Ec"+sonx "ef" = "Ef" sonx "eaux" = "o" sonx ('e':'a':'n':'n':cs) = 'a':'n':sonx cs sonx ('e':'a':'n':cs) = '2':sonx cs sonx ('e':'a':'u':cs) = 'o':sonx cs-sonx ('e':'f':'f':cs) = 'é':'f':sonx cs+sonx ('e':'f':'f':cs) = 'E':'f':sonx cs+sonx ('e':'g':'m':cs) = 'E':sonx ('g':'m':cs) sonx "ein" = "1" sonx ('e':'i':'n':c:cs)- | c == 'n' = 'é':'n':sonx cs- | isVowel c = 'é':'n':sonx (c:cs)+ | c == 'n' = 'E':'n':sonx cs+ | isVowel c = 'E':'n':sonx (c:cs) | otherwise = '1':sonx (c:cs)-sonx ('e':'i':cs) = 'é':sonx cs-sonx ('e':'l':'l':cs) = 'é':'l':sonx cs+sonx ('e':'i':cs) = 'E':sonx cs+sonx ('e':'l':'l':cs) = 'E':'l':sonx cs sonx ('e':'l':c:cs)- | isConson c = 'é':sonx ('l':c:cs)+ | isConson c = 'E':sonx ('l':c:cs) | otherwise = 'e':sonx ('l':c:cs)-sonx ('e':'m':'m':cs) = 'é':'m':sonx cs+sonx ('e':'m':'m':cs) = 'E':'m':sonx cs sonx ('e':'m':'p':cs) = '2':sonx cs-sonx ('e':'n':'n':cs) = 'é':'n':sonx cs+sonx ('e':'n':'n':cs) = 'E':'n':sonx cs sonx "en" = "2" sonx ('e':'n':c:cs) | isVowel c = 'e':'n':sonx (c:cs) | otherwise = '2':sonx (c:cs)-sonx "er" = "é"-sonx "ert" = "ér"-sonx ('e':'r':'r':cs) = 'é':'r':sonx cs-sonx ('e':'r':'f':cs) = 'é':'r':sonx ('f':cs)+sonx "er" = "E"+sonx "ert" = "Er"+sonx ('e':'r':'r':cs) = 'E':'r':sonx cs+sonx ('e':'r':'f':cs) = 'E':'r':sonx ('f':cs) sonx "es" = ""-sonx ('e':'s':'c':'h':cs) = 'é':'C':sonx cs+sonx ('e':'s':'c':'h':cs) = 'E':'C':sonx cs+sonx "essent" = "Es" sonx ('e':'s':c:cs)- | c == 'h' = 'é':sonx ('h':cs)- | c == 'n' = 'é':sonx ('n':cs)- | c == 's' = 'é':'s':sonx cs- | isConson c = 'é':'s':sonx (c:cs)+ | c == 'h' = 'E':sonx ('h':cs)+ | c == 'n' = 'E':sonx ('n':cs)+ | c == 's' = 'E':'s':sonx cs+ | isConson c = 'E':'s':sonx (c:cs) | otherwise = 'e':'z':sonx (c:cs) sonx ('é':'s':c:cs)- | c == 's' = 'é':'s':sonx cs- | isConson c = 'é':'s':sonx (c:cs)- | otherwise = 'é':'z':sonx (c:cs)-sonx ('e':'t':'t':cs) = 'é':'t':sonx cs-sonx "et" = "é"+ | c == 's' = 'E':'s':sonx cs+ | isConson c = 'E':'s':sonx (c:cs)+ | otherwise = 'E':'z':sonx (c:cs)+sonx ('e':'t':'t':cs) = 'E':'t':sonx cs+sonx "et" = "E" sonx ('e':'t':cs) = 'e':'t':sonx cs sonx ('e':'u':'n':c:cs) | isVowel c = 'e':'n':sonx (c:cs)@@ -217,23 +223,30 @@ sonx "eux" = "e" sonx ('e':'u':'x':'i':cs) = 'e':'z':sonx ('i':cs) sonx ('e':'u':cs) = 'e':sonx cs-sonx "ex" = "éks"+sonx "ex" = "Eks" sonx ('e':'y':c:cs)- | isConson c = 'é':sonx (c:cs)- | otherwise = 'é':sonx ('y':c:cs)-sonx "ez" = "é"+ | isConson c = 'E':sonx (c:cs)+ | otherwise = 'E':sonx ('y':c:cs)+sonx "ez" = "E" -sonx ('è':cs) = 'é':sonx cs-sonx ('ê':cs) = 'é':sonx cs-sonx ('ë':'l':cs) = 'é':sonx ('l':cs)+sonx ('è':cs) = 'E':sonx cs+sonx ('ê':c:cs)+ | c == 't' = 'E':sonx ('t':cs)+ | otherwise = 'E':sonx(c:cs)+sonx ('ë':'l':cs) = 'E':sonx ('l':cs)+sonx "é" = "E"+sonx ('é':c:cs)+ | c == 't' = 'E':'t':sonx cs+ | otherwise = 'E':sonx(c:cs) + -- Starting with 'f' sonx ('f':'f':cs) = 'f':sonx cs -- Starting with 'g' sonx "g" = "" sonx ('g':'e':cs) = 'j':sonx ('e':cs)-sonx ('g':'é':cs) = 'j':sonx ('é':cs)+sonx ('g':'é':cs) = 'j':sonx ('E':cs) sonx ('g':'i':cs) = 'j':sonx ('i':cs) sonx ('g':'n':cs) = 'n':sonx cs sonx ('g':'y':cs) = 'j':sonx ('y':cs)@@ -247,13 +260,14 @@ -- Starting with 'i' sonx "ic" = "ik" sonx "ics" = "ik"-sonx ('i':'e':'n':'n':cs) = 'i':'é':'n':sonx cs+sonx ('i':'e':'n':'n':cs) = 'i':'E':'n':sonx cs sonx ('i':'e':'n':cs) = 'i':'1':sonx cs sonx "in" = "1" sonx ('i':'n':c:cs) | c == 'n' = 'i':'n':sonx cs | isVowel c = 'i':'n':sonx (c:cs) | otherwise = '1':sonx (c:cs)+sonx "issent" = "is" sonx ('i':'s':c:cs) | c == 's' = 'i':'s':sonx cs | isConson c = 'i':'s':sonx (c:cs)@@ -287,6 +301,7 @@ | otherwise = '3':sonx (c:cs) sonx ('o':'n':'n':cs) = 'o':'n':sonx cs sonx ('o':'n':cs) = '3':sonx cs+sonx "ossent" = "os" sonx ('o':'s':c:cs) | c == 's' = 'o':'s':sonx cs | isConson c = 'o':'s':sonx (c:cs)@@ -302,7 +317,7 @@ sonx "p" = "" sonx ('p':'h':cs) = 'f':sonx cs sonx ('p':'p':cs) = 'p':sonx cs-sonx ('p':'a':'y':'s':cs) = 'p':'é':sonx ('i':'s':cs)+sonx ('p':'a':'y':'s':cs) = 'p':'E':sonx ('i':'s':cs) -- Starting with 'q' sonx ('q':'u':'r':cs) = 'k':'u':sonx ('r':cs)@@ -315,15 +330,19 @@ -- Starting with 's' sonx "s" = "" sonx ('s':'s':cs) = 's':sonx cs+sonx ('s':'t':cs) = 's':'t':sonx cs sonx ('s':'c':'i':cs) = 's':sonx ('i':cs) -- Starting with 't' sonx "t" = ""+sonx ('t':'i':'e':'r':cs) = 't':sonx ('i':'e':'r':cs)+sonx ('t':'i':cs) = 's':sonx ('i':cs) sonx ('t':'t':cs) = 't':sonx cs -- Starting with 'u' sonx "un" = "1" sonx ('û':cs) = 'u':sonx cs+sonx "ussent" = "us" sonx ('u':'s':c:cs) | c == 's' = 'u':'s':sonx cs | isConson c = 'u':'s':sonx (c:cs)@@ -359,7 +378,24 @@ -- -- prop> length (sonnex w) <= length w sonnex :: String -> String-sonnex = sonx . (map toLower)+sonnex = sonnex' . map toLower+ where sonnex' "cerf" = "sEr"+ sonnex' "cerfs" = "sEr"+ sonnex' "de" = "de"+ sonnex' "est" = "E"+ sonnex' "es" = "E"+ sonnex' "huit" = "uit"+ sonnex' "les" = "lE"+ sonnex' "mer" = "mEr"+ sonnex' "mes" = "mE"+ sonnex' "ressent" = "res2"+ sonnex' "serf" = "sEr"+ sonnex' "serfs" = "sEr"+ sonnex' ('s':'e':'p':'t':cs) = 's':'E':'t':sonx cs+ sonnex' "ses" = "sE"+ sonnex' "tes" = "tE"+ sonnex' ('t':'i':'e':'n':cs) = 't':sonx ('i':'e':'n':cs)+ sonnex' word = sonx word -- | Compute a Sonnex code for a french phrase. --@@ -367,5 +403,5 @@ -- Since it uses the words/unwords couple, superfluous space character -- are removed. sonnexPhrase :: String -> String-sonnexPhrase phrase = unwords $ map sonnex (words phrase)+sonnexPhrase = unwords . map sonnex . words
+ test/test-sonnex.hs view
@@ -0,0 +1,122 @@+{-# LANGUAGE TemplateHaskell #-}+{-|+Module : TestSonnex+Description : Tests for HaMinitel+Copyright : (c) Frédéric BISSON, 2014+License : GPL-3+Maintainer : zigazou@free.fr+Stability : alpha+Portability : POSIX++Tests for Sonnex+-}++module Main where++import Control.Monad (unless)+import System.Exit (exitFailure)++import Test.QuickCheck+import Test.QuickCheck.All (quickCheckAll)++import Text.Sonnex++allTheSame :: (Eq a) => [a] -> Bool+allTheSame xs = all (== head xs) (tail xs)++homonymsList :: [[String]]+homonymsList =+ [ [ "amande", "amende"]+ , [ "ancre", "encre" ]+ , [ "autel", "hôtel" ]+ , [ "balade", "ballade" ]+ , [ "basilic", "basilique"]+ , [ "boulot", "bouleau" ]+ , [ "cane", "canne" ]+ , [ "censé", "sensé" ]+ , [ "compte", "comte", "conte" ]+ , [ "cygne", "signe" ]+ , [ "date", "datte" ]+ , [ "dessin", "dessein" ]+ , [ "différend", "différent"]+ , [ "du", "dû" ]+ , [ "filtre", "philtre" ]+ , [ "flan", "flanc" ]+ , [ "foi", "foie", "fois" ]+ , [ "gène", "gêne" ]+ , [ "golf", "golfe" ]+ , [ "héraut", "héro", "héros" ]+ , [ "lacer", "lasser" ]+ , [ "lire", "lyre" ]+ , [ "maire", "mer", "mère" ]+ , [ "mal","mâle", "malle" ]+ , [ "mite", "mythe" ]+ , [ "pain", "pin" ]+ , [ "palais", "palet" ]+ , [ "a", "à" ]+ , [ "au", "aux", "haut" ]+ , [ "cerf", "serf", "serre" ]+ , [ "choeur", "chœur", "cœur", "coeur" ]+ , [ "cahos", "chaos" ]+ , [ "ce", "se" ]+ , [ "ai", "es", "est", "et" ]+ , [ "cric", "crique" ]+ , [ "on", "ont" ]+ , [ "champ", "chant" ]+ , [ "ou", "où" ]+ --, [ "c'est", "s'est", "ces", "ses", "sais", "sait" ]+ , [ "col", "colle" ]+ --, [ "mes", "mais", "m'est", "mets", "met" ]+ , [ "colon", "côlon" ]+ , [ "son", "sont", "sons" ]+ --, [ "court", "cours", "courent", "cour", "courre" ]+ , [ "ta", "t'a", "tas" ]+ , [ "dans", "d'en", "dent" ]+ , [ "ma", "m'a", "m'as", "mas", "mât" ]+ , [ "mon", "m'ont", "mont" ]+ , [ "la", "l'a", "l'as", "là" ]+ , [ "au", "aux", "haut" ]+ , [ "leur", "leurs", "l'heure", "leurre" ]+ , [ "sa", "ça", "çà" ]+ --, [ "les", "l'ai", "l'es", "l'est", "laid", "lait", "laie" ]+ , [ "peu", "peut", "peux" ]+ , [ "quand", "quant", "qu'en" ]+ , [ "ni", "n'y", "nie", "nies", "nid", "nids" ]+ , [ "ton", "t'ont", "thon" ]+ , [ "sans", "s'en", "sang", "cent" ]+ , [ "tant", "temps", "tend", "tends", "t'en" ]+ , [ "sois", "soit", "soient", "soie" ]+ , [ "quelque", "quelques" ]+ , [ "mur", "mûr", "mûre", "mure" ]+ , [ "dis", "dit", "dix" ]+ --, [ "quel", "quels", "quelle", "quelles", "qu'elle", "qu'elles" ]+ , [ "tous", "tout", "toux" ]+ , [ "si", "s'y", "scie" ]+ ]++prop_homonyms = forAll (elements homonymsList) $ \homonyms ->+ allTheSame (map sonnex homonyms)++tests :: [(String, String)]+tests =+ [ ("sept", "sEt")+ , ("septième", "sEtiEm")+ , ("huit", "uit")+ , ("potion", "posi3")+ , ("constitution", "k3stitusi3")+ , ("chrétien", "krEti1")+ , ("châtier", "CatiE")+ , ("tienne", "tiEn")+ , ("manger", "m2jE")+ , ("siffler", "siflE")+ , ("passionnant", "pasion2")+ ]++prop_tests = forAll (elements tests) $ \(source, result) ->+ sonnex source == result++return []++main = do+ allPass <- $quickCheckAll+ unless allPass exitFailure