duckling 0.1.6.1 → 0.2.0.0
raw patch · 1034 files changed
+87009/−33770 lines, 1034 filesdep +regex-pcre-builtindep ~aesondep ~attoparsecdep ~bytestringsetup-changednew-uploaderPVP ok
version bump matches the API change (PVP)
Dependencies added: regex-pcre-builtin
Dependency ranges changed: aeson, attoparsec, bytestring, containers, dependent-sum, extra, hashable, haskell-src-exts, regex-base, regex-pcre, snap-server, tasty, tasty-hunit, text-show, time, timezone-olson
API changes (from Hackage documentation)
This diff is very large; some files are shown as “too large to diff”. Download the raw patch for the complete diff.
Files
- CHANGELOG.md +784/−0
- Duckling/AmountOfMoney/AR/Corpus.hs +3/−2
- Duckling/AmountOfMoney/AR/Rules.hs +11/−2
- Duckling/AmountOfMoney/BG/Corpus.hs +1/−2
- Duckling/AmountOfMoney/BG/Rules.hs +1/−2
- Duckling/AmountOfMoney/EN/AU/Corpus.hs +21/−2
- Duckling/AmountOfMoney/EN/AU/Rules.hs +21/−3
- Duckling/AmountOfMoney/EN/BZ/Corpus.hs +21/−2
- Duckling/AmountOfMoney/EN/BZ/Rules.hs +21/−3
- Duckling/AmountOfMoney/EN/CA/Corpus.hs +21/−2
- Duckling/AmountOfMoney/EN/CA/Rules.hs +21/−3
- Duckling/AmountOfMoney/EN/Corpus.hs +71/−2
- Duckling/AmountOfMoney/EN/GB/Corpus.hs +20/−2
- Duckling/AmountOfMoney/EN/GB/Rules.hs +21/−3
- Duckling/AmountOfMoney/EN/IE/Corpus.hs +21/−2
- Duckling/AmountOfMoney/EN/IE/Rules.hs +21/−2
- Duckling/AmountOfMoney/EN/IN/Corpus.hs +21/−2
- Duckling/AmountOfMoney/EN/IN/Rules.hs +21/−3
- Duckling/AmountOfMoney/EN/JM/Corpus.hs +21/−3
- Duckling/AmountOfMoney/EN/JM/Rules.hs +21/−3
- Duckling/AmountOfMoney/EN/NZ/Corpus.hs +21/−2
- Duckling/AmountOfMoney/EN/NZ/Rules.hs +21/−3
- Duckling/AmountOfMoney/EN/PH/Corpus.hs +21/−2
- Duckling/AmountOfMoney/EN/PH/Rules.hs +21/−3
- Duckling/AmountOfMoney/EN/Rules.hs +87/−4
- Duckling/AmountOfMoney/EN/TT/Corpus.hs +21/−2
- Duckling/AmountOfMoney/EN/TT/Rules.hs +21/−3
- Duckling/AmountOfMoney/EN/US/Corpus.hs +21/−2
- Duckling/AmountOfMoney/EN/US/Rules.hs +21/−3
- Duckling/AmountOfMoney/EN/ZA/Corpus.hs +21/−2
- Duckling/AmountOfMoney/EN/ZA/Rules.hs +21/−3
- Duckling/AmountOfMoney/ES/Corpus.hs +15/−2
- Duckling/AmountOfMoney/ES/Rules.hs +115/−2
- Duckling/AmountOfMoney/FR/Corpus.hs +1/−2
- Duckling/AmountOfMoney/FR/Rules.hs +1/−3
- Duckling/AmountOfMoney/GA/Corpus.hs +1/−2
- Duckling/AmountOfMoney/GA/Rules.hs +1/−2
- Duckling/AmountOfMoney/HE/Corpus.hs +124/−0
- Duckling/AmountOfMoney/HE/Rules.hs +348/−0
- Duckling/AmountOfMoney/HR/Corpus.hs +40/−4
- Duckling/AmountOfMoney/HR/Rules.hs +188/−3
- Duckling/AmountOfMoney/Helpers.hs +44/−8
- Duckling/AmountOfMoney/ID/Corpus.hs +46/−3
- Duckling/AmountOfMoney/ID/Rules.hs +128/−2
- Duckling/AmountOfMoney/IT/Corpus.hs +77/−0
- Duckling/AmountOfMoney/IT/Rules.hs +270/−0
- Duckling/AmountOfMoney/KA/Corpus.hs +136/−0
- Duckling/AmountOfMoney/KA/Rules.hs +347/−0
- Duckling/AmountOfMoney/KO/Corpus.hs +35/−2
- Duckling/AmountOfMoney/KO/Rules.hs +107/−5
- Duckling/AmountOfMoney/MN/Corpus.hs +95/−0
- Duckling/AmountOfMoney/MN/Rules.hs +260/−0
- Duckling/AmountOfMoney/NB/Corpus.hs +468/−2
- Duckling/AmountOfMoney/NB/Rules.hs +199/−36
- Duckling/AmountOfMoney/NL/Corpus.hs +3/−2
- Duckling/AmountOfMoney/NL/Rules.hs +1/−2
- Duckling/AmountOfMoney/PT/Corpus.hs +1/−2
- Duckling/AmountOfMoney/PT/Rules.hs +1/−2
- Duckling/AmountOfMoney/RO/Corpus.hs +1/−2
- Duckling/AmountOfMoney/RO/Rules.hs +1/−2
- Duckling/AmountOfMoney/RU/Corpus.hs +10/−2
- Duckling/AmountOfMoney/RU/Rules.hs +11/−2
- Duckling/AmountOfMoney/Rules.hs +37/−3
- Duckling/AmountOfMoney/SV/Corpus.hs +1/−2
- Duckling/AmountOfMoney/SV/Rules.hs +1/−2
- Duckling/AmountOfMoney/TR/Corpus.hs +55/−0
- Duckling/AmountOfMoney/TR/Rules.hs +160/−0
- Duckling/AmountOfMoney/Types.hs +51/−12
- Duckling/AmountOfMoney/VI/Corpus.hs +36/−2
- Duckling/AmountOfMoney/VI/Rules.hs +171/−11
- Duckling/AmountOfMoney/ZH/Corpus.hs +21/−2
- Duckling/AmountOfMoney/ZH/Rules.hs +88/−27
- Duckling/Api.hs +5/−6
- Duckling/Core.hs +3/−3
- Duckling/CreditCardNumber/Corpus.hs +75/−0
- Duckling/CreditCardNumber/Helpers.hs +123/−0
- Duckling/CreditCardNumber/Rules.hs +72/−0
- Duckling/CreditCardNumber/Types.hs +61/−0
- Duckling/Debug.hs +7/−8
- Duckling/Dimensions.hs +53/−22
- Duckling/Dimensions/AF.hs +17/−0
- Duckling/Dimensions/AR.hs +9/−10
- Duckling/Dimensions/BG.hs +7/−7
- Duckling/Dimensions/BN.hs +17/−0
- Duckling/Dimensions/CA.hs +17/−0
- Duckling/Dimensions/CS.hs +4/−5
- Duckling/Dimensions/Common.hs +8/−8
- Duckling/Dimensions/DA.hs +6/−7
- Duckling/Dimensions/DE.hs +8/−7
- Duckling/Dimensions/EL.hs +6/−7
- Duckling/Dimensions/EN.hs +10/−11
- Duckling/Dimensions/ES.hs +10/−10
- Duckling/Dimensions/ET.hs +4/−5
- Duckling/Dimensions/FA.hs +16/−0
- Duckling/Dimensions/FI.hs +16/−0
- Duckling/Dimensions/FR.hs +10/−11
- Duckling/Dimensions/GA.hs +9/−10
- Duckling/Dimensions/HE.hs +6/−7
- Duckling/Dimensions/HI.hs +6/−6
- Duckling/Dimensions/HR.hs +10/−11
- Duckling/Dimensions/HU.hs +6/−7
- Duckling/Dimensions/ID.hs +4/−5
- Duckling/Dimensions/IS.hs +17/−0
- Duckling/Dimensions/IT.hs +9/−9
- Duckling/Dimensions/JA.hs +6/−7
- Duckling/Dimensions/KA.hs +7/−4
- Duckling/Dimensions/KM.hs +22/−0
- Duckling/Dimensions/KN.hs +17/−0
- Duckling/Dimensions/KO.hs +10/−11
- Duckling/Dimensions/LO.hs +17/−0
- Duckling/Dimensions/ML.hs +18/−0
- Duckling/Dimensions/MN.hs +23/−0
- Duckling/Dimensions/MY.hs +3/−4
- Duckling/Dimensions/NB.hs +6/−7
- Duckling/Dimensions/NE.hs +3/−4
- Duckling/Dimensions/NL.hs +9/−9
- Duckling/Dimensions/PL.hs +6/−7
- Duckling/Dimensions/PT.hs +10/−11
- Duckling/Dimensions/RO.hs +10/−11
- Duckling/Dimensions/RU.hs +9/−9
- Duckling/Dimensions/SK.hs +18/−0
- Duckling/Dimensions/SV.hs +7/−8
- Duckling/Dimensions/SW.hs +17/−0
- Duckling/Dimensions/TA.hs +4/−4
- Duckling/Dimensions/TE.hs +17/−0
- Duckling/Dimensions/TH.hs +17/−0
- Duckling/Dimensions/TR.hs +9/−9
- Duckling/Dimensions/Types.hs +18/−17
- Duckling/Dimensions/UK.hs +6/−5
- Duckling/Dimensions/VI.hs +6/−7
- Duckling/Dimensions/ZH.hs +9/−10
- Duckling/Distance/BG/Corpus.hs +1/−2
- Duckling/Distance/BG/Rules.hs +1/−2
- Duckling/Distance/CS/Corpus.hs +1/−2
- Duckling/Distance/CS/Rules.hs +1/−2
- Duckling/Distance/DE/Corpus.hs +74/−0
- Duckling/Distance/DE/Rules.hs +172/−0
- Duckling/Distance/EN/Corpus.hs +47/−2
- Duckling/Distance/EN/Rules.hs +59/−58
- Duckling/Distance/ES/Corpus.hs +1/−2
- Duckling/Distance/ES/Rules.hs +1/−2
- Duckling/Distance/FR/Corpus.hs +1/−2
- Duckling/Distance/FR/Rules.hs +1/−2
- Duckling/Distance/GA/Corpus.hs +1/−2
- Duckling/Distance/GA/Rules.hs +1/−2
- Duckling/Distance/HR/Corpus.hs +1/−2
- Duckling/Distance/HR/Rules.hs +1/−2
- Duckling/Distance/Helpers.hs +22/−3
- Duckling/Distance/IT/Corpus.hs +50/−0
- Duckling/Distance/IT/Rules.hs +81/−0
- Duckling/Distance/KM/Corpus.hs +59/−0
- Duckling/Distance/KM/Rules.hs +178/−0
- Duckling/Distance/KO/Corpus.hs +1/−2
- Duckling/Distance/KO/Rules.hs +1/−2
- Duckling/Distance/MN/Corpus.hs +57/−0
- Duckling/Distance/MN/Rules.hs +49/−0
- Duckling/Distance/NL/Corpus.hs +1/−2
- Duckling/Distance/NL/Rules.hs +1/−2
- Duckling/Distance/PT/Corpus.hs +1/−2
- Duckling/Distance/PT/Rules.hs +1/−2
- Duckling/Distance/RO/Corpus.hs +1/−2
- Duckling/Distance/RO/Rules.hs +1/−2
- Duckling/Distance/RU/Corpus.hs +1/−2
- Duckling/Distance/RU/Rules.hs +1/−2
- Duckling/Distance/Rules.hs +1/−2
- Duckling/Distance/SV/Corpus.hs +1/−2
- Duckling/Distance/SV/Rules.hs +1/−2
- Duckling/Distance/TR/Corpus.hs +1/−2
- Duckling/Distance/TR/Rules.hs +1/−2
- Duckling/Distance/Types.hs +1/−2
- Duckling/Distance/ZH/Corpus.hs +27/−2
- Duckling/Distance/ZH/Rules.hs +116/−5
- Duckling/DistanceUnits/Types.hs +190/−0
- Duckling/Duration/AR/Corpus.hs +1/−2
- Duckling/Duration/AR/Rules.hs +1/−2
- Duckling/Duration/BG/Corpus.hs +1/−2
- Duckling/Duration/BG/Rules.hs +4/−5
- Duckling/Duration/DA/Rules.hs +1/−2
- Duckling/Duration/DE/Rules.hs +172/−60
- Duckling/Duration/EL/Corpus.hs +1/−2
- Duckling/Duration/EL/Rules.hs +4/−5
- Duckling/Duration/EN/Corpus.hs +73/−2
- Duckling/Duration/EN/Rules.hs +118/−11
- Duckling/Duration/ES/Corpus.hs +58/−0
- Duckling/Duration/ES/Rules.hs +98/−0
- Duckling/Duration/FR/Corpus.hs +1/−2
- Duckling/Duration/FR/Rules.hs +1/−2
- Duckling/Duration/GA/Corpus.hs +1/−2
- Duckling/Duration/GA/Rules.hs +1/−2
- Duckling/Duration/HE/Rules.hs +1/−2
- Duckling/Duration/HI/Corpus.hs +35/−2
- Duckling/Duration/HI/Rules.hs +121/−11
- Duckling/Duration/HR/Rules.hs +1/−2
- Duckling/Duration/HU/Corpus.hs +1/−2
- Duckling/Duration/HU/Rules.hs +1/−2
- Duckling/Duration/Helpers.hs +29/−5
- Duckling/Duration/IT/Rules.hs +1/−2
- Duckling/Duration/JA/Corpus.hs +1/−2
- Duckling/Duration/KA/Corpus.hs +58/−0
- Duckling/Duration/KA/Rules.hs +155/−0
- Duckling/Duration/KO/Corpus.hs +1/−2
- Duckling/Duration/KO/Rules.hs +1/−2
- Duckling/Duration/MN/Corpus.hs +67/−0
- Duckling/Duration/MN/Rules.hs +117/−0
- Duckling/Duration/NB/Corpus.hs +1/−2
- Duckling/Duration/NB/Rules.hs +1/−2
- Duckling/Duration/NL/Corpus.hs +17/−2
- Duckling/Duration/NL/Rules.hs +49/−2
- Duckling/Duration/PL/Corpus.hs +2/−2
- Duckling/Duration/PL/Rules.hs +2/−3
- Duckling/Duration/PT/Corpus.hs +1/−2
- Duckling/Duration/RO/Corpus.hs +1/−2
- Duckling/Duration/RO/Rules.hs +1/−2
- Duckling/Duration/RU/Corpus.hs +1/−2
- Duckling/Duration/RU/Rules.hs +2/−3
- Duckling/Duration/Rules.hs +1/−2
- Duckling/Duration/SV/Corpus.hs +1/−2
- Duckling/Duration/SV/Rules.hs +1/−2
- Duckling/Duration/TR/Corpus.hs +1/−2
- Duckling/Duration/TR/Rules.hs +18/−6
- Duckling/Duration/Types.hs +1/−2
- Duckling/Duration/UK/Corpus.hs +78/−0
- Duckling/Duration/UK/Rules.hs +144/−0
- Duckling/Duration/ZH/Corpus.hs +57/−2
- Duckling/Duration/ZH/Rules.hs +301/−0
- Duckling/Email/Corpus.hs +1/−2
- Duckling/Email/DE/Corpus.hs +64/−0
- Duckling/Email/DE/Rules.hs +41/−0
- Duckling/Email/EN/Corpus.hs +1/−2
- Duckling/Email/EN/Rules.hs +1/−2
- Duckling/Email/FR/Corpus.hs +1/−2
- Duckling/Email/FR/Rules.hs +1/−2
- Duckling/Email/IS/Corpus.hs +39/−0
- Duckling/Email/IS/Rules.hs +39/−0
- Duckling/Email/IT/Corpus.hs +1/−2
- Duckling/Email/IT/Rules.hs +1/−2
- Duckling/Email/Rules.hs +1/−2
- Duckling/Email/Types.hs +5/−3
- Duckling/Engine.hs +4/−6
- Duckling/Engine/Regex.hs +1/−2
- Duckling/Locale.hs +66/−15
- Duckling/Numeral/AF/Corpus.hs +152/−0
- Duckling/Numeral/AF/Rules.hs +210/−0
- Duckling/Numeral/AR/Corpus.hs +88/−2
- Duckling/Numeral/AR/EG/Corpus.hs +257/−0
- Duckling/Numeral/AR/EG/Helpers.hs +80/−0
- Duckling/Numeral/AR/EG/Rules.hs +343/−0
- Duckling/Numeral/AR/Helpers.hs +80/−0
- Duckling/Numeral/AR/Rules.hs +64/−23
- Duckling/Numeral/BG/Corpus.hs +1/−2
- Duckling/Numeral/BG/Rules.hs +1/−2
- Duckling/Numeral/BN/Corpus.hs +101/−0
- Duckling/Numeral/BN/Rules.hs +169/−0
- Duckling/Numeral/CA/Corpus.hs +162/−0
- Duckling/Numeral/CA/Rules.hs +300/−0
- Duckling/Numeral/CS/Corpus.hs +1/−2
- Duckling/Numeral/CS/Rules.hs +1/−2
- Duckling/Numeral/DA/Corpus.hs +1/−2
- Duckling/Numeral/DA/Rules.hs +4/−3
- Duckling/Numeral/DE/Corpus.hs +5/−2
- Duckling/Numeral/DE/Rules.hs +6/−5
- Duckling/Numeral/EL/Corpus.hs +1/−2
- Duckling/Numeral/EL/Rules.hs +1/−2
- Duckling/Numeral/EN/Corpus.hs +18/−2
- Duckling/Numeral/EN/Rules.hs +26/−13
- Duckling/Numeral/ES/AR/Corpus.hs +32/−0
- Duckling/Numeral/ES/AR/Rules.hs +58/−0
- Duckling/Numeral/ES/CL/Corpus.hs +32/−0
- Duckling/Numeral/ES/CL/Rules.hs +58/−0
- Duckling/Numeral/ES/CO/Corpus.hs +32/−0
- Duckling/Numeral/ES/CO/Rules.hs +58/−0
- Duckling/Numeral/ES/Corpus.hs +48/−92
- Duckling/Numeral/ES/ES/Corpus.hs +32/−0
- Duckling/Numeral/ES/ES/Rules.hs +67/−0
- Duckling/Numeral/ES/MX/Corpus.hs +32/−0
- Duckling/Numeral/ES/MX/Rules.hs +58/−0
- Duckling/Numeral/ES/PE/Corpus.hs +32/−0
- Duckling/Numeral/ES/PE/Rules.hs +58/−0
- Duckling/Numeral/ES/Rules.hs +132/−171
- Duckling/Numeral/ES/VE/Corpus.hs +32/−0
- Duckling/Numeral/ES/VE/Rules.hs +58/−0
- Duckling/Numeral/ET/Corpus.hs +1/−2
- Duckling/Numeral/ET/Rules.hs +1/−2
- Duckling/Numeral/FA/Corpus.hs +102/−0
- Duckling/Numeral/FA/Rules.hs +254/−0
- Duckling/Numeral/FI/Corpus.hs +122/−0
- Duckling/Numeral/FI/Rules.hs +141/−0
- Duckling/Numeral/FR/Corpus.hs +8/−2
- Duckling/Numeral/FR/Rules.hs +8/−3
- Duckling/Numeral/GA/Corpus.hs +1/−2
- Duckling/Numeral/GA/Rules.hs +1/−2
- Duckling/Numeral/HE/Corpus.hs +5/−2
- Duckling/Numeral/HE/Rules.hs +11/−2
- Duckling/Numeral/HI/Corpus.hs +18/−2
- Duckling/Numeral/HI/Rules.hs +143/−52
- Duckling/Numeral/HR/Corpus.hs +1/−2
- Duckling/Numeral/HR/Rules.hs +1/−2
- Duckling/Numeral/HU/Corpus.hs +1/−2
- Duckling/Numeral/HU/Rules.hs +1/−2
- Duckling/Numeral/Helpers.hs +1/−2
- Duckling/Numeral/ID/Corpus.hs +1/−2
- Duckling/Numeral/ID/Rules.hs +1/−2
- Duckling/Numeral/IS/Corpus.hs +79/−0
- Duckling/Numeral/IS/Rules.hs +73/−0
- Duckling/Numeral/IT/Corpus.hs +10/−2
- Duckling/Numeral/IT/Rules.hs +8/−8
- Duckling/Numeral/JA/Corpus.hs +1/−2
- Duckling/Numeral/JA/Rules.hs +1/−2
- Duckling/Numeral/KA/Corpus.hs +381/−4
- Duckling/Numeral/KA/Rules.hs +366/−22
- Duckling/Numeral/KM/Corpus.hs +107/−0
- Duckling/Numeral/KM/Rules.hs +163/−0
- Duckling/Numeral/KN/Corpus.hs +67/−0
- Duckling/Numeral/KN/Rules.hs +90/−0
- Duckling/Numeral/KO/Corpus.hs +1/−2
- Duckling/Numeral/KO/Rules.hs +1/−2
- Duckling/Numeral/LO/Corpus.hs +89/−0
- Duckling/Numeral/LO/Rules.hs +153/−0
- Duckling/Numeral/ML/Corpus.hs +100/−0
- Duckling/Numeral/ML/Rules.hs +138/−0
- Duckling/Numeral/MN/Corpus.hs +104/−0
- Duckling/Numeral/MN/Rules.hs +319/−0
- Duckling/Numeral/MY/Corpus.hs +1/−2
- Duckling/Numeral/MY/Rules.hs +1/−2
- Duckling/Numeral/NB/Corpus.hs +302/−2
- Duckling/Numeral/NB/Rules.hs +161/−20
- Duckling/Numeral/NE/Corpus.hs +1/−2
- Duckling/Numeral/NE/Rules.hs +1/−2
- Duckling/Numeral/NL/Corpus.hs +14/−2
- Duckling/Numeral/NL/Rules.hs +3/−4
- Duckling/Numeral/PL/Corpus.hs +17/−2
- Duckling/Numeral/PL/Rules.hs +31/−2
- Duckling/Numeral/PT/Corpus.hs +1/−2
- Duckling/Numeral/PT/Rules.hs +1/−2
- Duckling/Numeral/RO/Corpus.hs +9/−3
- Duckling/Numeral/RO/Rules.hs +33/−20
- Duckling/Numeral/RU/Corpus.hs +24/−2
- Duckling/Numeral/RU/Rules.hs +15/−4
- Duckling/Numeral/Rules.hs +1/−2
- Duckling/Numeral/SK/Corpus.hs +110/−0
- Duckling/Numeral/SK/Rules.hs +309/−0
- Duckling/Numeral/SV/Corpus.hs +1/−2
- Duckling/Numeral/SV/Rules.hs +1/−2
- Duckling/Numeral/SW/Corpus.hs +86/−0
- Duckling/Numeral/SW/Rules.hs +104/−0
- Duckling/Numeral/TA/Corpus.hs +1/−2
- Duckling/Numeral/TA/Rules.hs +1/−2
- Duckling/Numeral/TE/Corpus.hs +123/−0
- Duckling/Numeral/TE/Rules.hs +161/−0
- Duckling/Numeral/TH/Corpus.hs +153/−0
- Duckling/Numeral/TH/Rules.hs +460/−0
- Duckling/Numeral/TR/Corpus.hs +1/−2
- Duckling/Numeral/TR/Rules.hs +5/−5
- Duckling/Numeral/Types.hs +1/−2
- Duckling/Numeral/UK/Corpus.hs +1/−2
- Duckling/Numeral/UK/Rules.hs +1/−2
- Duckling/Numeral/VI/Corpus.hs +9/−3
- Duckling/Numeral/VI/Rules.hs +5/−7
- Duckling/Numeral/ZH/Corpus.hs +60/−2
- Duckling/Numeral/ZH/Rules.hs +180/−8
- Duckling/Ordinal/AR/Corpus.hs +1/−2
- Duckling/Ordinal/AR/Rules.hs +1/−2
- Duckling/Ordinal/BG/Corpus.hs +1/−2
- Duckling/Ordinal/BG/Rules.hs +1/−2
- Duckling/Ordinal/CA/Corpus.hs +126/−0
- Duckling/Ordinal/CA/Rules.hs +104/−0
- Duckling/Ordinal/DA/Corpus.hs +22/−8
- Duckling/Ordinal/DA/Rules.hs +124/−40
- Duckling/Ordinal/DE/Corpus.hs +1/−2
- Duckling/Ordinal/DE/Rules.hs +63/−51
- Duckling/Ordinal/EL/Corpus.hs +1/−2
- Duckling/Ordinal/EL/Rules.hs +1/−2
- Duckling/Ordinal/EN/Corpus.hs +1/−2
- Duckling/Ordinal/EN/Rules.hs +1/−2
- Duckling/Ordinal/ES/Corpus.hs +6/−2
- Duckling/Ordinal/ES/Rules.hs +2/−3
- Duckling/Ordinal/ET/Corpus.hs +1/−2
- Duckling/Ordinal/ET/Rules.hs +1/−2
- Duckling/Ordinal/FR/Corpus.hs +1/−2
- Duckling/Ordinal/FR/Rules.hs +48/−49
- Duckling/Ordinal/GA/Corpus.hs +1/−2
- Duckling/Ordinal/GA/Rules.hs +1/−2
- Duckling/Ordinal/HE/Corpus.hs +1/−2
- Duckling/Ordinal/HE/Rules.hs +1/−2
- Duckling/Ordinal/HI/Corpus.hs +1/−2
- Duckling/Ordinal/HI/Rules.hs +1/−2
- Duckling/Ordinal/HR/Corpus.hs +1/−2
- Duckling/Ordinal/HR/Rules.hs +1/−2
- Duckling/Ordinal/HU/Corpus.hs +1/−2
- Duckling/Ordinal/HU/Rules.hs +1/−2
- Duckling/Ordinal/Helpers.hs +8/−9
- Duckling/Ordinal/ID/Corpus.hs +1/−2
- Duckling/Ordinal/ID/Rules.hs +1/−2
- Duckling/Ordinal/IT/Corpus.hs +1/−2
- Duckling/Ordinal/IT/Rules.hs +1/−2
- Duckling/Ordinal/JA/Corpus.hs +1/−2
- Duckling/Ordinal/JA/Rules.hs +1/−2
- Duckling/Ordinal/KA/Corpus.hs +69/−0
- Duckling/Ordinal/KA/Rules.hs +145/−0
- Duckling/Ordinal/KM/Corpus.hs +37/−0
- Duckling/Ordinal/KM/Rules.hs too large to diff
- Duckling/Ordinal/KO/Corpus.hs too large to diff
- Duckling/Ordinal/KO/Rules.hs too large to diff
- Duckling/Ordinal/ML/Corpus.hs too large to diff
- Duckling/Ordinal/ML/Rules.hs too large to diff
- Duckling/Ordinal/MN/Corpus.hs too large to diff
- Duckling/Ordinal/MN/Rules.hs too large to diff
- Duckling/Ordinal/NB/Corpus.hs too large to diff
- Duckling/Ordinal/NB/Rules.hs too large to diff
- Duckling/Ordinal/NL/Corpus.hs too large to diff
- Duckling/Ordinal/NL/Rules.hs too large to diff
- Duckling/Ordinal/PL/Corpus.hs too large to diff
- Duckling/Ordinal/PL/Rules.hs too large to diff
- Duckling/Ordinal/PT/Corpus.hs too large to diff
- Duckling/Ordinal/PT/Rules.hs too large to diff
- Duckling/Ordinal/RO/Corpus.hs too large to diff
- Duckling/Ordinal/RO/Rules.hs too large to diff
- Duckling/Ordinal/RU/Corpus.hs too large to diff
- Duckling/Ordinal/RU/Rules.hs too large to diff
- Duckling/Ordinal/SV/Corpus.hs too large to diff
- Duckling/Ordinal/SV/Rules.hs too large to diff
- Duckling/Ordinal/TA/Corpus.hs too large to diff
- Duckling/Ordinal/TA/Rules.hs too large to diff
- Duckling/Ordinal/TR/Corpus.hs too large to diff
- Duckling/Ordinal/TR/Rules.hs too large to diff
- Duckling/Ordinal/Types.hs too large to diff
- Duckling/Ordinal/UK/Corpus.hs too large to diff
- Duckling/Ordinal/UK/Rules.hs too large to diff
- Duckling/Ordinal/VI/Corpus.hs too large to diff
- Duckling/Ordinal/VI/Rules.hs too large to diff
- Duckling/Ordinal/ZH/Corpus.hs too large to diff
- Duckling/Ordinal/ZH/Rules.hs too large to diff
- Duckling/PhoneNumber/AR/Corpus.hs too large to diff
- Duckling/PhoneNumber/AR/Rules.hs too large to diff
- Duckling/PhoneNumber/Corpus.hs too large to diff
- Duckling/PhoneNumber/PT/Corpus.hs too large to diff
- Duckling/PhoneNumber/PT/Rules.hs too large to diff
- Duckling/PhoneNumber/Rules.hs too large to diff
- Duckling/PhoneNumber/Types.hs too large to diff
- Duckling/Quantity/AR/Corpus.hs too large to diff
- Duckling/Quantity/AR/Rules.hs too large to diff
- Duckling/Quantity/EN/Corpus.hs too large to diff
- Duckling/Quantity/EN/Rules.hs too large to diff
- Duckling/Quantity/ES/Corpus.hs too large to diff
- Duckling/Quantity/ES/Rules.hs too large to diff
- Duckling/Quantity/FR/Corpus.hs too large to diff
- Duckling/Quantity/FR/Rules.hs too large to diff
- Duckling/Quantity/HR/Corpus.hs too large to diff
- Duckling/Quantity/HR/Rules.hs too large to diff
- Duckling/Quantity/Helpers.hs too large to diff
- Duckling/Quantity/KM/Corpus.hs too large to diff
- Duckling/Quantity/KM/Rules.hs too large to diff
- Duckling/Quantity/KO/Corpus.hs too large to diff
- Duckling/Quantity/KO/Rules.hs too large to diff
- Duckling/Quantity/MN/Corpus.hs too large to diff
- Duckling/Quantity/MN/Rules.hs too large to diff
- Duckling/Quantity/NL/Corpus.hs too large to diff
- Duckling/Quantity/NL/Rules.hs too large to diff
- Duckling/Quantity/PT/Corpus.hs too large to diff
- Duckling/Quantity/PT/Rules.hs too large to diff
- Duckling/Quantity/RO/Corpus.hs too large to diff
- Duckling/Quantity/RO/Rules.hs too large to diff
- Duckling/Quantity/RU/Corpus.hs too large to diff
- Duckling/Quantity/RU/Rules.hs too large to diff
- Duckling/Quantity/Types.hs too large to diff
- Duckling/Quantity/ZH/Corpus.hs too large to diff
- Duckling/Quantity/ZH/Rules.hs too large to diff
- Duckling/Ranking/Classifiers.hs too large to diff
- Duckling/Ranking/Classifiers/AF_XX.hs too large to diff
- Duckling/Ranking/Classifiers/AR_EG.hs too large to diff
- Duckling/Ranking/Classifiers/AR_XX.hs too large to diff
- Duckling/Ranking/Classifiers/BG_XX.hs too large to diff
- Duckling/Ranking/Classifiers/BN_XX.hs too large to diff
- Duckling/Ranking/Classifiers/CA_XX.hs too large to diff
- Duckling/Ranking/Classifiers/DA_XX.hs too large to diff
- Duckling/Ranking/Classifiers/DE_XX.hs too large to diff
- Duckling/Ranking/Classifiers/EL_XX.hs too large to diff
- Duckling/Ranking/Classifiers/EN_CA.hs too large to diff
- Duckling/Ranking/Classifiers/EN_GB.hs too large to diff
- Duckling/Ranking/Classifiers/EN_US.hs too large to diff
- Duckling/Ranking/Classifiers/EN_XX.hs too large to diff
- Duckling/Ranking/Classifiers/ES_XX.hs too large to diff
- Duckling/Ranking/Classifiers/FA_XX.hs too large to diff
- Duckling/Ranking/Classifiers/FI_XX.hs too large to diff
- Duckling/Ranking/Classifiers/FR_XX.hs too large to diff
- Duckling/Ranking/Classifiers/HE_XX.hs too large to diff
- Duckling/Ranking/Classifiers/HR_XX.hs too large to diff
- Duckling/Ranking/Classifiers/IS_XX.hs too large to diff
- Duckling/Ranking/Classifiers/IT_XX.hs too large to diff
- Duckling/Ranking/Classifiers/KM_XX.hs too large to diff
- Duckling/Ranking/Classifiers/KN_XX.hs too large to diff
- Duckling/Ranking/Classifiers/KO_XX.hs too large to diff
- Duckling/Ranking/Classifiers/LO_XX.hs too large to diff
- Duckling/Ranking/Classifiers/ML_XX.hs too large to diff
- Duckling/Ranking/Classifiers/MN_XX.hs too large to diff
- Duckling/Ranking/Classifiers/NB_XX.hs too large to diff
- Duckling/Ranking/Classifiers/NL_BE.hs too large to diff
- Duckling/Ranking/Classifiers/NL_NL.hs too large to diff
- Duckling/Ranking/Classifiers/NL_XX.hs too large to diff
- Duckling/Ranking/Classifiers/PL_XX.hs too large to diff
- Duckling/Ranking/Classifiers/PT_XX.hs too large to diff
- Duckling/Ranking/Classifiers/RO_XX.hs too large to diff
- Duckling/Ranking/Classifiers/RU_XX.hs too large to diff
- Duckling/Ranking/Classifiers/SK_XX.hs too large to diff
- Duckling/Ranking/Classifiers/SV_XX.hs too large to diff
- Duckling/Ranking/Classifiers/SW_XX.hs too large to diff
- Duckling/Ranking/Classifiers/TE_XX.hs too large to diff
- Duckling/Ranking/Classifiers/TH_XX.hs too large to diff
- Duckling/Ranking/Classifiers/TR_XX.hs too large to diff
- Duckling/Ranking/Classifiers/UK_XX.hs too large to diff
- Duckling/Ranking/Classifiers/VI_XX.hs too large to diff
- Duckling/Ranking/Classifiers/ZH_CN.hs too large to diff
- Duckling/Ranking/Classifiers/ZH_HK.hs too large to diff
- Duckling/Ranking/Classifiers/ZH_MO.hs too large to diff
- Duckling/Ranking/Classifiers/ZH_TW.hs too large to diff
- Duckling/Ranking/Classifiers/ZH_XX.hs too large to diff
- Duckling/Ranking/Extraction.hs too large to diff
- Duckling/Ranking/Rank.hs too large to diff
- Duckling/Ranking/Types.hs too large to diff
- Duckling/Regex/Types.hs too large to diff
- Duckling/Region.hs too large to diff
- Duckling/Resolve.hs too large to diff
- Duckling/Rules.hs too large to diff
- Duckling/Rules/AF.hs too large to diff
- Duckling/Rules/AR.hs too large to diff
- Duckling/Rules/BG.hs too large to diff
- Duckling/Rules/BN.hs too large to diff
- Duckling/Rules/CA.hs too large to diff
- Duckling/Rules/CS.hs too large to diff
- Duckling/Rules/Common.hs too large to diff
- Duckling/Rules/DA.hs too large to diff
- Duckling/Rules/DE.hs too large to diff
- Duckling/Rules/EL.hs too large to diff
- Duckling/Rules/EN.hs too large to diff
- Duckling/Rules/ES.hs too large to diff
- Duckling/Rules/ET.hs too large to diff
- Duckling/Rules/FA.hs too large to diff
- Duckling/Rules/FI.hs too large to diff
- Duckling/Rules/FR.hs too large to diff
- Duckling/Rules/GA.hs too large to diff
- Duckling/Rules/HE.hs too large to diff
- Duckling/Rules/HI.hs too large to diff
- Duckling/Rules/HR.hs too large to diff
- Duckling/Rules/HU.hs too large to diff
- Duckling/Rules/ID.hs too large to diff
- Duckling/Rules/IS.hs too large to diff
- Duckling/Rules/IT.hs too large to diff
- Duckling/Rules/JA.hs too large to diff
- Duckling/Rules/KA.hs too large to diff
- Duckling/Rules/KM.hs too large to diff
- Duckling/Rules/KN.hs too large to diff
- Duckling/Rules/KO.hs too large to diff
- Duckling/Rules/LO.hs too large to diff
- Duckling/Rules/ML.hs too large to diff
- Duckling/Rules/MN.hs too large to diff
- Duckling/Rules/MY.hs too large to diff
- Duckling/Rules/NB.hs too large to diff
- Duckling/Rules/NE.hs too large to diff
- Duckling/Rules/NL.hs too large to diff
- Duckling/Rules/PL.hs too large to diff
- Duckling/Rules/PT.hs too large to diff
- Duckling/Rules/RO.hs too large to diff
- Duckling/Rules/RU.hs too large to diff
- Duckling/Rules/SK.hs too large to diff
- Duckling/Rules/SV.hs too large to diff
- Duckling/Rules/SW.hs too large to diff
- Duckling/Rules/TA.hs too large to diff
- Duckling/Rules/TE.hs too large to diff
- Duckling/Rules/TH.hs too large to diff
- Duckling/Rules/TR.hs too large to diff
- Duckling/Rules/UK.hs too large to diff
- Duckling/Rules/VI.hs too large to diff
- Duckling/Rules/ZH.hs too large to diff
- Duckling/Temperature/AR/Corpus.hs too large to diff
- Duckling/Temperature/AR/Rules.hs too large to diff
- Duckling/Temperature/EN/Corpus.hs too large to diff
- Duckling/Temperature/EN/Rules.hs too large to diff
- Duckling/Temperature/ES/Corpus.hs too large to diff
- Duckling/Temperature/ES/Rules.hs too large to diff
- Duckling/Temperature/FR/Corpus.hs too large to diff
- Duckling/Temperature/FR/Rules.hs too large to diff
- Duckling/Temperature/GA/Corpus.hs too large to diff
- Duckling/Temperature/GA/Rules.hs too large to diff
- Duckling/Temperature/HI/Corpus.hs too large to diff
- Duckling/Temperature/HI/Rules.hs too large to diff
- Duckling/Temperature/HR/Corpus.hs too large to diff
- Duckling/Temperature/HR/Rules.hs too large to diff
- Duckling/Temperature/Helpers.hs too large to diff
- Duckling/Temperature/IT/Corpus.hs too large to diff
- Duckling/Temperature/IT/Rules.hs too large to diff
- Duckling/Temperature/JA/Corpus.hs too large to diff
- Duckling/Temperature/JA/Rules.hs too large to diff
- Duckling/Temperature/KM/Corpus.hs too large to diff
- Duckling/Temperature/KM/Rules.hs too large to diff
- Duckling/Temperature/KO/Corpus.hs too large to diff
- Duckling/Temperature/KO/Rules.hs too large to diff
- Duckling/Temperature/MN/Corpus.hs too large to diff
- Duckling/Temperature/MN/Rules.hs too large to diff
- Duckling/Temperature/PT/Corpus.hs too large to diff
- Duckling/Temperature/PT/Rules.hs too large to diff
- Duckling/Temperature/RO/Corpus.hs too large to diff
- Duckling/Temperature/RO/Rules.hs too large to diff
- Duckling/Temperature/Rules.hs too large to diff
- Duckling/Temperature/TR/Corpus.hs too large to diff
- Duckling/Temperature/TR/Rules.hs too large to diff
- Duckling/Temperature/Types.hs too large to diff
- Duckling/Temperature/ZH/Corpus.hs too large to diff
- Duckling/Temperature/ZH/Rules.hs too large to diff
- Duckling/Testing/Types.hs too large to diff
- Duckling/Time/AR/Corpus.hs too large to diff
- Duckling/Time/AR/Rules.hs too large to diff
- Duckling/Time/BG/Corpus.hs too large to diff
- Duckling/Time/BG/Rules.hs too large to diff
- Duckling/Time/Computed.hs too large to diff
- Duckling/Time/Corpus.hs too large to diff
- Duckling/Time/DA/Corpus.hs too large to diff
- Duckling/Time/DA/Rules.hs too large to diff
- Duckling/Time/DE/Corpus.hs too large to diff
- Duckling/Time/DE/Rules.hs too large to diff
- Duckling/Time/EL/Corpus.hs too large to diff
- Duckling/Time/EL/Rules.hs too large to diff
- Duckling/Time/EN/AU/Corpus.hs too large to diff
- Duckling/Time/EN/AU/Rules.hs too large to diff
- Duckling/Time/EN/BZ/Corpus.hs too large to diff
- Duckling/Time/EN/BZ/Rules.hs too large to diff
- Duckling/Time/EN/CA/Corpus.hs too large to diff
- Duckling/Time/EN/CA/Rules.hs too large to diff
- Duckling/Time/EN/Corpus.hs too large to diff
- Duckling/Time/EN/GB/Corpus.hs too large to diff
- Duckling/Time/EN/GB/Rules.hs too large to diff
- Duckling/Time/EN/IE/Corpus.hs too large to diff
- Duckling/Time/EN/IE/Rules.hs too large to diff
- Duckling/Time/EN/IN/Corpus.hs too large to diff
- Duckling/Time/EN/IN/Rules.hs too large to diff
- Duckling/Time/EN/JM/Corpus.hs too large to diff
- Duckling/Time/EN/JM/Rules.hs too large to diff
- Duckling/Time/EN/NZ/Corpus.hs too large to diff
- Duckling/Time/EN/NZ/Rules.hs too large to diff
- Duckling/Time/EN/PH/Corpus.hs too large to diff
- Duckling/Time/EN/PH/Rules.hs too large to diff
- Duckling/Time/EN/Rules.hs too large to diff
- Duckling/Time/EN/TT/Corpus.hs too large to diff
- Duckling/Time/EN/TT/Rules.hs too large to diff
- Duckling/Time/EN/US/Corpus.hs too large to diff
- Duckling/Time/EN/US/Rules.hs too large to diff
- Duckling/Time/EN/ZA/Corpus.hs too large to diff
- Duckling/Time/EN/ZA/Rules.hs too large to diff
- Duckling/Time/ES/Corpus.hs too large to diff
- Duckling/Time/ES/Rules.hs too large to diff
- Duckling/Time/FR/Corpus.hs too large to diff
- Duckling/Time/FR/Rules.hs too large to diff
- Duckling/Time/GA/Corpus.hs too large to diff
- Duckling/Time/GA/Rules.hs too large to diff
- Duckling/Time/HE/Corpus.hs too large to diff
- Duckling/Time/HE/Rules.hs too large to diff
- Duckling/Time/HR/Corpus.hs too large to diff
- Duckling/Time/HR/Rules.hs too large to diff
- Duckling/Time/HU/Corpus.hs too large to diff
- Duckling/Time/HU/Rules.hs too large to diff
- Duckling/Time/Helpers.hs too large to diff
- Duckling/Time/HolidayHelpers.hs too large to diff
- Duckling/Time/IT/Corpus.hs too large to diff
- Duckling/Time/IT/Rules.hs too large to diff
- Duckling/Time/KA/Corpus.hs too large to diff
- Duckling/Time/KA/Rules.hs too large to diff
- Duckling/Time/KO/Corpus.hs too large to diff
- Duckling/Time/KO/Rules.hs too large to diff
- Duckling/Time/NB/Corpus.hs too large to diff
- Duckling/Time/NB/Rules.hs too large to diff
- Duckling/Time/NL/BE/Corpus.hs too large to diff
- Duckling/Time/NL/BE/Rules.hs too large to diff
- Duckling/Time/NL/Corpus.hs too large to diff
- Duckling/Time/NL/NL/Rules.hs too large to diff
- Duckling/Time/NL/Rules.hs too large to diff
- Duckling/Time/PL/Corpus.hs too large to diff
- Duckling/Time/PL/Rules.hs too large to diff
- Duckling/Time/PT/Corpus.hs too large to diff
- Duckling/Time/PT/Rules.hs too large to diff
- Duckling/Time/RO/Corpus.hs too large to diff
- Duckling/Time/RO/Rules.hs too large to diff
- Duckling/Time/RU/Corpus.hs too large to diff
- Duckling/Time/RU/Rules.hs too large to diff
- Duckling/Time/SV/Corpus.hs too large to diff
- Duckling/Time/SV/Rules.hs too large to diff
- Duckling/Time/TR/Corpus.hs too large to diff
- Duckling/Time/TR/Rules.hs too large to diff
- Duckling/Time/TimeZone/Parse.hs too large to diff
- Duckling/Time/Types.hs too large to diff
- Duckling/Time/UK/Corpus.hs too large to diff
- Duckling/Time/UK/Rules.hs too large to diff
- Duckling/Time/VI/Corpus.hs too large to diff
- Duckling/Time/VI/Rules.hs too large to diff
- Duckling/Time/ZH/CN/Corpus.hs too large to diff
- Duckling/Time/ZH/CN/Rules.hs too large to diff
- Duckling/Time/ZH/Corpus.hs too large to diff
- Duckling/Time/ZH/HK/Corpus.hs too large to diff
- Duckling/Time/ZH/HK/Rules.hs too large to diff
- Duckling/Time/ZH/MO/Corpus.hs too large to diff
- Duckling/Time/ZH/MO/Rules.hs too large to diff
- Duckling/Time/ZH/Rules.hs too large to diff
- Duckling/Time/ZH/TW/Corpus.hs too large to diff
- Duckling/Time/ZH/TW/Rules.hs too large to diff
- Duckling/TimeGrain/AR/Rules.hs too large to diff
- Duckling/TimeGrain/BG/Rules.hs too large to diff
- Duckling/TimeGrain/DA/Rules.hs too large to diff
- Duckling/TimeGrain/DE/Rules.hs too large to diff
- Duckling/TimeGrain/EL/Rules.hs too large to diff
- Duckling/TimeGrain/EN/Rules.hs too large to diff
- Duckling/TimeGrain/ES/Rules.hs too large to diff
- Duckling/TimeGrain/FI/Rules.hs too large to diff
- Duckling/TimeGrain/FR/Rules.hs too large to diff
- Duckling/TimeGrain/GA/Rules.hs too large to diff
- Duckling/TimeGrain/HE/Rules.hs too large to diff
- Duckling/TimeGrain/HI/Rules.hs too large to diff
- Duckling/TimeGrain/HR/Rules.hs too large to diff
- Duckling/TimeGrain/HU/Rules.hs too large to diff
- Duckling/TimeGrain/IT/Rules.hs too large to diff
- Duckling/TimeGrain/JA/Rules.hs too large to diff
- Duckling/TimeGrain/KA/Rules.hs too large to diff
- Duckling/TimeGrain/KO/Rules.hs too large to diff
- Duckling/TimeGrain/MN/Rules.hs too large to diff
- Duckling/TimeGrain/NB/Rules.hs too large to diff
- Duckling/TimeGrain/NL/Rules.hs too large to diff
- Duckling/TimeGrain/PL/Rules.hs too large to diff
- Duckling/TimeGrain/PT/Rules.hs too large to diff
- Duckling/TimeGrain/RO/Rules.hs too large to diff
- Duckling/TimeGrain/RU/Rules.hs too large to diff
- Duckling/TimeGrain/SV/Rules.hs too large to diff
- Duckling/TimeGrain/TR/Rules.hs too large to diff
- Duckling/TimeGrain/Types.hs too large to diff
- Duckling/TimeGrain/UK/Rules.hs too large to diff
- Duckling/TimeGrain/VI/Rules.hs too large to diff
- Duckling/TimeGrain/ZH/Rules.hs too large to diff
- Duckling/Types.hs too large to diff
- Duckling/Types/Document.hs too large to diff
- Duckling/Types/Stash.hs too large to diff
- Duckling/Url/Corpus.hs too large to diff
- Duckling/Url/Helpers.hs too large to diff
- Duckling/Url/Rules.hs too large to diff
- Duckling/Url/Types.hs too large to diff
- Duckling/Volume/AR/Corpus.hs too large to diff
- Duckling/Volume/AR/Rules.hs too large to diff
- Duckling/Volume/DE/Corpus.hs too large to diff
- Duckling/Volume/DE/Rules.hs too large to diff
- Duckling/Volume/EN/Corpus.hs too large to diff
- Duckling/Volume/EN/Rules.hs too large to diff
- Duckling/Volume/ES/Corpus.hs too large to diff
- Duckling/Volume/ES/Rules.hs too large to diff
- Duckling/Volume/FR/Corpus.hs too large to diff
- Duckling/Volume/FR/Rules.hs too large to diff
- Duckling/Volume/GA/Corpus.hs too large to diff
- Duckling/Volume/GA/Rules.hs too large to diff
- Duckling/Volume/HR/Corpus.hs too large to diff
- Duckling/Volume/HR/Rules.hs too large to diff
- Duckling/Volume/Helpers.hs too large to diff
- Duckling/Volume/IT/Corpus.hs too large to diff
- Duckling/Volume/IT/Rules.hs too large to diff
- Duckling/Volume/KM/Corpus.hs too large to diff
- Duckling/Volume/KM/Rules.hs too large to diff
- Duckling/Volume/KO/Corpus.hs too large to diff
- Duckling/Volume/KO/Rules.hs too large to diff
- Duckling/Volume/MN/Corpus.hs too large to diff
- Duckling/Volume/MN/Rules.hs too large to diff
- Duckling/Volume/NL/Corpus.hs too large to diff
- Duckling/Volume/NL/Rules.hs too large to diff
- Duckling/Volume/PT/Corpus.hs too large to diff
- Duckling/Volume/PT/Rules.hs too large to diff
- Duckling/Volume/RO/Corpus.hs too large to diff
- Duckling/Volume/RO/Rules.hs too large to diff
- Duckling/Volume/RU/Corpus.hs too large to diff
- Duckling/Volume/RU/Rules.hs too large to diff
- Duckling/Volume/Rules.hs too large to diff
- Duckling/Volume/TR/Corpus.hs too large to diff
- Duckling/Volume/TR/Rules.hs too large to diff
- Duckling/Volume/Types.hs too large to diff
- Duckling/Volume/ZH/Corpus.hs too large to diff
- Duckling/Volume/ZH/Rules.hs too large to diff
- PATENTS too large to diff
- README.md too large to diff
- Setup.hs too large to diff
- duckling.cabal too large to diff
- exe/CustomDimensionExample.hs too large to diff
- exe/Duckling/Data/TimeZone.hs too large to diff
- exe/Duckling/Ranking/Generate.hs too large to diff
- exe/Duckling/Ranking/Train.hs too large to diff
- exe/DucklingExpensive.hs too large to diff
- exe/DucklingRequestSample.hs too large to diff
- exe/ExampleMain.hs too large to diff
- exe/RegenMain.hs too large to diff
- tests/Duckling/AmountOfMoney/AR/Tests.hs too large to diff
- tests/Duckling/AmountOfMoney/BG/Tests.hs too large to diff
- tests/Duckling/AmountOfMoney/EN/Tests.hs too large to diff
- tests/Duckling/AmountOfMoney/ES/Tests.hs too large to diff
- tests/Duckling/AmountOfMoney/FR/Tests.hs too large to diff
- tests/Duckling/AmountOfMoney/GA/Tests.hs too large to diff
- tests/Duckling/AmountOfMoney/HE/Tests.hs too large to diff
- tests/Duckling/AmountOfMoney/HR/Tests.hs too large to diff
- tests/Duckling/AmountOfMoney/ID/Tests.hs too large to diff
- tests/Duckling/AmountOfMoney/IT/Tests.hs too large to diff
- tests/Duckling/AmountOfMoney/KA/Tests.hs too large to diff
- tests/Duckling/AmountOfMoney/KO/Tests.hs too large to diff
- tests/Duckling/AmountOfMoney/MN/Tests.hs too large to diff
- tests/Duckling/AmountOfMoney/NB/Tests.hs too large to diff
- tests/Duckling/AmountOfMoney/NL/Tests.hs too large to diff
- tests/Duckling/AmountOfMoney/PT/Tests.hs too large to diff
- tests/Duckling/AmountOfMoney/RO/Tests.hs too large to diff
- tests/Duckling/AmountOfMoney/RU/Tests.hs too large to diff
- tests/Duckling/AmountOfMoney/SV/Tests.hs too large to diff
- tests/Duckling/AmountOfMoney/TR/Tests.hs too large to diff
- tests/Duckling/AmountOfMoney/Tests.hs too large to diff
- tests/Duckling/AmountOfMoney/VI/Tests.hs too large to diff
- tests/Duckling/AmountOfMoney/ZH/Tests.hs too large to diff
- tests/Duckling/Api/Tests.hs too large to diff
- tests/Duckling/CreditCardNumber/Tests.hs too large to diff
- tests/Duckling/Dimensions/Tests.hs too large to diff
- tests/Duckling/Distance/BG/Tests.hs too large to diff
- tests/Duckling/Distance/CS/Tests.hs too large to diff
- tests/Duckling/Distance/DE/Tests.hs too large to diff
- tests/Duckling/Distance/EN/Tests.hs too large to diff
- tests/Duckling/Distance/ES/Tests.hs too large to diff
- tests/Duckling/Distance/FR/Tests.hs too large to diff
- tests/Duckling/Distance/GA/Tests.hs too large to diff
- tests/Duckling/Distance/HR/Tests.hs too large to diff
- tests/Duckling/Distance/IT/Tests.hs too large to diff
- tests/Duckling/Distance/KM/Tests.hs too large to diff
- tests/Duckling/Distance/KO/Tests.hs too large to diff
- tests/Duckling/Distance/MN/Tests.hs too large to diff
- tests/Duckling/Distance/NL/Tests.hs too large to diff
- tests/Duckling/Distance/PT/Tests.hs too large to diff
- tests/Duckling/Distance/RO/Tests.hs too large to diff
- tests/Duckling/Distance/RU/Tests.hs too large to diff
- tests/Duckling/Distance/SV/Tests.hs too large to diff
- tests/Duckling/Distance/TR/Tests.hs too large to diff
- tests/Duckling/Distance/Tests.hs too large to diff
- tests/Duckling/Distance/ZH/Tests.hs too large to diff
- tests/Duckling/Duration/AR/Tests.hs too large to diff
- tests/Duckling/Duration/BG/Tests.hs too large to diff
- tests/Duckling/Duration/EL/Tests.hs too large to diff
- tests/Duckling/Duration/EN/Tests.hs too large to diff
- tests/Duckling/Duration/ES/Tests.hs too large to diff
- tests/Duckling/Duration/FR/Tests.hs too large to diff
- tests/Duckling/Duration/GA/Tests.hs too large to diff
- tests/Duckling/Duration/HI/Tests.hs too large to diff
- tests/Duckling/Duration/HU/Tests.hs too large to diff
- tests/Duckling/Duration/JA/Tests.hs too large to diff
- tests/Duckling/Duration/KA/Tests.hs too large to diff
- tests/Duckling/Duration/KO/Tests.hs too large to diff
- tests/Duckling/Duration/MN/Tests.hs too large to diff
- tests/Duckling/Duration/NB/Tests.hs too large to diff
- tests/Duckling/Duration/NL/Tests.hs too large to diff
- tests/Duckling/Duration/PL/Tests.hs too large to diff
- tests/Duckling/Duration/PT/Tests.hs too large to diff
- tests/Duckling/Duration/RO/Tests.hs too large to diff
- tests/Duckling/Duration/RU/Tests.hs too large to diff
- tests/Duckling/Duration/SV/Tests.hs too large to diff
- tests/Duckling/Duration/TR/Tests.hs too large to diff
- tests/Duckling/Duration/Tests.hs too large to diff
- tests/Duckling/Duration/UK/Tests.hs too large to diff
- tests/Duckling/Duration/ZH/Tests.hs too large to diff
- tests/Duckling/Email/DE/Tests.hs too large to diff
- tests/Duckling/Email/EN/Tests.hs too large to diff
- tests/Duckling/Email/FR/Tests.hs too large to diff
- tests/Duckling/Email/IS/Tests.hs too large to diff
- tests/Duckling/Email/IT/Tests.hs too large to diff
- tests/Duckling/Email/Tests.hs too large to diff
- tests/Duckling/Engine/Tests.hs too large to diff
- tests/Duckling/Numeral/AF/Tests.hs too large to diff
- tests/Duckling/Numeral/AR/Tests.hs too large to diff
- tests/Duckling/Numeral/BG/Tests.hs too large to diff
- tests/Duckling/Numeral/BN/Tests.hs too large to diff
- tests/Duckling/Numeral/CA/Tests.hs too large to diff
- tests/Duckling/Numeral/CS/Tests.hs too large to diff
- tests/Duckling/Numeral/DA/Tests.hs too large to diff
- tests/Duckling/Numeral/DE/Tests.hs too large to diff
- tests/Duckling/Numeral/EL/Tests.hs too large to diff
- tests/Duckling/Numeral/EN/Tests.hs too large to diff
- tests/Duckling/Numeral/ES/Tests.hs too large to diff
- tests/Duckling/Numeral/ET/Tests.hs too large to diff
- tests/Duckling/Numeral/FA/Tests.hs too large to diff
- tests/Duckling/Numeral/FI/Tests.hs too large to diff
- tests/Duckling/Numeral/FR/Tests.hs too large to diff
- tests/Duckling/Numeral/GA/Tests.hs too large to diff
- tests/Duckling/Numeral/HE/Tests.hs too large to diff
- tests/Duckling/Numeral/HI/Tests.hs too large to diff
- tests/Duckling/Numeral/HR/Tests.hs too large to diff
- tests/Duckling/Numeral/HU/Tests.hs too large to diff
- tests/Duckling/Numeral/ID/Tests.hs too large to diff
- tests/Duckling/Numeral/IS/Tests.hs too large to diff
- tests/Duckling/Numeral/IT/Tests.hs too large to diff
- tests/Duckling/Numeral/JA/Tests.hs too large to diff
- tests/Duckling/Numeral/KA/Tests.hs too large to diff
- tests/Duckling/Numeral/KM/Tests.hs too large to diff
- tests/Duckling/Numeral/KN/Tests.hs too large to diff
- tests/Duckling/Numeral/KO/Tests.hs too large to diff
- tests/Duckling/Numeral/LO/Tests.hs too large to diff
- tests/Duckling/Numeral/ML/Tests.hs too large to diff
- tests/Duckling/Numeral/MN/Tests.hs too large to diff
- tests/Duckling/Numeral/MY/Tests.hs too large to diff
- tests/Duckling/Numeral/NB/Tests.hs too large to diff
- tests/Duckling/Numeral/NE/Tests.hs too large to diff
- tests/Duckling/Numeral/NL/Tests.hs too large to diff
- tests/Duckling/Numeral/PL/Tests.hs too large to diff
- tests/Duckling/Numeral/PT/Tests.hs too large to diff
- tests/Duckling/Numeral/RO/Tests.hs too large to diff
- tests/Duckling/Numeral/RU/Tests.hs too large to diff
- tests/Duckling/Numeral/SK/Tests.hs too large to diff
- tests/Duckling/Numeral/SV/Tests.hs too large to diff
- tests/Duckling/Numeral/SW/Tests.hs too large to diff
- tests/Duckling/Numeral/TA/Tests.hs too large to diff
- tests/Duckling/Numeral/TE/Tests.hs too large to diff
- tests/Duckling/Numeral/TH/Tests.hs too large to diff
- tests/Duckling/Numeral/TR/Tests.hs too large to diff
- tests/Duckling/Numeral/Tests.hs too large to diff
- tests/Duckling/Numeral/UK/Tests.hs too large to diff
- tests/Duckling/Numeral/VI/Tests.hs too large to diff
- tests/Duckling/Numeral/ZH/Tests.hs too large to diff
- tests/Duckling/Ordinal/AR/Tests.hs too large to diff
- tests/Duckling/Ordinal/BG/Tests.hs too large to diff
- tests/Duckling/Ordinal/CA/Tests.hs too large to diff
- tests/Duckling/Ordinal/DA/Tests.hs too large to diff
- tests/Duckling/Ordinal/DE/Tests.hs too large to diff
- tests/Duckling/Ordinal/EL/Tests.hs too large to diff
- tests/Duckling/Ordinal/EN/Tests.hs too large to diff
- tests/Duckling/Ordinal/ES/Tests.hs too large to diff
- tests/Duckling/Ordinal/ET/Tests.hs too large to diff
- tests/Duckling/Ordinal/FR/Tests.hs too large to diff
- tests/Duckling/Ordinal/GA/Tests.hs too large to diff
- tests/Duckling/Ordinal/HE/Tests.hs too large to diff
- tests/Duckling/Ordinal/HI/Tests.hs too large to diff
- tests/Duckling/Ordinal/HR/Tests.hs too large to diff
- tests/Duckling/Ordinal/HU/Tests.hs too large to diff
- tests/Duckling/Ordinal/ID/Tests.hs too large to diff
- tests/Duckling/Ordinal/IT/Tests.hs too large to diff
- tests/Duckling/Ordinal/JA/Tests.hs too large to diff
- tests/Duckling/Ordinal/KA/Tests.hs too large to diff
- tests/Duckling/Ordinal/KM/Tests.hs too large to diff
- tests/Duckling/Ordinal/KO/Tests.hs too large to diff
- tests/Duckling/Ordinal/ML/Tests.hs too large to diff
- tests/Duckling/Ordinal/MN/Tests.hs too large to diff
- tests/Duckling/Ordinal/NB/Tests.hs too large to diff
- tests/Duckling/Ordinal/NL/Tests.hs too large to diff
- tests/Duckling/Ordinal/PL/Tests.hs too large to diff
- tests/Duckling/Ordinal/PT/Tests.hs too large to diff
- tests/Duckling/Ordinal/RO/Tests.hs too large to diff
- tests/Duckling/Ordinal/RU/Tests.hs too large to diff
- tests/Duckling/Ordinal/SV/Tests.hs too large to diff
- tests/Duckling/Ordinal/TA/Tests.hs too large to diff
- tests/Duckling/Ordinal/TR/Tests.hs too large to diff
- tests/Duckling/Ordinal/Tests.hs too large to diff
- tests/Duckling/Ordinal/UK/Tests.hs too large to diff
- tests/Duckling/Ordinal/VI/Tests.hs too large to diff
- tests/Duckling/Ordinal/ZH/Tests.hs too large to diff
- tests/Duckling/PhoneNumber/AR/Tests.hs too large to diff
- tests/Duckling/PhoneNumber/PT/Tests.hs too large to diff
- tests/Duckling/PhoneNumber/Tests.hs too large to diff
- tests/Duckling/Quantity/AR/Tests.hs too large to diff
- tests/Duckling/Quantity/EN/Tests.hs too large to diff
- tests/Duckling/Quantity/ES/Tests.hs too large to diff
- tests/Duckling/Quantity/FR/Tests.hs too large to diff
- tests/Duckling/Quantity/HR/Tests.hs too large to diff
- tests/Duckling/Quantity/KM/Tests.hs too large to diff
- tests/Duckling/Quantity/KO/Tests.hs too large to diff
- tests/Duckling/Quantity/MN/Tests.hs too large to diff
- tests/Duckling/Quantity/NL/Tests.hs too large to diff
- tests/Duckling/Quantity/PT/Tests.hs too large to diff
- tests/Duckling/Quantity/RO/Tests.hs too large to diff
- tests/Duckling/Quantity/RU/Tests.hs too large to diff
- tests/Duckling/Quantity/Tests.hs too large to diff
- tests/Duckling/Quantity/ZH/Tests.hs too large to diff
- tests/Duckling/Temperature/AR/Tests.hs too large to diff
- tests/Duckling/Temperature/EN/Tests.hs too large to diff
- tests/Duckling/Temperature/ES/Tests.hs too large to diff
- tests/Duckling/Temperature/FR/Tests.hs too large to diff
- tests/Duckling/Temperature/GA/Tests.hs too large to diff
- tests/Duckling/Temperature/HI/Tests.hs too large to diff
- tests/Duckling/Temperature/HR/Tests.hs too large to diff
- tests/Duckling/Temperature/IT/Tests.hs too large to diff
- tests/Duckling/Temperature/JA/Tests.hs too large to diff
- tests/Duckling/Temperature/KM/Tests.hs too large to diff
- tests/Duckling/Temperature/KO/Tests.hs too large to diff
- tests/Duckling/Temperature/MN/Tests.hs too large to diff
- tests/Duckling/Temperature/PT/Tests.hs too large to diff
- tests/Duckling/Temperature/RO/Tests.hs too large to diff
- tests/Duckling/Temperature/TR/Tests.hs too large to diff
- tests/Duckling/Temperature/Tests.hs too large to diff
- tests/Duckling/Temperature/ZH/Tests.hs too large to diff
- tests/Duckling/Testing/Asserts.hs too large to diff
- tests/Duckling/Tests.hs too large to diff
- tests/Duckling/Time/AR/Tests.hs too large to diff
- tests/Duckling/Time/BG/Tests.hs too large to diff
- tests/Duckling/Time/DA/Tests.hs too large to diff
- tests/Duckling/Time/DE/Tests.hs too large to diff
- tests/Duckling/Time/EL/Tests.hs too large to diff
- tests/Duckling/Time/EN/Tests.hs too large to diff
- tests/Duckling/Time/ES/Tests.hs too large to diff
- tests/Duckling/Time/FR/Tests.hs too large to diff
- tests/Duckling/Time/GA/Tests.hs too large to diff
- tests/Duckling/Time/HE/Tests.hs too large to diff
- tests/Duckling/Time/HR/Tests.hs too large to diff
- tests/Duckling/Time/HU/Tests.hs too large to diff
- tests/Duckling/Time/IT/Tests.hs too large to diff
- tests/Duckling/Time/KA/Tests.hs too large to diff
- tests/Duckling/Time/KO/Tests.hs too large to diff
- tests/Duckling/Time/NB/Tests.hs too large to diff
- tests/Duckling/Time/NL/Tests.hs too large to diff
- tests/Duckling/Time/PL/Tests.hs too large to diff
- tests/Duckling/Time/PT/Tests.hs too large to diff
- tests/Duckling/Time/RO/Tests.hs too large to diff
- tests/Duckling/Time/RU/Tests.hs too large to diff
- tests/Duckling/Time/SV/Tests.hs too large to diff
- tests/Duckling/Time/Tests.hs too large to diff
- tests/Duckling/Time/UK/Tests.hs too large to diff
- tests/Duckling/Time/VI/Tests.hs too large to diff
- tests/Duckling/Time/ZH/Tests.hs too large to diff
- tests/Duckling/Url/Tests.hs too large to diff
- tests/Duckling/Volume/AR/Tests.hs too large to diff
- tests/Duckling/Volume/DE/Tests.hs too large to diff
- tests/Duckling/Volume/EN/Tests.hs too large to diff
- tests/Duckling/Volume/ES/Tests.hs too large to diff
- tests/Duckling/Volume/FR/Tests.hs too large to diff
- tests/Duckling/Volume/GA/Tests.hs too large to diff
- tests/Duckling/Volume/HR/Tests.hs too large to diff
- tests/Duckling/Volume/IT/Tests.hs too large to diff
- tests/Duckling/Volume/KM/Tests.hs too large to diff
- tests/Duckling/Volume/KO/Tests.hs too large to diff
- tests/Duckling/Volume/MN/Tests.hs too large to diff
- tests/Duckling/Volume/NL/Tests.hs too large to diff
- tests/Duckling/Volume/PT/Tests.hs too large to diff
- tests/Duckling/Volume/RO/Tests.hs too large to diff
- tests/Duckling/Volume/RU/Tests.hs too large to diff
- tests/Duckling/Volume/TR/Tests.hs too large to diff
- tests/Duckling/Volume/Tests.hs too large to diff
- tests/Duckling/Volume/ZH/Tests.hs too large to diff
- tests/TestMain.hs too large to diff
@@ -0,0 +1,784 @@+# Changelog for [`duckling` package](https://github.com/facebook/duckling)++## 0.2.0.0++### Core+ * Bump versions on dependencies+ * ExampleMain: add support for setting the port+ * Support for GHC >= 8.8.x && GHC <= 9.0.1+ * Relicense to BSD-3+ * Probabilistic layer bug fix+ * Remove dependency on Data.Some+ * Depend on regex-pcre-builtin on Windows+ * Update cabal-version to 2.2+ * Migrate to GitHub CI over Travis+ * Some attempts at getting smaller parse trees (less exploitable)++### Rulesets++* Common+ * Correct CDT TimeZone offset CDT is (-300), not 540.+ * Fixed BST and IST offsets. BST is +1 (60) and IST is +5:30 (330)+ * Make unicode output in tests sane by not relying on `Show`+ * Add type=value to JSON response for Email, PhoneNumber, and Url, for consistency+ * CreditCardNumber: **new!** (duckling can now recognise credit cards)+ * Email: Add DE (German) + IS (Icelandic) spelled out email+ * Numeral: Don't accept dashes ('-') as token separators+ * Time: Add Karva Chauth holiday+ * Time: Add Vaisakhi holiday+ * Time: Add daylight savings start/endtimes to holidays+ * Time: Add Purim and Shushan Purim (Jewish holidays)+ * Time: Add Guru Gobind Singh Jayanti holiday+ * Time: Extend support for Ramadan and Eid al-Fitr from 1950 to 2050+ * Time: Add support for Parsi New Year+ * Time: Add support for Dayananda Saraswati Jayanti holiday+ * Time: Extend support for Mawlid from 1950 to 1998+ * Time: Add Rabindra Jayanti holiday+ * Time: Add Guru Ravidass Jayanti holiday+ * Time: Extend support for Eid al-Adha from 1950 to 2000+ * Time: Add Krishna Janmashtami holiday+ * Time: Add Mahavir Jayanti holiday+ * Time: Add Maha Shivaratri holiday+ * Time: add Ugadi holiday+ * Volume: interval support++* AF (Afrikaans)+ * Numeral: **new!**++* AR (Arabic)+ * Add a new locale: EG (Egyptian)+ * AmountOfMoney: Add more variants of EGP+ * Numeral: Add support for numerals written in Arabic script+ * Numeral: Support decimals and comma-separated integers+ * PhoneNumber: **new!**+ * Time: Add periodic times+ * Time: Add rule for a week ago++* BG (Bulgarian)+ * Time: **new!**++* BN (Bengali)+ * Numeral: **new!**++* CA (Catalan)+ * Numeral: **new!**+ * Ordinal: **new!**++* DA (Danish)+ * Ordinal: Add support for larger spelled-out ordinals+ * Time: recognise abbreviation 'kl'++* DE (German)+ * Distance: **new!**+ * Duration: Add more common durations+ * Numeral: Fix typo on "fünfzehn"(15)+ * Time: Fix wrong parsing of YYYY-MM-DD dates+ * Time: Add rule for 'the day before yesterday'+ * Time: Fix a bug for "fünfter"¬+ * Time: support for "am ersten Dezember" to " am einunddreißigsten Dezember"¬+ * Time: now recognise "der fünfte Dezember"¬+ * Time: Add support for (pre-)computed holidays+ * Time: Don't parse 'so'+ * Time: improve approximations+ * Time: Add rule for week after next+ * Time: Add rule for montag in n wochen+ * Volume: **new!**++* EN (English)+ * AmountOfMoney: Add support for subunits of dollars, e.g. nickels, dimes, quarters, as well as the number of coins+ * AmountOfMoney: Add support for latent+ * AmountOfMoney: Add support for lakh and crore+ * AmountOfMoney: correct regex to match three letter currency codes beginning with C+ * AmountOfMoney: Make ruleInterval{Max,Min} symmetric+ * AmountOfMoney: Support abbreviations of lakh and crore+ * AmountOfMoney: Add UAH currency+ * AmountOfMoney: Add HKD+ * AmountOfMoney: dollar and \<amount-of-money\>+ * AmountOfMoney: dollar and a half+ * AmountOfMoney: intersection for \<amount-of-money\> and a half+ * AmountOfMoney: extend interval support+ * AmountOfMoney: Add more variants of EGP+ * Distance: Support composite distances+ * Distance: one meter and \<distance\>+ * Distance: \<distance\> meters and \<distance\>+ * Distance: Add interval support+ * Duration: Fix composite durations without delimiters.+ It previously only worked with+ commas/'and'-separated tokens+ * Duration: Support more words in `ruleDurationNumeralMore`+ * Duration: \<integer\> and a half minutes+ * Duration: support for \<integer\> hour and \<integer\>+ * Duration: parse Xm as X minutes and X.Y hrs as X.Y hours+ * Duration: Leverage TimeGrain for x.y hours+ * Duration: Support composite duration+ * Numeral: Fix ambiguous parses when both ruleNegative and ruleMultiply apply+ * Numeral: Extend fraction rule+ * Numeral: Add mixed fraction rules+ * Numeral: Add prefix of 10/100/10_000 rules+ * Quantity: Support 'k.g' and 'k.g.' for kilograms+ * Temperature: Support temperatures with decimal values+ * Time: Fix palm sunday regex+ * Time: Fix latent time of days like "ten thirty"+ * Time: Don't parse time of days above 12 with meridiem+ like "13 am"+ * Time: Add rule to match \<time\> + \<timezone\>+ * Time: Add "all week"/"rest of the week" rules+ * Time: Parse time intervals like: 2015-03-28 17:00:00/2015-03-28 21:00:00+ * Time: Add rules to handle "DD/MM/YYYY" or "DD MM YYYY"+ * Time: Add support for YYYYQQ and YYQQ expressions, like+ '2018Q4' and '18Q4'+ * Time: Add rule for 'during \<month\>'+ * Time: Restrict 'on' absorption to days+ * Time: Fix durations, upper intervals should all be exclusive+ * Time: Fix grain on some intervals for time-of-days+ * Time: Add rule 'in \<duration\> at \<time-ofday\>+ * Time: Add \<datetime\> - \<datetime\> (interval) timezone rule+ * Time: '\<day\> in \<duration\> should only operate on grain \> Hour+ * Time: Add '\<integer\> \<day-of-week\> from \<time\>' rule+ * Time: Add \<duration\> past \<time\>+ * Time: Make 'the week' resolve to interval from `today` to `end of week`+ * Time: Add support for \<hour\>h\<min\>+ * Time: Add rule for a quarter after \<hour-of-day\>+ * Time: Support 'Martin Luther Kings Day'+ * Time: Add more holiday aliases (Veteran Day, Mardi Gras, St. Paddy's Day)+ * Time: Intersect "9 tomorrow morning"+ * Time: Support 'Chinese New Years'+ * Time: Support "Saint" Patrick's Day+ * Time: Add Ratha-Yatra Holiday+ * Time: Add support for Ganesh Chaturthi holiday+ * Time: Add rama navami holiday+ * Time: Add '\<part-of-day\> at \<time-of-day\>' rule+ * Time: Modify 'this|last|next \<cycle\>' to capture things like "the month" in "the first Saturday of the month"+ * Time: Support 'the \<day-of-month\> of \<month\>'+ * Time: Add Orthodox Good Friday holiday+ * Time: The (nth) closest (day) to (time)+ * Time: Add rule for 'midday'+ * Time: Fix a problem with parsing fractional minutes+ * Time: parse 'upcoming xxx weeks' and 'xxx upcoming weeks'+ * Time: Add new rule to parse phrase in the pattern 'xxx minutes to \<hour-of-day\>+ * Time: Add support for spelled-out times+ * Time: Add support to parse \<ordinal\> \<day-of-week\>+ * Time: Fix parsing 'next \<day-of-week\>'+ * Time: Treat 'coming' as 'next'+ * Time: Make duckling time not treat 0:xx and 12:xx ambiguously+ * Add 'asap', 'at the moment' to EN time+ * Parse latent year intervals+ * Time: last \<duration\>+ * Time: \<time\> \<day-of-month\>+ * Volume: Extend interval support+ * Time: Handle 2-digit date in existing DD/MM/YYYY rule++* EN_UK (English, United Kingdom)+ * Duration: **new!**+ * Time: **new!**++* EN_US (English, United States)+ * Time: Super Tuesday++* ES (Spanish)+ * AmountOfMoney: Add support for intervals+ * Duration: Add support for parsing phrases like half hour, quarter of an hour+ * Duration: Support composite durations+ * Numeral: Fix typo of 22 (veinto -> venti)+ * Numeral: Add locale rules, since Spain and South America use different decimal separators+ * Numeral: parse 'cero dos' as 'dos'+ * Numeral: composite numerals+ * Ordinal: Add missing 'tercer' regex+ * Quantity: **new!**+ * Time: Add support for periodic holidays+ * Time: Fix `ruleYearLatent` to not match numerals that could be hours+ * Time: Make 'n horas' latent+ * Time: Fixed a problem with parsing 'day of month' that contains 'dia'+ * Time: Add rule for 'next week'+ * Time: \<ordinal\> \<day-of-month\>+ * Time: support for 'noon'+ * Time: Allow para before timestamps+ * Time: Add rule to parse '\<time-of-day\> (in the afternoon)'+ * Time: Add rule to parse 'last \<day-of-week\> of \<time\>'+ * Time: Add rule for next week+ * Time: Add more corpus for tomorrow so that tomorrow latent doesn't prevail+ * Time: Fix multi-word timestamps++* FA (Persian)+ * Numeral: **new!**++* FI (Finnish)+ * Numeral: **new!**++* FR (French)+ * Temperature: Support temperatures with decimal values+ * Time: Update month interval rules to handle ordinals+ and spelled-out numerals (e.g. "du premier au+ quinze juin")+ * Volume: Add 'Centilitre' type++* HE (Hebrew)+ * AmountOfMoney: add more rules++* HI (Hindi)+ * Duration: Pakhwada (पखवाड़ा) is 15 days n, not a fortnight+ * Duration: Add support for composite duration+ * Duration: Add support for specific times+ * Numeral: Support more numerals+ * Temperature: **new!**+ * Time: Add support for quarter till, quarter past, and half++* ID (Indonesian)+ * AmountOfMoney: support intervals++* IS (Icelandic)+ * Numeral: **new!**++* IT (Italian)+ * AmountOfMoney: **new!**+ * Distance: **new!**+ * Duration: Fix ruleDurationAgo++* KA (Georgian)+ * AmountOfMoney: **new!**+ * Duration: **new!**+ * Numeral: **new!**+ * Ordinal: **new!**+ * Time: **new!**+ * Time: Improvements for times in the past+ * Time: Add support for quarters++* KM (Khmer)+ * Distance: **new!**+ * Numeral: **new!**+ * Ordinal: **new!**+ * Quantity: **new!**+ * Temperature: **new!**+ * Volume: **new!**++* KN (Kannada)+ * Numeral: **new!**++* KO (Korean)+ * AmountOfMoney: support intervals++* LO (Lao)+ * Numeral: **new!**++* ML (Malayalam)+ * Numeral: **new!**+ * Ordinal: **new!**++* MN (Mongolian)+ * Numeral: **new!**++* NL (Dutch)+ * AmountOfMoney: make decimal thousands separator optional+ * Duration: Add 'anderhalf uur'+ * Duration: support composite durations+ * Quantity: **new!**+ * Time: Add support for King's Day (Koningsdag)+ * Time: stop 'for \<number\>' from resolving as times+ * Volume: remove gallon+ * Volume: Fix typo in milliliter++* NO (Norwegian)+ * AmountOfMoney: Parse more currencies+ * Numeral: The written numeral 8 had a typo: "otte" -> "åtte"+ * Numeral: Parse powers of ten with spaces as well as dots+ * Numeral: Add more textual powers of ten+ * Numeral: Parse textual numbers from 21 to 99 with _and_ without spaces+ * Time: Add support for half an hour before as e.g. "halv to"+ * Time: Add support for alternative clock denotation "klokka"+ * Time: Add support for alternative tomorrow denotation "i morra"+ * Time: Add some more unambiguous datetime parsing++* PL (Polish)+ * Numeral: Add support for seventy, eighty, ninety+ * Duration: Fix typo: miej -> mniej+ * Time: Add 'evening' to corpus++* PT (Portuguese)+ * Ordinal: Add 13..99+ * Ordinal: Corpus, keep accents consistent+ * Time: Last and quarter expressions++* RO (Romanian)+ * Numeral: Fix multipliers with values above 20+ In Romanian, for numerals above 20, we+ say '20 de milioane', not '20 milioane'.+ * Time: Implement 'the day after tomorrow'++* RU (Russian)+ * AmountOfMoney: Add UAH currency+ * Numeral: Be more permissive with numerals [20, 90]+ * Time: **new!**++* SK (Slovak)+ * Numeral: **new!**++* SW (Swahili)+ * Numeral: **new!**++* TA (Tamil)+ * Ordinal: **new!**++* TE (Telugu)+ * Numeral: **new!**++* TH (Thai)+ * Numeral: **new!**++* TR (Turkish)+ * AmountOfMoney: **new!**+ * Time: **new!**++* VI (Vietnamese)+ * AmountOfMoney: Add interval support+ * AmountOfMoney: ruleNg, ruleDollar, ruleVND modified to better capture usage of VI+ * Numeral: Add "ngàn" common synonym of "nghìn", and "chục",+ colloquially used to count tens.+ * Numeral: Remove ? in some regex where they don't make sense+ * Time: Fix double-digit month matching+ * Time: don't parse ngày++* ZH (Chinese)+ * Duration: Add more common expressions+ * Numeral: Add more common expressions+ * Time: Parse YYYY-MM+ * Time: Value before month can be integer or chinese char+ * Time: Add support for (pre-)computed holidays+ * Time: Add more common expressions+ * Volume: **new!**++### Server+ * Skip logfile creation if no logging+ * Document how example application can use specific dimensions only+ * Use System.FilePath.Posix instead of System.FilePath+ * Use all dimensions by default+ * Load timezones more leniently+ * Docker: Reduce size of image drastically+ * Dockerfile: Use Debian Buster++## 0.1.6.1++### Core++* Warn against incomplete pattern matching in GHC options+* Updated readme for custom dimensions+* Coding style documentation++### Rulesets++* Common+ * AmountOfMoney: change `financeWith` to `isAmountOfMoney` where applicable+ * Temperature: implement temperature intervals++* EN+ * AmountOfMoney: support "grand"+ * Time: Absorb "since" before month/year+ * Time: Fix before/after/until/since + <year>+ * Time: Make partial meridies latent+ * Time: Global Youth Service Day+ * Time: Vesak+ * Time: Earth Hour+ * Time: Regex update for Rosh Hashanah and Chanukkah+ * Time: add <time> for <duration> rules+ * Distance: Millimeter units and UK spellings+ * Duration: Handle half time grains++* EN_US+ * Time: Fix Emancipation Day+ * Time: Tax Day+ * Time: Siblings Day+ * Time: EMS Week and EMSC Day++* EN_AU+ * Time: Ekka++* EN_XX+ * Time: Administrative Professionals' Day+ * Time: Parse 'second last week of October 2018'+ * Time: AD/BC parsing for years++* AR+ * Numeral: Fix dual big numbers+ * Numeral: Fix million++* DA_XX+ * Time: Remove 'man'++* DE+ * Time: Remove am/pm rule++* HI+ * Duration: **new!**+ * TimeGrain: **new!**++* NL+ * Time: Fix Sinterklaas for Belgium++* RO+ * AmountOfMoney: Fix for values above 20+ * AmountOfMoney: Support intervals+ * Distance: Fix for values above 20+ * Duration: Fix for values above 20+ * Quantity: Fix for values above 20+ * Temperature: Fix for values above 20+ * Volume: Fix for values above 20++* ZH+ * Quantity: **new!**+ * Time: Support Periodic Holidays++## 0.1.6.0++### Core++The `value` field of `Entity` is now typed! Use `toJText` to get the JSON-encoded string back.++## 0.1.5.0++### Testing+* Prompt ambiguous parses in corpus tests++### Rulesets++* Common+ * Add an option to return latent time entities.+ * AmountOfMoney: Distribute ruleUnitAmount to all languages+ * Time: Make all years latent+ * Lambda-case for Rule production+ * Numeral: fix intersect rule to work with negative numbers+ * Support custom dimensions++* BG_XX:+ * Distance: **new!**+ * TimeGrain: **new!**+ * Duration: **new!**+ * Ordinal: **new!**++* EN_XX+ * Time: periodic holidays+ * Time: handle Easter+ * Time: parse "DD MM YYYY", "MM DD YYYY" as date instead of only phone fix+ * Time: added rules for the beginning / end of year / month / week+ * Time: "late tonight"+ * Time: "last night" and "late last night"+ * Time: fixes in holidays+ * Time: Return Holiday Name in response+ * Duration: composite+ * Time: support for this|last|next season+ * Time: added Easter-based holidays+ * Time: precomputed Orthodox Easter dates+ * Time: added Orthodox Easter-based holidays+ * Time: fix Labour Day, add Heroes' Day and National Patriots' Day+ * Time: Chinese New Year+ * Time: added Boss's Day+ * Time: fix computed past series and Jewish holidays+ * Time: added rules to cover EOY, EOM, BOY, BOM+ * Time: rule <Day of month> of month+ * Time: Islamic holidays+ * Time: fix "in" + year+ * Time: Added precomputed Jewish holiday "Tu BiShvat"+ * Time: time + n years ago/in n years+ * Time: make "may" latent+ * Duration: move composite duration rule to English+ * Time: add Diwali, Navaratri, Vasant Panchami, Holika Dahan, Holi and other Hindu holidays++* EN_AU+ * Time: add Reconciliation Day++* EN_CA+ * Time: add Discovery day+ * Time: Add "Groundhogs day" in regex for "Groundhog Day"++* EN_GB+ * Time: fixed mother's day++* EN_US+ * Time: Washington's birthday, President day and Lincoln's birthday+ * Time: Add "Groundhogs day" in regex for "Groundhog Day"++* ES_XX+ * Time: use `mkRuleSeasons`++* DE_XX+ * Time: return Holiday Name in response++* NL_XX+ * Time: return Holiday Name in response+ * AmountOfMoney: **new!**++* PL_XX+ * Time: month regex fix++* RU_XX+ * Ordinal: refactor pattern match to hashmap lookup++* SV_XX+ * Distance: **new!**+ * Distance: fix mil++* TA_XX+ * Numerals: **new!**++* VI_XX+ * AmountOfMoney: Use comma "," as decimal separator++* ZH_XX+ * Distance: **new!**+ * Time: remove unused `ruleLastTuesdayLastJuly`+ * Numeral/Distance/Time: generalize and expand digit specifier usage+ * AmountOfMoney: **new!**++## 0.1.4.0++### Core+* Bumped to LTS 9.10+* API: Added `Node` to `Entity` to return the parse tree++### Rulesets+* Common+ * AmountOfMoney: don't recursively compare cents+ * AmountOfMoney: don't allow decreasing intervals+ * Duration: added `type` in response+ * Numeral: common rule to parse numbers+ * Numeral: common rule to parse fractions+ * Numeral: don't compose negative numbers+ * Time: fixed empty values for past datetimes+ * Time: fixed case sensitivity for timezones+ * Url: fragments support+* AR_XX+ * AmountOfMoney: **new!**+ * Duration: **new!**+ * Ordinal: more rules+ * Quantity: **new!**+ * Temperature: **new!**+ * Time: **new!**+ * Volume: **new!**+* DE_XX+ * Numeral: fixed keiner+ * Time: fixed this/next/last for holidays/months/days of week/seasons/weekend only+* EL_XX+ * Duration: **new!**+ * Numeral: **new!**+ * Ordinal: **new!**+ * Time: **new!**+* EN_GB+ * Time: fix parsing Oct-Dec months+* EN_XX+ * AmountOfMoney: intervals support+ * Distance: intervals support+ * Email: spelled out 'dot'+ * Numeral: prevent double negatives+ * Numeral: skip hundred for alphabetical numbers only+ * Quantity: intervals support+ * Time: don't parse "at" + phone number+ * Time: fixed date format in non-US locales+ * Time: fixed Thanksgiving in locales+ * Time: don't parse "this in 2 minutes"+ * Time: spelled out times + AM/PM+ * Time: fixed case sensitivity+ * Time: fixed "from" + time of day+ * Time: support MM.DD.YYYY+* FR_XX+ * Numeral: space as thousand separator+* GA_XX+ * Numeral: fix old vigesimal+* HI_XX+ * Numeral: **new!**+ * Ordinal: **new!**+* JA_XX+ * Time: removed dimension, as it is not implemented yet+* NE_XX+ * Numeral: **new!**+* NL_XX+ * Time: **new!**+ * Time: don't be too eager on days of week+ * Time: today/tomorrow/yesterday evening/afternoon/morning+ * Time: fixed this/next/last for holidays/months/days of week/seasons/weekend only+* PT_XX+ * Numeral: fixed rules+* RU_XX+ * AmountOfMoney: **new!**+ * Distance: **new!**+ * Duration:: **new!**+ * Numeral: 1.5 rule, more 0 rules, fixed 11, 300 and 400+ * Ordinal: fixes+ * Quantity: **new!**+ * Volume: **new!**+* SV_XX+ * Duration: extend support for "about" + duration++### Server+* Fixed Dockerfile+* Added reference time parameter++## 0.1.3.0++### Core+* Support locales+* Don't allow matches in the middle of words++### Rulesets+* Common+ * All: converted back all escaped characters to unicode+ * Time: don't shift duration on "`Duration` before/after `Time`"+ * Time: don't parse subsequent numbers+ * Time: fix `nthDOWOfMonth`+ * Time: reuse the `weekend` helper in all languages+* BG_XX+ * AmountOfMoney: **new!**+ * Numeral: **new!**+* DA_XX+ * Time: Consolidated rules for months and days of week+* DE_XX+ * Time: don't parse "nächste 5"+ * Time: Consolidated rules for months and days of week+ * Time: Consolidated rules for holidays, instants and seasons+* EN_CA+ * Time: Fixed Thanksgiving Day+* EN_GB+ * Time: Fixed DDMM and YYYYDDMM+* EN_XX+ * Time: "for `Duration` from `Time`"+ * Time: "from 10 to 16 August"+ * Time: "August 27th-30th"+ * Time: "23rd to 26th Oct", "1-8 september"+ * Time: Support misspelled "tonights" and "weekends"+ * Quantity: Support ounces+ * Email: restrict domain extensions to letters when spelling out+* ES_XX+ * Time: Consolidated rules for months and days of week+ * Ordinal: Fixed "first" variants + accents+* FR_XX+ * Time: don't parse "a un"+ * Time: Consolidated rules for months and days of week+* GA_XX+ * Time: Consolidated rules for months and days of week+* HE_XX+ * Time: Consolidated rules for months+* HR_XX+ * Time: Consolidated rules for months and days of week+* HU_XX+ * Duration: **new!**+ * Numeral: **new!**+ * Ordinal: **new!**+ * Time: **new!**+* IT_XX+ * Time: Consolidated rules for months and days of week+* JA_XX+ *Numeral: Optimized regex lookup+* KA_XX+ * Numeral: **new!**+* NB_XX+ * Time: Consolidated rules for months and days of week+* NL_XX+ * Duration: **new!**+* PL_XX+ * Time: don't parse "nie"+ * Time: don't parse ordinals without context+ * Time: Consolidated rules for months and days of week+* PT_XX+ * Time: don't parse "um" alone+ * Time: don't parse "ter"+* RO_XX+ * Time: Consolidated rules for months and days of week+ * Time: don't parse "sa"+* SV_XX+ * Ordinal: Fixed ordinals+ * Time: "i + day-of-week"+ * Time: Consolidated rules for months and days of week+* VI_XX+ * Time: Consolidated rules for months and days of week+* ZH_TW+ * Time: Fixed National Day+* ZH_XX+ * Time: Consolidated rules for months and days of week++## 0.1.2.0++### Core++* `weekend` production helper+* Numeral flag for Time patterns++### Rulesets++* FR+ * Time+ * `début|milieu|fin de matinée` (`early|mid|late morning`)+ * `début|milieu|fin de après-midi` (`early|mid|late afternoon`)+ * `début|milieu|fin de journée` (`early|mid|late day`)+ * `début|fin de soirée` (`early|late evening`)+ * `début|fin de mois` (`early|late month`)+ * `début|fin d'année` (`early|late year`)+ * `plus tard` (`later`)+ * `plus tard que ...` (`later than ...`)+ * `plus tard <time>` (`later than <time>`)+ * `plus tard <part-of-day>` (`later than <part-of-day>`)+* EN+ * Time+ * Support dates of type mm-dd+ * Fix issue #50 "last weekend of october"+ * Added a rule to handle "from <month> dd-dd"+ * Add MM/YYYY+* DE+ * Time+ * Make last dot optional in "13.03."+ * Handle variations of "13.-15.10." correctly+ * Treat "14/15Uhr" the same as "14-15Uhr"+ * Extended "bis" to also match "bis zum" and "auf den"+ * Changed `hh:mm` matching to also get the expression "17h00"+* PT+ * Numeral+ * Numerals between 100 and 999 in Portuguese fixed+* GA+ * Ordinal+ * Also match old-style -adh ending++## 0.1.1.0++### Core+* More optimizations for `Time` internals.+* `Entity` value is now a `Value` (was a JSON-encoded `Text`).++### Rulesets+* Common+ * AmountOfMoney: MYR currency+ * Duration: Helper for "<numeral>.<numeral> hours"+* CS+ * Distance: **new!**+ * Numeral: **new!**+* DE+ * Ordinal: Don't parse "1.1."+ * Time: Small improvements+* EN+ * AmountOfMoney+ * Support pence as cents+ * Support Malaysian ringgits+ * Distance: Abbreviations for inches, miles+ * Numeral: Fractions+ * Quantity: Generic product+ * Time+ * Allow spaces in e.g. "2 / 15"+ * Afternoonish+ * Early/mid/late month+* ID+ * Numeral: Optimization for regex matching+* KO+ * Time: Fixed typo in the day after tomorrow+* SV+ * Time: vid+* TR+ * Distance: **new!**+ * Duration: **new!**+ * Numeral: Comma as decimal mark+ * Temperature: **new!**+ * Volume: **new!**+* ZH+ * Time: Cantonese support++### Server+* Added dockerfile+* Fixed warnings around logs++## 0.1.0.0++* Initial version. Released on an unsuspecting world.
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -87,6 +86,8 @@ [ "42 EGP" , "42 جنيه مصري" , "42 جنيهات مصريه"+ , "42 ج.م"+ , "42 ج.م." ] , examples (simple QAR 42) [ "42 QAR"
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -52,6 +51,15 @@ , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly Pound } +ruleEgpAbrreviation :: Rule+ruleEgpAbrreviation = Rule+ { name = "EGP abbreviation"+ , pattern =+ [ regex "ج[.]م[.]?"+ ]+ , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly EGP+ }+ ruleDinars :: Rule ruleDinars = Rule { name = "dinars"@@ -391,6 +399,7 @@ [ ruleUnitAmount , ruleCent , rulePounds+ , ruleEgpAbrreviation , ruleDinars , ruleDirhams , ruleRiyals
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-} @@ -27,6 +26,26 @@ ] , examples (simple AUD 10000) [ "10 grand"+ , "two hundred thousand nickels"+ ]+ , examples (simple AUD 1)+ [ "four quarters"+ , "ten dimes"+ , "twenty nickels"+ ]+ , examples (simple AUD 0.1)+ [ "dime"+ , "a dime"+ , "two nickels"+ ]+ , examples (simple AUD 0.25)+ [ "quarter"+ , "a quarter"+ , "five nickels"+ ]+ , examples (simple AUD 0.05)+ [ "nickel"+ , "a nickel" ] ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-} {-# LANGUAGE LambdaCase #-}@@ -13,17 +12,22 @@ ( rules ) where +import Data.HashMap.Strict (HashMap) import Data.String+import Data.Text (Text) import Prelude import Duckling.AmountOfMoney.Helpers import Duckling.AmountOfMoney.Types (Currency(..)) import Duckling.Numeral.Helpers (isPositive)+import Duckling.Regex.Types import Duckling.Types +import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text+import qualified Duckling.AmountOfMoney.Helpers as Helpers import qualified Duckling.Numeral.Types as TNumeral - ruleAGrand :: Rule ruleAGrand = Rule { name = "a grand"@@ -46,8 +50,22 @@ _ -> Nothing } +ruleDollarCoin :: Rule+ruleDollarCoin = Rule+ { name = "dollar coin"+ , pattern =+ [ regex "(nickel|dime|quarter)s?"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) -> do+ c <- HashMap.lookup (Text.toLower match) Helpers.dollarCoins+ Just . Token AmountOfMoney . withValue c $ currencyOnly AUD+ _ -> Nothing+ }+ rules :: [Rule] rules = [ ruleAGrand , ruleGrand+ , ruleDollarCoin ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-} @@ -27,6 +26,26 @@ ] , examples (simple Dollar 10000) [ "10 grand"+ , "two hundred thousand nickels"+ ]+ , examples (simple Dollar 1)+ [ "four quarters"+ , "ten dimes"+ , "twenty nickels"+ ]+ , examples (simple Dollar 0.1)+ [ "dime"+ , "a dime"+ , "two nickels"+ ]+ , examples (simple Dollar 0.25)+ [ "quarter"+ , "a quarter"+ , "five nickels"+ ]+ , examples (simple Dollar 0.05)+ [ "nickel"+ , "a nickel" ] ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-} {-# LANGUAGE LambdaCase #-}@@ -13,17 +12,22 @@ ( rules ) where +import Data.HashMap.Strict (HashMap) import Data.String+import Data.Text (Text) import Prelude import Duckling.AmountOfMoney.Helpers import Duckling.AmountOfMoney.Types (Currency(..)) import Duckling.Numeral.Helpers (isPositive)+import Duckling.Regex.Types import Duckling.Types +import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text+import qualified Duckling.AmountOfMoney.Helpers as Helpers import qualified Duckling.Numeral.Types as TNumeral - ruleAGrand :: Rule ruleAGrand = Rule { name = "a grand"@@ -48,8 +52,22 @@ _ -> Nothing } +ruleDollarCoin :: Rule+ruleDollarCoin = Rule+ { name = "dollar coin"+ , pattern =+ [ regex "(nickel|dime|quarter)s?"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) -> do+ c <- HashMap.lookup (Text.toLower match) Helpers.dollarCoins+ Just . Token AmountOfMoney . withValue c $ currencyOnly Dollar+ _ -> Nothing+ }+ rules :: [Rule] rules = [ ruleAGrand , ruleGrand+ , ruleDollarCoin ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-} @@ -27,6 +26,26 @@ ] , examples (simple CAD 10000) [ "10 grand"+ , "two hundred thousand nickels"+ ]+ , examples (simple CAD 1)+ [ "four quarters"+ , "ten dimes"+ , "twenty nickels"+ ]+ , examples (simple CAD 0.1)+ [ "dime"+ , "a dime"+ , "two nickels"+ ]+ , examples (simple CAD 0.25)+ [ "quarter"+ , "a quarter"+ , "five nickels"+ ]+ , examples (simple CAD 0.05)+ [ "nickel"+ , "a nickel" ] ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-} {-# LANGUAGE LambdaCase #-}@@ -13,17 +12,22 @@ ( rules ) where +import Data.HashMap.Strict (HashMap) import Data.String+import Data.Text (Text) import Prelude import Duckling.AmountOfMoney.Helpers import Duckling.AmountOfMoney.Types (Currency(..)) import Duckling.Numeral.Helpers (isPositive)+import Duckling.Regex.Types import Duckling.Types +import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text+import qualified Duckling.AmountOfMoney.Helpers as Helpers import qualified Duckling.Numeral.Types as TNumeral - ruleAGrand :: Rule ruleAGrand = Rule { name = "a grand"@@ -46,8 +50,22 @@ _ -> Nothing } +ruleDollarCoin :: Rule+ruleDollarCoin = Rule+ { name = "dollar coin"+ , pattern =+ [ regex "(nickel|dime|quarter)s?"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) -> do+ c <- HashMap.lookup (Text.toLower match) Helpers.dollarCoins+ Just . Token AmountOfMoney . withValue c $ currencyOnly CAD+ _ -> Nothing+ }+ rules :: [Rule] rules = [ ruleAGrand , ruleGrand+ , ruleDollarCoin ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -11,12 +10,14 @@ module Duckling.AmountOfMoney.EN.Corpus ( corpus , negativeCorpus+ , latentCorpus ) where import Data.String import Prelude import Duckling.AmountOfMoney.Types+import Duckling.Resolve (Options(..)) import Duckling.Testing.Types negativeCorpus :: NegativeCorpus@@ -29,6 +30,21 @@ corpus :: Corpus corpus = (testContext, testOptions, allExamples) +latentCorpus :: Corpus+latentCorpus = (testContext, testOptions {withLatent = True}, xs)+ where+ xs = concat+ [ examples (simple Unnamed 5)+ [ "five"+ , "5"+ , "about 5"+ ]+ , examples (simple Unnamed 7.2)+ [ "7.2"+ , "7.20000"+ ]+ ]+ allExamples :: [Example] allExamples = concat [ examples (simple Dollar 1)@@ -59,6 +75,7 @@ [ "USD3.14" , "3.14US$" , "US$ 3.14"+ , "US$3 and fourteen" ] , examples (simple EUR 20) [ "20\x20ac"@@ -98,7 +115,24 @@ [ "GBP3.01" , "GBP 3.01" , "3 GBP 1 pence"+ , "3 GBP and one" ]+ , examples (simple CAD 3.03)+ [ "CAD3.03"+ , "CAD 3.03"+ , "3 CAD 3 cents"+ ]+ , examples (simple CHF 3.04)+ [ "CHF3.04"+ , "CHF 3.04"+ , "3 CHF 4 cents"+ ]+ , examples (simple CNY 3)+ [ "CNY3"+ , "CNY 3"+ , "3 CNY"+ , "3 yuan"+ ] , examples (simple Unnamed 42) [ "42 bucks" , "around 42 bucks"@@ -115,6 +149,12 @@ , examples (simple EGP 42) [ "42 EGP" , "42 egyptianpound"+ , "42 LE"+ , "42 L.E"+ , "42 l.e."+ , "42 le"+ , "42 geneh"+ , "42 genihat masriya" ] , examples (simple QAR 42) [ "42 QAR"@@ -186,11 +226,40 @@ [ "under seven euros" , "less than 7 EUR" , "lower than 7€"+ , "no more than 7 euros"+ , "at most 7€" ] , examples (above Dollar 1.42) [ "more than 1 dollar and forty-two cents" , "at least $1.42" , "over 1.42 dollars" , "above a dollar and 42 cents"+ , "no less than $1.42"+ ]+ , examples (simple INR 5e5)+ [ "5 lakh rupees"+ , "five lakhs rupees"+ ]+ , examples (between INR (7, 9e5))+ [ "7-9 lakh rupees"+ ]+ , examples (simple INR 4e7)+ [ "four crore rupees"+ , "4 crores rupees"+ ]+ , examples (simple MNT 10)+ [ "ten tugriks"+ , "10 Tugrik"+ , "10MNT"+ ]+ , examples (simple USD 4.7e9)+ [ "US$4.7 billion"+ , "a US$4.7 billion"+ , "a US$ 4.7 billion"+ ]+ , examples (simple UAH 3.04)+ [ "UAH3.04"+ , "UAH 3.04"+ , "3 UAH 4 kopiykas" ] ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-} @@ -27,6 +26,25 @@ ] , examples (simple GBP 10000) [ "10 grand"+ ]+ , examples (simple Dollar 1)+ [ "four quarters"+ , "ten dimes"+ , "twenty nickels"+ ]+ , examples (simple Dollar 0.1)+ [ "dime"+ , "a dime"+ , "two nickels"+ ]+ , examples (simple Dollar 0.25)+ [ "quarter"+ , "a quarter"+ , "five nickels"+ ]+ , examples (simple Dollar 0.05)+ [ "nickel"+ , "a nickel" ] ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-} {-# LANGUAGE LambdaCase #-}@@ -13,17 +12,22 @@ ( rules ) where +import Data.HashMap.Strict (HashMap) import Data.String+import Data.Text (Text) import Prelude import Duckling.AmountOfMoney.Helpers import Duckling.AmountOfMoney.Types (Currency(..)) import Duckling.Numeral.Helpers (isPositive)+import Duckling.Regex.Types import Duckling.Types +import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text+import qualified Duckling.AmountOfMoney.Helpers as Helpers import qualified Duckling.Numeral.Types as TNumeral - ruleAGrand :: Rule ruleAGrand = Rule { name = "a grand"@@ -46,8 +50,22 @@ _ -> Nothing } +ruleDollarCoin :: Rule+ruleDollarCoin = Rule+ { name = "dollar coin"+ , pattern =+ [ regex "(nickel|dime|quarter)s?"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) -> do+ c <- HashMap.lookup (Text.toLower match) Helpers.dollarCoins+ Just . Token AmountOfMoney . withValue c $ currencyOnly Dollar+ _ -> Nothing+ }+ rules :: [Rule] rules = [ ruleAGrand , ruleGrand+ , ruleDollarCoin ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-} @@ -27,6 +26,26 @@ ] , examples (simple Dollar 10000) [ "10 grand"+ , "two hundred thousand nickels"+ ]+ , examples (simple Dollar 1)+ [ "four quarters"+ , "ten dimes"+ , "twenty nickels"+ ]+ , examples (simple Dollar 0.1)+ [ "dime"+ , "a dime"+ , "two nickels"+ ]+ , examples (simple Dollar 0.25)+ [ "quarter"+ , "a quarter"+ , "five nickels"+ ]+ , examples (simple Dollar 0.05)+ [ "nickel"+ , "a nickel" ] ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-} {-# LANGUAGE LambdaCase #-}@@ -13,14 +12,20 @@ ( rules ) where +import Data.HashMap.Strict (HashMap) import Data.String+import Data.Text (Text) import Prelude import Duckling.AmountOfMoney.Helpers import Duckling.AmountOfMoney.Types (Currency(..)) import Duckling.Numeral.Helpers (isPositive)+import Duckling.Regex.Types import Duckling.Types +import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text+import qualified Duckling.AmountOfMoney.Helpers as Helpers import qualified Duckling.Numeral.Types as TNumeral @@ -48,8 +53,22 @@ _ -> Nothing } +ruleDollarCoin :: Rule+ruleDollarCoin = Rule+ { name = "dollar coin"+ , pattern =+ [ regex "(nickel|dime|quarter)s?"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) -> do+ c <- HashMap.lookup (Text.toLower match) Helpers.dollarCoins+ Just . Token AmountOfMoney . withValue c $ currencyOnly Dollar+ _ -> Nothing+ }+ rules :: [Rule] rules = [ ruleAGrand , ruleGrand+ , ruleDollarCoin ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-} @@ -27,6 +26,26 @@ ] , examples (simple Dollar 10000) [ "10 grand"+ , "two hundred thousand nickels"+ ]+ , examples (simple Dollar 1)+ [ "four quarters"+ , "ten dimes"+ , "twenty nickels"+ ]+ , examples (simple Dollar 0.1)+ [ "dime"+ , "a dime"+ , "two nickels"+ ]+ , examples (simple Dollar 0.25)+ [ "quarter"+ , "a quarter"+ , "five nickels"+ ]+ , examples (simple Dollar 0.05)+ [ "nickel"+ , "a nickel" ] ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-} {-# LANGUAGE LambdaCase #-}@@ -13,17 +12,22 @@ ( rules ) where +import Data.HashMap.Strict (HashMap) import Data.String+import Data.Text (Text) import Prelude import Duckling.AmountOfMoney.Helpers import Duckling.AmountOfMoney.Types (Currency(..)) import Duckling.Numeral.Helpers (isPositive)+import Duckling.Regex.Types import Duckling.Types +import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text+import qualified Duckling.AmountOfMoney.Helpers as Helpers import qualified Duckling.Numeral.Types as TNumeral - ruleAGrand :: Rule ruleAGrand = Rule { name = "a grand"@@ -46,8 +50,22 @@ _ -> Nothing } +ruleDollarCoin :: Rule+ruleDollarCoin = Rule+ { name = "dollar coin"+ , pattern =+ [ regex "(nickel|dime|quarter)s?"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) -> do+ c <- HashMap.lookup (Text.toLower match) Helpers.dollarCoins+ Just . Token AmountOfMoney . withValue c $ currencyOnly Dollar+ _ -> Nothing+ }+ rules :: [Rule] rules = [ ruleAGrand , ruleGrand+ , ruleDollarCoin ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-} @@ -27,9 +26,28 @@ ] , examples (simple JMD 10000) [ "10 grand"+ , "two hundred thousand nickels" ]+ , examples (simple JMD 1)+ [ "four quarters"+ , "ten dimes"+ , "twenty nickels"+ ]+ , examples (simple JMD 0.1)+ [ "dime"+ , "a dime"+ , "two nickels"+ ]+ , examples (simple JMD 0.25)+ [ "quarter"+ , "a quarter"+ , "five nickels"+ ]+ , examples (simple JMD 0.05)+ [ "nickel"+ , "a nickel"+ ] ]- negativeExamples :: [Text] negativeExamples = [ "grand"
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-} {-# LANGUAGE LambdaCase #-}@@ -13,17 +12,22 @@ ( rules ) where +import Data.HashMap.Strict (HashMap) import Data.String+import Data.Text (Text) import Prelude import Duckling.AmountOfMoney.Helpers import Duckling.AmountOfMoney.Types (Currency(..)) import Duckling.Numeral.Helpers (isPositive)+import Duckling.Regex.Types import Duckling.Types +import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text+import qualified Duckling.AmountOfMoney.Helpers as Helpers import qualified Duckling.Numeral.Types as TNumeral - ruleAGrand :: Rule ruleAGrand = Rule { name = "a grand"@@ -48,8 +52,22 @@ _ -> Nothing } +ruleDollarCoin :: Rule+ruleDollarCoin = Rule+ { name = "dollar coin"+ , pattern =+ [ regex "(nickel|dime|quarter)s?"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) -> do+ c <- HashMap.lookup (Text.toLower match) Helpers.dollarCoins+ Just . Token AmountOfMoney . withValue c $ currencyOnly JMD+ _ -> Nothing+ }+ rules :: [Rule] rules = [ ruleAGrand , ruleGrand+ , ruleDollarCoin ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-} @@ -27,6 +26,26 @@ ] , examples (simple NZD 10000) [ "10 grand"+ , "two hundred thousand nickels"+ ]+ , examples (simple NZD 1)+ [ "four quarters"+ , "ten dimes"+ , "twenty nickels"+ ]+ , examples (simple NZD 0.1)+ [ "dime"+ , "a dime"+ , "two nickels"+ ]+ , examples (simple NZD 0.25)+ [ "quarter"+ , "a quarter"+ , "five nickels"+ ]+ , examples (simple NZD 0.05)+ [ "nickel"+ , "a nickel" ] ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-} {-# LANGUAGE LambdaCase #-}@@ -13,17 +12,22 @@ ( rules ) where +import Data.HashMap.Strict (HashMap) import Data.String+import Data.Text (Text) import Prelude import Duckling.AmountOfMoney.Helpers import Duckling.AmountOfMoney.Types (Currency(..)) import Duckling.Numeral.Helpers (isPositive)+import Duckling.Regex.Types import Duckling.Types +import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text+import qualified Duckling.AmountOfMoney.Helpers as Helpers import qualified Duckling.Numeral.Types as TNumeral - ruleAGrand :: Rule ruleAGrand = Rule { name = "a grand"@@ -48,8 +52,22 @@ _ -> Nothing } +ruleDollarCoin :: Rule+ruleDollarCoin = Rule+ { name = "dollar coin"+ , pattern =+ [ regex "(nickel|dime|quarter)s?"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) -> do+ c <- HashMap.lookup (Text.toLower match) Helpers.dollarCoins+ Just . Token AmountOfMoney . withValue c $ currencyOnly NZD+ _ -> Nothing+ }+ rules :: [Rule] rules = [ ruleAGrand , ruleGrand+ , ruleDollarCoin ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-} @@ -27,6 +26,26 @@ ] , examples (simple Dollar 10000) [ "10 grand"+ , "two hundred thousand nickels"+ ]+ , examples (simple Dollar 1)+ [ "four quarters"+ , "ten dimes"+ , "twenty nickels"+ ]+ , examples (simple Dollar 0.1)+ [ "dime"+ , "a dime"+ , "two nickels"+ ]+ , examples (simple Dollar 0.25)+ [ "quarter"+ , "a quarter"+ , "five nickels"+ ]+ , examples (simple Dollar 0.05)+ [ "nickel"+ , "a nickel" ] ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-} {-# LANGUAGE LambdaCase #-}@@ -13,17 +12,22 @@ ( rules ) where +import Data.HashMap.Strict (HashMap) import Data.String+import Data.Text (Text) import Prelude import Duckling.AmountOfMoney.Helpers import Duckling.AmountOfMoney.Types (Currency(..)) import Duckling.Numeral.Helpers (isPositive)+import Duckling.Regex.Types import Duckling.Types +import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text+import qualified Duckling.AmountOfMoney.Helpers as Helpers import qualified Duckling.Numeral.Types as TNumeral - ruleAGrand :: Rule ruleAGrand = Rule { name = "a grand"@@ -48,8 +52,22 @@ _ -> Nothing } +ruleDollarCoin :: Rule+ruleDollarCoin = Rule+ { name = "dollar coin"+ , pattern =+ [ regex "(nickel|dime|quarter)s?"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) -> do+ c <- HashMap.lookup (Text.toLower match) dollarCoins+ Just . Token AmountOfMoney . withValue c $ Helpers.currencyOnly Dollar+ _ -> Nothing+ }+ rules :: [Rule] rules = [ ruleAGrand , ruleGrand+ , ruleDollarCoin ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -66,6 +65,24 @@ _ -> Nothing } +ruleEgpAbrreviation :: Rule+ruleEgpAbrreviation = Rule+ { name = "livre égyptienne"+ , pattern =+ [ regex "[lL].?[eE].?"+ ]+ , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly EGP+ }++ruleEgpArabizi :: Rule+ruleEgpArabizi = Rule+ { name = "geneh"+ , pattern =+ [ regex "[Gg][eiy]*n[eiy]*h(at)?( m[aiey]?sr[eiy]+a?)?"+ ]+ , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly EGP+ }+ ruleRiyals :: Rule ruleRiyals = Rule { name = "riyals"@@ -111,6 +128,15 @@ , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly MYR } +ruleHryvnia :: Rule+ruleHryvnia = Rule+ { name = "hryvnia"+ , pattern =+ [ regex "hryvnia" -- TODO: complete+ ]+ , prod = \_ -> Just $ Token AmountOfMoney $ currencyOnly UAH+ }+ ruleCent :: Rule ruleCent = Rule { name = "cent"@@ -120,6 +146,15 @@ , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly Cent } +ruleKopiyka :: Rule+ruleKopiyka = Rule+ { name = "kopiyka"+ , pattern =+ [ regex "kopiy(ok|kas?)"+ ]+ , prod = \_ -> Just $ Token AmountOfMoney $ currencyOnly Cent+ }+ ruleBucks :: Rule ruleBucks = Rule { name = "bucks"@@ -143,6 +178,47 @@ _ -> Nothing } +ruleAbsorbA :: Rule+ruleAbsorbA = Rule+ { name = "a <amount-of-money>"+ , pattern =+ [ regex "an?"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \case+ (_:Token AmountOfMoney fd:_) -> Just $ Token AmountOfMoney fd+ _ -> Nothing+ }++ruleADollarCoin :: Rule+ruleADollarCoin = Rule+ { name = "a <dollar coin>"+ , pattern =+ [ regex "an?"+ , Predicate isDollarCoin+ ]+ , prod = \tokens -> case tokens of+ (_:+ Token AmountOfMoney fd:+ _) -> Just . Token AmountOfMoney $ fd+ _ -> Nothing+ }++ruleNumDollarCoins :: Rule+ruleNumDollarCoins = Rule+ { name = "X <dollar coins>"+ , pattern =+ [ Predicate isNatural+ , Predicate isDollarCoin+ ]+ , prod = \tokens -> case tokens of+ (Token Numeral NumeralData{TNumeral.value = c}:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just d,+ TAmountOfMoney.currency = cur}:+ _) -> Just . Token AmountOfMoney $ withValue (c * d) $ currencyOnly cur+ _ -> Nothing+ }+ ruleIntersectAndXCents :: Rule ruleIntersectAndXCents = Rule { name = "intersect (and X cents)"@@ -297,7 +373,7 @@ ruleIntervalMax = Rule { name = "under/less/lower/no more than <amount-of-money>" , pattern =- [ regex "under|(less|lower|not? more) than"+ [ regex "under|at most|(less|lower|not? more) than" , Predicate isSimpleAmountOfMoney ] , prod = \tokens -> case tokens of@@ -312,7 +388,7 @@ ruleIntervalMin = Rule { name = "over/above/at least/more than <amount-of-money>" , pattern =- [ regex "over|above|at least|more than"+ [ regex "over|above|at least|(more|not? less) than" , Predicate isSimpleAmountOfMoney ] , prod = \tokens -> case tokens of@@ -327,10 +403,14 @@ rules = [ ruleUnitAmount , ruleACurrency+ , ruleAbsorbA , ruleBucks , ruleCent+ , ruleADollarCoin+ , ruleNumDollarCoins , ruleDinars , ruleDirham+ , ruleHryvnia , ruleIntersect , ruleIntersectAndNumeral , ruleIntersectAndXCents@@ -341,7 +421,10 @@ , ruleIntervalMin , ruleIntervalNumeralDash , ruleIntervalDash+ , ruleKopiyka , ruleOtherPounds+ , ruleEgpAbrreviation+ , ruleEgpArabizi , rulePounds , rulePrecision , ruleRinggit
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-} @@ -27,6 +26,26 @@ ] , examples (simple TTD 10000) [ "10 grand"+ , "two hundred thousand nickels"+ ]+ , examples (simple TTD 1)+ [ "four quarters"+ , "ten dimes"+ , "twenty nickels"+ ]+ , examples (simple TTD 0.1)+ [ "dime"+ , "a dime"+ , "two nickels"+ ]+ , examples (simple TTD 0.25)+ [ "quarter"+ , "a quarter"+ , "five nickels"+ ]+ , examples (simple TTD 0.05)+ [ "nickel"+ , "a nickel" ] ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-} {-# LANGUAGE LambdaCase #-}@@ -13,17 +12,22 @@ ( rules ) where +import Data.HashMap.Strict (HashMap) import Data.String+import Data.Text (Text) import Prelude import Duckling.AmountOfMoney.Helpers import Duckling.AmountOfMoney.Types (Currency(..)) import Duckling.Numeral.Helpers (isPositive)+import Duckling.Regex.Types import Duckling.Types +import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text+import qualified Duckling.AmountOfMoney.Helpers as Helpers import qualified Duckling.Numeral.Types as TNumeral - ruleAGrand :: Rule ruleAGrand = Rule { name = "a grand"@@ -48,8 +52,22 @@ _ -> Nothing } +ruleDollarCoin :: Rule+ruleDollarCoin = Rule+ { name = "dollar coin"+ , pattern =+ [ regex "(nickel|dime|quarter)s?"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) -> do+ c <- HashMap.lookup (Text.toLower match) Helpers.dollarCoins+ Just . Token AmountOfMoney . withValue c $ currencyOnly TTD+ _ -> Nothing+ }+ rules :: [Rule] rules = [ ruleAGrand , ruleGrand+ , ruleDollarCoin ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-} @@ -27,6 +26,26 @@ ] , examples (simple USD 10000) [ "10 grand"+ , "two hundred thousand nickels"+ ]+ , examples (simple USD 1)+ [ "four quarters"+ , "ten dimes"+ , "twenty nickels"+ ]+ , examples (simple USD 0.1)+ [ "dime"+ , "a dime"+ , "two nickels"+ ]+ , examples (simple USD 0.25)+ [ "quarter"+ , "a quarter"+ , "five nickels"+ ]+ , examples (simple USD 0.05)+ [ "nickel"+ , "a nickel" ] ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-} {-# LANGUAGE LambdaCase #-}@@ -13,17 +12,22 @@ ( rules ) where +import Data.HashMap.Strict (HashMap) import Data.String+import Data.Text (Text) import Prelude import Duckling.AmountOfMoney.Helpers import Duckling.AmountOfMoney.Types (Currency(..)) import Duckling.Numeral.Helpers (isPositive)+import Duckling.Regex.Types import Duckling.Types +import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text+import qualified Duckling.AmountOfMoney.Helpers as Helpers import qualified Duckling.Numeral.Types as TNumeral - ruleAGrand :: Rule ruleAGrand = Rule { name = "a grand"@@ -46,8 +50,22 @@ _ -> Nothing } +ruleDollarCoin :: Rule+ruleDollarCoin = Rule+ { name = "dollar coin"+ , pattern =+ [ regex "(nickel|dime|quarter)s?"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) -> do+ c <- HashMap.lookup (Text.toLower match) Helpers.dollarCoins+ Just . Token AmountOfMoney . withValue c $ currencyOnly USD+ _ -> Nothing+ }+ rules :: [Rule] rules = [ ruleAGrand , ruleGrand+ , ruleDollarCoin ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-} @@ -27,6 +26,26 @@ ] , examples (simple Dollar 10000) [ "10 grand"+ , "two hundred thousand nickels"+ ]+ , examples (simple Dollar 1)+ [ "four quarters"+ , "ten dimes"+ , "twenty nickels"+ ]+ , examples (simple Dollar 0.1)+ [ "dime"+ , "a dime"+ , "two nickels"+ ]+ , examples (simple Dollar 0.25)+ [ "quarter"+ , "a quarter"+ , "five nickels"+ ]+ , examples (simple Dollar 0.05)+ [ "nickel"+ , "a nickel" ] ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-} {-# LANGUAGE LambdaCase #-}@@ -13,17 +12,22 @@ ( rules ) where +import Data.HashMap.Strict (HashMap) import Data.String+import Data.Text (Text) import Prelude import Duckling.AmountOfMoney.Helpers import Duckling.AmountOfMoney.Types (Currency(..)) import Duckling.Numeral.Helpers (isPositive)+import Duckling.Regex.Types import Duckling.Types +import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text+import qualified Duckling.AmountOfMoney.Helpers as Helpers import qualified Duckling.Numeral.Types as TNumeral - ruleAGrand :: Rule ruleAGrand = Rule { name = "a grand"@@ -48,8 +52,22 @@ _ -> Nothing } +ruleDollarCoin :: Rule+ruleDollarCoin = Rule+ { name = "dollar coin"+ , pattern =+ [ regex "(nickel|dime|quarter)s?"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) -> do+ c <- HashMap.lookup (Text.toLower match) Helpers.dollarCoins+ Just . Token AmountOfMoney . withValue c $ currencyOnly Dollar+ _ -> Nothing+ }+ rules :: [Rule] rules = [ ruleAGrand , ruleGrand+ , ruleDollarCoin ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -64,5 +63,19 @@ [ "15 Pt" , "15pta" , "15Ptas"+ ]+ , examples (between Dollar (10, 20))+ [ "entre 10 y 20 dólares"+ , "de $10 y $20"+ , "$10 - 20 dólares"+ , "10 - 20 $"+ ]+ , examples (under Dollar 10)+ [ "menos de 10 dólares"+ , "no más de $10"+ ]+ , examples (above Dollar 10)+ [ "no menos de 10 dólares"+ , "más de $10" ] ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -128,6 +127,114 @@ _ -> Nothing } +ruleIntervalBetweenNumeral :: Rule+ruleIntervalBetweenNumeral = Rule+ { name = "between|from <numeral> to|and <amount-of-money>"+ , pattern =+ [ regex "de|entre"+ , Predicate isPositive+ , regex "a|y"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \case+ (_:+ Token Numeral NumeralData{TNumeral.value = from}:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c}:+ _) | from < to ->+ Just $ Token AmountOfMoney $ withInterval (from, to) $ currencyOnly c+ _ -> Nothing+ }++ruleIntervalBetween :: Rule+ruleIntervalBetween = Rule+ { name = "between|from <amount-of-money> to|and <amount-of-money>"+ , pattern =+ [ regex "de|entre"+ , Predicate isSimpleAmountOfMoney+ , regex "a|y"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \case+ (_:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just from,+ TAmountOfMoney.currency = c1}:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c2}:+ _) | from < to && c1 == c2 ->+ Just $ Token AmountOfMoney $ withInterval (from, to) $ currencyOnly c1+ _ -> Nothing+ }++ruleIntervalNumeralDash :: Rule+ruleIntervalNumeralDash = Rule+ { name = "<numeral> - <amount-of-money>"+ , pattern =+ [ Predicate isNatural+ , regex "-"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = from}:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c}:+ _) | from < to->+ Just $ Token AmountOfMoney $ withInterval (from, to) $ currencyOnly c+ _ -> Nothing+ }++ruleIntervalDash :: Rule+ruleIntervalDash = Rule+ { name = "<amount-of-money> - <amount-of-money>"+ , pattern =+ [ Predicate isSimpleAmountOfMoney+ , regex "-"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \case+ (Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just from,+ TAmountOfMoney.currency = c1}:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c2}:+ _) | from < to && c1 == c2 ->+ Just $ Token AmountOfMoney $ withInterval (from, to) $ currencyOnly c1+ _ -> Nothing+ }++ruleIntervalMax :: Rule+ruleIntervalMax = Rule+ { name = "less/no more than <amount-of-money>"+ , pattern =+ [ regex "menos de|no más de"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \case+ (_:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c}:+ _) -> Just $ Token AmountOfMoney $ withMax to $ currencyOnly c+ _ -> Nothing+ }++ruleIntervalMin :: Rule+ruleIntervalMin = Rule+ { name = "no less/more than <amount-of-money>"+ , pattern =+ [ regex "más de|no menos de"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \case+ (_:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c}:+ _) -> Just $ Token AmountOfMoney $ withMin to $ currencyOnly c+ _ -> Nothing+ }+ rules :: [Rule] rules = [ ruleUnitAmount@@ -138,4 +245,10 @@ , ruleIntersectAndXCents , ruleIntersectXCents , rulePounds+ , ruleIntervalBetweenNumeral+ , ruleIntervalBetween+ , ruleIntervalNumeralDash+ , ruleIntervalDash+ , ruleIntervalMax+ , ruleIntervalMin ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -205,7 +204,6 @@ _) -> Just . Token AmountOfMoney . withMin to $ currencyOnly c _ -> Nothing }- rulePounds :: Rule rulePounds = Rule
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -0,0 +1,124 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.++{-# LANGUAGE OverloadedStrings #-}++module Duckling.AmountOfMoney.HE.Corpus+ ( corpus+ ) where++import Data.String+import Prelude++import Duckling.AmountOfMoney.Types+import Duckling.Locale+import Duckling.Resolve+import Duckling.Testing.Types++corpus :: Corpus+corpus =+ (testContext { locale = makeLocale HE Nothing }, testOptions, allExamples)++allExamples :: [Example]+allExamples = concat+ [ examples (simple ILS 10)+ [ "עשר שקל"+ , "עשרה שקלים"+ , "עשר ש״ח"+ , "עשר שח"+ , "10₪"+ ]+ , examples (simple ILS 10000)+ [ "עשר אלף שקל"+ , "10000 שקלים"+ , "10 אשח"+ , "10 אש״ח"+ ]+ , examples (simple ILS 10000000)+ [ "10 מיליון שקלים"+ , "10 משח"+ , "10 מש״ח"+ ]+ , examples (simple ILS 0.01)+ [ "אגורה"+ ]+ , examples (simple ILS 1)+ [ "שקל"+ , "שקל אחד"+ , "שקל בודד"+ , "100 אגורות"+ ]+ , examples (simple ILS 0.05)+ [ "חמש אגורות"+ ]+ , examples (simple ILS 0)+ [ "אפס ש״ח"+ ]+ , examples (simple ILS 1.5)+ [ "שקל וחצי"+ , "1.5 ש״ח"+ ]+ , examples (simple ILS 2)+ [ "שנקל"+ , "2 שקל"+ ]+ , examples (simple Dollar 10)+ [ "$10"+ , "10$"+ , "עשר דולר"+ , "עשרה דולר"+ , "עשרה דולרים"+ , "עשר דולרים"+ ]+ , examples (simple Dollar 20)+ [ "עשרים דולר"+ ]+ , examples (simple Dollar 2.23)+ [ "2 דולר ו23 סנט"+ ]+ , examples (simple EUR 20)+ [ "20€"+ , "20 יורו"+ , "EUR 20"+ , "20 אירו"+ ]+ , examples (simple EUR 29.99)+ [ "29.99 יורו"+ ]+ , examples (simple Pound 9)+ [ "£9"+ , "תשע פאונד"+ ]+ , examples (simple GBP 1)+ [ "לירה שטרלינג"+ ]+ , examples (simple GBP 10)+ [ "10 לירות שטרלינג"+ ]+ , examples (between Dollar (10, 20))+ [ "מ10 עד 20 דולר"+ , "מעשר עד עשרים דולר"+ , "בין 10 ל20 דולר"+ , "10$-20$"+ , "10-20$"+ , "10-20 דולר"+ , "בין 10 דולר ל20 דולר"+ ]+ , examples (under EUR 7)+ [ "פחות מ7 יורו"+ , "עד 7 יורו"+ , "לא יותר מ7 יורו"+ , "מתחת ל7 יורו"+ , "לא מעל 7 יורו"+ ]+ , examples (above Dollar 5)+ [ "יותר מ5 דולר"+ , "מעל 5 דולר"+ , "מ5 דולר"+ , "לא פחות מ5 דולר"+ , "לא מתחת ל5 דולר"+ ]+ ]
@@ -0,0 +1,348 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+module Duckling.AmountOfMoney.HE.Rules+ ( rules+ ) where++import Data.Maybe+import Data.String+import Prelude++import Duckling.AmountOfMoney.Helpers+import Duckling.AmountOfMoney.Types+ ( Currency(..)+ , AmountOfMoneyData(..)+ )+import Duckling.Dimensions.Types+import Duckling.Numeral.Helpers+ ( isPositive+ )+import Duckling.Numeral.Types (NumeralData(..))+import Duckling.Types+import qualified Duckling.AmountOfMoney.Types as TAmountOfMoney+import qualified Duckling.Numeral.Types as TNumeral++ruleUnitAmount :: Rule+ruleUnitAmount = Rule+ { name = "<unit> <amount>"+ , pattern =+ [ Predicate isCurrencyOnly+ , Predicate isPositive+ ]+ , prod = \case+ (Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.currency = c}:+ Token Numeral NumeralData{TNumeral.value = v}:+ _) -> Just . Token AmountOfMoney . withValue v $ currencyOnly c+ _ -> Nothing+ }++ruleOneShekel :: Rule+ruleOneShekel = Rule+ { name = "שקל"+ , pattern = [regex "שקל( אחד| בודד)?"]+ , prod = \_ -> Just . Token AmountOfMoney $ withValue 1 $ currencyOnly ILS+ }+ruleTwoShekel :: Rule+ruleTwoShekel = Rule+ { name = "שנקל"+ , pattern = [regex "שנקל"]+ , prod = \_ -> Just . Token AmountOfMoney $ withValue 2 $ currencyOnly ILS+ }+ruleOneAgura :: Rule+ruleOneAgura = Rule+ { name = "oneAgura"+ , pattern = [regex "אגורה( אחת| בודדת)?"]+ , prod = \_ -> Just . Token AmountOfMoney $ withValue 0.01 $+ currencyOnly ILS+ }+ruleShekel :: Rule+ruleShekel = Rule+ { name = "שקל"+ , pattern = [regex "שקל(ים)?|ש״?ח"]+ , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly ILS+ }++ruleThousandShekel :: Rule+ruleThousandShekel = Rule+ { name = "אש״ח"+ , pattern =+ [ Predicate isPositive+ , regex "אש״?ח"+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = v}:+ _) -> Just . Token AmountOfMoney $ withValue (v*1000) $+ currencyOnly ILS+ _ -> Nothing+ }++ruleMillionShekel :: Rule+ruleMillionShekel = Rule+ { name = "מש״ח"+ , pattern =+ [ Predicate isPositive+ , regex "מש״?ח"+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = v}:+ _) -> Just . Token AmountOfMoney $ withValue (v*1000000) $+ currencyOnly ILS+ _ -> Nothing+ }+ruleAgura :: Rule+ruleAgura = Rule+ { name = "multiple agura"+ , pattern =+ [ Predicate isPositive+ , regex "אגורות"+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = v}:+ _) -> Just . Token AmountOfMoney $ withValue (v*0.01) $+ currencyOnly ILS+ _ -> Nothing+ }++ruleIntersect :: Rule+ruleIntersect = Rule+ { name = "intersect"+ , pattern =+ [ Predicate isWithoutCents+ , regex "ו"+ , Predicate isPositive+ ]+ , prod = \case+ (Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just v,+ TAmountOfMoney.currency = c}:+ _:+ Token Numeral NumeralData { TNumeral.value = p }:+ _) -> Just . Token AmountOfMoney $ withValue (v + p) $ currencyOnly c+ _ -> Nothing+ }++ruleIntersectAndXCents :: Rule+ruleIntersectAndXCents = Rule+ { name = "intersect (and X cents)"+ , pattern =+ [ Predicate isWithoutCents+ , regex "ו"+ , Predicate isCents+ ]+ , prod = \case+ (Token AmountOfMoney fd :+ _ :+ Token AmountOfMoney AmountOfMoneyData { TAmountOfMoney.value = Just c }:+ _) -> Just . Token AmountOfMoney $ withCents c fd+ _ -> Nothing+ }++rulePounds :: Rule+rulePounds = Rule+ { name = "£"+ , pattern =+ [ regex "פאונד(ים)?"+ ]+ , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly Pound+ }++ruleDollar :: Rule+ruleDollar = Rule+ { name = "$"+ , pattern =+ [ regex "דולר(ים)?"+ ]+ , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly Dollar+ }++ruleCent :: Rule+ruleCent = Rule+ { name = "cent"+ , pattern =+ [ regex "סנט(ים)?"+ ]+ , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly Cent+ }++ruleEUR :: Rule+ruleEUR = Rule+ { name = "€"+ , pattern =+ [ regex "אירו|יורו"+ ]+ , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly EUR+ }+ruleOneGBP :: Rule+ruleOneGBP = Rule+ { name = "OneGBP"+ , pattern =+ [ regex "לירה שטרלינג"+ ]+ , prod = \_ -> Just . Token AmountOfMoney $ withValue 1 $ currencyOnly GBP+ }+ruleGBP :: Rule+ruleGBP = Rule+ { name = "OneGBP"+ , pattern =+ [ regex "לירות שטרלינג"+ ]+ , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly GBP+ }++rulePrecision :: Rule+rulePrecision = Rule+ { name = "about|exactly <amount-of-money>"+ , pattern =+ [ regex "בערך|בדיוק|קרוב ל"+ , Predicate isMoneyWithValue+ ]+ , prod = \case+ (_:+ token:+ _) -> Just token+ _ -> Nothing+ }++ruleIntervalBetweenNumeral :: Rule+ruleIntervalBetweenNumeral = Rule+ { name = "between|from <numeral> to|and <amount-of-money>"+ , pattern =+ [ regex "מ?|בין "+ , Predicate isPositive+ , regex "עד |ל"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \case+ (_:+ Token Numeral NumeralData { TNumeral.value = from }:+ _:+ Token AmountOfMoney AmountOfMoneyData { TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c }:+ _) | from < to ->+ Just . Token AmountOfMoney . withInterval (from, to) $ currencyOnly c+ _ -> Nothing+ }++ruleIntervalBetween :: Rule+ruleIntervalBetween = Rule+ { name = "between|from <amount-of-money> to|and <amount-of-money>"+ , pattern =+ [ regex "מ?|בין "+ , Predicate isSimpleAmountOfMoney+ , regex "עד |ל"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \case+ (_:+ Token AmountOfMoney AmountOfMoneyData { TAmountOfMoney.value = Just from,+ TAmountOfMoney.currency = c1 }:+ _:+ Token AmountOfMoney AmountOfMoneyData { TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c2 }:+ _) | from < to && c1 == c2 ->+ Just . Token AmountOfMoney . withInterval (from, to) $+ currencyOnly c1+ _ -> Nothing+ }++ruleIntervalNumeralDash :: Rule+ruleIntervalNumeralDash = Rule+ { name = "<numeral> - <amount-of-money>"+ , pattern =+ [ Predicate isPositive+ , regex "-"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \case+ (Token Numeral NumeralData { TNumeral.value = from }:+ _:+ Token AmountOfMoney AmountOfMoneyData { TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c }:+ _) | from < to -> Just . Token AmountOfMoney . withInterval (from, to) $+ currencyOnly c+ _ -> Nothing+ }++ruleIntervalDash :: Rule+ruleIntervalDash = Rule+ { name = "<amount-of-money> - <amount-of-money>"+ , pattern =+ [ Predicate isSimpleAmountOfMoney+ , regex "-"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \case+ (Token AmountOfMoney AmountOfMoneyData { TAmountOfMoney.value = Just from,+ TAmountOfMoney.currency = c1 }:+ _:+ Token AmountOfMoney AmountOfMoneyData { TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c2 }:+ _) | from < to && c1 == c2 ->+ Just . Token AmountOfMoney . withInterval (from, to) $+ currencyOnly c1+ _ -> Nothing+ }++ruleIntervalMax :: Rule+ruleIntervalMax = Rule+ { name = "under/less/lower/no more than <amount-of-money>"+ , pattern =+ [ regex "פחות מ|עד|לא יותר מ|מתחת ל?|לא מעל"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \case+ (_:+ Token AmountOfMoney AmountOfMoneyData { TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c }:+ _) -> Just . Token AmountOfMoney . withMax to $ currencyOnly c+ _ -> Nothing+ }++ruleIntervalMin :: Rule+ruleIntervalMin = Rule+ { name = "over/above/at least/more than <amount-of-money>"+ , pattern =+ [ regex "יותר מ|מעל|מ|לא פחות מ|לא מתחת ל"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \case+ (_:+ Token AmountOfMoney AmountOfMoneyData { TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c }:+ _) -> Just . Token AmountOfMoney . withMin to $ currencyOnly c+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleUnitAmount+ , ruleCent+ , ruleEUR+ , ruleIntersectAndXCents+ , ruleIntervalBetweenNumeral+ , ruleIntervalBetween+ , ruleIntervalMax+ , ruleIntervalMin+ , ruleIntervalNumeralDash+ , ruleIntervalDash+ , rulePounds+ , ruleOneGBP+ , ruleGBP+ , rulePrecision+ , ruleIntersect+ , ruleAgura+ , ruleShekel+ , ruleOneShekel+ , ruleTwoShekel+ , ruleOneAgura+ , ruleThousandShekel+ , ruleMillionShekel+ , ruleDollar+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-} @@ -24,11 +23,18 @@ allExamples :: [Example] allExamples = concat- [ examples (simple Dollar 10)+ [ examples (simple Dollar 1)+ [ "$1"+ , "jedan dolar"+ ]+ , examples (simple Dollar 10) [ "$10" , "10$" , "deset dolara" ]+ , examples (simple Cent 1)+ [ "jedan cent"+ ] , examples (simple Cent 10) [ "deset centa" ]@@ -46,6 +52,9 @@ , "2 dolara 23" , "dva dolara i 23" ]+ , examples (simple HRK 1)+ [ "jedna kuna"+ ] , examples (simple HRK 2.23) [ "2 kune i 23 lipe" , "dvije kune 23 lipe"@@ -62,6 +71,9 @@ , "dvjesto kuna" , "dvjesta kuna" ]+ , examples (simple EUR 1)+ [ "jedan euro"+ ] , examples (simple EUR 20) [ "20€" , "20 euros"@@ -94,4 +106,28 @@ [ "GBP3,01" , "GBP 3,01" ]- ]+ , examples (between Dollar (100, 200))+ [ "od 100 do 200 dolara"+ , "od 100 dolara do 200 dolara"+ , "otprilike 100 do 200 dolara"+ , "otprilike 100 dolara do 200 dolara"+ , "100 dolara - 200 dolara"+ , "100-200 dolara"+ , "oko 100-200 dolara"+ , "u blizini 100-200 dolara"+ , "skoro 100-200 dolara"+ , "približno 100 do 200 dolara"+ , "izmedju 100 i 200 dolara"+ , "izmedju 100 dolara i 200 dolara"+ ]+ , examples (under EUR 7)+ [ "manje od EUR 7"+ , "ispod EUR 7"+ ]+ , examples (above Dollar 1.42)+ [ "više od jednog dolara i četrdeset dva centa"+ , "najmanje 1,42 dolara"+ , "preko 1,42 dolara"+ , "iznad 1,42 dolara"+ ]+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-} {-# LANGUAGE LambdaCase #-}@@ -29,6 +28,20 @@ import qualified Duckling.AmountOfMoney.Types as TAmountOfMoney import qualified Duckling.Numeral.Types as TNumeral +ruleACurrency :: Rule+ruleACurrency = Rule+ { name = "a <currency>"+ , pattern =+ [ regex "jed(an|na|no)"+ , Predicate isCurrencyOnly+ ]+ , prod = \tokens -> case tokens of+ (_:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.currency = c}:+ _) -> Just . Token AmountOfMoney $ withValue 1 $ currencyOnly c+ _ -> Nothing+ }+ ruleUnitAmount :: Rule ruleUnitAmount = Rule { name = "<unit> <amount>"@@ -198,9 +211,172 @@ , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly AED } +rulePrecision :: Rule+rulePrecision = Rule+ { name = "about|exactly <amount-of-money>"+ , pattern =+ [ regex "oko|otprilike|u blizini|skoro|približno"+ , Predicate isMoneyWithValue+ ]+ , prod = \tokens -> case tokens of+ (_:token:_) -> Just token+ _ -> Nothing+ }++ruleIntervalNumeralDash :: Rule+ruleIntervalNumeralDash = Rule+ { name = "<numeral> - <amount-of-money>"+ , pattern =+ [ Predicate isNatural+ , regex "-"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \tokens -> case tokens of+ (Token Numeral NumeralData{TNumeral.value = from}:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c}:+ _) | from < to->+ Just . Token AmountOfMoney . withInterval (from, to) $ currencyOnly c+ _ -> Nothing+ }++ruleIntervalDash :: Rule+ruleIntervalDash = Rule+ { name = "<amount-of-money> - <amount-of-money>"+ , pattern =+ [ Predicate isSimpleAmountOfMoney+ , regex "-"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \tokens -> case tokens of+ (Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just from,+ TAmountOfMoney.currency = c1}:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c2}:+ _) | from < to && c1 == c2 ->+ Just . Token AmountOfMoney . withInterval (from, to) $ currencyOnly c1+ _ -> Nothing+ }++ruleIntervalBetweenNumeral1 :: Rule+ruleIntervalBetweenNumeral1 = Rule+ { name = "between|from <numeral> to|and <amount-of-money>"+ , pattern =+ [ regex "od|otprilike|približno"+ , Predicate isPositive+ , regex "do"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \tokens -> case tokens of+ (_:+ Token Numeral NumeralData{TNumeral.value = from}:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c}:+ _) | from < to ->+ Just . Token AmountOfMoney . withInterval (from, to) $ currencyOnly c+ _ -> Nothing+ }++ruleIntervalBetweenNumeral2 :: Rule+ruleIntervalBetweenNumeral2 = Rule+ { name = "between|from <numeral> to|and <amount-of-money>"+ , pattern =+ [ regex "izmedju"+ , Predicate isPositive+ , regex "i"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \tokens -> case tokens of+ (_:+ Token Numeral NumeralData{TNumeral.value = from}:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c}:+ _) | from < to ->+ Just . Token AmountOfMoney . withInterval (from, to) $ currencyOnly c+ _ -> Nothing+ }++ruleIntervalBetween1 :: Rule+ruleIntervalBetween1 = Rule+ { name = "between|from <amount-of-money> to|and <amount-of-money>"+ , pattern =+ [ regex "od|otprilike"+ , Predicate isSimpleAmountOfMoney+ , regex "do"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \tokens -> case tokens of+ (_:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just from,+ TAmountOfMoney.currency = c1}:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c2}:+ _) | from < to && c1 == c2 ->+ Just . Token AmountOfMoney . withInterval (from, to) $ currencyOnly c1+ _ -> Nothing+ }++ruleIntervalBetween2 :: Rule+ruleIntervalBetween2 = Rule+ { name = "between|from <amount-of-money> to|and <amount-of-money>"+ , pattern =+ [ regex "izmedju"+ , Predicate isSimpleAmountOfMoney+ , regex "i"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \tokens -> case tokens of+ (_:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just from,+ TAmountOfMoney.currency = c1}:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c2}:+ _) | from < to && c1 == c2 ->+ Just . Token AmountOfMoney . withInterval (from, to) $ currencyOnly c1+ _ -> Nothing+ }++ruleIntervalMin :: Rule+ruleIntervalMin = Rule+ { name = "over/above/at least/more than <amount-of-money>"+ , pattern =+ [ regex "više od|najmanje|preko|iznad"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \tokens -> case tokens of+ (_:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c}:+ _) -> Just . Token AmountOfMoney . withMin to $ currencyOnly c+ _ -> Nothing+ }++ruleIntervalMax :: Rule+ruleIntervalMax = Rule+ { name = "under/less/lower/no more than <amount-of-money>"+ , pattern =+ [ regex "ispod|manje od"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \tokens -> case tokens of+ (_:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c}:+ _) -> Just . Token AmountOfMoney . withMax to $ currencyOnly c+ _ -> Nothing+ }++ rules :: [Rule] rules =- [ ruleUnitAmount+ [ ruleACurrency+ , ruleUnitAmount , ruleDollar , rulePound , ruleOtherPounds@@ -215,4 +391,13 @@ , ruleKwd , ruleQar , ruleSar+ , rulePrecision+ , ruleIntervalNumeralDash+ , ruleIntervalDash+ , ruleIntervalBetweenNumeral1+ , ruleIntervalBetweenNumeral2+ , ruleIntervalBetween1+ , ruleIntervalBetween2+ , ruleIntervalMin+ , ruleIntervalMax ]
@@ -2,18 +2,19 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}-+{-# LANGUAGE NamedFieldPuns #-} module Duckling.AmountOfMoney.Helpers ( currencyOnly+ , valueOnly , isSimpleAmountOfMoney , isCent , isCents+ , isDollarCoin , isCurrencyOnly , isDime , isMoneyWithValue@@ -23,18 +24,42 @@ , withMax , withMin , withValue+ , mkLatent+ , dollarCoins ) where +import Data.HashMap.Strict (HashMap) import Data.Maybe (isJust)+import Data.String+import Data.Text (Text) import Prelude -import Duckling.AmountOfMoney.Types (Currency (..), AmountOfMoneyData (..))+import Duckling.AmountOfMoney.Types+ ( Currency (..)+ , AmountOfMoneyData (..)+ , amountOfMoneyData'+ ) import Duckling.Numeral.Types (getIntValue, isInteger) import Duckling.Dimensions.Types import Duckling.Types hiding (Entity(..)) +import qualified Data.HashMap.Strict as HashMap+ -- -----------------------------------------------------------------+-- Dollar coin Types++dollarCoins :: HashMap Text Double+dollarCoins = HashMap.fromList+ [ ("nickel", 0.05)+ , ("nickels", 0.05)+ , ("dime", 0.1)+ , ("dimes", 0.1)+ , ("quarter", 0.25)+ , ("quarters", 0.25)+ ]++-- ----------------------------------------------------------------- -- Patterns isCents :: Predicate@@ -56,6 +81,12 @@ {value = Nothing, minValue = Nothing, maxValue = Nothing}) = True isCurrencyOnly _ = False +isDollarCoin :: Predicate+isDollarCoin (Token AmountOfMoney AmountOfMoneyData{value = Just d, currency}) =+ elem d [0.05, 0.1, 0.25] && elem currency [Dollar, AUD, CAD, JMD,+ NZD, SGD, TTD, USD]+isDollarCoin _ = False+ isSimpleAmountOfMoney :: Predicate isSimpleAmountOfMoney (Token AmountOfMoney AmountOfMoneyData {value = Just _, minValue = Nothing, maxValue = Nothing}) = True@@ -77,17 +108,19 @@ -- Production currencyOnly :: Currency -> AmountOfMoneyData-currencyOnly c = AmountOfMoneyData- {currency = c, value = Nothing, minValue = Nothing, maxValue = Nothing}+currencyOnly c = amountOfMoneyData'{currency = c} +valueOnly :: Double -> AmountOfMoneyData+valueOnly x = amountOfMoneyData'{value = Just x}+ withValue :: Double -> AmountOfMoneyData -> AmountOfMoneyData withValue x fd = fd {value = Just x} withCents :: Double -> AmountOfMoneyData -> AmountOfMoneyData withCents x fd@AmountOfMoneyData {value = Just value} = fd {value = Just $ value + x / 100}-withCents x AmountOfMoneyData {value = Nothing} = AmountOfMoneyData- {value = Just x, currency = Cent, minValue = Nothing, maxValue = Nothing}+withCents x AmountOfMoneyData {value = Nothing} =+ amountOfMoneyData'{value = Just x, currency = Cent} withInterval :: (Double, Double) -> AmountOfMoneyData -> AmountOfMoneyData withInterval (from, to) fd = fd@@ -98,3 +131,6 @@ withMax :: Double -> AmountOfMoneyData -> AmountOfMoneyData withMax x fd = fd {maxValue = Just x}++mkLatent :: AmountOfMoneyData -> AmountOfMoneyData+mkLatent fd = fd {latent = True}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -39,7 +38,7 @@ [ "USD1,23" ] , examples (simple Dollar 2)- [ "2 dola"+ [ "2 dolar" , "dua dolar" ] , examples (simple EUR 20)@@ -79,5 +78,49 @@ [ "10 yen" , "10¥" , "10 ¥."+ ]+ , examples (between Dollar(10, 20))+ [ "antara 10 sampai 20 dolar"+ , "dari 10 dolar sampai 20 dolar"+ , "sekitar 10 sampai 20 dolar"+ , "antara 10 hingga 20 dolar"+ , "sekitar 10 dolar hingga 20 dolar"+ , "kira-kira 10-20 dolar"+ , "10-20 dolar"+ ]+ , examples (between IDR(1000, 10000))+ [ "antara Rp1000 sampai Rp10000"+ , "dari 1000 Rupiah hingga 10000 Rupiah"+ , "sekitar 1000 sampai 10000 Rupiah"+ , "1000-10000 Rupiah"+ , "kira-kira Rp1000 sampai Rp10000"+ , "dari Rp1.000 sampai Rp10.000"+ , "antara 1.000 hingga 10.000 Rupiah"+ , "kira-kira 1.000-10.000 Rupiah"+ , "sekitar 1.000 hingga 10.000 Rupiah"+ ]+ , examples (under EUR 7)+ [ "kurang dari 7 euro"+ , "di bawah EUR 7"+ , "tidak sampai 7 euro"+ , "lebih murah dari EUR 7"+ ]+ , examples (under IDR 500)+ [ "kurang dari 500 Rupiah"+ , "tidak sampai Rp500"+ , "di bawah Rp 500"+ , "lebih murah dari 500 rupiah"+ ]+ , examples (above USD 1.42)+ [ "di atas USD1,42"+ , "lebih dari USD1,42"+ , "melebihi USD1,42"+ , "melewati USD1,42"+ ]+ , examples (above IDR 33000)+ [ "di atas 33.000 Rupiah"+ , "lebih dari Rp33000"+ , "melebihi Rp33.000"+ , "melewati 33000 rupiah" ] ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -91,6 +90,126 @@ , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly JPY } +rulePrecision :: Rule+rulePrecision = Rule+ { name = "about|exactly <amount-of-money>"+ , pattern =+ [ regex "tepatnya|kira-kira|sekitar|hampir"+ , Predicate isMoneyWithValue+ ]+ , prod = \case+ (_:token:_) -> Just token+ _ -> Nothing+ }++ruleIntervalBetweenNumeral :: Rule+ruleIntervalBetweenNumeral = Rule+ { name = "between|from <numeral> to|and <amount-of-money>"+ , pattern =+ [ regex "sekitar|dari|antara"+ , Predicate isPositive+ , regex "sampai|hingga"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \case+ (_:+ Token Numeral NumeralData{TNumeral.value = from}:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c}:+ _) | from < to ->+ Just . Token AmountOfMoney . withInterval (from, to) $ currencyOnly c+ _ -> Nothing+ }++ruleIntervalBetween :: Rule+ruleIntervalBetween = Rule+ { name = "between|from <amount-of-money> to|and <amount-of-money>"+ , pattern =+ [ regex "sekitar|dari|antara|kira-kira"+ , Predicate isSimpleAmountOfMoney+ , regex "sampai|hingga"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \case+ (_:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just from,+ TAmountOfMoney.currency = c1}:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c2}:+ _) | from < to && c1 == c2 ->+ Just . Token AmountOfMoney . withInterval (from, to) $ currencyOnly c1+ _ -> Nothing+ }++ruleIntervalNumeralDash :: Rule+ruleIntervalNumeralDash = Rule+ { name = "<numeral> - <amount-of-money>"+ , pattern =+ [ Predicate isNatural+ , regex "\\-"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = from}:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c}:+ _) | from < to ->+ Just . Token AmountOfMoney . withInterval (from, to) $ currencyOnly c+ _ -> Nothing+ }++ruleIntervalDash :: Rule+ruleIntervalDash = Rule+ { name = "<amount-of-money> - <amount-of-money>"+ , pattern =+ [ Predicate isSimpleAmountOfMoney+ , regex "\\-"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \case+ (Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just from,+ TAmountOfMoney.currency = c1}:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c2}:+ _) | from < to && c1 == c2 ->+ Just . Token AmountOfMoney . withInterval (from, to) $ currencyOnly c1+ _ -> Nothing+ }++ruleIntervalMax :: Rule+ruleIntervalMax = Rule+ { name = "under/less/lower/no more than <amount-of-money>"+ , pattern =+ [ regex "(kurang|lebih murah) dari|tidak sampai|di bawah"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \case+ (_:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c}:+ _) -> Just . Token AmountOfMoney . withMax to $ currencyOnly c+ _ -> Nothing+ }++ruleIntervalMin :: Rule+ruleIntervalMin = Rule+ { name = "over/above/at least/more than <amount-of-money>"+ , pattern =+ [ regex "di atas|lebih dari|melebihi|melewati"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \case+ (_:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c}:+ _) -> Just . Token AmountOfMoney . withMin to $ currencyOnly c+ _ -> Nothing+ }+ rules :: [Rule] rules = [ ruleUnitAmount@@ -99,4 +218,11 @@ , ruleIntersect , ruleJpy , rulePounds+ , rulePrecision+ , ruleIntervalBetweenNumeral+ , ruleIntervalBetween+ , ruleIntervalMax+ , ruleIntervalMin+ , ruleIntervalNumeralDash+ , ruleIntervalDash ]
@@ -0,0 +1,77 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}++module Duckling.AmountOfMoney.IT.Corpus+ ( corpus+ ) where++import Data.String+import Prelude++import Duckling.AmountOfMoney.Types+import Duckling.Locale+import Duckling.Resolve+import Duckling.Testing.Types++corpus :: Corpus+corpus = (testContext {locale = makeLocale IT Nothing}, testOptions, allExamples)++allExamples :: [Example]+allExamples = concat+ [ examples (simple Dollar 10)+ [ "$10"+ , "10$"+ , "dieci dollari"+ ]+ , examples (simple Dollar 10000)+ [ "$10.000"+ , "10K$"+ , "$10k"+ , "10 000 dollari"+ , "10 000,00 $"+ ]+ , examples (simple USD 1.23)+ [ "USD1,23"+ , "1 USD e 23 centesimi"+ , "1 USD 23 centesimi"+ ]+ , examples (simple EUR 20)+ [ "20€"+ , "20 euro"+ , "20 Euro"+ , "20 Euro"+ , "EUR 20"+ ]+ , examples (simple EUR 29.99)+ [ "EUR29,99"+ ]+ , examples (simple Pound 9)+ [ "nove sterline"+ , "quasi nove sterline"+ ]+ , examples (simple GBP 3.01)+ [ "GBP3,01"+ , "GBP 3,01"+ ]+ , examples (between EUR (10, 20))+ [ "tra 10 e 20 euro"+ , "tra 10 euro e 20 euro"+ , "10 - 20 euro"+ , "10 euro - 20 euro"+ ]+ , examples (above EUR 10)+ [ "almeno 10 euro"+ , "più di 10 euro"+ , "più di 10 euro"+ ]+ , examples (under Dollar 10)+ [ "meno di 10 dollari"+ , "non più di 10 dollari"+ ]+ ]
@@ -0,0 +1,270 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}++module Duckling.AmountOfMoney.IT.Rules+ ( rules+ ) where++import Data.Maybe+import Data.String+import Prelude+import qualified Data.Text as Text++import Duckling.AmountOfMoney.Helpers+import Duckling.AmountOfMoney.Types (Currency (..), AmountOfMoneyData (..))+import Duckling.Dimensions.Types+import Duckling.Numeral.Helpers (isNatural, isPositive)+import Duckling.Numeral.Types (NumeralData (..))+import Duckling.Regex.Types (GroupMatch (..))+import Duckling.Types+import qualified Duckling.AmountOfMoney.Types as TAmountOfMoney+import qualified Duckling.Numeral.Types as TNumeral++ruleUnitAmount :: Rule+ruleUnitAmount = Rule+ { name = "<unit> <amount>"+ , pattern =+ [ Predicate isCurrencyOnly+ , Predicate isPositive+ ]+ , prod = \case+ (Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.currency = c}:+ Token Numeral NumeralData{TNumeral.value = v}:+ _) -> Just . Token AmountOfMoney . withValue v $ currencyOnly c+ _ -> Nothing+ }++ruleIntersectAndNumeral :: Rule+ruleIntersectAndNumeral = Rule+ { name = "intersect (and number)"+ , pattern =+ [ Predicate isWithoutCents+ , regex "e"+ , Predicate isNatural+ ]+ , prod = \tokens -> case tokens of+ (Token AmountOfMoney fd:+ _:+ Token Numeral NumeralData{TNumeral.value = c}:+ _) -> Just . Token AmountOfMoney $ withCents c fd+ _ -> Nothing+ }++rulePrecision :: Rule+rulePrecision = Rule+ { name = "precision"+ , pattern =+ [ regex "esattamente|quasi|più o meno|circa"+ , Predicate isMoneyWithValue+ ]+ , prod = \tokens -> case tokens of+ (_:token:_) -> Just token+ _ -> Nothing+ }++ruleCent :: Rule+ruleCent = Rule+ { name = "cent"+ , pattern =+ [ regex "cent(esim)i?o?"+ ]+ , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly Cent+ }++ruleIntersectXCents :: Rule+ruleIntersectXCents = Rule+ { name = "intersect (X cents)"+ , pattern =+ [ Predicate isWithoutCents+ , Predicate isCents+ ]+ , prod = \tokens -> case tokens of+ (Token AmountOfMoney fd:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just c}:+ _) -> Just . Token AmountOfMoney $ withCents c fd+ _ -> Nothing+ }++ruleIntervalBetweenNumeral :: Rule+ruleIntervalBetweenNumeral = Rule+ { name = "between|from <numeral> to|and <amount-of-money>"+ , pattern =+ [ regex "tra"+ , Predicate isPositive+ , regex "e"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \tokens -> case tokens of+ (_:+ Token Numeral NumeralData{TNumeral.value = from}:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c}:+ _) | from < to ->+ Just . Token AmountOfMoney . withInterval (from, to) $ currencyOnly c+ _ -> Nothing+ }+++ruleIntervalBetween :: Rule+ruleIntervalBetween = Rule+ { name = "between|from <amount-of-money> to|and <amount-of-money>"+ , pattern =+ [ regex "tra"+ , Predicate isSimpleAmountOfMoney+ , regex "e"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \tokens -> case tokens of+ (_:+ Token AmountOfMoney AmountOfMoneyData {+ TAmountOfMoney.value = Just from,+ TAmountOfMoney.currency = c1+ }:+ _:+ Token AmountOfMoney AmountOfMoneyData {+ TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c2+ }:+ _) | c1 == c2, from < to ->+ Just . Token AmountOfMoney . withInterval (from, to) $ currencyOnly c1+ _ -> Nothing+ }+++ruleIntervalNumeralDash :: Rule+ruleIntervalNumeralDash = Rule+ { name = "<numeral> - <amount-of-money>"+ , pattern =+ [ Predicate isNatural+ , regex "-"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \tokens -> case tokens of+ (Token Numeral NumeralData{TNumeral.value = from}:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c}:+ _) | from < to ->+ Just . Token AmountOfMoney . withInterval (from, to) $ currencyOnly c+ _ -> Nothing+ }++ruleIntervalDash :: Rule+ruleIntervalDash = Rule+ { name = "<amount-of-money> - <amount-of-money>"+ , pattern =+ [ Predicate isSimpleAmountOfMoney+ , regex "-"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \tokens -> case tokens of+ (Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just from,+ TAmountOfMoney.currency = c1}:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c2}:+ _) | from < to && c1 == c2 ->+ Just . Token AmountOfMoney . withInterval (from, to) $ currencyOnly c1+ _ -> Nothing+ }++ruleIntervalMax :: Rule+ruleIntervalMax = Rule+ { name = "under/less/lower/no more than <amount-of-money>"+ , pattern =+ [ regex "(meno|non più) di"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \tokens -> case tokens of+ (_:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c}:+ _) -> Just . Token AmountOfMoney . withMax to $ currencyOnly c+ _ -> Nothing+ }++ruleIntervalMin :: Rule+ruleIntervalMin = Rule+ { name = "over/above/at least/more than <amount-of-money>"+ , pattern =+ [ regex "più di|almeno"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \tokens -> case tokens of+ (_:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c}:+ _) -> Just . Token AmountOfMoney . withMin to $ currencyOnly c+ _ -> Nothing+ }++ruleCurrencies :: Rule+ruleCurrencies = Rule+ { name = "£, $"+ , pattern =+ [ regex "(dollari|sterline)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) -> case Text.toLower match of+ "dollari" -> Just . Token AmountOfMoney $ currencyOnly Dollar+ "sterline" -> Just . Token AmountOfMoney $ currencyOnly Pound+ _ -> Nothing+ _ -> Nothing+ }++ruleIntersectAndXCents :: Rule+ruleIntersectAndXCents = Rule+ { name = "intersect (and X cents)"+ , pattern =+ [ Predicate isWithoutCents+ , regex "e"+ , Predicate isCents+ ]+ , prod = \tokens -> case tokens of+ (Token AmountOfMoney fd:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just c}:+ _) -> Just . Token AmountOfMoney $ withCents c fd+ _ -> Nothing+ }++ruleIntersect :: Rule+ruleIntersect = Rule+ { name = "intersect"+ , pattern =+ [ Predicate isWithoutCents+ , Predicate isNatural+ ]+ , prod = \tokens -> case tokens of+ (Token AmountOfMoney fd:+ Token Numeral NumeralData{TNumeral.value = c}:+ _) -> Just . Token AmountOfMoney $ withCents c fd+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleUnitAmount+ , ruleCent+ , ruleIntersect+ , ruleIntersectAndNumeral+ , ruleIntersectAndXCents+ , ruleIntersectXCents+ , ruleIntervalBetween+ , ruleIntervalBetweenNumeral+ , ruleIntervalDash+ , ruleIntervalMax+ , ruleIntervalMin+ , ruleIntervalNumeralDash+ , ruleCurrencies+ , rulePrecision+ ]
@@ -0,0 +1,136 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.++-- /Note/: All commented-out tests are failing due to https://github.com/facebook/duckling/issues/541+{-# LANGUAGE OverloadedStrings #-}++module Duckling.AmountOfMoney.KA.Corpus+ ( corpus+ ) where++import Data.String+import Prelude++import Duckling.AmountOfMoney.Types+import Duckling.Locale+import Duckling.Resolve+import Duckling.Testing.Types++corpus :: Corpus+corpus = (testContext {locale = makeLocale KA Nothing}, testOptions, allExamples)++allExamples :: [Example]+allExamples = concat+ [ examples (simple Dollar 1)+ [ "$1"+ , "ერთი დოლარი"+ , "1 დოლარი"+ ]+ , examples (simple Dollar 10)+ [ "$10"+ , "$ 10"+ , "10$"+ , "10 დოლარი"+ , "ათი დოლარი"+ ]+ , examples (simple Cent 10)+ [ "10 ცენტი"+ , "ათი ცენტი"+ , "10 c"+ , "10¢"+ ]+ , examples (simple Dollar 1e4)+ [ "$10K"+ , "10k$"+ , "$10,000"+ ]+ , examples (simple USD 3.14)+ [ "USD3.14"+ , "3.14US$"+ , "US$ 3.14"+ ]+ , examples (simple EUR 20)+ [ "20\x20ac"+ , "20 ევრო"+ , "EUR 20"+ , "EUR 20.0"+ , "20€"+ , "20 €ur"+ ]+ , examples (simple Pound 10)+ [ "\x00a3\&10"+ , "ათი ფუნტი"+ ]+ , examples (simple Dollar 20.43)+ [ "$20 და 43c"+ , "20 დოლარი და 43c"+ , "20 დოლარი 43 ცენტი"+ , "ოცი დოლარი 43 ცენტი"+ -- , "ოცი დოლარი და ორმოცდასამი ცენტი"+ ]+ , examples (simple GBP 3.01)+ [ "GBP3.01"+ , "GBP 3.01"+ , "3 GBP 1 პენსი"+ ]+ , examples (simple KWD 42)+ [ "42 KWD"+ , "42 ქუვეითური დინარი"+ ]+ , examples (simple LBP 42)+ [ "42 LBP"+ , "42 ლიბანური ფუნტი"+ ]+ , examples (simple EGP 42)+ [ "42 EGP"+ , "42 ეგვიპტური ფუნტი"+ ]+ , examples (simple QAR 42)+ [ "42 QAR"+ , "42 კატარული რიალი"+ ]+ , examples (between Dollar (10, 20))+ [ "დაახლოებით 10-20 დოლარი"+ -- , "10 დოლარიდან 20 დოლარამდე"+ -- , "10-დან 20 დოლარამდე"+ , "გძეტა $10-$20"+ , "10-20 დოლარი"+ ]+{-+ , examples (between Dollar (1.1, 1.3))+ [ "1.1-დან 1.3 დოლარამდე"+ , "ერთი მთელი ერთი დოლარიდან ერთი მთელი სამ დოლარამდე"+ ]+ , examples (under EUR 7)+ [ "7 ევრომდე"+ , "7 ევროზე ნაკლები"+ ]+ , examples (above Dollar 1.42)+ [ "1 დოლარი და 42 ცენტზე მეტი"+ ]+ , examples (between GEL (10, 20))+ [ "დაახლოებით 10-20 ლარი"+ , "10 ლარიდან 20 ლარამდე"+ , "10-დან 20 ლარამდე"+ , "გძეტა 10-20 ლარი"+ , "10-20 ლარი"+ ]+ , examples (between GEL (1.1, 1.3))+ [ "1.1-დან 1.3 ლარამდე"+ , "ერთი მთელი ერთი ლარიდან ერთი მთელი სამ ლარამდე"+ ]+ , examples (under GEL 7)+ [ "7 ლარამდე"+ , "7 ლარზე ნაკლები"+ ]+ , examples (above GEL 1.42)+ [ "1 ლარი და 42 თეთრზე მეტი"+ ]+ , examples (between GEL (1, 4))+ [ "1ლარიდან 4ლარამდე"+ ]+-}+ ]
@@ -0,0 +1,347 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}++module Duckling.AmountOfMoney.KA.Rules+ ( rules+ ) where++import Data.Maybe+import Data.String+import Prelude+import qualified Data.Text as Text++import Duckling.AmountOfMoney.Helpers+import Duckling.AmountOfMoney.Types (Currency(..), AmountOfMoneyData (..))+import Duckling.Dimensions.Types+import Duckling.Numeral.Helpers (isNatural, isPositive)+import Duckling.Numeral.Types (NumeralData (..))+import Duckling.Regex.Types+import Duckling.Types+import qualified Duckling.AmountOfMoney.Types as TAmountOfMoney+import qualified Duckling.Numeral.Types as TNumeral++ruleUnitAmount :: Rule+ruleUnitAmount = Rule+ { name = "<unit> <amount>"+ , pattern =+ [ Predicate isCurrencyOnly+ , Predicate isPositive+ ]+ , prod = \case+ (Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.currency = c}:+ Token Numeral NumeralData{TNumeral.value = v}:+ _) -> Just . Token AmountOfMoney . withValue v $ currencyOnly c+ _ -> Nothing+ }++rulePounds :: Rule+rulePounds = Rule+ { name = "£"+ , pattern =+ [ regex "(გირვანქა )?სტერლინგი?ს?(ად)?თ?|(გირვანქა )?ფუნ?ტი?ს?(ად)?თ?"+ ]+ , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly Pound+ }++ruleOtherPounds :: Rule+ruleOtherPounds = Rule+ { name = "other pounds"+ , pattern =+ [ regex "(ეგვიპტური|ლიბანური) ?ფუნ?ტი?ს?(ად)?თ?"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) -> case Text.toLower match of+ "ეგვიპტური" -> Just . Token AmountOfMoney $ currencyOnly EGP+ "ლიბანური" -> Just . Token AmountOfMoney $ currencyOnly LBP+ _ -> Nothing+ _ -> Nothing+ }++ruleRiyals :: Rule+ruleRiyals = Rule+ { name = "riyals"+ , pattern =+ [ regex "(კატარული|საუდის არაბული) ?რიალი?"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) -> case Text.toLower match of+ "კატარული" -> Just . Token AmountOfMoney $ currencyOnly QAR+ "საუდის არაბული" -> Just . Token AmountOfMoney $ currencyOnly SAR+ _ -> Nothing+ _ -> Nothing+ }++ruleDinars :: Rule+ruleDinars = Rule+ { name = "dinars"+ , pattern =+ [ regex "(ქუვეითური)? ?დინარი?"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) -> case Text.toLower match of+ "ქუვეითური" -> Just . Token AmountOfMoney $ currencyOnly KWD+ _ -> Nothing+ _ -> Nothing+ }++ruleDirham :: Rule+ruleDirham = Rule+ { name = "დირჰემი"+ , pattern =+ [ regex "დირჰემი?"+ ]+ , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly AED+ }++ruleRinggit :: Rule+ruleRinggit = Rule+ { name = "ringgit"+ , pattern =+ [ regex "(მალაიზი?ური? )?რინგიტი?"+ ]+ , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly MYR+ }++ruleCent :: Rule+ruleCent = Rule+ { name = "cent"+ , pattern =+ [ regex "ცენტი?ს?(ად)?თ?|თეთრი?ს?(ად)?თ?|პენსი?ს?(ად)?თ?|ევროცენტი?ს?(ად)?თ?"+ ]+ , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly Cent+ }++ruleLari :: Rule+ruleLari = Rule+ { name = "Lari"+ , pattern =+ [ regex "(ლარი?ს?(ად)?თ?)|GEL"+ ]+ , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly GEL+ }++ruleDollars :: Rule+ruleDollars = Rule+ { name = "Dollars"+ , pattern =+ [ regex "დოლარი?ს?(ად)?თ?"+ ]+ , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly Dollar+ }++ruleEuros :: Rule+ruleEuros = Rule+ { name = "Euros"+ , pattern =+ [ regex "ევრო?ს?დ?თ?"+ ]+ , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly EUR+ }++ruleACurrency :: Rule+ruleACurrency = Rule+ { name = "a <currency>"+ , pattern =+ [ Predicate isCurrencyOnly+ ]+ , prod = \tokens -> case tokens of+ (Token AmountOfMoney fd:+ _) -> Just . Token AmountOfMoney $ fd {TAmountOfMoney.value = Just 1}+ _ -> Nothing+ }++ruleIntersectAndXCents :: Rule+ruleIntersectAndXCents = Rule+ { name = "intersect (and X cents)"+ , pattern =+ [ Predicate isWithoutCents+ , regex "და"+ , Predicate isCents+ ]+ , prod = \tokens -> case tokens of+ (Token AmountOfMoney fd:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just c}:+ _) -> Just . Token AmountOfMoney $ withCents c fd+ _ -> Nothing+ }++ruleIntersectAndNumeral :: Rule+ruleIntersectAndNumeral = Rule+ { name = "intersect (and number)"+ , pattern =+ [ Predicate isWithoutCents+ , regex "და"+ , Predicate isNatural+ ]+ , prod = \tokens -> case tokens of+ (Token AmountOfMoney fd:+ _:+ Token Numeral NumeralData{TNumeral.value = c}:+ _) -> Just . Token AmountOfMoney $ withCents c fd+ _ -> Nothing+ }++ruleIntersectXCents :: Rule+ruleIntersectXCents = Rule+ { name = "intersect (X cents)"+ , pattern =+ [ Predicate isWithoutCents+ , Predicate isCents+ ]+ , prod = \tokens -> case tokens of+ (Token AmountOfMoney fd:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just c}:+ _) -> Just . Token AmountOfMoney $ withCents c fd+ _ -> Nothing+ }++rulePrecision :: Rule+rulePrecision = Rule+ { name = "about|exactly <amount-of-money>"+ , pattern =+ [ regex "ზუსტად|იმენა|დაახლოებით|გძეტა"+ , Predicate isMoneyWithValue+ ]+ , prod = \tokens -> case tokens of+ (_:token:_) -> Just token+ _ -> Nothing+ }++ruleIntervalBetweenNumeral :: Rule+ruleIntervalBetweenNumeral = Rule+ { name = "between|from <numeral> to|and <amount-of-money>"+ , pattern =+ [ Predicate isPositive+ , regex "-დან|დან"+ , Predicate isSimpleAmountOfMoney+ , regex "-ა?მდე|ა?მდე"+ ]+ , prod = \tokens -> case tokens of+ (Token Numeral NumeralData{TNumeral.value = from}:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c}:+ _) | from < to ->+ Just . Token AmountOfMoney . withInterval (from, to) $ currencyOnly c+ _ -> Nothing+ }++ruleIntervalBetween :: Rule+ruleIntervalBetween = Rule+ { name = "between|from <amount-of-money> to|and <amount-of-money>"+ , pattern =+ [ Predicate isSimpleAmountOfMoney+ , regex "-დან|დან"+ , Predicate isSimpleAmountOfMoney+ , regex "-ა?მდე|ა?მდე"+ ]+ , prod = \tokens -> case tokens of+ (Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just from,+ TAmountOfMoney.currency = c1}:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c2}:+ _) | from < to && c1 == c2 ->+ Just . Token AmountOfMoney . withInterval (from, to) $ currencyOnly c1+ _ -> Nothing+ }++ruleIntervalNumeralDash :: Rule+ruleIntervalNumeralDash = Rule+ { name = "<numeral> - <amount-of-money>"+ , pattern =+ [ Predicate isNatural+ , regex "-"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \tokens -> case tokens of+ (Token Numeral NumeralData{TNumeral.value = from}:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c}:+ _) | from < to->+ Just . Token AmountOfMoney . withInterval (from, to) $ currencyOnly c+ _ -> Nothing+ }++ruleIntervalDash :: Rule+ruleIntervalDash = Rule+ { name = "<amount-of-money> - <amount-of-money>"+ , pattern =+ [ Predicate isSimpleAmountOfMoney+ , regex "-"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \tokens -> case tokens of+ (Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just from,+ TAmountOfMoney.currency = c1}:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c2}:+ _) | from < to && c1 == c2 ->+ Just . Token AmountOfMoney . withInterval (from, to) $ currencyOnly c1+ _ -> Nothing+ }++ruleIntervalMax :: Rule+ruleIntervalMax = Rule+ { name = "under/less/lower/no more than <amount-of-money>"+ , pattern =+ [ Predicate isSimpleAmountOfMoney+ , regex "-ა?მდე|ა?მდე|(-ზე|ზე) ნაკლები"+ ]+ , prod = \tokens -> case tokens of+ (Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c}:+ _) -> Just . Token AmountOfMoney . withMax to $ currencyOnly c+ _ -> Nothing+ }++ruleIntervalMin :: Rule+ruleIntervalMin = Rule+ { name = "over/above/at least/more than <amount-of-money>"+ , pattern =+ [ Predicate isSimpleAmountOfMoney+ , regex "-დან|დან|(-ზე|ზე) მეტი"+ ]+ , prod = \tokens -> case tokens of+ (Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c}:+ _) -> Just . Token AmountOfMoney . withMin to $ currencyOnly c+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleUnitAmount+ , ruleACurrency+ , ruleDollars+ , ruleCent+ , ruleEuros+ , ruleDinars+ , ruleDirham+ , ruleIntersectAndNumeral+ , ruleIntersectAndXCents+ , ruleIntersectXCents+ , ruleIntervalBetweenNumeral+ , ruleIntervalBetween+ , ruleIntervalMax+ , ruleIntervalMin+ , ruleIntervalNumeralDash+ , ruleIntervalDash+ , ruleOtherPounds+ , rulePounds+ , rulePrecision+ , ruleRinggit+ , ruleRiyals+ , ruleLari+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -75,5 +74,39 @@ [ "십원" , "10원" , "10₩"+ ]+ , examples (between KRW (25000, 30000))+ [ "25000 - 30000원"+ , "25000원 - 30000원"+ , "이만오천원 - 삼만원"+ ]+ , examples (above KRW 5000)+ [ "5000원 이상"+ , "5000원 초과"+ , "오천원 이상"+ , "오천원 초과"+ ]+ , examples (under KRW 10000)+ [ "10000원 이하"+ , "10000원 미만"+ , "만원 이하"+ , "만원 미만"+ ]+ , examples (between Dollar (10, 20))+ [ "10 - 20 달러"+ , "10달러 - 20달러"+ , "십달러 - 이십달러"+ ]+ , examples (above Dollar 10)+ [ "10달러 이상"+ , "10달러 초과"+ , "십달러 이상"+ , "십달러 초과"+ ]+ , examples (under Dollar 10)+ [ "10달러 이하"+ , "10달러 미만"+ , "십달러 이하"+ , "십달러 미만" ] ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -21,7 +20,7 @@ import Duckling.Dimensions.Types import Duckling.AmountOfMoney.Helpers import Duckling.AmountOfMoney.Types (Currency(..), AmountOfMoneyData (..))-import Duckling.Numeral.Helpers (isPositive)+import Duckling.Numeral.Helpers (isNatural, isPositive) import Duckling.Numeral.Types (NumeralData (..)) import Duckling.Types import qualified Duckling.AmountOfMoney.Types as TAmountOfMoney@@ -87,7 +86,7 @@ ruleCent = Rule { name = "cent" , pattern =- [ regex "cents?|센(트|츠)"+ [ regex "센트" ] , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly Cent }@@ -158,11 +157,108 @@ ruleDirham = Rule { name = "dirham" , pattern =- [ regex "dirhams?"+ [ regex "디르함" ] , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly AED } +ruleIntervalBetweenNumeral :: Rule+ruleIntervalBetweenNumeral = Rule+ { name = "between|from <numeral> to|and <amount-of-money>"+ , pattern =+ [ Predicate isPositive+ , regex "에서"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \case+ (Token Numeral NumeralData {TNumeral.value = from}:+ _:+ Token AmountOfMoney AmountOfMoneyData {TAmountOfMoney.value = Just to, TAmountOfMoney.currency = c}:+ _) ->+ (Just (Token AmountOfMoney $ withInterval (from, to) $ currencyOnly c))+ _ -> Nothing+ }++ruleIntervalBetween :: Rule+ruleIntervalBetween = Rule+ { name = "between|from <amount-of-money> to|and <amount-of-money>"+ , pattern =+ [ Predicate isSimpleAmountOfMoney+ , regex "부터"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \case+ (Token AmountOfMoney AmountOfMoneyData {TAmountOfMoney.value = Just from, TAmountOfMoney.currency = c1}:+ _:+ Token AmountOfMoney AmountOfMoneyData {TAmountOfMoney.value = Just to, TAmountOfMoney.currency = c2}:+ _) | c1 == c2 ->+ (Just (Token AmountOfMoney $ withInterval (from, to) $ currencyOnly c1))+ _ -> Nothing+ }++ruleIntervalNumeralDash :: Rule+ruleIntervalNumeralDash = Rule+ { name = "<numeral> - <amount-of-money>"+ , pattern =+ [ Predicate isNatural+ , regex "-"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \case+ (Token Numeral NumeralData {TNumeral.value = from}:+ _:+ Token AmountOfMoney AmountOfMoneyData {TAmountOfMoney.value = Just to, TAmountOfMoney.currency = c}:+ _) ->+ (Just (Token AmountOfMoney $ withInterval (from, to) $ currencyOnly c))+ _ -> Nothing+ }++ruleIntervalDash :: Rule+ruleIntervalDash = Rule+ { name = "<amount-of-money> - <amount-of-money>"+ , pattern =+ [ Predicate isSimpleAmountOfMoney+ , regex "-"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \case+ (Token AmountOfMoney AmountOfMoneyData {TAmountOfMoney.value = Just from, TAmountOfMoney.currency = c1}:+ _:+ Token AmountOfMoney AmountOfMoneyData {TAmountOfMoney.value = Just to, TAmountOfMoney.currency = c2}:+ _) | c1 == c2 ->+ (Just (Token AmountOfMoney $ withInterval (from, to) $ currencyOnly c1))+ _ -> Nothing+ }++ruleIntervalMax :: Rule+ruleIntervalMax = Rule+ { name = "under/less/lower/no more than <amount-of-money>"+ , pattern =+ [ Predicate isSimpleAmountOfMoney+ , regex "미만|이하"+ ]+ , prod = \case+ (Token AmountOfMoney AmountOfMoneyData {TAmountOfMoney.value = Just to, TAmountOfMoney.currency = c}:+ _:+ _) -> (Just (Token AmountOfMoney $ withMax to $ currencyOnly c))+ _ -> Nothing+ }++ruleIntervalMin :: Rule+ruleIntervalMin = Rule+ { name = "over/above/at least/more than <amount-of-money>"+ , pattern =+ [ Predicate isSimpleAmountOfMoney+ , regex "초과|이상"+ ]+ , prod = \case+ (Token AmountOfMoney AmountOfMoneyData {TAmountOfMoney.value = Just to, TAmountOfMoney.currency = c}:+ _:+ _) -> (Just (Token AmountOfMoney $ withMin to $ currencyOnly c))+ _ -> Nothing+ }++ rules :: [Rule] rules = [ ruleUnitAmount@@ -178,4 +274,10 @@ , ruleIntersectXCents , ruleKrw , rulePounds+ , ruleIntervalBetweenNumeral+ , ruleIntervalBetween+ , ruleIntervalNumeralDash+ , ruleIntervalDash+ , ruleIntervalMax+ , ruleIntervalMin ]
@@ -0,0 +1,95 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}++module Duckling.AmountOfMoney.MN.Corpus+ ( corpus+ ) where++import Data.String+import Prelude++import Duckling.AmountOfMoney.Types+import Duckling.Locale+import Duckling.Resolve+import Duckling.Testing.Types++corpus :: Corpus+corpus = (testContext {locale = makeLocale MN Nothing}, testOptions, allExamples)++allExamples :: [Example]+allExamples = concat+ [ examples (simple MNT 1)+ [ "1 төг"+ , "нэг төгрөг"+ , "1 ₮"+ , "1 төгрөг"+ ]+ , examples (simple MNT 10)+ [ "10 төгрөг"+ , "₮ 10"+ , "10₮"+ , "10MNT"+ , "10төг"+ , "10 төгрөг"+ , "төгрөг 10"+ , "10 төгрөгийн"+ ]+ , examples (simple Dollar 1)+ [ "$1"+ , "нэг доллар"+ ]+ , examples (simple Dollar 10)+ [ "$10"+ , "$ 10"+ , "10$"+ , "10 доллар"+ , "арван доллар"+ ]+ , examples (simple Cent 10)+ [ "10 цент"+ , "арван пени"+ , "арван цент"+ , "10 c"+ , "10¢"+ ]+ , examples (simple EUR 20)+ [ "20€"+ , "20 €ur"+ , "20 евро"+ , "Евро 20"+ ]+ , examples (simple Pound 10)+ [ "\x00a3\&10"+ , "арван фунт"+ ]+ , examples (simple INR 20)+ [ "20Rs"+ , "Rs20"+ ]+ , examples (simple GBP 3.01)+ [ "GBP3.01"+ , "GBP 3.01"+ , "3.01 Английн фунт"+ ]+ , examples (under MNT 10)+ [ "10₮-c бага"+ ]+ , examples (above MNT 20)+ [ "20MNT-c их"+ ]+ , examples (between MNT (5, 10))+ [ "5-c MNT10 хүртэл"+ , "5-c ₮10 хүртэл"+ , "5-c 10 MNT хүртэл"+ , "MNT5-c 10 хүртэл"+ , "MNT5-c 10₮ хооронд"+ , "5-c ₮10-н хооронд"+ , "MNT5-c 10₮-н хүртэл"+ ]+ ]
@@ -0,0 +1,260 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}++module Duckling.AmountOfMoney.MN.Rules+ ( rules+ ) where++import Data.Maybe+import Data.String+import Prelude++import Duckling.AmountOfMoney.Helpers+import Duckling.AmountOfMoney.Types (Currency(..), AmountOfMoneyData(..))+import Duckling.Dimensions.Types+import Duckling.Numeral.Helpers (isNatural, isPositive)+import Duckling.Numeral.Types (NumeralData (..))+import Duckling.Regex.Types+import Duckling.Types+import qualified Duckling.AmountOfMoney.Types as TAmountOfMoney+import qualified Duckling.Numeral.Types as TNumeral++ruleUnitAmount :: Rule+ruleUnitAmount = Rule+ { name = "<unit> <amount>"+ , pattern =+ [ Predicate isCurrencyOnly+ , Predicate isPositive+ ]+ , prod = \case+ (Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.currency = c}:+ Token Numeral NumeralData{TNumeral.value = v}:+ _) -> Just . Token AmountOfMoney . withValue v $ currencyOnly c+ _ -> Nothing+ }++ruleTugriks :: Rule+ruleTugriks = Rule+ { name = "төг"+ , pattern =+ [ regex "төг(рөг(ийн)?)?"+ ]+ , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly MNT+ }++rulePounds :: Rule+rulePounds = Rule+ { name = "£"+ , pattern =+ [ regex "фунт(аар|тай|аас)?"+ ]+ , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly Pound+ }++ruleGBP :: Rule+ruleGBP = Rule+ { name = "Mongolian GBP"+ , pattern =+ [ regex "Английн\\s+фунт"+ ]+ , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly GBP+ }++ruleDollar :: Rule+ruleDollar = Rule+ { name = "$"+ , pattern =+ [ regex "доллар(ын|оор|оос|той)?"+ ]+ , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly Dollar+ }++ruleCent :: Rule+ruleCent = Rule+ { name = "cent"+ , pattern =+ [ regex "цент(ийн|ээс|ээр|тэй)?|пени|пенс(ээр|гээр|тэй|ээс|гээс)?|ц"+ ]+ , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly Cent+ }++ruleEUR :: Rule+ruleEUR = Rule+ { name = "€"+ , pattern =+ [ regex "евро"+ ]+ , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly EUR+ }++ruleBucks :: Rule+ruleBucks = Rule+ { name = "bucks"+ , pattern =+ [ regex "бакс(аар|тай|аас)?"+ ]+ , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly Unnamed+ }++rulePrecision :: Rule+rulePrecision = Rule+ { name = "about|exactly <amount-of-money>"+ , pattern =+ [ regex "яг|ойролцоогоор|бараг"+ , Predicate isMoneyWithValue+ ]+ , prod = \case+ (_:token:_) -> Just token+ _ -> Nothing+ }++ruleIntervalBetweenNumeral :: Rule+ruleIntervalBetweenNumeral = Rule+ { name = "between|from <numeral> to|and <amount-of-money>"+ , pattern =+ [ Predicate isPositive+ , regex "-c"+ , Predicate isSimpleAmountOfMoney+ , regex "(-н\\s+)?(хооронд|хүртэл)"+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = from}:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c}:+ _) | from < to ->+ Just . Token AmountOfMoney . withInterval (from, to) $ currencyOnly c+ _ -> Nothing+ }++ruleIntervalBetweenNumeral2 :: Rule+ruleIntervalBetweenNumeral2 = Rule+ { name = "between|from <amount-of-money> to|and <numeral>"+ , pattern =+ [ Predicate isSimpleAmountOfMoney+ , regex "-c"+ , Predicate isNatural+ , regex "(-н\\s+)?(хооронд|хүртэл)"+ ]+ , prod = \case+ (Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just from,+ TAmountOfMoney.currency = c}:+ _:+ Token Numeral NumeralData{TNumeral.value = to}:+ _) | from < to ->+ Just . Token AmountOfMoney . withInterval (from, to) $ currencyOnly c+ _ -> Nothing+ }++ruleIntervalBetween :: Rule+ruleIntervalBetween = Rule+ { name = "between|from <amount-of-money> to|and <amount-of-money>"+ , pattern =+ [ Predicate isSimpleAmountOfMoney+ , regex "-c"+ , Predicate isSimpleAmountOfMoney+ , regex "(-н\\s+)?(хооронд|хүртэл)"+ ]+ , prod = \case+ (Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just from,+ TAmountOfMoney.currency = c1}:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c2}:+ _) | from < to && c1 == c2 ->+ Just . Token AmountOfMoney . withInterval (from, to) $ currencyOnly c1+ _ -> Nothing+ }++ruleIntervalNumeralDash :: Rule+ruleIntervalNumeralDash = Rule+ { name = "<numeral> - <amount-of-money>"+ , pattern =+ [ Predicate isPositive+ , regex "-"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = from}:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c}:+ _) | from < to ->+ Just . Token AmountOfMoney . withInterval (from, to) $ currencyOnly c+ _ -> Nothing+ }++ruleIntervalDash :: Rule+ruleIntervalDash = Rule+ { name = "<amount-of-money> - <amount-of-money>"+ , pattern =+ [ Predicate isSimpleAmountOfMoney+ , regex "-"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \case+ (Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just from,+ TAmountOfMoney.currency = c1}:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c2}:+ _) | from < to && c1 == c2 ->+ Just . Token AmountOfMoney . withInterval (from, to) $ currencyOnly c1+ _ -> Nothing+ }++ruleIntervalMax :: Rule+ruleIntervalMax = Rule+ { name = "under/less/lower/no more than <amount-of-money>"+ , pattern =+ [ Predicate isSimpleAmountOfMoney+ , regex "-c\\s+(бага|доогуур|ихгүй)"+ ]+ , prod = \case+ (Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c}:+ _) -> Just . Token AmountOfMoney . withMax to $ currencyOnly c+ _ -> Nothing+ }++ruleIntervalMin :: Rule+ruleIntervalMin = Rule+ { name = "over/above/at least/more than <amount-of-money>"+ , pattern =+ [ Predicate isSimpleAmountOfMoney+ , regex "-c\\s+(их|дээгүүр|илүү)"+ ]+ , prod = \case+ (Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c}:+ _) -> Just . Token AmountOfMoney . withMin to $ currencyOnly c+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleUnitAmount+ , ruleBucks+ , ruleCent+ , ruleDollar+ , ruleEUR+ , ruleGBP+ , ruleIntervalBetweenNumeral+ , ruleIntervalBetweenNumeral2+ , ruleIntervalBetween+ , ruleIntervalMax+ , ruleIntervalMin+ , ruleIntervalNumeralDash+ , ruleIntervalDash+ , rulePounds+ , rulePrecision+ , ruleTugriks+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -46,12 +45,479 @@ , "10kr" , "ti kroner" , "10 NOK"+ , "ti norske kroner" ]+ , examples (simple SEK 10)+ [ "10kronor"+ , "10 svenske kroner"+ , "10 svenske kr"+ , "10 svenske kronor"+ , "ti kronor"+ ]+ , examples (simple DKK 10)+ [ "10 danske kroner"+ , "ti danske kroner"+ , "ti danske kr"+ ]+ , examples (simple AUD 10)+ [ "10 australske dollar"+ , "10 australske dollars"+ ]+ , examples (simple CAD 10)+ [ "10 kanadiske dollar"+ , "10 kanadiske dollars"+ , "10 canadiske dollar"+ , "10 canadiske dollars"+ ]+ , examples (simple CHF 10)+ [ "10 sveitsiske franc"+ , "10 sveitsiske francs"+ ]+ , examples (simple CNY 10)+ [ "10 yuan"+ , "10 kinesiske yuan"+ , "10 kinesisk yuan"+ , "10 renminbi"+ , "10 kinesiske renminbi"+ , "10 kinesisk renminbi"+ ]+ , examples (simple CZK 10)+ [ "10 koruna"+ , "10 tsjekkiske koruna"+ ]+ , examples (simple INR 10)+ [ "10 rupi"+ , "10 rupier"+ , "10 rupee"+ , "10 rupees"+ , "10 indisk rupi"+ , "10 indiske rupi"+ , "10 indiske rupee"+ , "10 indiske rupees"+ , "10 indiske rupier"+ , "10 indisk rupier"+ , "ti rupi"+ , "ti rupier"+ , "ti indisk rupi"+ , "ti indiske rupi"+ , "ti indiske rupee"+ , "ti indiske rupees"+ , "ti indiske rupier"+ , "ti indisk rupier"+ ]+ , examples (simple JPY 10)+ [ "10 japanske yen"+ , "10 yen"+ , "ti japanske yen"+ , "ti yen"+ ]+ , examples (simple PKR 10)+ [ "10 pakistansk rupi"+ , "10 pakistanske rupi"+ , "10 pakistanske rupee"+ , "10 pakistanske rupees"+ , "10 pakistanske rupier"+ , "10 pakistansk rupier"+ , "ti pakistansk rupi"+ , "ti pakistanske rupi"+ , "ti pakistanske rupee"+ , "ti pakistanske rupees"+ , "ti pakistanske rupier"+ , "ti pakistansk rupier"+ ]+ , examples (simple PLN 10)+ [ "10 zloty"+ , "10 sloty"+ , "10 polske zloty"+ , "10 polske sloty"+ , "ti zloty"+ , "ti sloty"+ , "ti polske zloty"+ , "ti polske sloty"+ ]+ , examples (simple SGD 10)+ [ "10 singapore dollar"+ , "10 singapore dollars"+ , "10 singaporske dollar"+ , "10 singaporske dollars"+ , "ti singapore dollar"+ , "ti singapore dollars"+ , "ti singaporske dollar"+ , "ti singaporske dollars"+ ]+ , examples (simple THB 10)+ [ "10 bhat"+ , "10 thai baht"+ , "10 thai bhat"+ , "10 thailand baht"+ , "10 thailand bhat"+ , "10 thailandske baht"+ , "10 thailandske bhat"+ , "ti baht"+ , "ti bhat"+ , "ti thai baht"+ , "ti thai bhat"+ , "ti thailand baht"+ , "ti thailand bhat"+ , "ti thailandske baht"+ , "ti thailandske bhat"+ ]+ , examples (simple ZAR 10)+ [ "10 rand"+ , "10 sørafrikanske rand"+ , "10 sør-afrikanske rand"+ , "10 rand"+ , "10 sørafrikanske rand"+ , "10 sør-afrikanske rand"+ , "ti rand"+ , "ti sørafrikanske rand"+ , "ti sør-afrikanske rand"+ ] , examples (simple NOK 2.23) [ "2 kroner og 23 øre" , "to kroner 23 øre" , "to kroner og 23 øre" , "to kr 23"+ ]+ , examples (simple SEK 2.23)+ [ "2 kronor og 23 öre"+ , "to kronor 23 öre"+ , "to svenske kronor 23 öre"+ , "to svenske kroner 23 öre"+ , "to svenske kroner 23 øre"+ , "to kronor og 23 öre"+ , "to svenske kronor og 23 öre"+ , "to svenske kroner og 23 öre"+ , "to svenske kroner og 23 øre"+ , "to svensk kroner og 23 øre"+ ]+ , examples (simple DKK 2.23)+ [ "2 danske kroner og 23 øre"+ , "to danske kroner 23 øre"+ , "to danske kroner og 23 øre"+ , "to danske kr 23"+ , "to dansk kr 23"+ ]+ , examples (simple USD 2.23)+ [ "2 amerikanske dollar og 23 cent"+ , "2 amerikanske dollars og 23 cent"+ , "2 amerikanske dollar og 23 cents"+ , "2 amerikanske dollars og 23 cents"+ , "to amerikanske dollar 23 cent"+ , "to amerikanske dollars 23 cent"+ , "to amerikanske dollar 23 cents"+ , "to amerikanske dollars 23 cents"+ , "to amerikanske dollar og 23 cent"+ , "to amerikanske dollars og 23 cent"+ , "to amerikanske dollar og 23 cents"+ , "to amerikanske dollars og 23 cents"+ , "to amerikanske dollar 23"+ , "to amerikanske dollars 23"+ ]+ , examples (simple AUD 2.23)+ [ "2 australske dollar og 23 cent"+ , "2 australske dollars og 23 cent"+ , "2 australske dollar og 23 cents"+ , "2 australske dollars og 23 cents"+ , "to australske dollar 23 cent"+ , "to australske dollars 23 cent"+ , "to australske dollar 23 cents"+ , "to australske dollars 23 cents"+ , "to australske dollar og 23 cent"+ , "to australske dollars og 23 cent"+ , "to australske dollar og 23 cents"+ , "to australske dollars og 23 cents"+ , "to australske dollar 23"+ , "to australske dollars 23"+ ]+ , examples (simple CAD 2.23)+ [ "2 kanadiske dollar og 23 cent"+ , "2 kanadiske dollars og 23 cent"+ , "2 canadiske dollar og 23 cent"+ , "2 canadiske dollars og 23 cent"+ , "2 kanadiske dollar og 23 cents"+ , "2 kanadiske dollars og 23 cents"+ , "2 canadiske dollar og 23 cents"+ , "2 canadiske dollars og 23 cents"+ , "to kanadiske dollar 23 cent"+ , "to kanadiske dollars 23 cent"+ , "to canadiske dollar 23 cent"+ , "to canadiske dollars 23 cent"+ , "to kanadiske dollar 23 cents"+ , "to kanadiske dollars 23 cents"+ , "to canadiske dollar 23 cents"+ , "to canadiske dollars 23 cents"+ , "to kanadiske dollar og 23 cent"+ , "to kanadiske dollars og 23 cent"+ , "to canadiske dollar og 23 cent"+ , "to canadiske dollars og 23 cent"+ , "to kanadiske dollar og 23 cents"+ , "to kanadiske dollars og 23 cents"+ , "to canadiske dollar og 23 cents"+ , "to canadiske dollars og 23 cents"+ , "to kanadiske dollar 23"+ , "to kanadiske dollars 23"+ , "to canadiske dollar 23"+ , "to canadiske dollars 23"+ ]+ , examples (simple CHF 2.23)+ [ "2 sveitsiske franc og 23 rappen"+ , "2 sveitsiske francs og 23 rappen"+ , "2 sveitsiske franc og 23 rp"+ , "2 sveitsiske francs og 23 rp"+ , "2 sveitsiske franc og 23 centime"+ , "2 sveitsiske francs og 23 centime"+ , "2 sveitsiske franc og 23 c"+ , "2 sveitsiske francs og 23 c"+ , "2 sveitsiske franc og 23 centesimo"+ , "2 sveitsiske francs og 23 centesimo"+ , "2 sveitsiske franc og 23 ct"+ , "2 sveitsiske francs og 23 ct"+ , "2 sveitsiske franc og 23 rap"+ , "2 sveitsiske francs og 23 rap"+ , "to sveitsiske franc 23 rappen"+ , "to sveitsiske francs 23 rappen"+ , "to sveitsiske franc 23 rp"+ , "to sveitsiske francs 23 rp"+ , "to sveitsiske franc 23 centime"+ , "to sveitsiske francs 23 centime"+ , "to sveitsiske franc 23 c"+ , "to sveitsiske francs 23 c"+ , "to sveitsiske franc 23 centesimo"+ , "to sveitsiske francs 23 centesimo"+ , "to sveitsiske franc 23 ct"+ , "to sveitsiske francs 23 ct"+ , "to sveitsiske franc 23 rap"+ , "to sveitsiske francs 23 rap"+ , "to sveitsiske franc og 23 rappen"+ , "to sveitsiske francs og 23 rappen"+ , "to sveitsiske franc og 23 rp"+ , "to sveitsiske francs og 23 rp"+ , "to sveitsiske franc og 23 centime"+ , "to sveitsiske francs og 23 centime"+ , "to sveitsiske franc og 23 c"+ , "to sveitsiske francs og 23 c"+ , "to sveitsiske franc og 23 centesimo"+ , "to sveitsiske francs og 23 centesimo"+ , "to sveitsiske franc og 23 ct"+ , "to sveitsiske francs og 23 ct"+ , "to sveitsiske franc og 23 rap"+ , "to sveitsiske francs og 23 rap"+ , "to sveitsiske franc 23"+ , "to sveitsiske francs 23"+ ]+ , examples (simple CNY 2.23)+ [ "2 yuan og 23 fen"+ , "2 kinesiske yuan og 23 fen"+ , "2 renminbi og 23 fen"+ , "2 kinesiske renminbi og 23 fen"+ , "to yuan 23 fen"+ , "to kinesiske yuan 23 fen"+ , "to renminbi 23 fen"+ , "to kinesiske renminbi 23 fen"+ , "to yuan og 23 fen"+ , "to kinesiske yuan og 23 fen"+ , "to renminbi og 23 fen"+ , "to kinesiske renminbi og 23 fen"+ , "to yuan 23"+ , "to kinesiske yuan 23"+ , "to renminbi 23"+ , "to kinesiske renminbi 23"+ ]+ , examples (simple CZK 2.23)+ [ "2 koruna og 23 haleru"+ , "2 tsjekkiske koruna og 23 haleru"+ , "to koruna 23 haleru"+ , "to tsjekkiske koruna 23 haleru"+ , "to koruna og 23 haleru"+ , "to tsjekkiske koruna og 23 haleru"+ , "to koruna 23"+ , "to tsjekkiske koruna 23"+ ]+ , examples (simple HKD 2.23)+ [ "2 hong kong dollar og 23 cent"+ , "2 hong kong dollar og 23 cents"+ , "2 hong kong dollars og 23 cent"+ , "2 hong kong dollars og 23 cents"+ , "2 hong kong dollar og 23 cents"+ , "2 hong kong dollars og 23 cents"+ , "to hong kong dollar 23 cent"+ , "to hong kong dollars 23 cent"+ , "to hong kong dollar 23 cents"+ , "to hong kong dollars 23 cents"+ , "to hong kong dollar og 23 cent"+ , "to hong kong dollars og 23 cent"+ , "to hong kong dollar og 23 cents"+ , "to hong kong dollars og 23 cents"+ , "to hong kong dollar 23"+ , "to hong kong dollars 23"+ ]+ , examples (simple INR 2.23)+ [ "2 indiske rupi og 23 paise"+ , "2 indiske rupier og 23 paise"+ , "to indiske rupi 23 paise"+ , "to indiske rupier 23 paise"+ , "to indiske rupier 23 paise"+ , "to indiske rupi og 23 paise"+ , "to indiske rupier og 23 paise"+ , "to indiske rupi 23"+ , "to indiske rupier 23"+ ]+ , examples (simple NZD 2.23)+ [ "2 new zealand dollar og 23 cent"+ , "2 new zealand dollars og 23 cent"+ , "2 new zealand dollars og 23 cents"+ , "2 new zealandske dollar og 23 cent"+ , "2 new zealandske dollars og 23 cent"+ , "2 new zealandske dollars og 23 cents"+ , "2 new zealand dollar og 23 cents"+ , "2 new zealand dollars og 23 cents"+ , "2 nz dollar og 23 cents"+ , "2 nz dollars og 23 cents"+ , "to new zealand dollar 23 cent"+ , "to new zealand dollars 23 cent"+ , "to new zealand dollars 23 cents"+ , "to new zealandske dollar 23 cent"+ , "to new zealandske dollars 23 cent"+ , "to new zealandske dollars 23 cents"+ , "to new zealand dollar 23 cents"+ , "to new zealand dollars 23 cents"+ , "to new zealand dollars 23 cent"+ , "to new zealand dollar og 23 cent"+ , "to new zealand dollars og 23 cent"+ , "to new zealandske dollar og 23 cent"+ , "to new zealandske dollars og 23 cent"+ , "to new zealandske dollars og 23 cents"+ , "to new zealand dollar og 23 cents"+ , "to new zealand dollars og 23 cent"+ , "to new zealand dollars og 23 cents"+ , "to new zealand dollar 23"+ , "to new zealand dollars 23"+ , "to new zealandske dollar 23"+ , "to new zealandske dollars 23"+ , "to nz dollar 23"+ , "to nz dollars 23"+ ]+ , examples (simple PLN 2.23)+ [ "2 zloty og 23 groszy"+ , "2 sloty og 23 groszy"+ , "2 polske zloty og 23 groszy"+ , "2 polske sloty og 23 groszy"+ , "to zloty 23 groszy"+ , "to sloty 23 groszy"+ , "to polske zloty 23 groszy"+ , "to polske sloty 23 groszy"+ , "to zloty og 23 groszy"+ , "to sloty og 23 groszy"+ , "to polske zloty og 23 groszy"+ , "to polske sloty og 23 groszy"+ , "to zloty 23"+ , "to sloty 23"+ , "to polske zloty 23"+ , "to polske sloty 23"+ ]+ , examples (simple SGD 2.23)+ [ "2 singapore dollar og 23 cent"+ , "2 singapore dollars og 23 cent"+ , "2 singaporske dollar og 23 cent"+ , "2 singaporske dollars og 23 cent"+ , "2 singapore dollar og 23 cents"+ , "2 singapore dollars og 23 cents"+ , "to singapore dollar 23 cent"+ , "to singapore dollars 23 cent"+ , "to singaporske dollar 23 cent"+ , "to singaporske dollars 23 cent"+ , "to singapore dollar 23 cents"+ , "to singapore dollars 23 cents"+ , "to singapore dollar og 23 cent"+ , "to singapore dollars og 23 cent"+ , "to singaporske dollar og 23 cent"+ , "to singaporske dollars og 23 cent"+ , "to singapore dollar og 23 cents"+ , "to singapore dollars og 23 cents"+ , "to singapore dollar 23"+ , "to singapore dollars 23"+ , "to singaporske dollar 23"+ , "to singaporske dollars 23"+ ]+ , examples (simple ZAR 2.23)+ [ "2 rand og 23 cent"+ , "2 sørafrikanske rand og 23 cent"+ , "2 sørafrikanske rand og 23 cents"+ , "2 sør-afrikanske rand og 23 cent"+ , "2 sør-afrikanske rand og 23 cents"+ , "to rand 23 cent"+ , "to sørafrikanske rand 23 cent"+ , "to sørafrikanske rand 23 cents"+ , "to sør-afrikanske rand 23 cent"+ , "to sør-afrikanske rand 23 cents"+ , "to rand og 23 cent"+ , "to sørafrikanske rand og 23 cent"+ , "to sørafrikanske rand og 23 cents"+ , "to sør-afrikanske rand og 23 cent"+ , "to sør-afrikanske rand og 23 cents"+ , "to rand 23"+ , "to sørafrikanske rand 23"+ , "to sør-afrikanske rand 23"+ ]+ , examples (simple THB 2.23)+ [ "2 baht og 23 satang"+ , "2 bhat og 23 satang"+ , "2 thai baht og 23 satang"+ , "2 thai bhat og 23 satang"+ , "2 thailandske baht og 23 satang"+ , "2 thailandske bhat og 23 satang"+ , "to baht 23 satang"+ , "to bhat 23 satang"+ , "to thai baht 23 satang"+ , "to thai bhat 23 satang"+ , "to thailandske baht 23 satang"+ , "to thailandske bhat 23 satang"+ , "to baht og 23 satang"+ , "to bhat og 23 satang"+ , "to thai baht og 23 satang"+ , "to thai bhat og 23 satang"+ , "to thailandske baht og 23 satang"+ , "to thailandske bhat og 23 satang"+ , "to baht 23"+ , "to bhat 23"+ , "to thai baht 23"+ , "to thai bhat 23"+ , "to thailandske baht 23"+ , "to thailandske bhat 23"+ ]+ , examples (simple Cent 10)+ [ "ti cent"+ , "ti cents"+ , "ti pence"+ , "ti penny"+ , "ti pennies"+ , "10 cent"+ , "10 cents"+ , "10 cents"+ , "10 pence"+ , "10 penny"+ , "10 øre"+ , "10 ører"+ , "10 öre"+ , "10 örer"+ , "10 p"+ , "10 c"+ , "10 fen"+ , "10 haleru"+ , "10 groszy"+ , "10 paise"+ , "10 paisa"+ , "10 centesimo"+ , "10 centesimi"+ , "10 centime"+ , "10 centimes"+ , "10 ct"+ , "10 rap"+ , "10 rappen"+ , "10 rappens"+ , "10 rp"+ , "10 satang" ] , examples (simple EUR 20) [ "20€"
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -37,7 +36,7 @@ , prod = \case (Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.currency = c}: Token Numeral NumeralData{TNumeral.value = v}:- _) -> Just . Token AmountOfMoney . withValue v $ currencyOnly c+ _) -> Just $ Token AmountOfMoney . withValue v $ currencyOnly c _ -> Nothing } @@ -49,11 +48,11 @@ , regex "og" , Predicate isNatural ]- , prod = \tokens -> case tokens of+ , prod = \case (Token AmountOfMoney fd: _: Token Numeral NumeralData{TNumeral.value = c}:- _) -> Just . Token AmountOfMoney $ withCents c fd+ _) -> Just $ Token AmountOfMoney $ withCents c fd _ -> Nothing } @@ -64,7 +63,7 @@ [ regex "omtrent|cirka|rundt|ca" , Predicate isMoneyWithValue ]- , prod = \tokens -> case tokens of+ , prod = \case (_:token:_) -> Just token _ -> Nothing }@@ -73,9 +72,10 @@ ruleCent = Rule { name = "cent" , pattern =- [ regex "cents?|penn(y|ies)|(ø)re"+ [ regex "cent(?:\\b|s)|\\bc\\b|pen(?:ce|ny|nies)|\\bp\\b|(?:ø|ö)rer?|fen|haleru|groszy|pais(?:e|a)\+ \|centesim(?:o|i)|centimes?|\\bct?\\b|\\brp?\\b|rap(?:pen)?s?|satang" ]- , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly Cent+ , prod = const $ Just $ Token AmountOfMoney $ currencyOnly Cent } ruleIntersectXCents :: Rule@@ -85,26 +85,10 @@ [ Predicate isWithoutCents , Predicate isCents ]- , prod = \tokens -> case tokens of+ , prod = \case (Token AmountOfMoney fd: Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just c}:- _) -> Just . Token AmountOfMoney $ withCents c fd- _ -> Nothing- }--ruleIntersectXCentsWithAnd :: Rule-ruleIntersectXCentsWithAnd = Rule- { name = "intersect (X cents) with and"- , pattern =- [ Predicate isWithoutCents- , regex "og"- , Predicate isCents- ]- , prod = \tokens -> case tokens of- (Token AmountOfMoney fd:- _:- Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just c}:- _) -> Just . Token AmountOfMoney $ withCents c fd+ _) -> Just $ Token AmountOfMoney $ withCents c fd _ -> Nothing } @@ -112,18 +96,18 @@ ruleNok = Rule { name = "NOK" , pattern =- [ regex "kr(oner)?"+ [ regex "(?:norske? ?)?kr(?:oner?)?" ]- , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly NOK+ , prod = const $ Just $ Token AmountOfMoney $ currencyOnly NOK } rulePound :: Rule rulePound = Rule { name = "£" , pattern =- [ regex "pund?"+ [ regex "po?und?s?" ]- , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly Pound+ , prod = const $ Just $ Token AmountOfMoney $ currencyOnly Pound } ruleIntersectAndXCents :: Rule@@ -134,11 +118,11 @@ , regex "og" , Predicate isCents ]- , prod = \tokens -> case tokens of+ , prod = \case (Token AmountOfMoney fd: _: Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just c}:- _) -> Just . Token AmountOfMoney $ withCents c fd+ _) -> Just $ Token AmountOfMoney $ withCents c fd _ -> Nothing } @@ -149,10 +133,10 @@ [ Predicate isWithoutCents , Predicate isNatural ]- , prod = \tokens -> case tokens of+ , prod = \case (Token AmountOfMoney fd: Token Numeral NumeralData{TNumeral.value = c}:- _) -> Just . Token AmountOfMoney $ withCents c fd+ _) -> Just $ Token AmountOfMoney $ withCents c fd _ -> Nothing } @@ -162,9 +146,171 @@ , pattern = [ regex "dirhams?" ]- , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly AED+ , prod = const $ Just $ Token AmountOfMoney $ currencyOnly AED } +ruleSEK :: Rule+ruleSEK = Rule+ { name = "SEK"+ , pattern =+ [ regex "(?:svenske? )?kron(?:a|or)|svenske? kr(?:oner?)?"+ ]+ , prod = const $ Just $ Token AmountOfMoney $ currencyOnly SEK+ }++ruleGBP :: Rule+ruleGBP = Rule+ { name = "GBP"+ , pattern =+ [ regex "(?:britiske?|engelske?) po?unds?"+ ]+ , prod = const $ Just $ Token AmountOfMoney $ currencyOnly GBP+ }++ruleDKK :: Rule+ruleDKK = Rule+ { name = "DKK"+ , pattern =+ [ regex "danske? kr(?:oner?)?"+ ]+ , prod = const $ Just $ Token AmountOfMoney $ currencyOnly DKK+ }++ruleUSD :: Rule+ruleUSD = Rule+ { name = "USD"+ , pattern =+ [ regex "amerikanske? dollars?"+ ]+ , prod = const $ Just $ Token AmountOfMoney $ currencyOnly USD+ }++ruleAUD :: Rule+ruleAUD = Rule+ { name = "AUD"+ , pattern =+ [ regex "australske? dollars?"+ ]+ , prod = const $ Just $ Token AmountOfMoney $ currencyOnly AUD+ }++ruleCAD :: Rule+ruleCAD = Rule+ { name = "CAD"+ , pattern =+ [ regex "(?:k|c)anadiske? dollars?"+ ]+ , prod = const $ Just $ Token AmountOfMoney $ currencyOnly CAD+ }++ruleCHF :: Rule+ruleCHF = Rule+ { name = "CHF"+ , pattern =+ [ regex "sveitsiske? francs?"+ ]+ , prod = const $ Just $ Token AmountOfMoney $ currencyOnly CHF+ }++ruleCNY :: Rule+ruleCNY = Rule+ { name = "CNY"+ , pattern =+ [ regex "(?:kinesiske? )?(?:yuan|renminbi)"+ ]+ , prod = const $ Just $ Token AmountOfMoney $ currencyOnly CNY+ }++ruleCZK :: Rule+ruleCZK = Rule+ { name = "CZK"+ , pattern =+ [ regex "(?:tsjekkiske? )?koruna"+ ]+ , prod = const $ Just $ Token AmountOfMoney $ currencyOnly CZK+ }++ruleHKD :: Rule+ruleHKD = Rule+ { name = "HKD"+ , pattern =+ [ regex "hong kong dollars?"+ ]+ , prod = const $ Just $ Token AmountOfMoney $ currencyOnly HKD+ }++ruleINR :: Rule+ruleINR = Rule+ { name = "INR"+ , pattern =+ [ regex "(?:indiske? )?rup(?:i(?:er)?|ees?)"+ ]+ , prod = const $ Just $ Token AmountOfMoney $ currencyOnly INR+ }++ruleJPY :: Rule+ruleJPY = Rule+ { name = "JPY"+ , pattern =+ [ regex "japanske? yen"+ ]+ , prod = const $ Just $ Token AmountOfMoney $ currencyOnly JPY+ }++ruleNZD :: Rule+ruleNZD = Rule+ { name = "NZD"+ , pattern =+ [ regex "(?:nz|new zealand(?:ske)?) dollars?"+ ]+ , prod = const $ Just $ Token AmountOfMoney $ currencyOnly NZD+ }++rulePKR :: Rule+rulePKR = Rule+ { name = "PKR"+ , pattern =+ [ regex "pakistanske? rup(?:i(?:er)?|ees?)"+ ]+ , prod = const $ Just $ Token AmountOfMoney $ currencyOnly PKR+ }++rulePLN :: Rule+rulePLN = Rule+ { name = "PLN"+ , pattern =+ [ regex "(?:polske? )?(?:z|s)?lotys?"+ ]+ , prod = const $ Just $ Token AmountOfMoney $ currencyOnly PLN+ }++ruleSGD :: Rule+ruleSGD = Rule+ { name = "SGD"+ , pattern =+ [ regex "singapor(?:e|ske?) dollars?"+ ]+ , prod = const $ Just $ Token AmountOfMoney $ currencyOnly SGD+ }++ruleTHB :: Rule+ruleTHB = Rule+ { name = "THB"+ , pattern =+ [ regex "(?:thai(?:land(?:ske?)?)? )?b(?:ah|ha)t"+ ]+ , prod = const $ Just $ Token AmountOfMoney $ currencyOnly THB+ }++ruleZAR :: Rule+ruleZAR = Rule+ { name = "ZAR"+ , pattern =+ [ regex "(?:sør(?: |-)?afrika(?:nske?)? )?rand"+ ]+ , prod = const $ Just $ Token AmountOfMoney $ currencyOnly ZAR+ }+ rules :: [Rule] rules = [ ruleUnitAmount@@ -175,7 +321,24 @@ , ruleIntersectAndNumeral , ruleIntersectAndXCents , ruleIntersectXCents- , ruleIntersectXCentsWithAnd , ruleNok , rulePound+ , ruleSEK+ , ruleDKK+ , ruleUSD+ , ruleAUD+ , ruleCAD+ , ruleGBP+ , ruleCHF+ , ruleCNY+ , ruleCZK+ , ruleHKD+ , ruleINR+ , ruleJPY+ , ruleNZD+ , rulePKR+ , rulePLN+ , ruleSGD+ , ruleTHB+ , ruleZAR ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -47,6 +46,8 @@ [ "$10K" , "10k$" , "$10000"+ , "$10.000"+ , "$10.000,00" , "10000,00 $" ] , examples (simple USD 3.14)
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -140,6 +139,15 @@ , "42RM" , "RM42" , "MYR42"+ ]+ , examples (simple UAH 3.04)+ [ "UAH 3.04"+ , "UAH3.04"+ , "3.04 грн"+ , "грн 3.04"+ , "₴3.04"+ , "₴ 3.04"+ , "3.04₴" ] , examples (between Dollar (10, 20)) [ "между 10 и 20 долларами"
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -97,6 +96,15 @@ , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly Unnamed } +ruleHryvnia :: Rule+ruleHryvnia = Rule+ { name = "Hryvnia"+ , pattern =+ [ regex "грн"+ ]+ , prod = \_ -> Just $ Token AmountOfMoney $ currencyOnly UAH+ }+ ruleIntersectAndXCents :: Rule ruleIntersectAndXCents = Rule { name = "intersect (and X cents)"@@ -304,6 +312,7 @@ , ruleCent , ruleDollar , ruleEUR+ , ruleHryvnia , ruleIntersect , ruleIntersectAndNumeral , ruleIntersectAndXCents
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -41,12 +40,15 @@ , ("cad", CAD) , ("¢", Cent) , ("c", Cent)+ , ("chf", CHF) , ("cny", CNY)+ , ("czk", CZK) , ("rmb", CNY) , ("yuan", CNY) , ("$", Dollar) , ("dinar", Dinar) , ("dinars", Dinar)+ , ("dkk", DKK) , ("dollar", Dollar) , ("dollars", Dollar) , ("egp", EGP)@@ -60,9 +62,13 @@ , ("€uros", EUR) , ("€urs", EUR) , ("gbp", GBP)+ , ("gel", GEL)+ , ("hkd", HKD) , ("hrk", HRK) , ("idr", IDR) , ("ils", ILS)+ , ("₪", ILS)+ , ("nis", ILS) , ("inr", INR) , ("iqd", IQD) , ("rs", INR)@@ -73,15 +79,23 @@ , ("jod", JOD) , ("¥", JPY) , ("jpy", JPY)+ , ("lari", GEL)+ , ("\x20BE", GEL) , ("yen", JPY) , ("krw", KRW) , ("kwd", KWD) , ("lbp", LBP) , ("mad", MAD)+ , ("mnt", MNT) , ("myr", MYR) , ("rm", MYR)+ , ("₮", MNT)+ , ("tugrik", MNT)+ , ("tugriks", MNT) , ("nok", NOK) , ("nzd", NZD)+ , ("pkr", PKR)+ , ("pln", PLN) , ("£", Pound) , ("pt", PTS) , ("pta", PTS)@@ -100,17 +114,24 @@ , ("sgd", SGD) , ("shekel", ILS) , ("shekels", ILS)+ , ("thb", THB) , ("ttd", TTD)+ , ("₴", UAH)+ , ("uah", UAH) , ("usd", USD) , ("us$", USD) , ("vnd", VND)+ , ("zar", ZAR)+ , ("tl", TRY)+ , ("lira", TRY)+ , ("₺", TRY) ] ruleCurrencies :: Rule ruleCurrencies = Rule { name = "currencies" , pattern =- [ regex "(aed|aud|bgn|brl|byn|¢|c|cad|cny|\\$|dinars?|dollars?|egp|(e|€)uro?s?|€|gbp|hrk|idr|ils|inr|iqd|jmd|jod|¥|jpy|krw|kwd|lbp|mad|myr|rm|nok|nzd|£|pta?s?|qar|₽|rs\\.?|riy?als?|ron|rub|rupees?|sar|sek|sgb|shekels?|ttd|us(d|\\$)|vnd|yen|yuan)"+ [ regex "(aed|aud|bgn|brl|byn|¢|cad|chf|cny|c|\\$|dinars?|dkk|dollars?|egp|(e|€)uro?s?|€|gbp|gel|\x20BE|hkd|hrk|idr|ils|₪|inr|iqd|jmd|jod|¥|jpy|lari|krw|kwd|lbp|mad|₮|mnt|tugriks?|myr|rm|nis|nok|nzd|£|pkr|pln|pta?s?|qar|₽|rs\\.?|riy?als?|ron|rub|rupees?|sar|sek|sgb|shekels?|thb|ttd|₴|uah|us(d|\\$)|vnd|yen|yuan|zar|tl|lira|₺)" ] , prod = \tokens -> case tokens of (Token RegexMatch (GroupMatch (match:_)):_) -> do@@ -133,8 +154,21 @@ _ -> Nothing } +ruleAmountLatent :: Rule+ruleAmountLatent = Rule+ { name = "<amount> (latent)"+ , pattern =+ [ Predicate isPositive+ ]+ , prod = \tokens -> case tokens of+ (Token Numeral NumeralData{TNumeral.value = v}:_) ->+ Just . Token AmountOfMoney . mkLatent $ valueOnly v+ _ -> Nothing+ }+ rules :: [Rule] rules = [ ruleAmountUnit+ , ruleAmountLatent , ruleCurrencies ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -0,0 +1,55 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.++{-# LANGUAGE OverloadedStrings #-}++module Duckling.AmountOfMoney.TR.Corpus+ ( corpus+ ) where++import Data.String (fromString)+import Prelude++import Duckling.AmountOfMoney.Types+import Duckling.Testing.Types+import Duckling.Locale+import Duckling.Resolve++corpus :: Corpus+corpus = (testContext {locale = makeLocale TR Nothing}, testOptions, allExamples)++allExamples :: [Example]+allExamples = concat+ [ examples (simple TRY 10000)+ [ "10 bin lira"+ , "on bin lira"+ , "10000 lira"+ ]+ , examples (simple TRY 1)+ [ "bir lira"+ , "1 lira"+ ]+ , examples (simple Cent 10)+ [ "on kuruş"+ , "10 kuruş"+ ]+ , examples (simple Cent 25)+ [ "25 kuruş"+ , "yirmi beş kuruş"+ ]+ , examples (simple Cent 5)+ [ "beş kuruş"+ , "5 kuruş"+ ]+ , examples (simple Cent 66)+ [ "altmış altı kuruş"+ , "66 kuruş"+ ]+ , examples (simple TRY 100.75)+ [ "yüz lira yetmiş beş kuruş"+ , "100 lira 75 kuruş"+ ]+ ]
@@ -0,0 +1,160 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}++module Duckling.AmountOfMoney.TR.Rules+ ( rules+ ) where++import Data.String (fromString)+import Prelude++import Duckling.AmountOfMoney.Helpers+import Duckling.AmountOfMoney.Types (Currency(..), AmountOfMoneyData (..))+import Duckling.Dimensions.Types+import Duckling.Numeral.Helpers (isNatural, isPositive)+import Duckling.Numeral.Types (NumeralData (..))+import Duckling.Types+import qualified Duckling.AmountOfMoney.Types as TAmountOfMoney+import qualified Duckling.Numeral.Types as TNumeral++ruleUnitAmount :: Rule+ruleUnitAmount = Rule+ { name = "<unit> <amount>"+ , pattern =+ [ Predicate isCurrencyOnly+ , Predicate isPositive+ ]+ , prod = \case+ (Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.currency = c}:+ Token Numeral NumeralData{TNumeral.value = v}:+ _) -> Just $ Token AmountOfMoney $ withValue v $ currencyOnly c+ _ -> Nothing+ }++rulePounds :: Rule+rulePounds = Rule+ { name = "₺"+ , pattern =+ [ regex "₺"+ ]+ , prod = \_ -> Just $ Token AmountOfMoney $ currencyOnly TRY+ }++ruleCent :: Rule+ruleCent = Rule+ { name = "cent"+ , pattern =+ [ regex "kuruş?"+ ]+ , prod = \_ -> Just $ Token AmountOfMoney $ currencyOnly Cent+ }++ruleADollarCoin :: Rule+ruleADollarCoin = Rule+ { name = "a <dollar coin>"+ , pattern =+ [ regex "kuruş"+ , Predicate isDollarCoin+ ]+ , prod = \tokens -> case tokens of+ (_:+ Token AmountOfMoney fd:+ _) -> Just $ Token AmountOfMoney fd+ _ -> Nothing+ }++ruleNumDollarCoins :: Rule+ruleNumDollarCoins = Rule+ { name = "X <dollar coins>"+ , pattern =+ [ Predicate isNatural+ , Predicate isDollarCoin+ ]+ , prod = \tokens -> case tokens of+ (Token Numeral NumeralData{TNumeral.value = c}:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just d,+ TAmountOfMoney.currency = cur}:+ _) -> Just $ Token AmountOfMoney $ withValue (c * d) $ currencyOnly cur+ _ -> Nothing+ }++ruleIntersectAndXCents :: Rule+ruleIntersectAndXCents = Rule+ { name = "intersect (and X cents)"+ , pattern =+ [ Predicate isWithoutCents+ , regex "(lira|tl)"+ , Predicate isCents+ ]+ , prod = \tokens -> case tokens of+ (Token AmountOfMoney fd:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just c}:+ _) -> Just $ Token AmountOfMoney $ withCents c fd+ _ -> Nothing+ }++ruleIntersect :: Rule+ruleIntersect = Rule+ { name = "intersect"+ , pattern =+ [ Predicate isWithoutCents+ , Predicate isNatural+ ]+ , prod = \tokens -> case tokens of+ (Token AmountOfMoney fd:+ Token Numeral NumeralData{TNumeral.value = c}:+ _) -> Just $ Token AmountOfMoney $ withCents c fd+ _ -> Nothing+ }++ruleIntersectAndNumeral :: Rule+ruleIntersectAndNumeral = Rule+ { name = "intersect (and number)"+ , pattern =+ [ Predicate isWithoutCents+ , regex "(lira|tl)"+ , Predicate isNatural+ ]+ , prod = \tokens -> case tokens of+ (Token AmountOfMoney fd:+ _:+ Token Numeral NumeralData{TNumeral.value = c}:+ _) -> Just $ Token AmountOfMoney $ withCents c fd+ _ -> Nothing+ }++ruleIntersectXCents :: Rule+ruleIntersectXCents = Rule+ { name = "intersect (X cents)"+ , pattern =+ [ Predicate isWithoutCents+ , Predicate isCents+ ]+ , prod = \tokens -> case tokens of+ (Token AmountOfMoney fd:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just c}:+ _) -> Just $ Token AmountOfMoney $ withCents c fd+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleUnitAmount+ , ruleCent+ , ruleADollarCoin+ , ruleNumDollarCoins+ , ruleIntersect+ , ruleIntersectAndNumeral+ , ruleIntersectAndXCents+ , ruleIntersectXCents+ , rulePounds+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE DeriveAnyClass #-}@@ -23,7 +22,7 @@ import Prelude import qualified Data.HashMap.Strict as H -import Duckling.Resolve (Resolve(..))+import Duckling.Resolve (Resolve(..), Options(..)) data Currency -- ambiguous@@ -42,10 +41,14 @@ | BRL | BYN | CAD+ | CHF | CNY+ | CZK+ | DKK | EGP | EUR | GBP+ | HKD | HRK | IDR | ILS@@ -54,13 +57,17 @@ | JMD | JOD | JPY+ | GEL | KRW | KWD | LBP | MAD+ | MNT | MYR | NOK | NZD+ | PKR+ | PLN | PTS | QAR | RON@@ -68,9 +75,13 @@ | SAR | SEK | SGD+ | THB | TTD | USD | VND+ | ZAR+ | UAH+ | TRY deriving (Eq, Generic, Hashable, Show, Ord, NFData) instance ToJSON Currency where@@ -88,10 +99,14 @@ toJSON BRL = "BRL" toJSON BYN = "BYN" toJSON CAD = "CAD"+ toJSON CHF = "CHF" toJSON CNY = "CNY"+ toJSON CZK = "CZK"+ toJSON DKK = "DKK" toJSON EGP = "EGP" toJSON EUR = "EUR" toJSON GBP = "GBP"+ toJSON HKD = "HKD" toJSON HRK = "HRK" toJSON IDR = "IDR" toJSON ILS = "ILS"@@ -100,47 +115,71 @@ toJSON JMD = "JMD" toJSON JOD = "JOD" toJSON JPY = "JPY"+ toJSON GEL = "GEL" toJSON KRW = "KRW" toJSON KWD = "KWD" toJSON LBP = "LBP" toJSON MAD = "MAD"+ toJSON MNT = "MNT" toJSON MYR = "MYR" toJSON NOK = "NOK" toJSON NZD = "NZD" toJSON PTS = "PTS"+ toJSON PKR = "PKR"+ toJSON PLN = "PLN" toJSON QAR = "QAR" toJSON RON = "RON" toJSON RUB = "RUB" toJSON SAR = "SAR" toJSON SEK = "SEK" toJSON SGD = "SGD"+ toJSON THB = "THB" toJSON TTD = "TTD" toJSON USD = "USD" toJSON VND = "VND"+ toJSON ZAR = "ZAR"+ toJSON UAH = "UAH"+ toJSON TRY = "TRY" data AmountOfMoneyData = AmountOfMoneyData { value :: Maybe Double , currency :: Currency , minValue :: Maybe Double , maxValue :: Maybe Double+ , latent :: Bool } deriving (Eq, Generic, Hashable, Show, Ord, NFData) instance Resolve AmountOfMoneyData where type ResolvedValue AmountOfMoneyData = AmountOfMoneyValue+ resolve _ Options {withLatent = False} AmountOfMoneyData {latent = True} =+ Nothing resolve _ _ AmountOfMoneyData {value = Nothing, minValue = Nothing- , maxValue = Nothing} = Nothing- resolve _ _ AmountOfMoneyData {value = Just value, currency} =- Just (simple currency value, False)+ , maxValue = Nothing} =+ Nothing+ resolve _ _ AmountOfMoneyData {value = Just value, currency, latent} =+ Just (simple currency value, latent) resolve _ _ AmountOfMoneyData {value = Nothing, currency = c- , minValue = Just from, maxValue = Just to} =- Just (between c (from, to), False)+ , minValue = Just from, maxValue = Just to+ , latent} =+ Just (between c (from, to), latent) resolve _ _ AmountOfMoneyData {value = Nothing, currency = c- , minValue = Just v, maxValue = Nothing} =- Just (above c v, False)+ , minValue = Just v, maxValue = Nothing+ , latent} =+ Just (above c v, latent) resolve _ _ AmountOfMoneyData {value = Nothing, currency = c- , minValue = Nothing, maxValue = Just v} =- Just (under c v, False)+ , minValue = Nothing, maxValue = Just v+ , latent} =+ Just (under c v, latent)++amountOfMoneyData' :: AmountOfMoneyData+amountOfMoneyData' = AmountOfMoneyData+ { value = Nothing+ , currency = Unnamed+ , minValue = Nothing+ , maxValue = Nothing+ , latent = False+ } data IntervalDirection = Above | Under deriving (Eq, Generic, Hashable, Ord, Show, NFData)
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -100,5 +99,40 @@ , examples (simple AED 1) [ "1 AED." , "1 dirham"+ ]+ , examples (between VND (1000, 2000))+ [ "giữa 1000 và 2000 đồng"+ , "giữa 1000 đồng và 2000 đồng"+ , "từ 1000 đồng đến 2000 đồng"+ , "từ 1000 VNĐ tới 2000 VNĐ"+ , "từ 1000 đến 2000 đồng"+ , "khoảng 1000-2000 đồng"+ , "khoảng chừng từ 1000 đến 2000 đồng"+ , "tầm khoảng 1000 tới 2000 đồng"+ , "xấp xỉ VND1000-VND2000"+ , "1000-2000 đồng"+ ]+ , examples (between Dollar (1.1, 1.3))+ [ "giữa 1,1 và 1,3 đô la"+ , "từ 1 phẩy 1 đến một chấm ba đô la"+ ]+ , examples (under VND 7000)+ [ "dưới bảy ngàn đồng"+ , "ít hơn bảy nghìn đồng"+ , "kém hơn 7k đồng"+ , "không tới 7000 đồng"+ , "không cao hơn 7000 đồng"+ , "không hơn 7.000 đồng"+ , "không quá 7.000 đồng"+ , "từ 7000 đồng trở xuống"+ ]+ , examples (above Dollar 1.42)+ [ "nhiều hơn 1 đô la và bốn mươi hai xen"+ , "ít nhất $1,42"+ , "hơn 1,42 đô la"+ , "trên một đô la và 42 xu"+ , "không ít hơn 1,42 đô la"+ , "cao hơn $1,42"+ , "từ $1,42 trở lên" ] ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -45,7 +44,7 @@ ruleNg = Rule { name = "đồng" , pattern =- [ regex "đồng?"+ [ regex "đ(ồng)?" ] , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly VND }@@ -54,7 +53,7 @@ ruleDollar = Rule { name = "$" , pattern =- [ regex "đô la|đô mỹ|đ(ô)?"+ [ regex "đô( la)?( mỹ)?" ] , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly Dollar }@@ -63,7 +62,7 @@ ruleVnd = Rule { name = "VNĐ" , pattern =- [ regex "vn(Đ|\\$)"+ [ regex "vn(Đ|D|\\$)" ] , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly VND }@@ -72,7 +71,7 @@ ruleCent = Rule { name = "cent" , pattern =- [ regex "xen|xu?|penn(y|ies)"+ [ regex "xen|xu|cắc|penn(y|ies)" ] , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly Cent }@@ -81,7 +80,7 @@ rulePounds = Rule { name = "£" , pattern =- [ regex "pounds?"+ [ regex "pounds?|pao" ] , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly Pound }@@ -93,7 +92,7 @@ [ Predicate isWithoutCents , Predicate isNatural ]- , prod = \tokens -> case tokens of+ , prod = \case (Token AmountOfMoney fd: Token Numeral NumeralData{TNumeral.value = c}: _) -> Just . Token AmountOfMoney $ withCents c fd@@ -108,7 +107,7 @@ , regex "và" , Predicate isNatural ]- , prod = \tokens -> case tokens of+ , prod = \case (Token AmountOfMoney fd: _: Token Numeral NumeralData{TNumeral.value = c}:@@ -123,7 +122,7 @@ [ Predicate isWithoutCents , Predicate isCents ]- , prod = \tokens -> case tokens of+ , prod = \case (Token AmountOfMoney fd: Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just c}: _) -> Just . Token AmountOfMoney $ withCents c fd@@ -138,7 +137,7 @@ , regex "và" , Predicate isCents ]- , prod = \tokens -> case tokens of+ , prod = \case (Token AmountOfMoney fd: _: Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just c}:@@ -155,6 +154,158 @@ , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly AED } +rulePrecision :: Rule+rulePrecision = Rule+ { name = "about|exactly <amount-of-money>"+ , pattern =+ [ regex "đúng|chính xác|khoảng( chừng)?|tầm|xấp xỉ|gần"+ , Predicate isMoneyWithValue+ ]+ , prod = \case+ (_:token:_) -> Just token+ _ -> Nothing+ }++ruleIntervalBetweenNumeral :: Rule+ruleIntervalBetweenNumeral = Rule+ { name = "between|from <numeral> to|and <amount-of-money>"+ , pattern =+ [ regex "từ|giữa|khoảng"+ , Predicate isPositive+ , regex "đến|tới|và"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \case+ (_:+ Token Numeral NumeralData{TNumeral.value = from}:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c}:+ _) | from < to ->+ Just . Token AmountOfMoney . withInterval (from, to) $ currencyOnly c+ _ -> Nothing+ }++ruleIntervalBetween :: Rule+ruleIntervalBetween = Rule+ { name = "từ|giữa <amount-of-money> đến|tới|và <amount-of-money>"+ , pattern =+ [ regex "từ|giữa"+ , Predicate isSimpleAmountOfMoney+ , regex "đến|tới|và"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \case+ (_:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just from,+ TAmountOfMoney.currency = c1}:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c2}:+ _) | from < to && c1 == c2 ->+ Just . Token AmountOfMoney . withInterval (from, to) $ currencyOnly c1+ _ -> Nothing+ }++ruleIntervalNumeralDash :: Rule+ruleIntervalNumeralDash = Rule+ { name = "<numeral> - <amount-of-money>"+ , pattern =+ [ Predicate isNatural+ , regex "-"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = from}:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c}:+ _) | from < to->+ Just . Token AmountOfMoney . withInterval (from, to) $ currencyOnly c+ _ -> Nothing+ }++ruleIntervalDash :: Rule+ruleIntervalDash = Rule+ { name = "<amount-of-money> - <amount-of-money>"+ , pattern =+ [ Predicate isSimpleAmountOfMoney+ , regex "-"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \case+ (Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just from,+ TAmountOfMoney.currency = c1}:+ _:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c2}:+ _) | from < to && c1 == c2 ->+ Just . Token AmountOfMoney . withInterval (from, to) $ currencyOnly c1+ _ -> Nothing+ }++ruleIntervalMax :: Rule+ruleIntervalMax = Rule+ { name = "under/less/lower/no more than <amount-of-money>"+ , pattern =+ [ regex "dưới|(bé|ít|thấp|kém|không( cao| nhiều)?) hơn|không (đến|tới|quá)|(nhiều|cao) nhất"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \case+ (_:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c}:+ _) -> Just . Token AmountOfMoney . withMax to $ currencyOnly c+ _ -> Nothing+ }++ruleIntervalMax2 :: Rule+ruleIntervalMax2 = Rule+ { name = "under <amount-of-money>"+ , pattern =+ [ regex "từ"+ , Predicate isSimpleAmountOfMoney+ , regex "trở xuống"+ ]+ , prod = \case+ (_:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c}:+ _) -> Just . Token AmountOfMoney . withMax to $ currencyOnly c+ _ -> Nothing+ }++ruleIntervalMin :: Rule+ruleIntervalMin = Rule+ { name = "over/above/at least/more than <amount-of-money>"+ , pattern =+ [ regex "trên|(lớn |nhiều |cao |không (thấp|ít|kém) )?hơn|(ít|thấp) nhất"+ , Predicate isSimpleAmountOfMoney+ ]+ , prod = \case+ (_:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c}:+ _) -> Just . Token AmountOfMoney . withMin to $ currencyOnly c+ _ -> Nothing+ }++ruleIntervalMin2 :: Rule+ruleIntervalMin2 = Rule+ { name = "above <amount-of-money>"+ , pattern =+ [ regex "từ"+ , Predicate isSimpleAmountOfMoney+ , regex "trở lên"+ ]+ , prod = \case+ (_:+ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to,+ TAmountOfMoney.currency = c}:+ _) -> Just . Token AmountOfMoney . withMin to $ currencyOnly c+ _ -> Nothing+ }+ rules :: [Rule] rules = [ ruleUnitAmount@@ -165,7 +316,16 @@ , ruleIntersectAndNumeral , ruleIntersectVXXuxen , ruleIntersectXXuxen+ , ruleIntervalBetweenNumeral+ , ruleIntervalBetween+ , ruleIntervalDash+ , ruleIntervalNumeralDash+ , ruleIntervalMax+ , ruleIntervalMax2+ , ruleIntervalMin+ , ruleIntervalMin2 , ruleNg , rulePounds+ , rulePrecision , ruleVnd ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -29,12 +28,14 @@ [ examples (simple Cent 5) [ "五分" , "5分"+ , "五仙" ] , examples (simple Cent 20) [ "20分" , "二十分" , "2角" , "两毛"+ , "两毫" ] , examples (simple Cent 25) [ "25分"@@ -45,11 +46,27 @@ , examples (simple Dollar 7) [ "7块" , "七元"+ , "七蚊" ]+ , examples (simple Dollar 5.5)+ [ "五個半"+ ]+ , examples (simple Dollar 1.5)+ [ "個半"+ , "一個半"+ ]+ , examples (simple Dollar 1.9)+ [ "個九"+ ] , examples (simple CNY 3.14) [ "3.14人民币" , "人民幣3.14" ]+ , examples (simple HKD 3.14)+ [ "3.14港幣"+ , "港幣3.14"+ , "港幣三個一毫四"+ ] , examples (under Dollar 1.2) [ "1.2元以下" , "最多一块二角"@@ -59,10 +76,12 @@ [ "3.04块以上" , "至少三块四分" , "至少三块零四"+ , "起碼三蚊零四" ] , examples (between Dollar (5.6, 5.78)) [ "5.6到5.78元" , "五元六角-五元七毛八分" , "五块六到五块七毛八"+ , "五蚊六毫至五蚊七毫八" ] ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -17,12 +16,11 @@ import Data.Maybe import Data.String import Prelude-import qualified Data.Text as Text import Duckling.AmountOfMoney.Helpers import Duckling.AmountOfMoney.Types (Currency (..), AmountOfMoneyData (..)) import Duckling.Dimensions.Types-import Duckling.Numeral.Helpers (isNatural, isPositive, oneOf)+import Duckling.Numeral.Helpers (isNatural, isPositive, oneOf, numberBetween, decimalsToDouble) import Duckling.Numeral.Types (NumeralData (..)) import Duckling.Regex.Types import Duckling.Types@@ -35,7 +33,7 @@ , pattern = [ regex "人民币|人民幣" ]- , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly CNY+ , prod = \_ -> Just $ Token AmountOfMoney $ currencyOnly CNY } ruleCNYPrefix :: Rule@@ -47,17 +45,39 @@ ] , prod = \case (_:Token Numeral NumeralData{TNumeral.value = v}:_) ->- Just . Token AmountOfMoney . withValue v $ currencyOnly CNY+ Just $ Token AmountOfMoney $ withValue v $ currencyOnly CNY _ -> Nothing } +ruleHKD :: Rule+ruleHKD = Rule+ { name = "HKD"+ , pattern =+ [ regex "港幣"+ ]+ , prod = \_ -> Just $ Token AmountOfMoney $ currencyOnly HKD+ }++ruleHKDPrefix :: Rule+ruleHKDPrefix = Rule+ { name = "hkd prefix"+ , pattern =+ [ regex "港幣"+ , Predicate isPositive+ ]+ , prod = \case+ (_:Token Numeral NumeralData{TNumeral.value = v}:_) ->+ Just $ Token AmountOfMoney $ withValue v $ currencyOnly HKD+ _ -> Nothing+ }+ ruleCent :: Rule ruleCent = Rule { name = "cent" , pattern =- [ regex "分"+ [ regex "分|仙" ]- , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly Cent+ , prod = \_ -> Just $ Token AmountOfMoney $ currencyOnly Cent } ruleDime :: Rule@@ -65,11 +85,11 @@ { name = "dime" , pattern = [ Predicate isPositive- , regex "角|毛"+ , regex "角|毛|毫" ] , prod = \case (Token Numeral NumeralData{TNumeral.value = v}:_) ->- Just . Token AmountOfMoney $+ Just $ Token AmountOfMoney $ withCents (v * 10) $ currencyOnly Cent _ -> Nothing }@@ -78,9 +98,9 @@ ruleDollar = Rule { name = "dollar" , pattern =- [ regex "元|圆|块"+ [ regex "元|圆|块|蚊|個" ]- , prod = \_ -> Just . Token AmountOfMoney $ currencyOnly Dollar+ , prod = \_ -> Just $ Token AmountOfMoney $ currencyOnly Dollar } rulePrecision :: Rule@@ -118,7 +138,7 @@ (Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just d}: Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just c}: _) ->- Just . Token AmountOfMoney $ withCents (c + d) $ currencyOnly Cent+ Just $ Token AmountOfMoney $ withCents (c + d) $ currencyOnly Cent _ -> Nothing } @@ -132,10 +152,23 @@ , prod = \case (Token AmountOfMoney fd: Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just c}:- _) -> Just . Token AmountOfMoney $ withCents c fd+ _) -> Just $ Token AmountOfMoney $ withCents c fd _ -> Nothing } +ruleIntersectDollarsAndAHalf :: Rule+ruleIntersectDollarsAndAHalf = Rule+ { name = "<amount-of-money> and a half"+ , pattern =+ [ Predicate $ and . sequence [isSimpleAmountOfMoney, isWithoutCents]+ , regex "半"+ ]+ , prod = \case+ (Token AmountOfMoney fd:_) ->+ Just $ Token AmountOfMoney $ withCents 50 fd+ _ -> Nothing+ }+ ruleIntersect :: Rule ruleIntersect = Rule { name = "intersect (implicit 0 delimited cents)"@@ -147,7 +180,7 @@ , prod = \case (Token AmountOfMoney fd:_: Token Numeral NumeralData{TNumeral.value = c}:- _) -> Just . Token AmountOfMoney $ withCents c fd+ _) -> Just $ Token AmountOfMoney $ withCents c fd _ -> Nothing } @@ -161,7 +194,7 @@ , prod = \case (Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just v}: Token Numeral NumeralData{TNumeral.value = c}:- _) -> Just . Token AmountOfMoney $ withCents (v + c) $ currencyOnly Cent+ _) -> Just $ Token AmountOfMoney $ withCents (v + c) $ currencyOnly Cent _ -> Nothing } @@ -175,16 +208,38 @@ , prod = \case (Token AmountOfMoney fd: Token Numeral NumeralData{TNumeral.value = d}:- _) -> Just . Token AmountOfMoney $ withCents (d * 10) fd+ _) -> Just $ Token AmountOfMoney $ withCents (d * 10) fd _ -> Nothing } +ruleOneDollarAndAHalf :: Rule+ruleOneDollarAndAHalf = Rule+ { name = "one dollar and a half (short form)"+ , pattern =+ [ regex "個半"+ ]+ , prod = \_ -> Just $ Token AmountOfMoney $ withValue 1.5 (currencyOnly Dollar)+ }++ruleOneDollarAnd :: Rule+ruleOneDollarAnd = Rule+ { name = "one dollar and x dimes (short form)"+ , pattern =+ [ regex "個"+ , numberBetween 1 10+ ]+ , prod = \case+ (_:Token Numeral NumeralData{TNumeral.value = v}:_) ->+ Just $ Token AmountOfMoney $ withValue (1 + decimalsToDouble(v)) (currencyOnly Dollar)+ _ -> Nothing+ }+ ruleIntervalNumeralDash :: Rule ruleIntervalNumeralDash = Rule { name = "<numeral> - <amount-of-money>" , pattern = [ Predicate isPositive- , regex "-|~|到"+ , regex "-|~|到|至" , Predicate isSimpleAmountOfMoney ] , prod = \case@@ -193,7 +248,7 @@ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to, TAmountOfMoney.currency = c}: _) | from < to ->- Just . Token AmountOfMoney . withInterval (from, to) $ currencyOnly c+ Just $ Token AmountOfMoney $ withInterval (from, to) $ currencyOnly c _ -> Nothing } @@ -202,7 +257,7 @@ { name = "<amount-of-money> - <amount-of-money>" , pattern = [ Predicate isSimpleAmountOfMoney- , regex "-|~|到"+ , regex "-|~|到|至" , Predicate isSimpleAmountOfMoney ] , prod = \case@@ -212,7 +267,7 @@ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to, TAmountOfMoney.currency = c2}: _) | from < to && c1 == c2 ->- Just . Token AmountOfMoney . withInterval (from, to) $ currencyOnly c1+ Just $ Token AmountOfMoney $ withInterval (from, to) $ currencyOnly c1 _ -> Nothing } @@ -220,7 +275,7 @@ ruleIntervalBound = Rule { name = "under/less/lower/no more than <amount-of-money> (最多|至少|最少)" , pattern =- [ regex "(最多|至少|最少)"+ [ regex "(最多|至少|最少|起碼)" , Predicate isSimpleAmountOfMoney ] , prod = \case@@ -228,9 +283,10 @@ Token AmountOfMoney AmountOfMoneyData{TAmountOfMoney.value = Just to, TAmountOfMoney.currency = c}: _) -> case match of- "最多" -> Just . Token AmountOfMoney . withMax to $ currencyOnly c- "最少" -> Just . Token AmountOfMoney . withMin to $ currencyOnly c- "至少" -> Just . Token AmountOfMoney . withMin to $ currencyOnly c+ "最多" -> Just $ Token AmountOfMoney $ withMax to $ currencyOnly c+ "最少" -> Just $ Token AmountOfMoney $ withMin to $ currencyOnly c+ "至少" -> Just $ Token AmountOfMoney $ withMin to $ currencyOnly c+ "起碼" -> Just $ Token AmountOfMoney $ withMin to $ currencyOnly c _ -> Nothing _ -> Nothing }@@ -247,8 +303,8 @@ TAmountOfMoney.currency = c}: Token RegexMatch (GroupMatch (match:_)): _) -> case match of- "以下" -> Just . Token AmountOfMoney . withMax to $ currencyOnly c- "以上" -> Just . Token AmountOfMoney . withMin to $ currencyOnly c+ "以下" -> Just $ Token AmountOfMoney $ withMax to $ currencyOnly c+ "以上" -> Just $ Token AmountOfMoney $ withMin to $ currencyOnly c _ -> Nothing _ -> Nothing }@@ -258,6 +314,8 @@ [ ruleCent , ruleCNY , ruleCNYPrefix+ , ruleHKD+ , ruleHKDPrefix , ruleDime , ruleDollar , ruleIntersect@@ -265,10 +323,13 @@ , ruleIntersect3 , ruleIntersectDimesAndCents , ruleIntersectDollarsAndDimesCents+ , ruleIntersectDollarsAndAHalf , ruleIntervalDash , ruleIntervalNumeralDash , ruleIntervalBound , ruleIntervalBound2 , rulePrecision , rulePrecision2+ , ruleOneDollarAndAHalf+ , ruleOneDollarAnd ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE NamedFieldPuns #-}@@ -36,22 +35,22 @@ import Duckling.Types -- | Parses `input` and returns a curated list of entities found.-parse :: Text -> Context -> Options -> [Some Dimension] -> [Entity]+parse :: Text -> Context -> Options -> [Seal Dimension] -> [Entity] parse input ctx options = map (formatToken input) . analyze input ctx options . HashSet.fromList -supportedDimensions :: HashMap Lang [Some Dimension]+supportedDimensions :: HashMap Lang [Seal Dimension] supportedDimensions = HashMap.fromList [ (l, allDimensions l) | l <- [minBound..maxBound] ] -- | Returns a curated list of resolved tokens found -- When `targets` is non-empty, returns only tokens of such dimensions.-analyze :: Text -> Context -> Options -> HashSet (Some Dimension)+analyze :: Text -> Context -> Options -> HashSet (Seal Dimension) -> [ResolvedToken] analyze input context@Context{..} options targets = rank (classifiers locale) targets . filter (\Resolved{node = Node{token = (Token d _)}} ->- HashSet.null targets || HashSet.member (This d) targets+ HashSet.null targets || HashSet.member (Seal d) targets ) $ parseAndResolve (rulesFor locale targets) input context options
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE NoRebindableSyntax #-}@@ -21,7 +20,8 @@ , Range(..) , Region(..) , ResolvedVal(..)- , Some(..)+ , Seal(..)+ , withSeal , fromName , makeLocale , toJText
@@ -0,0 +1,75 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}++module Duckling.CreditCardNumber.Corpus+ ( corpus+ , negativeCorpus+ ) where++import Prelude+import Data.String+import qualified Data.Text as T++import Duckling.CreditCardNumber.Types+import Duckling.CreditCardNumber.Helpers+import Duckling.Testing.Types++corpus :: Corpus+corpus = (testContext, testOptions, allExamples)++negativeCorpus :: NegativeCorpus+negativeCorpus = (testContext, testOptions, examples)+ where+ examples =+ [ T.replicate (minNumberDigits - 1) "0"+ , T.replicate (maxNumberDigits + 1) "0"+ , "invalid"+ , "4111111111111110"+ , "41111111-1111-1111"+ , "371449635398430"+ , "3714496353-98431"+ , "6011111111111110"+ , "60111111-1111-1117"+ , "5555555555554440"+ , "55555555-5555-4444"+ , "30569309025900"+ , "3056930902-5904"+ ]++allExamples :: [Example]+allExamples = concat+ [ examples+ (CreditCardNumberValue "4111111111111111" Visa)+ [ "4111111111111111"+ , "4111-1111-1111-1111"+ ]+ , examples+ (CreditCardNumberValue "371449635398431" Amex)+ [ "371449635398431"+ , "3714-496353-98431"+ ]+ , examples+ (CreditCardNumberValue "6011111111111117" Discover)+ [ "6011111111111117"+ , "6011-1111-1111-1117"+ ]+ , examples+ (CreditCardNumberValue "5555555555554444" Mastercard)+ [ "5555555555554444"+ , "5555-5555-5555-4444"+ ]+ , examples+ (CreditCardNumberValue "30569309025904" DinerClub)+ [ "30569309025904"+ , "3056-930902-5904"+ ]+ , examples+ (CreditCardNumberValue "3530111333300000" Other)+ [ "3530111333300000" ]+ ]
@@ -0,0 +1,123 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++module Duckling.CreditCardNumber.Helpers+ ( otherCreditCardNumberRegex+ , visaCreditCardNumberRegex+ , amexCreditCardNumberRegex+ , discoverCreditCardNumberRegex+ , mastercardCreditCardNumberRegex+ , dinerClubCreditCardNumberRegex+ , isValidCreditCardNumber+ , minNumberDigits+ , maxNumberDigits+ , creditCard+ ) where++import Data.Text (Text)+import Prelude+import Data.String++import Duckling.CreditCardNumber.Types (CreditCardNumberData(..))+import qualified Duckling.CreditCardNumber.Types as TCreditCardNumber+import qualified Data.Text as T+import qualified Data.Char as C+import qualified Data.Bits as B++-- -----------------------------------------------------------------+-- Patterns++otherCreditCardNumberRegex :: String+otherCreditCardNumberRegex =+ concat [ "("+ , "(?!" , visaCreditCardNumberRegex, ")"+ , "(?!" , amexCreditCardNumberRegex, ")"+ , "(?!" , discoverCreditCardNumberRegex, ")"+ , "(?!" , mastercardCreditCardNumberRegex, ")"+ , "(?!" , dinerClubCreditCardNumberRegex, ")"+ , "\\d{" , show minNumberDigits , "," , show maxNumberDigits , "}"+ , ")"+ ]++-- | Visa credit card regex informed by latest BIN info+visaCreditCardNumberRegex :: String+visaCreditCardNumberRegex = "(" ++ withoutDashes ++ "|" ++ withDashes ++")"+ where+ withoutDashes = "4[0-9]{15}"+ withDashes = "4[0-9]{3}-[0-9]{4}-[0-9]{4}-[0-9]{4}"++-- | American Express credit card regex informed by latest BIN info+amexCreditCardNumberRegex :: String+amexCreditCardNumberRegex = "(" ++ withoutDashes ++ "|" ++ withDashes ++")"+ where+ withoutDashes = "3[47][0-9]{13}"+ withDashes = "3[47][0-9]{2}-[0-9]{6}-[0-9]{5}"++-- | Discover credit card regex informed by latest BIN info+discoverCreditCardNumberRegex :: String+discoverCreditCardNumberRegex = "(" ++ withoutDashes ++ "|" ++ withDashes ++")"+ where+ withoutDashes = "6(?:011|[45][0-9]{2})[0-9]{12}"+ withDashes = "6(?:011|[45][0-9]{2})-[0-9]{4}-[0-9]{4}-[0-9]{4}"++-- | Mastercard credit card regex informed by latest BIN info+mastercardCreditCardNumberRegex :: String+mastercardCreditCardNumberRegex =+ "(" ++ withoutDashes ++ "|" ++ withDashes ++")"+ where+ withoutDashes = "5[1-5][0-9]{14}"+ withDashes = "5[1-5][0-9]{2}-[0-9]{4}-[0-9]{4}-[0-9]{4}"++-- | Diner Club credit card regex informed by latest BIN info+dinerClubCreditCardNumberRegex :: String+dinerClubCreditCardNumberRegex = "(" ++ withoutDashes ++ "|" ++ withDashes ++")"+ where+ withoutDashes = "3(?:0[0-5]|[68][0-9])[0-9]{11}"+ withDashes = "3(?:0[0-5]|[68][0-9])[0-9]-[0-9]{6}-[0-9]{4}"++-- -----------------------------------------------------------------+-- Validation++-- | An implementation of the Luhn algorithm (see+-- https://en.wikipedia.org/wiki/Luhn_algorithm) to check if a given credit card+-- number is valid+isValidCreditCardNumber :: Text -> Bool+isValidCreditCardNumber ccNum =+ T.length ccNum >= minNumberDigits &&+ T.length ccNum <= maxNumberDigits &&+ validCheckSum+ where+ validCheckSum :: Bool+ validCheckSum =+ T.all C.isDigit ccNum &&+ fst (T.foldr f (0, 0) ccNum) `rem` 10 == 0+ where+ f char (checksum, e) =+ let+ val = C.digitToInt char+ -- every even digit should be doubled+ d = sumDigits (B.shift val e)+ in (checksum + d, 1 - e)+ -- we only need sum of digits for numbers from 0 to 18+ sumDigits a+ | a > 9 = a - 9+ | otherwise = a++minNumberDigits :: Int+minNumberDigits = 8++maxNumberDigits :: Int+maxNumberDigits = 19++-- -----------------------------------------------------------------+-- Production++creditCard :: Text -> TCreditCardNumber.Issuer -> CreditCardNumberData+creditCard ccNum i =+ CreditCardNumberData { TCreditCardNumber.number = ccNum+ , TCreditCardNumber.issuer = i+ }
@@ -0,0 +1,72 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}++module Duckling.CreditCardNumber.Rules+ ( rules ) where++import Prelude+import Data.String+import Data.Text (Text)+import Data.Bool+import qualified Data.Text as T+import qualified Data.Char as C++import Duckling.Dimensions.Types+import Duckling.CreditCardNumber.Helpers+import qualified Duckling.CreditCardNumber.Types as TCreditCardNumber+import Duckling.Regex.Types+import Duckling.Types++creditCards :: [(Text, PatternItem, TCreditCardNumber.Issuer)]+creditCards =+ [ ( "visa credit card number"+ , regex visaCreditCardNumberRegex+ , TCreditCardNumber.Visa+ )+ , ( "amex card number"+ , regex amexCreditCardNumberRegex+ , TCreditCardNumber.Amex+ )+ , ( "discover card number"+ , regex discoverCreditCardNumberRegex+ , TCreditCardNumber.Discover+ )+ , ( "mastercard card number"+ , regex mastercardCreditCardNumberRegex+ , TCreditCardNumber.Mastercard+ )+ , ( "diner club card number"+ , regex dinerClubCreditCardNumberRegex+ , TCreditCardNumber.DinerClub+ )+ , ( "credit card number"+ , regex otherCreditCardNumberRegex+ , TCreditCardNumber.Other+ )+ ]++rules :: [Rule]+rules = map go creditCards+ where+ go :: (Text, PatternItem, TCreditCardNumber.Issuer) -> Rule+ go (name, regexPattern, i) = Rule+ { name = name+ , pattern = [ regexPattern ]+ , prod = \case+ (Token RegexMatch (GroupMatch (ccNumGroup:_)):_) ->+ bool+ Nothing+ (Just $ Token CreditCardNumber $ creditCard ccNum i)+ (isValidCreditCardNumber ccNum)+ where+ ccNum = T.filter C.isDigit ccNumGroup+ _ -> Nothing+ }
@@ -0,0 +1,61 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE NoRebindableSyntax #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeFamilies #-}++module Duckling.CreditCardNumber.Types where++import Control.DeepSeq+import Data.Aeson+import Data.Hashable+import Data.Text (Text)+import qualified Data.Text as Text+import GHC.Generics++import Prelude++import Duckling.Resolve (Resolve(..))++data Issuer+ = Visa+ | Amex+ | Discover+ | Mastercard+ | DinerClub+ | Other+ deriving (Eq, Generic, Hashable, Ord, Show, NFData)++instance ToJSON Issuer where+ toJSON = String . Text.toLower . Text.pack . show++data CreditCardNumberData = CreditCardNumberData+ { number :: Text+ , issuer :: Issuer+ }+ deriving (Eq, Generic, Hashable, Ord, Show, NFData)++instance Resolve CreditCardNumberData where+ type ResolvedValue CreditCardNumberData = CreditCardNumberValue+ resolve _ _ CreditCardNumberData {number, issuer} =+ Just (CreditCardNumberValue number issuer, False)++data CreditCardNumberValue = CreditCardNumberValue+ { vNumber :: Text+ , vIssuer :: Issuer+ }+ deriving (Eq, Ord, Show)++instance ToJSON CreditCardNumberValue where+ toJSON (CreditCardNumberValue number issuer) =+ object [ "value" .= number+ , "issuer" .= issuer+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE NamedFieldPuns #-}@@ -37,20 +36,20 @@ -- ----------------------------------------------------------------- -- API -debug :: Locale -> Text -> [Some Dimension] -> IO [Entity]+debug :: Locale -> Text -> [Seal Dimension] -> IO [Entity] debug locale = debugCustom testContext {locale = locale} testOptions -allParses :: Locale -> Text -> [Some Dimension] -> IO [Entity]+allParses :: Locale -> Text -> [Seal Dimension] -> IO [Entity] allParses l sentence targets = debugTokens sentence $ parses l sentence targets -fullParses :: Locale -> Text -> [Some Dimension] -> IO [Entity]+fullParses :: Locale -> Text -> [Seal Dimension] -> IO [Entity] fullParses l sentence targets = debugTokens sentence . filter (\Resolved{range = Range start end} -> start == 0 && end == n) $ parses l sentence targets where n = Text.length sentence -debugCustom :: Context -> Options -> Text -> [Some Dimension] -> IO [Entity]+debugCustom :: Context -> Options -> Text -> [Seal Dimension] -> IO [Entity] debugCustom context options sentence targets = debugTokens sentence . analyze sentence context options $ HashSet.fromList targets @@ -60,12 +59,12 @@ -- ----------------------------------------------------------------- -- Internals -parses :: Locale -> Text -> [Some Dimension] -> [ResolvedToken]+parses :: Locale -> Text -> [Seal Dimension] -> [ResolvedToken] parses l sentence targets = flip filter tokens $ \Resolved{node = Node{token = (Token d _)}} -> case targets of [] -> True- _ -> elem (This d) targets+ _ -> elem (Seal d) targets where tokens = parseAndResolve rules sentence testContext {locale = l} testOptions rules = rulesFor l $ HashSet.fromList targets
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -22,8 +21,11 @@ import Duckling.Locale import Duckling.Types import qualified Duckling.Dimensions.Common as CommonDimensions+import qualified Duckling.Dimensions.AF as AFDimensions import qualified Duckling.Dimensions.AR as ARDimensions import qualified Duckling.Dimensions.BG as BGDimensions+import qualified Duckling.Dimensions.BN as BNDimensions+import qualified Duckling.Dimensions.CA as CADimensions import qualified Duckling.Dimensions.CS as CSDimensions import qualified Duckling.Dimensions.DA as DADimensions import qualified Duckling.Dimensions.DE as DEDimensions@@ -31,6 +33,8 @@ import qualified Duckling.Dimensions.EN as ENDimensions import qualified Duckling.Dimensions.ES as ESDimensions import qualified Duckling.Dimensions.ET as ETDimensions+import qualified Duckling.Dimensions.FA as FADimensions+import qualified Duckling.Dimensions.FI as FIDimensions import qualified Duckling.Dimensions.FR as FRDimensions import qualified Duckling.Dimensions.GA as GADimensions import qualified Duckling.Dimensions.HE as HEDimensions@@ -38,10 +42,16 @@ import qualified Duckling.Dimensions.HR as HRDimensions import qualified Duckling.Dimensions.HU as HUDimensions import qualified Duckling.Dimensions.ID as IDDimensions+import qualified Duckling.Dimensions.IS as ISDimensions import qualified Duckling.Dimensions.IT as ITDimensions import qualified Duckling.Dimensions.JA as JADimensions import qualified Duckling.Dimensions.KA as KADimensions+import qualified Duckling.Dimensions.KM as KMDimensions+import qualified Duckling.Dimensions.KN as KNDimensions import qualified Duckling.Dimensions.KO as KODimensions+import qualified Duckling.Dimensions.LO as LODimensions+import qualified Duckling.Dimensions.ML as MLDimensions+import qualified Duckling.Dimensions.MN as MNDimensions import qualified Duckling.Dimensions.MY as MYDimensions import qualified Duckling.Dimensions.NB as NBDimensions import qualified Duckling.Dimensions.NE as NEDimensions@@ -50,44 +60,53 @@ import qualified Duckling.Dimensions.PT as PTDimensions import qualified Duckling.Dimensions.RO as RODimensions import qualified Duckling.Dimensions.RU as RUDimensions+import qualified Duckling.Dimensions.SK as SKDimensions import qualified Duckling.Dimensions.SV as SVDimensions+import qualified Duckling.Dimensions.SW as SWDimensions import qualified Duckling.Dimensions.TA as TADimensions+import qualified Duckling.Dimensions.TE as TEDimensions+import qualified Duckling.Dimensions.TH as THDimensions import qualified Duckling.Dimensions.TR as TRDimensions import qualified Duckling.Dimensions.UK as UKDimensions import qualified Duckling.Dimensions.VI as VIDimensions import qualified Duckling.Dimensions.ZH as ZHDimensions -allDimensions :: Lang -> [Some Dimension]++allDimensions :: Lang -> [Seal Dimension] allDimensions lang = CommonDimensions.allDimensions ++ langDimensions lang -- | Augments `targets` with all dependent dimensions.-explicitDimensions :: HashSet (Some Dimension) -> HashSet (Some Dimension)+explicitDimensions :: HashSet (Seal Dimension) -> HashSet (Seal Dimension) explicitDimensions targets = HashSet.union targets deps where deps = HashSet.unions . map dependents $ HashSet.toList targets -- | Ordinal depends on Numeral for JA, KO, and ZH.-dependents :: Some Dimension -> HashSet (Some Dimension)-dependents (This Distance) = HashSet.singleton (This Numeral)-dependents (This Duration) = HashSet.fromList [This Numeral, This TimeGrain]-dependents (This Numeral) = HashSet.empty-dependents (This Email) = HashSet.empty-dependents (This AmountOfMoney) = HashSet.singleton (This Numeral)-dependents (This Ordinal) = HashSet.singleton (This Numeral)-dependents (This PhoneNumber) = HashSet.empty-dependents (This Quantity) = HashSet.singleton (This Numeral)-dependents (This RegexMatch) = HashSet.empty-dependents (This Temperature) = HashSet.singleton (This Numeral)-dependents (This Time) =- HashSet.fromList [This Numeral, This Duration, This Ordinal, This TimeGrain]-dependents (This TimeGrain) = HashSet.empty-dependents (This Url) = HashSet.empty-dependents (This Volume) = HashSet.singleton (This Numeral)-dependents (This (CustomDimension dim)) = dimDependents dim+dependents :: Seal Dimension -> HashSet (Seal Dimension)+dependents (Seal CreditCardNumber) = HashSet.empty+dependents (Seal Distance) = HashSet.singleton (Seal Numeral)+dependents (Seal Duration) = HashSet.fromList [Seal Numeral, Seal TimeGrain]+dependents (Seal Numeral) = HashSet.empty+dependents (Seal Email) = HashSet.empty+dependents (Seal AmountOfMoney) = HashSet.singleton (Seal Numeral)+dependents (Seal Ordinal) = HashSet.singleton (Seal Numeral)+dependents (Seal PhoneNumber) = HashSet.empty+dependents (Seal Quantity) = HashSet.singleton (Seal Numeral)+dependents (Seal RegexMatch) = HashSet.empty+dependents (Seal Temperature) = HashSet.singleton (Seal Numeral)+dependents (Seal Time) =+ HashSet.fromList [Seal Numeral, Seal Duration, Seal Ordinal, Seal TimeGrain]+dependents (Seal TimeGrain) = HashSet.empty+dependents (Seal Url) = HashSet.empty+dependents (Seal Volume) = HashSet.singleton (Seal Numeral)+dependents (Seal (CustomDimension dim)) = dimDependents dim -langDimensions :: Lang -> [Some Dimension]+langDimensions :: Lang -> [Seal Dimension]+langDimensions AF = AFDimensions.allDimensions langDimensions AR = ARDimensions.allDimensions langDimensions BG = BGDimensions.allDimensions+langDimensions BN = BNDimensions.allDimensions+langDimensions CA = CADimensions.allDimensions langDimensions CS = CSDimensions.allDimensions langDimensions DA = DADimensions.allDimensions langDimensions DE = DEDimensions.allDimensions@@ -95,6 +114,8 @@ langDimensions EN = ENDimensions.allDimensions langDimensions ES = ESDimensions.allDimensions langDimensions ET = ETDimensions.allDimensions+langDimensions FA = FADimensions.allDimensions+langDimensions FI = FIDimensions.allDimensions langDimensions FR = FRDimensions.allDimensions langDimensions GA = GADimensions.allDimensions langDimensions HE = HEDimensions.allDimensions@@ -102,10 +123,16 @@ langDimensions HR = HRDimensions.allDimensions langDimensions HU = HUDimensions.allDimensions langDimensions ID = IDDimensions.allDimensions+langDimensions IS = ISDimensions.allDimensions langDimensions IT = ITDimensions.allDimensions langDimensions JA = JADimensions.allDimensions langDimensions KA = KADimensions.allDimensions+langDimensions KM = KMDimensions.allDimensions+langDimensions KN = KNDimensions.allDimensions langDimensions KO = KODimensions.allDimensions+langDimensions LO = LODimensions.allDimensions+langDimensions ML = MLDimensions.allDimensions+langDimensions MN = MNDimensions.allDimensions langDimensions MY = MYDimensions.allDimensions langDimensions NB = NBDimensions.allDimensions langDimensions NE = NEDimensions.allDimensions@@ -114,8 +141,12 @@ langDimensions PT = PTDimensions.allDimensions langDimensions RO = RODimensions.allDimensions langDimensions RU = RUDimensions.allDimensions+langDimensions SK = SKDimensions.allDimensions langDimensions SV = SVDimensions.allDimensions+langDimensions SW = SWDimensions.allDimensions langDimensions TA = TADimensions.allDimensions+langDimensions TE = TEDimensions.allDimensions+langDimensions TH = THDimensions.allDimensions langDimensions TR = TRDimensions.allDimensions langDimensions UK = UKDimensions.allDimensions langDimensions VI = VIDimensions.allDimensions
@@ -0,0 +1,17 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++module Duckling.Dimensions.AF+ ( allDimensions+ ) where++import Duckling.Dimensions.Types++allDimensions :: [Seal Dimension]+allDimensions =+ [ Seal Numeral+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.AR@@ -12,13 +11,13 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Duration- , This Numeral- , This Ordinal- , This Quantity- , This Temperature- , This Time- , This Volume+ [ Seal Duration+ , Seal Numeral+ , Seal Ordinal+ , Seal Quantity+ , Seal Temperature+ , Seal Time+ , Seal Volume ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.BG@@ -12,10 +11,11 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Distance- , This Duration- , This Numeral- , This Ordinal+ [ Seal Distance+ , Seal Duration+ , Seal Numeral+ , Seal Ordinal+ , Seal Time ]
@@ -0,0 +1,17 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++module Duckling.Dimensions.BN+ ( allDimensions+ ) where++import Duckling.Dimensions.Types++allDimensions :: [Seal Dimension]+allDimensions =+ [ Seal Numeral+ ]
@@ -0,0 +1,17 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++module Duckling.Dimensions.CA+ ( allDimensions+ ) where++import Duckling.Dimensions.Types++allDimensions :: [Seal Dimension]+allDimensions =+ [ Seal Numeral+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.CS@@ -12,8 +11,8 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Distance- , This Numeral+ [ Seal Distance+ , Seal Numeral ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.Common@@ -12,11 +11,12 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This AmountOfMoney- , This Email- , This Numeral- , This PhoneNumber- , This Url+ [ Seal AmountOfMoney+ , Seal CreditCardNumber+ , Seal Email+ , Seal Numeral+ , Seal PhoneNumber+ , Seal Url ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.DA@@ -12,10 +11,10 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Duration- , This Numeral- , This Ordinal- , This Time+ [ Seal Duration+ , Seal Numeral+ , Seal Ordinal+ , Seal Time ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.DE@@ -12,10 +11,12 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Duration- , This Numeral- , This Ordinal- , This Time+ [ Seal Distance+ , Seal Duration+ , Seal Numeral+ , Seal Ordinal+ , Seal Time+ , Seal Volume ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.EL@@ -12,10 +11,10 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Duration- , This Numeral- , This Ordinal- , This Time+ [ Seal Duration+ , Seal Numeral+ , Seal Ordinal+ , Seal Time ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.EN@@ -12,14 +11,14 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Distance- , This Duration- , This Numeral- , This Ordinal- , This Quantity- , This Temperature- , This Time- , This Volume+ [ Seal Distance+ , Seal Duration+ , Seal Numeral+ , Seal Ordinal+ , Seal Quantity+ , Seal Temperature+ , Seal Time+ , Seal Volume ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.ES@@ -12,13 +11,14 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Distance- , This Duration- , This Numeral- , This Ordinal- , This Temperature- , This Time- , This Volume+ [ Seal Distance+ , Seal Duration+ , Seal Numeral+ , Seal Ordinal+ , Seal Quantity+ , Seal Temperature+ , Seal Time+ , Seal Volume ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.ET@@ -12,8 +11,8 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Numeral- , This Ordinal+ [ Seal Numeral+ , Seal Ordinal ]
@@ -0,0 +1,16 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.++module Duckling.Dimensions.FA+ ( allDimensions+ ) where++import Duckling.Dimensions.Types++allDimensions :: [Seal Dimension]+allDimensions =+ [ Seal Numeral+ ]
@@ -0,0 +1,16 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.++module Duckling.Dimensions.FI+ ( allDimensions+ ) where++import Duckling.Dimensions.Types++allDimensions :: [Seal Dimension]+allDimensions =+ [ Seal Numeral+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.FR@@ -12,14 +11,14 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Distance- , This Duration- , This Numeral- , This Ordinal- , This Quantity- , This Temperature- , This Time- , This Volume+ [ Seal Distance+ , Seal Duration+ , Seal Numeral+ , Seal Ordinal+ , Seal Quantity+ , Seal Temperature+ , Seal Time+ , Seal Volume ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.GA@@ -12,13 +11,13 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Distance- , This Duration- , This Numeral- , This Ordinal- , This Temperature- , This Time- , This Volume+ [ Seal Distance+ , Seal Duration+ , Seal Numeral+ , Seal Ordinal+ , Seal Temperature+ , Seal Time+ , Seal Volume ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.HE@@ -12,10 +11,10 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Duration- , This Numeral- , This Ordinal- , This Time+ [ Seal Duration+ , Seal Numeral+ , Seal Ordinal+ , Seal Time ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.HI@@ -12,9 +11,10 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Duration- , This Numeral- , This Ordinal+ [ Seal Duration+ , Seal Numeral+ , Seal Ordinal+ , Seal Temperature ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.HR@@ -12,14 +11,14 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Distance- , This Duration- , This Numeral- , This Ordinal- , This Quantity- , This Temperature- , This Time- , This Volume+ [ Seal Distance+ , Seal Duration+ , Seal Numeral+ , Seal Ordinal+ , Seal Quantity+ , Seal Temperature+ , Seal Time+ , Seal Volume ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.HU@@ -12,10 +11,10 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Duration- , This Numeral- , This Ordinal- , This Time+ [ Seal Duration+ , Seal Numeral+ , Seal Ordinal+ , Seal Time ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.ID@@ -12,8 +11,8 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Numeral- , This Ordinal+ [ Seal Numeral+ , Seal Ordinal ]
@@ -0,0 +1,17 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++module Duckling.Dimensions.IS+ ( allDimensions+ ) where++import Duckling.Dimensions.Types++allDimensions :: [Seal Dimension]+allDimensions =+ [ Seal Numeral+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.IT@@ -12,12 +11,13 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Duration- , This Numeral- , This Ordinal- , This Temperature- , This Time- , This Volume+ [ Seal Distance+ , Seal Duration+ , Seal Numeral+ , Seal Ordinal+ , Seal Temperature+ , Seal Time+ , Seal Volume ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.JA@@ -12,10 +11,10 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Duration- , This Numeral- , This Ordinal- , This Temperature+ [ Seal Duration+ , Seal Numeral+ , Seal Ordinal+ , Seal Temperature ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.KA@@ -12,6 +11,10 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Numeral ]+ [ Seal Numeral+ , Seal Ordinal+ , Seal Duration+ , Seal Time+ ]
@@ -0,0 +1,22 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++module Duckling.Dimensions.KM+ ( allDimensions+ ) where++import Duckling.Dimensions.Types++allDimensions :: [Seal Dimension]+allDimensions =+ [ Seal Distance+ , Seal Numeral+ , Seal Ordinal+ , Seal Quantity+ , Seal Temperature+ , Seal Volume+ ]
@@ -0,0 +1,17 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++module Duckling.Dimensions.KN+ ( allDimensions+ ) where++import Duckling.Dimensions.Types++allDimensions :: [Seal Dimension]+allDimensions =+ [ Seal Numeral+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.KO@@ -12,14 +11,14 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Distance- , This Duration- , This Numeral- , This Ordinal- , This Quantity- , This Temperature- , This Time- , This Volume+ [ Seal Distance+ , Seal Duration+ , Seal Numeral+ , Seal Ordinal+ , Seal Quantity+ , Seal Temperature+ , Seal Time+ , Seal Volume ]
@@ -0,0 +1,17 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++module Duckling.Dimensions.LO+ ( allDimensions+ ) where++import Duckling.Dimensions.Types++allDimensions :: [Seal Dimension]+allDimensions =+ [ Seal Numeral+ ]
@@ -0,0 +1,18 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++module Duckling.Dimensions.ML+ ( allDimensions+ ) where++import Duckling.Dimensions.Types++allDimensions :: [Seal Dimension]+allDimensions =+ [ Seal Numeral,+ Seal Ordinal+ ]
@@ -0,0 +1,23 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++module Duckling.Dimensions.MN+ ( allDimensions+ ) where++import Duckling.Dimensions.Types++allDimensions :: [Seal Dimension]+allDimensions =+ [ Seal Distance+ , Seal Duration+ , Seal Numeral+ , Seal Ordinal+ , Seal Quantity+ , Seal Temperature+ , Seal Volume+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.MY@@ -12,7 +11,7 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Numeral+ [ Seal Numeral ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.NB@@ -12,10 +11,10 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Duration- , This Numeral- , This Ordinal- , This Time+ [ Seal Duration+ , Seal Numeral+ , Seal Ordinal+ , Seal Time ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.NE@@ -12,7 +11,7 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Numeral+ [ Seal Numeral ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.NL@@ -12,12 +11,13 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Distance- , This Duration- , This Numeral- , This Ordinal- , This Time- , This Volume+ [ Seal Distance+ , Seal Duration+ , Seal Numeral+ , Seal Ordinal+ , Seal Quantity+ , Seal Time+ , Seal Volume ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.PL@@ -12,10 +11,10 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Duration- , This Numeral- , This Ordinal- , This Time+ [ Seal Duration+ , Seal Numeral+ , Seal Ordinal+ , Seal Time ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.PT@@ -12,14 +11,14 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Distance- , This Duration- , This Numeral- , This Ordinal- , This Quantity- , This Temperature- , This Time- , This Volume+ [ Seal Distance+ , Seal Duration+ , Seal Numeral+ , Seal Ordinal+ , Seal Quantity+ , Seal Temperature+ , Seal Time+ , Seal Volume ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.RO@@ -12,14 +11,14 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Distance- , This Duration- , This Numeral- , This Ordinal- , This Quantity- , This Temperature- , This Time- , This Volume+ [ Seal Distance+ , Seal Duration+ , Seal Numeral+ , Seal Ordinal+ , Seal Quantity+ , Seal Temperature+ , Seal Time+ , Seal Volume ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.RU@@ -12,12 +11,13 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Distance- , This Duration- , This Numeral- , This Ordinal- , This Quantity- , This Volume+ [ Seal Distance+ , Seal Duration+ , Seal Numeral+ , Seal Ordinal+ , Seal Quantity+ , Seal Volume+ , Seal Time ]
@@ -0,0 +1,18 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree. An additional grant+-- of patent rights can be found in the PATENTS file in the same directory.+++module Duckling.Dimensions.SK+ ( allDimensions+ ) where++import Duckling.Dimensions.Types++allDimensions :: [Seal Dimension]+allDimensions =+ [ Seal Numeral+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.SV@@ -12,11 +11,11 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Distance- , This Duration- , This Numeral- , This Ordinal- , This Time+ [ Seal Distance+ , Seal Duration+ , Seal Numeral+ , Seal Ordinal+ , Seal Time ]
@@ -0,0 +1,17 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++module Duckling.Dimensions.SW+ ( allDimensions+ ) where++import Duckling.Dimensions.Types++allDimensions :: [Seal Dimension]+allDimensions =+ [ Seal Numeral+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.TA@@ -12,7 +11,8 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Numeral+ [ Seal Numeral+ , Seal Ordinal ]
@@ -0,0 +1,17 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++module Duckling.Dimensions.TE+ ( allDimensions+ ) where++import Duckling.Dimensions.Types++allDimensions :: [Seal Dimension]+allDimensions =+ [ Seal Numeral+ ]
@@ -0,0 +1,17 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++module Duckling.Dimensions.TH+ ( allDimensions+ ) where++import Duckling.Dimensions.Types++allDimensions :: [Seal Dimension]+allDimensions =+ [ Seal Numeral+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.TR@@ -12,12 +11,13 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Distance- , This Duration- , This Numeral- , This Ordinal- , This Temperature- , This Volume+ [ Seal Distance+ , Seal Duration+ , Seal Numeral+ , Seal Ordinal+ , Seal Temperature+ , Seal Time+ , Seal Volume ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -11,7 +10,7 @@ module Duckling.Dimensions.Types- ( Some(..)+ ( Seal(..) , Dimension(..) , fromName@@ -19,7 +18,6 @@ ) where import Data.Maybe-import Data.Some import Data.Text (Text) import Prelude import qualified Data.HashMap.Strict as HashMap@@ -29,6 +27,7 @@ toName :: Dimension a -> Text toName RegexMatch = "regex"+toName CreditCardNumber = "credit-card-number" toName Distance = "distance" toName Duration = "duration" toName Email = "email"@@ -44,20 +43,22 @@ toName Volume = "volume" toName (CustomDimension dim) = Text.pack (show dim) -fromName :: Text -> Maybe (Some Dimension)+fromName :: Text -> Maybe (Seal Dimension) fromName name = HashMap.lookup name m where m = HashMap.fromList- [ ("amount-of-money", This AmountOfMoney)- , ("distance", This Distance)- , ("duration", This Duration)- , ("email", This Email)- , ("number", This Numeral)- , ("ordinal", This Ordinal)- , ("phone-number", This PhoneNumber)- , ("quantity", This Quantity)- , ("temperature", This Temperature)- , ("time", This Time)- , ("url", This Url)- , ("volume", This Volume)+ [ ("amount-of-money", Seal AmountOfMoney)+ , ("credit-card-number", Seal CreditCardNumber)+ , ("distance", Seal Distance)+ , ("duration", Seal Duration)+ , ("email", Seal Email)+ , ("number", Seal Numeral)+ , ("ordinal", Seal Ordinal)+ , ("phone-number", Seal PhoneNumber)+ , ("quantity", Seal Quantity)+ , ("temperature", Seal Temperature)+ , ("time", Seal Time)+ , ("time-grain", Seal TimeGrain)+ , ("url", Seal Url)+ , ("volume", Seal Volume) ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.UK@@ -12,8 +11,10 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Numeral- , This Ordinal+ [ Seal Duration+ , Seal Numeral+ , Seal Ordinal+ , Seal Time ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.VI@@ -12,10 +11,10 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Duration- , This Numeral- , This Ordinal- , This Time+ [ Seal Duration+ , Seal Numeral+ , Seal Ordinal+ , Seal Time ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Dimensions.ZH@@ -12,13 +11,13 @@ import Duckling.Dimensions.Types -allDimensions :: [Some Dimension]+allDimensions :: [Seal Dimension] allDimensions =- [ This Distance- , This Duration- , This Numeral- , This Ordinal- , This Quantity- , This Temperature- , This Time+ [ Seal Distance+ , Seal Duration+ , Seal Numeral+ , Seal Ordinal+ , Seal Quantity+ , Seal Temperature+ , Seal Time ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -0,0 +1,74 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}++module Duckling.Distance.DE.Corpus+ ( corpus+ ) where++import Data.String+import Prelude++import Duckling.Distance.Types+import Duckling.Locale+import Duckling.Resolve+import Duckling.Testing.Types++corpus :: Corpus+corpus = (testContext {locale = makeLocale DE Nothing}, testOptions, allExamples)++allExamples :: [Example]+allExamples = concat+ [ examples (simple Kilometre 3)+ [ "3 kilometer"+ , "3 km"+ , "3km"+ , "3,0 km"+ ]+ , examples (simple Mile 8)+ [ "acht meilen"+ , "8 meilen"+ ]+ , examples (simple Metre 9)+ [ "9m"+ ]+ , examples (simple Centimetre 2)+ [ "2cm"+ , "2 zentimeter"+ ]+ , examples (simple Inch 5)+ [ "5''"+ , "fünf zoll"+ , "5\""+ ]+ , examples (simple Metre 1.87)+ [ "1,87 meter"+ ]+ , examples (between Kilometre (3, 5))+ [ "zwischen 3 und 5 kilometern"+ , "von 3km bis 5km"+ , "um die 3-5 kilometer"+ , "etwa 3km-5km"+ , "3-5 kilometer"+ ]+ , examples (under Mile 3.5)+ [ "unter 3,5 meilen"+ , "weniger als 3,5meilen"+ --, "niedriger als dreikommafünf meilen"+ ]+ , examples (above Inch 5)+ [ "mehr als fünf zoll"+ , "mindestens 5''"+ , "über 5\""+ ]+ , examples (between Millimetre (5, 6))+ [ "zwischen 5 und sechs Millimetern"+ , "zwischen 5 und sechs millimeter"+ , "5-6 mm"+ ]+ ]
@@ -0,0 +1,172 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+module Duckling.Distance.DE.Rules (rules) where++import Data.String+import Data.Text (Text)+import Prelude++import Duckling.Dimensions.Types+import Duckling.Distance.Helpers+import Duckling.Distance.Types (DistanceData(..))+import qualified Duckling.Distance.Types as TDistance+import Duckling.Numeral.Helpers+import Duckling.Numeral.Types (NumeralData(..))+import qualified Duckling.Numeral.Types as TNumeral+import Duckling.Types++distances :: [(Text, String, TDistance.Unit)]+distances =+ [ -- Imperial+ ("miles", "meilen?", TDistance.Mile)+ , ("inch", "(\"|''|zoll)", TDistance.Inch)+ -- Metric+ , ("km", "k(ilo)?m(etern?)?", TDistance.Kilometre)+ , ("meters", "m(etern?)?", TDistance.Metre)+ , ("centimeters", "(cm|[zc]entimetern?)", TDistance.Centimetre)+ , ("millimeters", "(mm|millimetern?)", TDistance.Millimetre)+ ]++rulePrecision :: Rule+rulePrecision = Rule+ { name = "about|exactly <dist>"+ , pattern =+ [ regex "genau|exakt|präzise|ungefähr|(in )?etwa|nahe?( an)?|um( die)?|fast|rund|gut"+ , dimension Distance+ ]+ , prod = \case+ (_:token:_) -> Just token+ _ -> Nothing+ }++ruleDistances :: [Rule]+ruleDistances = map go distances+ where+ go :: (Text, String, TDistance.Unit) -> Rule+ go (name, regexPattern, u) = Rule+ { name = name+ , pattern = [ dimension Distance, regex regexPattern ]+ , prod = \case+ (Token Distance dd:_) -> Just . Token Distance $ withUnit u dd+ _ -> Nothing+ }++ruleIntervalBetweenNumeral :: Rule+ruleIntervalBetweenNumeral = Rule+ { name = "between|from <numeral> to|and <dist>"+ , pattern =+ [ regex "zwischen|von"+ , Predicate isPositive+ , regex "bis|und"+ , Predicate isSimpleDistance+ ]+ , prod = \case+ (_:+ Token Numeral NumeralData{TNumeral.value = from}:+ _:+ Token Distance DistanceData{TDistance.value = Just to, TDistance.unit = Just u}:+ _) | from < to ->+ Just . Token Distance . withInterval (from, to) $ unitOnly u+ _ -> Nothing+ }++ruleIntervalBetween :: Rule+ruleIntervalBetween = Rule+ { name = "between|from <dist> to|and <dist>"+ , pattern =+ [ regex "zwischen|von"+ , Predicate isSimpleDistance+ , regex "und|bis"+ , Predicate isSimpleDistance+ ]+ , prod = \case+ (_:+ Token Distance DistanceData{TDistance.value = Just from, TDistance.unit = Just u1}:+ _:+ Token Distance DistanceData{TDistance.value = Just to, TDistance.unit = Just u2}:+ _) | from < to && u1 == u2 ->+ Just . Token Distance . withInterval (from, to) $ unitOnly u1+ _ -> Nothing+ }++ruleIntervalNumeralDash :: Rule+ruleIntervalNumeralDash = Rule+ { name = "<numeral> - <dist>"+ , pattern =+ [ Predicate isPositive+ , regex "-"+ , Predicate isSimpleDistance+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = from}:+ _:+ Token Distance DistanceData{TDistance.value = Just to, TDistance.unit = Just u}:+ _) | from < to ->+ Just . Token Distance . withInterval (from, to) $ unitOnly u+ _ -> Nothing+ }++ruleIntervalDash :: Rule+ruleIntervalDash = Rule+ { name = "<dist> - <dist>"+ , pattern =+ [ Predicate isSimpleDistance+ , regex "-"+ , Predicate isSimpleDistance+ ]+ , prod = \case+ (Token Distance DistanceData{TDistance.value = Just from, TDistance.unit = Just u1}:+ _:+ Token Distance DistanceData{TDistance.value = Just to, TDistance.unit = Just u2}:+ _) | from < to && u1 == u2 ->+ Just . Token Distance . withInterval (from, to) $ unitOnly u1+ _ -> Nothing+ }++ruleIntervalMax :: Rule+ruleIntervalMax = Rule+ { name = "under/less/lower/no more than <dist>"+ , pattern =+ [ regex "unter|höchstens|maximal|(weniger|nicht mehr) als"+ , Predicate isSimpleDistance+ ]+ , prod = \case+ (_:+ Token Distance DistanceData{TDistance.value = Just to, TDistance.unit = Just u}:+ _) -> Just . Token Distance . withMax to $ unitOnly u+ _ -> Nothing+ }++ruleIntervalMin :: Rule+ruleIntervalMin = Rule+ { name = "over/above/at least/more than <dist>"+ , pattern =+ [ regex "über|(mehr|nicht weniger) als|mindestens|wenigstens|minimal"+ , Predicate isSimpleDistance+ ]+ , prod = \case+ (_:+ Token Distance DistanceData{TDistance.value = Just to, TDistance.unit = Just u}:+ _) -> Just . Token Distance . withMin to $ unitOnly u+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleIntervalBetweenNumeral+ , ruleIntervalBetween+ , ruleIntervalMax+ , ruleIntervalMin+ , ruleIntervalNumeralDash+ , ruleIntervalDash+ , rulePrecision+ ]+ ++ ruleDistances
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -51,6 +50,52 @@ , examples (simple Metre 1.87) [ "1.87 meters" ]+ -- Composite values:+ , examples (simple Inch 94)+ [ "7 feet and 10 inches"+ , "7 feet, 10 inches"+ , "7 feet 10 inches"+ ]+ , examples (simple Metre 2001)+ [ "2 km and 1 meter"+ , "2 kilometer, 1 metre"+ , "2 kilometer 1 metre"+ ]+ , examples (simple Inch 166)+ [ "2 yards 7 ft 10 inches"+ , "2 yds, 7 feet and 10 inches"+ , "2 yards, 7 feet, 10 in"+ ]+ , examples (simple Foot 13)+ [ "2 yards and 7 feet"+ , "2 yards, 7 feet"+ , "2 yd 7'"+ ]+ , examples (simple Centimetre 1000806)+ [ "10 kms 8 metres 6 cm"+ , "10 kms, 8 meters, 6 cm"+ , "10 kms, 8 meters and 6 centimeters"+-- , "10 kms, 8 meters, and 6 cm" -- Oxford comma not supported+ ]+ , examples (simple Metre 1.3048)+ [ "1 meter and 1 foot"+ ]+ , examples (simple Kilometre 2.609344)+ [ "1 kilometer and 1 mile"+ ]+ , examples (simple M 3)+ -- The original, ambiguous "m" unit is preserved+ [ "3m"+ ]+ , examples (simple Centimetre 305)+ -- The ambiguous "m" unit is inferred as "meteres"+ [ "3m and 5cm"+ ]+ , examples (simple Foot 5281)+ -- The ambiguous "m" unit is inferred as "miles"+ [ "1m and 1ft"+ ]+ -- Ranges: , examples (between Kilometre (3, 5)) [ "between 3 and 5 kilometers" , "from 3km to 5km"
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -24,54 +23,23 @@ import Duckling.Numeral.Helpers import Duckling.Numeral.Types (NumeralData (..)) import Duckling.Types-import qualified Duckling.Distance.Types as TDistance+import qualified Duckling.Distance.Types as TDist import qualified Duckling.Numeral.Types as TNumeral -ruleDistanceFeetInch :: Rule-ruleDistanceFeetInch = Rule- { name = "<distance|feet> <distance|inch>"- , pattern =- [ Predicate $ isDistanceOfUnit TDistance.Foot- , Predicate $ isDistanceOfUnit TDistance.Inch- ]- , prod = \case- (Token Distance DistanceData {TDistance.value = Just feet}:- Token Distance DistanceData {TDistance.value = Just inches}:- _) -> Just . Token Distance . withUnit TDistance.Inch . distance $- feet * 12 + inches- _ -> Nothing- } -ruleDistanceFeetAndInch :: Rule-ruleDistanceFeetAndInch = Rule- { name = "<distance|feet> and <distance|inch>"- , pattern =- [ Predicate $ isDistanceOfUnit TDistance.Foot- , regex "and"- , Predicate $ isDistanceOfUnit TDistance.Inch- ]- , prod = \case- (Token Distance DistanceData {TDistance.value = Just feet}:- _:- Token Distance DistanceData {TDistance.value = Just inches}:- _) -> Just . Token Distance . withUnit TDistance.Inch . distance $- feet * 12 + inches- _ -> Nothing- }--distances :: [(Text, String, TDistance.Unit)]+distances :: [(Text, String, TDist.Unit)] distances = [ -- Imperial- ("miles", "mi(le(s)?)?", TDistance.Mile)- , ("yard", "y(ar)?ds?", TDistance.Yard)- , ("feet", "('|f(oo|ee)?ts?)", TDistance.Foot)- , ("inch", "(\"|''|in(ch(es)?)?)", TDistance.Inch)+ ("miles", "mi(le(s)?)?", TDist.Mile)+ , ("yard", "y(ar)?ds?", TDist.Yard)+ , ("feet", "('|f(oo|ee)?ts?)", TDist.Foot)+ , ("inch", "(\"|''|in(ch(es)?)?)", TDist.Inch) -- Metric- , ("km", "k(ilo)?m?(et(er|re))?s?", TDistance.Kilometre)- , ("meters", "met(er|re)s?", TDistance.Metre)- , ("centimeters", "cm|centimet(er|re)s?", TDistance.Centimetre)- , ("millimeters", "mm|millimet(er|re)s?", TDistance.Millimetre)+ , ("km", "k(ilo)?m?(et(er|re))?s?", TDist.Kilometre)+ , ("meters", "met(er|re)s?", TDist.Metre)+ , ("centimeters", "cm|centimet(er|re)s?", TDist.Centimetre)+ , ("millimeters", "mm|millimet(er|re)s?", TDist.Millimetre) -- Ambiguous- , ("m (miles or meters)", "m", TDistance.M)+ , ("m (miles or meters)", "m", TDist.M) ] rulePrecision :: Rule@@ -89,7 +57,7 @@ ruleDistances :: [Rule] ruleDistances = map go distances where- go :: (Text, String, TDistance.Unit) -> Rule+ go :: (Text, String, TDist.Unit) -> Rule go (name, regexPattern, u) = Rule { name = name , pattern = [ dimension Distance, regex regexPattern ]@@ -111,7 +79,7 @@ (_: Token Numeral NumeralData{TNumeral.value = from}: _:- Token Distance DistanceData{TDistance.value = Just to, TDistance.unit = Just u}:+ Token Distance DistanceData{TDist.value=Just to, TDist.unit=Just u}: _) | from < to -> Just . Token Distance . withInterval (from, to) $ unitOnly u _ -> Nothing@@ -128,9 +96,9 @@ ] , prod = \case (_:- Token Distance DistanceData{TDistance.value = Just from, TDistance.unit = Just u1}:+ Token Distance DistanceData{TDist.value=Just from, TDist.unit=Just u1}: _:- Token Distance DistanceData{TDistance.value = Just to, TDistance.unit = Just u2}:+ Token Distance DistanceData{TDist.value=Just to, TDist.unit=Just u2}: _) | from < to && u1 == u2 -> Just . Token Distance . withInterval (from, to) $ unitOnly u1 _ -> Nothing@@ -147,7 +115,7 @@ , prod = \case (Token Numeral NumeralData{TNumeral.value = from}: _:- Token Distance DistanceData{TDistance.value = Just to, TDistance.unit = Just u}:+ Token Distance DistanceData{TDist.value=Just to, TDist.unit=Just u}: _) | from < to -> Just . Token Distance . withInterval (from, to) $ unitOnly u _ -> Nothing@@ -162,9 +130,9 @@ , Predicate isSimpleDistance ] , prod = \case- (Token Distance DistanceData{TDistance.value = Just from, TDistance.unit = Just u1}:+ (Token Distance DistanceData{TDist.value=Just from, TDist.unit=Just u1}: _:- Token Distance DistanceData{TDistance.value = Just to, TDistance.unit = Just u2}:+ Token Distance DistanceData{TDist.value=Just to, TDist.unit=Just u2}: _) | from < to && u1 == u2 -> Just . Token Distance . withInterval (from, to) $ unitOnly u1 _ -> Nothing@@ -179,7 +147,7 @@ ] , prod = \case (_:- Token Distance DistanceData{TDistance.value = Just to, TDistance.unit = Just u}:+ Token Distance DistanceData{TDist.value=Just to, TDist.unit=Just u}: _) -> Just . Token Distance . withMax to $ unitOnly u _ -> Nothing }@@ -193,20 +161,53 @@ ] , prod = \case (_:- Token Distance DistanceData{TDistance.value = Just to, TDistance.unit = Just u}:+ Token Distance DistanceData{TDist.value=Just to, TDist.unit=Just u}: _) -> Just . Token Distance . withMin to $ unitOnly u _ -> Nothing } +-- | NOTE: Oxford comma is not supported.+ruleCompositeDistanceCommasAnd :: Rule+ruleCompositeDistanceCommasAnd = Rule+ { name = "composite <distance> (with ,/and)"+ , pattern =+ [ Predicate isSimpleDistance+ , regex ",|and"+ , Predicate isSimpleDistance+ ]+ , prod = \case+ (Token Distance DistanceData{TDist.value=Just v1, TDist.unit=Just u1}:+ _:+ Token Distance DistanceData{TDist.value=Just v2, TDist.unit=Just u2}:+ _) | u1 /= u2 && v1 > 0 && v2 > 0 -> Token Distance <$>+ distanceSum v1 u1 v2 u2+ _ -> Nothing+ }++ruleCompositeDistance :: Rule+ruleCompositeDistance = Rule+ { name = "composite <distance>"+ , pattern =+ [ Predicate isSimpleDistance+ , Predicate isSimpleDistance+ ]+ , prod = \case+ (Token Distance DistanceData{TDist.value=Just v1, TDist.unit=Just u1}:+ Token Distance DistanceData{TDist.value=Just v2, TDist.unit=Just u2}:+ _) | u1 /= u2 && v1 > 0 && v2 > 0 -> Token Distance <$>+ distanceSum v1 u1 v2 u2+ _ -> Nothing+ }+ rules :: [Rule] rules =- [ ruleDistanceFeetInch- , ruleDistanceFeetAndInch- , ruleIntervalBetweenNumeral+ [ ruleIntervalBetweenNumeral , ruleIntervalBetween , ruleIntervalMax , ruleIntervalMin , ruleIntervalNumeralDash , ruleIntervalDash- , rulePrecision]- ++ ruleDistances+ , rulePrecision+ , ruleCompositeDistanceCommasAnd+ , ruleCompositeDistance+ ] ++ ruleDistances
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-} {-# LANGUAGE OverloadedStrings #-}
@@ -2,14 +2,14 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-} module Duckling.Distance.Helpers ( distance+ , distanceSum , isDistanceOfUnit , isSimpleDistance , unitOnly@@ -21,11 +21,13 @@ ) where import Prelude+import Data.Semigroup ((<>)) import Duckling.Dimensions.Types import Duckling.Distance.Types (DistanceData(..)) import Duckling.Types import qualified Duckling.Distance.Types as TDistance+import qualified Duckling.DistanceUnits.Types as DGTypes -- ----------------------------------------------------------------- -- Patterns@@ -36,7 +38,8 @@ isSimpleDistance _ = False isDistanceOfUnit :: TDistance.Unit -> Predicate-isDistanceOfUnit unit (Token Distance DistanceData {TDistance.unit = Just u}) = unit == u+isDistanceOfUnit unit (Token Distance DistanceData {TDistance.unit = Just u}) =+ unit == u isDistanceOfUnit _ _ = False -- -----------------------------------------------------------------@@ -47,6 +50,22 @@ , TDistance.unit = Nothing , TDistance.minValue = Nothing , TDistance.maxValue = Nothing}++distanceSum ::+ Double+ -> TDistance.Unit+ -> Double+ -> TDistance.Unit+ -> Maybe DistanceData+distanceSum v1 u1 v2 u2 = unwrapContext $ cd1 <> cd2+ where+ wrapContext v u = DGTypes.ContextualDistance v $ DGTypes.toSystemUnit u+ cd1 = wrapContext v1 u1+ cd2 = wrapContext v2 u2++ unwrapContext DGTypes.Nonrelatable = Nothing+ unwrapContext (DGTypes.ContextualDistance v u) =+ Just $ withUnit (DGTypes.toRawUnit u) $ distance v unitOnly :: TDistance.Unit -> DistanceData unitOnly u = DistanceData {TDistance.unit = Just u
@@ -0,0 +1,50 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}++module Duckling.Distance.IT.Corpus+ ( corpus+ ) where++import Data.String+import Prelude++import Duckling.Distance.Types+import Duckling.Locale+import Duckling.Resolve+import Duckling.Testing.Types++context :: Context+context = testContext {locale = makeLocale IT Nothing}++corpus :: Corpus+corpus = (context, testOptions, allExamples)++allExamples :: [Example]+allExamples = concat+ [ examples (simple Kilometre 3)+ [ "3 kilometri"+ , "3 chilometri"+ , "3 km"+ , "3km"+ ]+ , examples (simple Kilometre 3.0)+ [ "3,0 km"+ ]+ , examples (simple Mile 8)+ [ "8 miglia"+ ]+ , examples (simple Metre 9)+ [ "9 metri"+ , "9m"+ ]+ , examples (simple Centimetre 2)+ [ "2cm"+ , "2 centimetri"+ ]+ ]
@@ -0,0 +1,81 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE OverloadedStrings #-}++module Duckling.Distance.IT.Rules+ ( rules+ ) where++import Data.String+import Prelude++import Duckling.Dimensions.Types+import Duckling.Distance.Helpers+import Duckling.Types+import qualified Duckling.Distance.Types as TDistance++ruleLatentDistKm :: Rule+ruleLatentDistKm = Rule+ { name = "<latent dist> km"+ , pattern =+ [ dimension Distance+ , regex "km|(k|ch)(ilo)?m?(etr)o?i?"+ ]+ , prod = \tokens -> case tokens of+ (Token Distance dd:_) ->+ Just . Token Distance $ withUnit TDistance.Kilometre dd+ _ -> Nothing+ }++ruleDistMeters :: Rule+ruleDistMeters = Rule+ { name = "<dist> meters"+ , pattern =+ [ dimension Distance+ , regex "metro?i?|m"+ ]+ , prod = \tokens -> case tokens of+ (Token Distance dd:_) ->+ Just . Token Distance $ withUnit TDistance.Metre dd+ _ -> Nothing+ }++ruleDistCentimeters :: Rule+ruleDistCentimeters = Rule+ { name = "<dist> centimeters"+ , pattern =+ [ dimension Distance+ , regex "cm|centimetro?i?"+ ]+ , prod = \tokens -> case tokens of+ (Token Distance dd:_) ->+ Just . Token Distance $ withUnit TDistance.Centimetre dd+ _ -> Nothing+ }++ruleDistMiles :: Rule+ruleDistMiles = Rule+ { name = "<dist> miles"+ , pattern =+ [ dimension Distance+ , regex "miglio?a?"+ ]+ , prod = \tokens -> case tokens of+ (Token Distance dd:_) ->+ Just . Token Distance $ withUnit TDistance.Mile dd+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleDistCentimeters+ , ruleDistMeters+ , ruleDistMiles+ , ruleLatentDistKm+ ]
@@ -0,0 +1,59 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}++module Duckling.Distance.KM.Corpus+ ( corpus+ ) where++import Data.String+import Prelude++import Duckling.Locale+import Duckling.Distance.Types+import Duckling.Resolve+import Duckling.Testing.Types++context :: Context+context = testContext{locale = makeLocale KM Nothing}++corpus :: Corpus+corpus = (context, testOptions, allExamples)++allExamples :: [Example]+allExamples = concat+ [ examples (simple Kilometre 3)+ [ "3 km"+ , "៣គីឡូ"+ , "បីគីឡូម៉ែត្រ"+ ]+ , examples (simple Centimetre 2)+ [ "2cm"+ , "២សង់ទីម៉ែត្រ"+ , "ពីរសង់ទីម៉ែត្រ"+ ]+ , examples (between Metre (3, 5))+ [ "ចាប់ពី 3 ដល់ 5 m"+ , "ចន្លោះពី ៣ ដល់ ៥ម៉ែត្រ"+ , "ចន្លោះ ៣ម៉ែត្រ និង ៥ម៉ែត្រ"+ , "ប្រហែល ៣-៥ ម៉ែត្រ"+ , "~3-5ម៉ែត្រ"+ ]+ , examples (under Centimetre 4)+ [ "តិចជាងបួនសង់ទីម៉ែត្រ"+ , "មិនលើស៤សង់ទីម៉ែត្រ"+ , "ក្រោម៤សង់ទីម៉ែត្រ"+ , "យ៉ាងច្រើន៤សង់ទីម៉ែត្រ"+ ]+ , examples (above Millimetre 10)+ [ "ច្រើនជាងដប់មីលីម៉ែត្រ"+ , "មិនតិចជាងដប់មីលីម៉ែត្រ"+ , "លើសពីដប់មីលីម៉ែត្រ"+ , "យ៉ាងតិចដប់មីលីម៉ែត្រ"+ ]+ ]
@@ -0,0 +1,178 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}++module Duckling.Distance.KM.Rules+ ( rules+ ) where++import Data.String+import Data.Text (Text)+import Prelude++import Duckling.Dimensions.Types+import Duckling.Distance.Helpers+import Duckling.Distance.Types (DistanceData(..))+import Duckling.Numeral.Helpers+import Duckling.Numeral.Types (NumeralData (..))+import Duckling.Types+import qualified Duckling.Distance.Types as TDistance+import qualified Duckling.Numeral.Types as TNumeral++distances :: [(Text, String, TDistance.Unit)]+distances = [ ("km", "km|គីឡូ(ម៉ែត្រ)?", TDistance.Kilometre)+ , ("meters", "m|ម៉ែត្រ", TDistance.Metre)+ , ("centimeters", "cm|សង់ទីម៉ែត្រ", TDistance.Centimetre)+ , ("millimeters", "mm|មីលីម៉ែត្រ", TDistance.Millimetre)+ ]++rulePrecision :: Rule+rulePrecision = Rule+ { name = "about|exactly <dist>"+ , pattern =+ [ regex "\\~|ប្រហែល"+ , dimension Distance+ ]+ , prod = \case+ (_:token:_) -> Just token+ _ -> Nothing+ }++ruleDistances :: [Rule]+ruleDistances = map go distances+ where+ go :: (Text, String, TDistance.Unit) -> Rule+ go (name, regexPattern, u) = Rule+ { name = name+ , pattern = [ dimension Distance, regex regexPattern ]+ , prod = \case+ (Token Distance dd:_) -> Just . Token Distance $ withUnit u dd+ _ -> Nothing+ }++ruleIntervalBetweenNumeral :: Rule+ruleIntervalBetweenNumeral = Rule+ { name = "between|from <numeral> to|and <dist>"+ , pattern =+ [ regex "ចន្លោះ(ពី)?|ចាប់ពី"+ , Predicate isPositive+ , regex "និង|ដល់"+ , Predicate isSimpleDistance+ ]+ , prod = \case+ (_:+ Token Numeral NumeralData{TNumeral.value = from}:+ _:+ Token Distance DistanceData{TDistance.value = Just to,+ TDistance.unit = Just u}:+ _) | from < to ->+ Just . Token Distance . withInterval (from, to) $ unitOnly u+ _ -> Nothing+ }++ruleIntervalBetween :: Rule+ruleIntervalBetween = Rule+ { name = "between|from <dist> to|and <dist>"+ , pattern =+ [ regex "ចន្លោះ(ពី)?|ចាប់ពី"+ , Predicate isSimpleDistance+ , regex "និង|ដល់"+ , Predicate isSimpleDistance+ ]+ , prod = \case+ (_:+ Token Distance DistanceData{TDistance.value = Just from,+ TDistance.unit = Just u1}:+ _:+ Token Distance DistanceData{TDistance.value = Just to,+ TDistance.unit = Just u2}:+ _) | from < to && u1 == u2 ->+ Just . Token Distance . withInterval (from, to) $ unitOnly u1+ _ -> Nothing+ }++ruleIntervalNumeralDash :: Rule+ruleIntervalNumeralDash = Rule+ { name = "<numeral> - <dist>"+ , pattern =+ [ Predicate isPositive+ , regex "-"+ , Predicate isSimpleDistance+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = from}:+ _:+ Token Distance DistanceData{TDistance.value = Just to,+ TDistance.unit = Just u}:+ _) | from < to ->+ Just . Token Distance . withInterval (from, to) $ unitOnly u+ _ -> Nothing+ }++ruleIntervalDash :: Rule+ruleIntervalDash = Rule+ { name = "<dist> - <dist>"+ , pattern =+ [ Predicate isSimpleDistance+ , regex "-"+ , Predicate isSimpleDistance+ ]+ , prod = \case+ (Token Distance DistanceData{TDistance.value = Just from,+ TDistance.unit = Just u1}:+ _:+ Token Distance DistanceData{TDistance.value = Just to,+ TDistance.unit = Just u2}:+ _) | from < to && u1 == u2 ->+ Just . Token Distance . withInterval (from, to) $ unitOnly u1+ _ -> Nothing+ }++ruleIntervalMax :: Rule+ruleIntervalMax = Rule+ { name = "Max Rule"+ , pattern =+ [ regex "ក្រោម|តិចជាង|មិនដល់|យ៉ាងច្រើន|មិនលើស"+ , Predicate isSimpleDistance+ ]+ , prod = \case+ (_:+ Token Distance DistanceData{TDistance.value = Just to,+ TDistance.unit = Just u}:+ _) -> Just . Token Distance . withMax to $ unitOnly u+ _ -> Nothing+ }++ruleIntervalMin :: Rule+ruleIntervalMin = Rule+ { name = "Min Rule"+ , pattern =+ [ regex "លើស(ពី)?|មិនតិចជាង|លើ|ច្រើនជាង|យ៉ាងតិច|យ៉ាងហោច"+ , Predicate isSimpleDistance+ ]+ , prod = \case+ (_:+ Token Distance DistanceData{TDistance.value = Just to,+ TDistance.unit = Just u}:+ _) -> Just . Token Distance . withMin to $ unitOnly u+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleIntervalBetweenNumeral+ , ruleIntervalBetween+ , ruleIntervalMax+ , ruleIntervalMin+ , ruleIntervalNumeralDash+ , ruleIntervalDash+ , rulePrecision+ ]+ ++ ruleDistances
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -0,0 +1,57 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}++module Duckling.Distance.MN.Corpus+ ( corpus+ ) where++import Data.String+import Prelude++import Duckling.Locale+import Duckling.Resolve+import Duckling.Distance.Types+import Duckling.Testing.Types++corpus :: Corpus+corpus = (testContext {locale = makeLocale MN Nothing}, testOptions, allExamples)++allExamples :: [Example]+allExamples = concat+ [ examples (simple Kilometre 3)+ [ "3 километр"+ , "3 км"+ , "3км"+ ]+ , examples (simple Mile 8)+ [ "8 миль"+ ]+ , examples (simple Metre 1)+ [ "1 м"+ , "1 метр"+ ]+ , examples (simple Centimetre 2)+ [ "2см"+ ]+ , examples (simple Millimetre 4)+ [ "4мм"+ , "4 миллиметр"+ ]+ , examples (simple Inch 5)+ [ "5 инч"+ , "5\""+ ]+ , examples (simple Foot 35)+ [ "35 фут"+ , "35'"+ ]+ , examples (simple Yard 47)+ [ "47 яард"+ ]+ ]
@@ -0,0 +1,49 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE OverloadedStrings #-}++module Duckling.Distance.MN.Rules+ ( rules+ ) where++import Data.String+import Data.Text (Text)+import Prelude++import Duckling.Dimensions.Types+import Duckling.Distance.Helpers+import Duckling.Distance.Types (DistanceData(..))+import Duckling.Types+import qualified Duckling.Distance.Types as TDistance++distances :: [(Text, String, TDistance.Unit)]+distances = [ ("<latent dist> km", "км|километр", TDistance.Kilometre)+ , ("<latent dist> feet", "('|фут)", TDistance.Foot)+ , ("<latent dist> inch", "(\"|''|дюйм|инч)", TDistance.Inch)+ , ("<latent dist> yard", "яард", TDistance.Yard)+ , ("<dist> meters", "м(етр(ийн|ээр)?)?", TDistance.Metre)+ , ("<dist> centimeters", "см|сантиметр", TDistance.Centimetre)+ , ("<dist> millimeters", "мм|миллиметр", TDistance.Millimetre)+ , ("<dist> miles", "мил(и|ь)", TDistance.Mile)+ ]++ruleDistances :: [Rule]+ruleDistances = map go distances+ where+ go :: (Text, String, TDistance.Unit) -> Rule+ go (name, regexPattern, u) = Rule+ { name = name+ , pattern = [ dimension Distance, regex regexPattern ]+ , prod = \tokens -> case tokens of+ (Token Distance dd:_) -> Just . Token Distance $ withUnit u dd+ _ -> Nothing+ }++rules :: [Rule]+rules = ruleDistances
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE DeriveAnyClass #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -68,5 +67,31 @@ , "1 miles" , "1英里" , "一英裏"+ ]+ , examples (simple Metre 1.9)+ [ "1.9 m"+ , "1.9米"+ , "米九"+ ]+ , examples (simple Metre 3.9)+ [ "3.9 m"+ , "3.9米"+ , "三米九"+ ]+ , examples (between Metre (1.6, 3.9))+ [ "1.6m-3.9m"+ , "1.6~3.9米"+ , "一點六至三點九公尺"+ , "米六到三米九"+ ]+ , examples (under Mile 3.5)+ [ "最多三點五英里"+ , "3.5英裏以下"+ ]+ , examples (above Inch 5)+ [ "至少5\""+ , "最少五吋"+ , "五英吋以上"+ , "起碼五英寸" ] ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -18,7 +17,10 @@ import Duckling.Dimensions.Types import Duckling.Distance.Helpers-import Duckling.Numeral.Types (NumeralData (..))+import Duckling.Distance.Types (DistanceData(..))+import Duckling.Numeral.Helpers+import Duckling.Numeral.Types+import Duckling.Regex.Types import Duckling.Types import qualified Duckling.Distance.Types as TDistance import qualified Duckling.Numeral.Types as TNumeral@@ -70,7 +72,7 @@ [ dimension Distance , regex "'|f(oo|ee)?ts?|英尺|呎" , dimension Distance- , regex "''|inch(es)?|英寸|英吋|吋"+ , regex "''|\"|inch(es)?|英寸|英吋|吋" ] , prod = \case (Token Distance dd:_) ->@@ -83,7 +85,7 @@ { name = "<dist> inch" , pattern = [ dimension Distance- , regex "''|inch(es)?|英寸|英吋|吋"+ , regex "''|\"|inch(es)?|英寸|英吋|吋" ] , prod = \case (Token Distance dd:_) ->@@ -117,6 +119,107 @@ _ -> Nothing } +ruleDistOneMeterAnd :: Rule+ruleDistOneMeterAnd = Rule+ { name = "one meter and <dist>"+ , pattern =+ [ regex "米"+ , Predicate isPositive+ ]+ , prod = \case+ (_:Token Numeral NumeralData{TNumeral.value = v}:_) ->+ Just . Token Distance $ withUnit TDistance.Metre (distance (1 + v/10))+ _ -> Nothing+ }++ruleDistMetersAnd :: Rule+ruleDistMetersAnd = Rule+ { name = "<dist> meters and <dist>"+ , pattern =+ [ Predicate isPositive+ , regex "米"+ , Predicate isPositive+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = v1}:_:+ Token Numeral NumeralData{TNumeral.value = v2}:_) ->+ Just . Token Distance $ withUnit TDistance.Metre (distance (v1 + v2/10))+ _ -> Nothing+ }++ruleIntervalNumeralDash :: Rule+ruleIntervalNumeralDash = Rule+ { name = "<numeral> - <dist>"+ , pattern =+ [ Predicate isPositive+ , regex "-|~|到|至"+ , Predicate isSimpleDistance+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = from}:+ _:+ Token Distance DistanceData{TDistance.value = Just to,+ TDistance.unit = Just u}:_) | from < to ->+ Just $ Token Distance $ withInterval (from, to) $ unitOnly u+ _ -> Nothing+ }++ruleIntervalDash :: Rule+ruleIntervalDash = Rule+ { name = "<dist> - <dist>"+ , pattern =+ [ Predicate isSimpleDistance+ , regex "-|~|到|至"+ , Predicate isSimpleDistance+ ]+ , prod = \case+ (Token Distance DistanceData{TDistance.value = Just from,+ TDistance.unit = Just u1}:+ _:+ Token Distance DistanceData{TDistance.value = Just to, TDistance.unit = Just u2}:+ _) | from < to && u1 == u2 ->+ Just $ Token Distance $ withInterval (from, to) $ unitOnly u1+ _ -> Nothing+ }++ruleIntervalBound :: Rule+ruleIntervalBound = Rule+ { name = "under/less/lower/no more than <amount-of-money> (最多|至少|最少)"+ , pattern =+ [ regex "(最多|至少|最少|起碼)"+ , Predicate isSimpleDistance+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):+ Token Distance DistanceData{TDistance.value = Just to,+ TDistance.unit = Just u}:+ _) -> case match of+ "最多" -> Just $ Token Distance $ withMax to $ unitOnly u+ "最少" -> Just $ Token Distance $ withMin to $ unitOnly u+ "至少" -> Just $ Token Distance $ withMin to $ unitOnly u+ "起碼" -> Just $ Token Distance $ withMin to $ unitOnly u+ _ -> Nothing+ _ -> Nothing+ }++ruleIntervalBound2 :: Rule+ruleIntervalBound2 = Rule+ { name = "under/less/lower/no more than <amount-of-money> (以下|以上)"+ , pattern =+ [ Predicate isSimpleDistance+ , regex "(以下|以上)"+ ]+ , prod = \case+ (Token Distance DistanceData{TDistance.value = Just to,+ TDistance.unit = Just u}:+ Token RegexMatch (GroupMatch (match:_)):+ _) -> case match of+ "以下" -> Just $ Token Distance $ withMax to $ unitOnly u+ "以上" -> Just $ Token Distance $ withMin to $ unitOnly u+ _ -> Nothing+ _ -> Nothing+ }+ rules :: [Rule] rules = [ ruleDistCentimeters@@ -126,4 +229,12 @@ , ruleDistKm , ruleDistMeters , ruleDistMiles+ , ruleDistOneMeterAnd+ , ruleDistMetersAnd+ , ruleDistOneMeterAnd+ , ruleDistMetersAnd+ , ruleIntervalNumeralDash+ , ruleIntervalDash+ , ruleIntervalBound+ , ruleIntervalBound2 ]
@@ -0,0 +1,190 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++-- | This module shadows names of some units previously defined in+-- 'Duckling.Distance.Types'.+-- Therefore, the units from that module must be used qualified by module.+module Duckling.DistanceUnits.Types+ ( ContextualDistance (..)+ , toSystemUnit+ , toRawUnit+ ) where++import Data.Semigroup+import Data.Tuple.Extra (both)+import Prelude++import qualified Duckling.Distance.Types as TDist+++-- | Supports deferred resolution of ambiguous units.+-- Note that this sum type cannot be simply replaced by+-- "Maybe (ContextualDistance Double DeferrableUnit)"+-- (with "Nothing" representing "Nonrelatable").+-- See "NOTE A" below.+data ContextualDistance+ = Nonrelatable+ -- ^ If two different ambiguous units were to be composed, then+ -- it would not be possible to decide which to resolve to. As of today,+ -- this won't happen since for now "M" is the lone ambiguous unit.+ | ContextualDistance Double DeferrableUnit++-- | This represents Units that have not yet been established as unrelatable.+-- The "Definite" constructor is purposely listed in front of "Ambiguous",+-- so that it will be preferred when taking choosing the "min" between+-- an "Ambiguous" and "Definite" unit.+data DeferrableUnit+ = Definite SystemUnit+ | Ambiguous AmbiguousUnit+ deriving (Eq, Ord)++-- | These measurement-system-specific units exist to disambiguate+-- the \"M\" of the 'Unit' type and to maintain the measurement-system context+-- for resolving to the appropriate precision.+--+-- It's also just handy to have separate programmatically accessible lists+-- of units for each type of measurement system.+data SystemUnit+ = Metric MetricUnit+ | Imperial ImperialUnit+ deriving (Eq, Ord)++data ImperialUnit+ = Inch+ | Foot+ | Yard+ | Mile+ deriving (Eq, Ord)++data MetricUnit+ = Millimetre+ | Centimetre+ | Metre+ | Kilometre+ deriving (Eq, Ord)++-- | Currently there is only one actually ambiguous unit, but this design allows+-- for expansion.+data AmbiguousUnit+ = M -- ^ "Miles" or "Metres"+ deriving (Eq, Ord)++-- | Represents a value with an unambiguous unit+data UnitValuePair = UnitValuePair SystemUnit Double++sumScaledUnits :: SystemUnit -> (UnitValuePair, UnitValuePair) -> Double+sumScaledUnits preferredUnit = uncurry (+) . both (scaleUnits preferredUnit)++-- | Determine the definite meaning of an "Ambiguous" unit using the context of+-- another "Definite" unit+reconcileAmbiguousWithDefinite ::+ Double+ -> AmbiguousUnit+ -> Double+ -> SystemUnit+ -> ContextualDistance+reconcileAmbiguousWithDefinite av au dv du =+ ContextualDistance combinedValue $ Definite preferredUnit+ where+ resolvedAmbiguousUnit = resolveUnit au du+ preferredUnit = du `min` resolvedAmbiguousUnit+ combinedValue = sumScaledUnits preferredUnit+ (UnitValuePair resolvedAmbiguousUnit av, UnitValuePair du dv)++-- | When both Metric and Imperial units are given, resolve to Metric.+-- Otherwise, preserve the original measurement system and use the smaller unit.+-- For the purpose of this resolution, all Metric units are considered "smaller"+-- than Imperial units.+instance Semigroup ContextualDistance where++ _ <> Nonrelatable = Nonrelatable+ Nonrelatable <> _ = Nonrelatable++ (ContextualDistance v1 u@(Ambiguous u1))+ <> (ContextualDistance v2 (Ambiguous u2))+ | u1 == u2 = ContextualDistance (v1 + v2) u+ | otherwise = Nonrelatable+ -- NOTE A: Needing to return "Nonrelatable" in this edge case is why+ -- the two-member "ContextualDistance" sum type cannot be simply+ -- represented as (Maybe (ContextualDistance Double DeferrableUnit)).++ (ContextualDistance av (Ambiguous au))+ <> (ContextualDistance dv (Definite du)) =+ reconcileAmbiguousWithDefinite av au dv du++ (ContextualDistance dv (Definite du))+ <> (ContextualDistance av (Ambiguous au)) =+ reconcileAmbiguousWithDefinite av au dv du++ (ContextualDistance v1 (Definite u1))+ <> (ContextualDistance v2 (Definite u2)) =+ ContextualDistance v $ Definite u+ where+ v = sumScaledUnits u (UnitValuePair u1 v1, UnitValuePair u2 v2)+ u = u1 `min` u2++resolveUnit :: AmbiguousUnit -> SystemUnit -> SystemUnit+resolveUnit M (Metric _) = Metric Metre+resolveUnit M (Imperial _) = Imperial Mile+++-- | Disambiguation of original Unit type+toSystemUnit :: TDist.Unit -> DeferrableUnit+toSystemUnit TDist.M = Ambiguous M+toSystemUnit TDist.Millimetre = Definite $ Metric Millimetre+toSystemUnit TDist.Centimetre = Definite $ Metric Centimetre+toSystemUnit TDist.Metre = Definite $ Metric Metre+toSystemUnit TDist.Kilometre = Definite $ Metric Kilometre+toSystemUnit TDist.Inch = Definite $ Imperial Inch+toSystemUnit TDist.Foot = Definite $ Imperial Foot+toSystemUnit TDist.Yard = Definite $ Imperial Yard+toSystemUnit TDist.Mile = Definite $ Imperial Mile++-- | Reconversion to original Unit type+toRawUnit :: DeferrableUnit -> TDist.Unit+toRawUnit (Ambiguous M) = TDist.M+toRawUnit (Definite (Metric Millimetre)) = TDist.Millimetre+toRawUnit (Definite (Metric Centimetre)) = TDist.Centimetre+toRawUnit (Definite (Metric Metre)) = TDist.Metre+toRawUnit (Definite (Metric Kilometre)) = TDist.Kilometre+toRawUnit (Definite (Imperial Inch)) = TDist.Inch+toRawUnit (Definite (Imperial Foot)) = TDist.Foot+toRawUnit (Definite (Imperial Yard)) = TDist.Yard+toRawUnit (Definite (Imperial Mile)) = TDist.Mile++-- | Convert a distance to the given units.+-- This only works if the unit is unambiguous.+scaleUnits ::+ SystemUnit -- ^ target unit+ -> UnitValuePair -- ^ Original unit and value+ -> Double+scaleUnits targetUnit (UnitValuePair startingUnit v)+ | startingUnit == targetUnit = v+ | otherwise = inSIUnits v startingUnit / inSIUnits 1 targetUnit++-- | This is used when distances+-- must be normalized across measurement systems.+-- The Metric metre is the Standard International unit of distance.+inSIUnits :: Double -> SystemUnit -> Double+inSIUnits val (Metric u) = inMetres u val+inSIUnits val (Imperial u) = inInches u val * metersPerInch++-- | This conversion factor is exact.+metersPerInch :: Double+metersPerInch = 0.0254++inMetres :: Fractional a => MetricUnit -> a -> a+inMetres Millimetre n = n / 1000+inMetres Centimetre n = n / 100+inMetres Metre n = n+inMetres Kilometre n = n * 1000++inInches :: Num a => ImperialUnit -> a -> a+inInches Inch n = n+inInches Foot n = 12 * n+inInches Yard n = 3 * inInches Foot n+inInches Mile n = 5280 * inInches Foot n
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -37,7 +36,7 @@ , dimension TimeGrain ] , prod = \tokens -> case tokens of- (_:Token TimeGrain grain:_) -> Token Duration <$> timesOneAndAHalf grain 0+ (_:Token TimeGrain grain:_) -> Token Duration <$> nPlusOneHalf grain 0 _ -> Nothing } @@ -49,7 +48,7 @@ , regex "и половина" ] , prod = \tokens -> case tokens of- (Token TimeGrain grain:_) -> Token Duration <$> timesOneAndAHalf grain 1+ (Token TimeGrain grain:_) -> Token Duration <$> nPlusOneHalf grain 1 _ -> Nothing } @@ -64,7 +63,7 @@ , prod = \tokens -> case tokens of (Token Numeral NumeralData{TNumeral.value = v}: Token TimeGrain grain:- _) -> timesOneAndAHalf grain (floor $ v) >>= Just . Token Duration+ _) -> nPlusOneHalf grain (floor $ v) >>= Just . Token Duration _ -> Nothing }
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,136 +2,248 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} module Duckling.Duration.DE.Rules ( rules ) where -import Control.Monad (join)-import qualified Data.Text as Text-import Prelude-import Data.String import Duckling.Dimensions.Types import Duckling.Duration.Helpers-import Duckling.Numeral.Helpers (parseInteger)-import Duckling.Numeral.Types (NumeralData (..))-import qualified Duckling.Numeral.Types as TNumeral import Duckling.Regex.Types+import Control.Monad (join)+import qualified Data.Text as Text+import Prelude+import Duckling.Numeral.Helpers (parseInteger)+import Duckling.Duration.Types (DurationData(..))+import qualified Duckling.Duration.Types as TDuration+import Data.String+import Duckling.Numeral.Types (NumeralData(..)) import qualified Duckling.TimeGrain.Types as TG+import qualified Duckling.Numeral.Types as TNumeral import Duckling.Types +ruleQuarterOfAnHour :: Rule+ruleQuarterOfAnHour = Rule+ { name = "quarter of an hour"+ , pattern =+ [ regex "(einer? )?Viertelstunde"+ ]+ , prod = \_ -> Just $ Token Duration $ duration TG.Minute 15+ }+ ruleHalfAnHour :: Rule ruleHalfAnHour = Rule { name = "half an hour" , pattern =- [ regex "(1/2\\s?|(einer )halbe?n? )stunde"+ [ regex "(1/2\\s?|(eine )?halbe |(einer )?halben )stunde" ]- , prod = \_ -> Just . Token Duration $ duration TG.Minute 30+ , prod = \_ -> Just $ Token Duration $ duration TG.Minute 30 } +ruleThreeQuartersOfAnHour :: Rule+ruleThreeQuartersOfAnHour = Rule+ { name = "three-quarters of an hour"+ , pattern =+ [ regex "3/4\\s?stunde|(einer? )?dreiviertel stunde|drei viertelstunden"+ ]+ , prod = \_ -> Just $ Token Duration $ duration TG.Minute 45+ }+ ruleFortnight :: Rule ruleFortnight = Rule { name = "fortnight" , pattern =- [ regex "(a|one)? fortnight"+ [ regex "zwei Wochen" ]- , prod = \_ -> Just . Token Duration $ duration TG.Day 14+ , prod = \_ -> Just $ Token Duration $ duration TG.Day 14 } -ruleIntegerMoreUnitofduration :: Rule-ruleIntegerMoreUnitofduration = Rule- { name = "<integer> more <unit-of-duration>"+rulePrecision :: Rule+rulePrecision = Rule+ { name = "about|exactly <duration>" , pattern =- [ Predicate isNatural- , regex "mehr|weniger"- , dimension TimeGrain+ [ regex "ungef(ä|a)hr|zirka|genau|exakt"+ , dimension Duration ]- , prod = \tokens -> case tokens of- (Token Numeral NumeralData{TNumeral.value = v}:- _:- Token TimeGrain grain:- _) -> Just . Token Duration . duration grain $ floor v+ , prod = \case+ (_:token:_) -> Just token _ -> Nothing } -ruleNumeralnumberHours :: Rule-ruleNumeralnumberHours = Rule- { name = "number.number hours"+ruleCommaNumeralHours :: Rule+ruleCommaNumeralHours = Rule+ { name = "number,number hours" , pattern =- [ regex "(\\d+)\\.(\\d+) stunden?"+ [ regex "(\\d+),(\\d+)"+ , Predicate $ isGrain TG.Hour ]- , prod = \tokens -> case tokens of+ , prod = \case (Token RegexMatch (GroupMatch (h:m:_)):_) -> do hh <- parseInteger h mnum <- parseInteger m let mden = 10 ^ Text.length m- Just . Token Duration $ minutesFromHourMixedFraction hh mnum mden+ Just $ Token Duration $ minutesFromHourMixedFraction hh mnum mden _ -> Nothing } -ruleIntegerAndAnHalfHours :: Rule-ruleIntegerAndAnHalfHours = Rule- { name = "<integer> and an half hours"+ruleCommaNumeralMinutes :: Rule+ruleCommaNumeralMinutes = Rule+ { name = "number,number minutes" , pattern =+ [ regex "(\\d+),(\\d+)"+ , Predicate $ isGrain TG.Minute+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (m:s:_)):_) -> do+ mm <- parseInteger m+ ss <- parseInteger s+ let sden = 10 ^ Text.length s+ Just $ Token Duration $ secondsFromHourMixedFraction mm ss sden+ _ -> Nothing+ }++ruleAndHalfHour :: Rule+ruleAndHalfHour = Rule+ { name = "<integer> and a half hour"+ , pattern = [ Predicate isNatural- , regex "ein ?halb stunden?"+ , regex "(und )?(ein(en?)? )?halb(en?)?"+ , Predicate $ isGrain TG.Hour ]- , prod = \tokens -> case tokens of+ , prod = \case (Token Numeral NumeralData{TNumeral.value = v}:_) ->- Just . Token Duration . duration TG.Minute $ 30 + 60 * floor v+ Just $ Token Duration $ duration TG.Minute $ 30 + 60 * floor v _ -> Nothing } -ruleAUnitofduration :: Rule-ruleAUnitofduration = Rule+ruleAndHalfMinute :: Rule+ruleAndHalfMinute = Rule+ { name = "<integer> and a half minutes"+ , pattern =+ [ Predicate isNatural+ , regex "(und )?(ein(en?)? ?)?halb(en?)?"+ , Predicate $ isGrain TG.Minute+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = v}:_) ->+ Just $ Token Duration $ duration TG.Second $ 30 + 60 * floor v+ _ -> Nothing+ }++ruleArticle :: Rule+ruleArticle = Rule { name = "a <unit-of-duration>" , pattern =- [ regex "eine?(r|n)?"+ [ regex "ein(en?)?" , dimension TimeGrain ]- , prod = \tokens -> case tokens of- (_:Token TimeGrain grain:_) -> Just . Token Duration $ duration grain 1+ , prod = \case+ (_:Token TimeGrain grain:_) -> Just $ Token Duration $ duration grain 1 _ -> Nothing } -ruleAboutDuration :: Rule-ruleAboutDuration = Rule- { name = "about <duration>"+ruleHalfTimeGrain :: Rule+ruleHalfTimeGrain = Rule+ { name = "half a <time-grain>" , pattern =- [ regex "ungefähr|zirka"+ [ regex "(ein(en)?)?(1/2|halbe?)"+ , dimension TimeGrain+ ]+ , prod = \case+ (_:Token TimeGrain grain:_) -> Token Duration <$> nPlusOneHalf grain 0+ _ -> Nothing+ }++ruleCompositeDurationCommasAnd :: Rule+ruleCompositeDurationCommasAnd = Rule+ { name = "composite <duration> (with ,/and)"+ , pattern =+ [ Predicate isNatural+ , dimension TimeGrain+ , regex ",|und" , dimension Duration ]- , prod = \tokens -> case tokens of- (_:token:_) -> Just token+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = v}:+ Token TimeGrain g:+ _:+ Token Duration dd@DurationData{TDuration.grain = dg}:+ _) | g > dg -> Just $ Token Duration $ duration g (floor v) <> dd _ -> Nothing } -ruleExactlyDuration :: Rule-ruleExactlyDuration = Rule- { name = "exactly <duration>"+ruleCompositeDuration :: Rule+ruleCompositeDuration = Rule+ { name = "composite <duration>" , pattern =- [ regex "genau|exakt"+ [ Predicate isNatural+ , dimension TimeGrain , dimension Duration ]- , prod = \tokens -> case tokens of- (_:token:_) -> Just token+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = v}:+ Token TimeGrain g:+ Token Duration dd@DurationData{TDuration.grain = dg}:+ _) | g > dg -> Just $ Token Duration $ duration g (floor v) <> dd _ -> Nothing } +ruleCompositeDurationAnd :: Rule+ruleCompositeDurationAnd = Rule+ { name = "composite <duration> and <duration>"+ , pattern =+ [ dimension Duration+ , regex ",|und"+ , dimension Duration+ ]+ , prod = \case+ (Token Duration DurationData{TDuration.value = v, TDuration.grain = g}:+ _:+ Token Duration dd@DurationData{TDuration.grain = dg}:+ _) | g > dg -> Just $ Token Duration $ duration g v <> dd+ _ -> Nothing+ }++ruleHoursAndMinutes :: Rule+ruleHoursAndMinutes = Rule+ { name = "<integer> hour and <integer>"+ , pattern =+ [ Predicate isNatural+ , regex "(ein(en?) )?stunden?( und)?"+ , Predicate isNatural+ , Predicate $ isGrain TG.Minute+ ]+ , prod = \case+ (Token Numeral h:+ _:+ Token Numeral m:+ _) -> Just $ Token Duration $ duration TG.Minute $+ floor (TNumeral.value m) + 60 * floor (TNumeral.value h)+ _ -> Nothing+ }+ rules :: [Rule] rules =- [ ruleAUnitofduration- , ruleAboutDuration- , ruleExactlyDuration- , ruleFortnight+ [ ruleQuarterOfAnHour , ruleHalfAnHour- , ruleIntegerAndAnHalfHours- , ruleIntegerMoreUnitofduration- , ruleNumeralnumberHours+ , ruleThreeQuartersOfAnHour+ , rulePrecision+ , ruleCommaNumeralHours+ , ruleCommaNumeralMinutes+ , ruleFortnight+ , ruleAndHalfHour+ , ruleAndHalfMinute+ , ruleArticle+ , ruleHalfTimeGrain+ , ruleCompositeDurationCommasAnd+ , ruleCompositeDuration+ , ruleCompositeDurationAnd+ , ruleHoursAndMinutes+ , ruleAndHalfMinute ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -159,7 +158,7 @@ , dimension TimeGrain ] , prod = \tokens -> case tokens of- (_:Token TimeGrain g:_) -> Token Duration <$> timesOneAndAHalf g 0+ (_:Token TimeGrain g:_) -> Token Duration <$> nPlusOneHalf g 0 _ -> Nothing } @@ -173,7 +172,7 @@ ] , prod = \tokens -> case tokens of (Token Numeral nd:_:Token TimeGrain grain:_) ->- timesOneAndAHalf grain (floor $ TNumeral.value nd) >>=+ nPlusOneHalf grain (floor $ TNumeral.value nd) >>= Just . Token Duration _ -> Nothing }@@ -189,7 +188,7 @@ , prod = \tokens -> case tokens of (Token RegexMatch (GroupMatch (num:_)):Token TimeGrain grain:_) -> HashMap.lookup (Text.toLower num) numeralMapEL >>=- timesOneAndAHalf grain >>=+ nPlusOneHalf grain >>= Just . Token Duration _ -> Nothing }
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -45,6 +44,13 @@ [ "2 mins" , "two minutes" , "2'"+ , "2 more minutes"+ , "two additional minutes"+ , "2 extra minutes"+ , "2 less minutes"+ , "2 fewer minutes"+ , "2m"+ , "2 m" ] , examples (DurationData 30 Day) [ "30 days"@@ -77,7 +83,33 @@ , examples (DurationData 90 Minute) [ "an hour and a half" , "one hour and half"+ , "1 hour thirty"+ , "1 hour and thirty"+ , "1.5 hours"+ , "1.5 hrs"+ , "one and two quarter hour"+ , "one and two quarters hour"+ , "one and two quarter of hour"+ , "one and two quarters of hour" ]+ , examples (DurationData 75 Minute)+ [ "1 hour fifteen"+ , "1 hour and fifteen"+ , "one and quarter hour"+ , "one and a quarter hour"+ , "one and one quarter hour"+ , "one and quarter of hour"+ , "one and a quarter of hour"+ , "one and one quarter of hour"+ ]+ , examples (DurationData 130 Minute)+ [ "2 hours ten"+ , "2 hour and 10"+ ]+ , examples (DurationData 3615 Second)+ [ "1 hour fifteen seconds"+ , "1 hour and fifteen seconds"+ ] , examples (DurationData 45 Day) [ "a month and a half" , "one month and half"@@ -85,8 +117,47 @@ , examples (DurationData 27 Month) [ "2 years and 3 months" , "2 years, 3 months"+ , "2 years 3 months" ] , examples (DurationData 31719604 Second) [ "1 year, 2 days, 3 hours and 4 seconds"+ , "1 year 2 days 3 hours and 4 seconds"+ -- Oxford comma not supported:+-- , "1 year, 2 days, 3 hours, and 4 seconds" ]+ , examples (DurationData 330 Second)+ [ "5 and a half minutes"+ , "five and half min"+ , "5 and an half minute"+ ]+ , examples (DurationData 105 Minute)+ [ "one and three quarter hour"+ , "one and three quarters hour"+ , "one and three quarter of hour"+ , "one and three quarters of hour"+ , "one and three quarter of hours"+ , "one and three quarters of hours"+ ]+ , examples (DurationData 135 Minute)+ [ "two and quarter hour"+ , "two and a quarter of hour"+ , "two and quarter of hours"+ , "two and a quarter of hours"+ ]+ , examples (DurationData 105 Minute)+ [ "an hour and 45 minutes"+ , "one hour and 45 minutes"+ ]+ , examples (DurationData 90 Second)+ [ "a minute and 30 seconds"+ , "one minute and 30 seconds"+ ]+ , examples (DurationData 3630 Second)+ [ "an hour and 30 seconds"]+ , examples (DurationData 930 Second)+ [ "15.5 minutes"+ , "15.5 minute"+ , "15.5 mins"+ , "15.5 min"+ ] ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -16,14 +15,13 @@ ) where import Data.Semigroup ((<>))-import Data.String import Prelude import qualified Data.Text as Text import Duckling.Dimensions.Types import Duckling.Duration.Helpers import Duckling.Duration.Types (DurationData(..))-import Duckling.Numeral.Helpers (parseInt, parseInteger)+import Duckling.Numeral.Helpers (parseInteger) import Duckling.Numeral.Types (NumeralData(..)) import Duckling.Regex.Types import Duckling.Types@@ -89,7 +87,7 @@ { name = "<integer> more <unit-of-duration>" , pattern = [ Predicate isNatural- , regex "more|less"+ , regex "more|additional|extra|less|fewer" , dimension TimeGrain ] , prod = \case@@ -102,7 +100,8 @@ ruleDurationDotNumeralHours = Rule { name = "number.number hours" , pattern =- [ regex "(\\d+)\\.(\\d+) *hours?"+ [ regex "(\\d+)\\.(\\d+)"+ , Predicate $ isGrain TG.Hour ] , prod = \case (Token RegexMatch (GroupMatch (h:m:_)):_) -> do@@ -126,6 +125,19 @@ _ -> Nothing } +ruleDurationAndHalfMinute :: Rule+ruleDurationAndHalfMinute = Rule+ { name = "<integer> and a half minutes"+ , pattern =+ [ Predicate isNatural+ , regex "and (an? )?half min(ute)?s?"+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = v}:_) ->+ Just . Token Duration . duration TG.Second $ 30 + 60 * floor v+ _ -> Nothing+ }+ ruleDurationA :: Rule ruleDurationA = Rule { name = "a <unit-of-duration>"@@ -146,7 +158,7 @@ , dimension TimeGrain ] , prod = \case- (_:Token TimeGrain grain:_) -> Token Duration <$> timesOneAndAHalf grain 0+ (_:Token TimeGrain grain:_) -> Token Duration <$> nPlusOneHalf grain 0 _ -> Nothing } @@ -159,10 +171,27 @@ , regex "and (a )?half" ] , prod = \case- (_:Token TimeGrain grain:_) -> Token Duration <$> timesOneAndAHalf grain 1+ (_:Token TimeGrain grain:_) -> Token Duration <$> nPlusOneHalf grain 1 _ -> Nothing } +ruleDurationHoursAndMinutes :: Rule+ruleDurationHoursAndMinutes = Rule+ { name = "<integer> hour and <integer>"+ , pattern =+ [ Predicate isNatural+ , regex "hours?( and)?"+ , Predicate isNatural+ ]+ , prod = \case+ (Token Numeral h:+ _:+ Token Numeral m:+ _) -> Just . Token Duration . duration TG.Minute $+ (floor $ TNumeral.value m) + 60 * floor (TNumeral.value h)+ _ -> Nothing+ }+ ruleDurationPrecision :: Rule ruleDurationPrecision = Rule { name = "about|exactly <duration>"@@ -175,37 +204,115 @@ _ -> Nothing } +-- | NOTE: Oxford comma is not supported.+ruleCompositeDurationCommasAnd :: Rule+ruleCompositeDurationCommasAnd = Rule+ { name = "composite <duration> (with ,/and)"+ , pattern =+ [ Predicate isNatural+ , dimension TimeGrain+ , regex ",|and"+ , dimension Duration+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = v}:+ Token TimeGrain g:+ _:+ Token Duration dd@DurationData{TDuration.grain = dg}:+ _) | g > dg -> Just . Token Duration $ duration g (floor v) <> dd+ _ -> Nothing+ }+ ruleCompositeDuration :: Rule ruleCompositeDuration = Rule { name = "composite <duration>" , pattern = [ Predicate isNatural , dimension TimeGrain- , regex ",|and" , dimension Duration ] , prod = \case (Token Numeral NumeralData{TNumeral.value = v}: Token TimeGrain g:- _: Token Duration dd@DurationData{TDuration.grain = dg}: _) | g > dg -> Just . Token Duration $ duration g (floor v) <> dd _ -> Nothing } +ruleCompositeDurationAnd :: Rule+ruleCompositeDurationAnd = Rule+ { name = "composite <duration> and <duration>"+ , pattern =+ [ dimension Duration+ , regex ",|and"+ , dimension Duration+ ]+ , prod = \case+ (Token Duration DurationData{TDuration.value = v, TDuration.grain = g}:+ _:+ Token Duration dd@DurationData{TDuration.grain = dg}:+ _) | g > dg -> Just . Token Duration $ duration g (v) <> dd+ _ -> Nothing+ }++ruleDurationDotNumeralMinutes :: Rule+ruleDurationDotNumeralMinutes = Rule+ { name = "number.number minutes"+ , pattern =+ [ regex "(\\d+)\\.(\\d+)"+ , Predicate $ isGrain TG.Minute+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (m:s:_)):_) -> do+ mm <- parseInteger m+ ss <- parseInteger s+ let sden = 10 ^ Text.length s+ Just $ Token Duration $ secondsFromHourMixedFraction mm ss sden+ _ -> Nothing+ }++ruleDurationNumeralAndQuarterHour :: Rule+ruleDurationNumeralAndQuarterHour = Rule+ { name = "<Integer> and <Integer> quarter of hour"+ , pattern =+ [ Predicate isNatural+ , regex "and (a |an |one |two |three )?quarters?( of)?( an)?"+ , Predicate $ isGrain TG.Hour+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = h}:+ Token RegexMatch (GroupMatch (match:_)):+ _) -> do+ q <- case Text.strip $ Text.toLower match of "a" -> Just 1+ "an" -> Just 1+ "one" -> Just 1+ "two" -> Just 2+ "three" -> Just 3+ _ -> Just 1+ Just . Token Duration . duration TG.Minute $ 15 * q + 60 * floor h+ _ -> Nothing+ }+ rules :: [Rule] rules =- [ ruleDurationQuarterOfAnHour+ [ ruleCompositeDurationCommasAnd+ , ruleDurationQuarterOfAnHour , ruleDurationHalfAnHourAbbrev , ruleDurationThreeQuartersOfAnHour , ruleDurationFortnight , ruleDurationNumeralMore , ruleDurationDotNumeralHours , ruleDurationAndHalfHour+ , ruleDurationAndHalfMinute , ruleDurationA , ruleDurationHalfATimeGrain , ruleDurationOneGrainAndHalf+ , ruleDurationHoursAndMinutes , ruleDurationPrecision , ruleNumeralQuotes , ruleCompositeDuration+ , ruleCompositeDurationAnd+ , ruleCompositeDurationCommasAnd+ , ruleDurationDotNumeralMinutes+ , ruleDurationNumeralAndQuarterHour ]
@@ -0,0 +1,58 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}++module Duckling.Duration.ES.Corpus+ ( corpus+ ) where++import Prelude+import Data.String++import Duckling.Duration.Types+import Duckling.Locale+import Duckling.Resolve+import Duckling.Testing.Types+import Duckling.TimeGrain.Types (Grain(..))++corpus :: Corpus+corpus = (testContext {locale = makeLocale ES Nothing}, testOptions, allExamples)++allExamples :: [Example]+allExamples = concat+ [ examples (DurationData 30 Minute)+ [ "media hora"+ , "media horas"+ , "30 minutos"+ , "treinta minutos"+ ]+ , examples (DurationData 15 Minute)+ [ "cuarto de hora"+ , "cuartos de hora"+ , "quince minutos"+ , "15 minutos"+ ]+ , examples (DurationData 45 Minute)+ [ "tres cuartos de hora"+ , "tres cuartos de horas"+ , "tres cuarto de hora"+ , "tres cuarto de horas"+ , "cuarenta y cinco minutos"+ , "45 minutos"+ ]+ , examples (DurationData 92 Minute)+ [+ "una hora y treinta y dos minutos"+ , "una hora treinta y dos minutos"+ ]+ , examples (DurationData 155 Minute)+ [+ "dos hora y treinta y cinco minutos"+ , "dos hora treinta y cinco minutos"+ ]+ ]
@@ -0,0 +1,98 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE NoRebindableSyntax #-}+{-# LANGUAGE OverloadedStrings #-}++module Duckling.Duration.ES.Rules+ ( rules+ ) where++import Prelude+import Data.Semigroup ((<>))+import Duckling.Dimensions.Types+import Duckling.Duration.Helpers+import Duckling.Duration.Types (DurationData(..))+import Duckling.Numeral.Types (NumeralData(..))+import Duckling.Types+import qualified Duckling.Duration.Types as TDuration+import qualified Duckling.Numeral.Types as TNumeral+import qualified Duckling.TimeGrain.Types as TG++ruleDurationQuarterOfAnHour :: Rule+ruleDurationQuarterOfAnHour = Rule+ { name = "quarter of an hour"+ , pattern =+ [ regex "cuartos? de hora"+ ]+ , prod = \_ -> Just $ Token Duration $ duration TG.Minute 15+ }++ruleDurationHalfOfAnHour :: Rule+ruleDurationHalfOfAnHour = Rule+ { name = "half of an hour"+ , pattern =+ [ regex "media horas?"+ ]+ , prod = \_ -> Just $ Token Duration $ duration TG.Minute 30+ }++ruleDurationThreeQuartersOfAnHour :: Rule+ruleDurationThreeQuartersOfAnHour = Rule+ { name = "three-quarters of an hour"+ , pattern =+ [ regex "tres cuartos? de horas?"+ ]+ , prod = \_ -> Just $ Token Duration $ duration TG.Minute 45+ }++ruleCompositeDurationCommasAnd :: Rule+ruleCompositeDurationCommasAnd = Rule+ { name = "composite <duration> (with and)"+ , pattern =+ [ Predicate isNatural+ , dimension TimeGrain+ , regex "y"+ , dimension Duration+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = v}:+ Token TimeGrain g:+ _:+ Token Duration dd@DurationData{TDuration.grain = dg}:+ _) | g > dg -> Just $ Token Duration $ duration g (floor v) <> dd+ _ -> Nothing+ }++ruleCompositeDuration :: Rule+ruleCompositeDuration = Rule+ {+ name = "composite <duration>"+ , pattern =+ [+ Predicate isNatural+ , dimension TimeGrain+ , dimension Duration+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = v}:+ Token TimeGrain g:+ Token Duration dd@DurationData{TDuration.grain = dg}:+ _) | g > dg -> Just $ Token Duration $ duration g (floor v) <> dd+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleDurationHalfOfAnHour+ , ruleDurationQuarterOfAnHour+ , ruleDurationThreeQuartersOfAnHour+ , ruleCompositeDuration+ , ruleCompositeDurationCommasAnd+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-} {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -36,6 +35,7 @@ , examples (DurationData 1 Day) [ "दिवस" , "एक दिन"+ , "बिल्कुल एक दिन" ] , examples (DurationData 14 Day) [ "पखवाड़ा"@@ -45,5 +45,38 @@ [ "एक साल" , "केवल एक वर्ष" , "लगभग एक साल"+ , "एक बरस"+ , "केवल एक साल"+ ]+ , examples (DurationData 21 Month)+ [ "पौने 2 साल"+ ]+ , examples (DurationData 105 Minute)+ [ "पौने 2 घंटा"+ ]+ , examples (DurationData 27 Month)+ [ "सवा 2 साल"+ , "2 साल और 3 महीना"+ , "2 साल, 3 महीना"+ , "2 साल 3 महीना"+ ]+ , examples (DurationData 135 Minute)+ [ "सवा 2 घंटा"+ ]+ , examples (DurationData 42 Month)+ [ "साड़े 3 साल"+ ]+ , examples (DurationData 210 Minute)+ [ "साड़े 3 घंटा"+ ]+ , examples (DurationData 31719604 Second)+ [ "1 साल, 2 दिन, 3 घंटा और 4 सेकंड"+ , "1 साल 2 दिन 3 घंटा और 4 सेकंड"+ ]+ , examples (DurationData 30 Month)+ [ "ढाई साल"+ ]+ , examples (DurationData 90 Minute)+ [ "डेढ़ घंटा" ] ]
@@ -2,18 +2,17 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} module Duckling.Duration.HI.Rules ( rules ) where -import Control.Monad (join) import Data.String import Data.HashMap.Strict (HashMap) import Data.Text (Text)@@ -23,34 +22,39 @@ import Duckling.Dimensions.Types import Duckling.Duration.Helpers-import Duckling.Numeral.Helpers (parseInteger)+import Duckling.Duration.Types (DurationData(..)) import Duckling.Numeral.Types (NumeralData (..)) import Duckling.Regex.Types import Duckling.Types+import qualified Duckling.Duration.Types as TDuration import qualified Duckling.Numeral.Types as TNumeral import qualified Duckling.TimeGrain.Types as TG avadhiMap :: HashMap Text TG.Grain avadhiMap = HashMap.fromList [ ("मिनट" , TG.Minute)+ , ("क्षण", TG.Minute) , ("घंटा" , TG.Hour) , ("दिवस" , TG.Day) , ("दिन" , TG.Day) , ("महीना", TG.Month)+ , ("माह", TG.Month)+ , ("मास", TG.Month) , ("वर्ष" , TG.Year) , ("साल" , TG.Year)+ , ("बरस", TG.Year) ] ruleAadha :: Rule ruleAadha = Rule { name = "half of a duration" , pattern =- [ regex "आधा ((साल|वर्ष)|(महीना)|(दिन|दिवस)|(घंटा)|(मिनट))"+ [ regex "आधा ((साल|वर्ष|बरस)|(महीना|मास|माह)|(दिन|दिवस)|(घंटा)|(मिनट|क्षण))" ] , prod = \tokens -> case tokens of (Token RegexMatch (GroupMatch (x:_)):_) -> do grain <- HashMap.lookup (Text.toLower x) avadhiMap- Token Duration <$> timesOneAndAHalf grain 0+ Token Duration <$> nPlusOneHalf grain 0 _ -> Nothing } @@ -60,7 +64,7 @@ , pattern = [ regex "पंद्रह मिनट" ]- , prod = \_ -> Just . Token Duration $ duration TG.Minute 15+ , prod = \_ -> Just $ Token Duration $ duration TG.Minute 15 } ruleDurationPakhwaada :: Rule@@ -69,7 +73,7 @@ , pattern = [ regex "((एक पखवाड़ा)|(पखवाड़ा))" ]- , prod = \_ -> Just . Token Duration $ duration TG.Day 14+ , prod = \_ -> Just $ Token Duration $ duration TG.Day 14 } ruleDurationDin :: Rule@@ -78,16 +82,16 @@ , pattern = [ regex "((एक दिन)|(एक दिवस)|(दिन|दिवस))" ]- , prod = \_ -> Just . Token Duration $ duration TG.Day 1+ , prod = \_ -> Just $ Token Duration $ duration TG.Day 1 } ruleDurationEkSaal :: Rule ruleDurationEkSaal = Rule { name = "one year" , pattern =- [ regex "एक (साल|वर्ष)"+ [ regex "एक (साल|वर्ष|बरस)" ]- , prod = \_ -> Just . Token Duration $ duration TG.Year 1+ , prod = \_ -> Just $ Token Duration $ duration TG.Year 1 } ruleDurationPreciseImprecise :: Rule@@ -102,7 +106,107 @@ _ -> Nothing } +rulePauneDuration :: Rule+rulePauneDuration = Rule+ { name = "Paune duration"+ , pattern =+ [ regex "पौने"+ , Predicate isNatural+ , dimension TimeGrain+ ]+ , prod = \case+ (_:+ Token Numeral NumeralData{TNumeral.value = v}:+ Token TimeGrain grain:+ _) -> Token Duration <$> timesThreeQuarter grain (floor (v - 1))+ _ -> Nothing+ } +ruleSavaDuration :: Rule+ruleSavaDuration = Rule+ { name = "Sava duration"+ , pattern =+ [ regex "सवा"+ , Predicate isNatural+ , dimension TimeGrain+ ]+ , prod = \case+ (_:+ Token Numeral NumeralData{TNumeral.value = v}:+ Token TimeGrain grain:+ _) -> Token Duration <$> timesOneQuarter grain (floor v)+ _ -> Nothing+ }++ruleSaadeDuration :: Rule+ruleSaadeDuration = Rule+ { name = "Saade duration"+ , pattern =+ [ regex "साढ़े|साड़े"+ , Predicate isNatural+ , dimension TimeGrain+ ]+ , prod = \case+ (_:+ Token Numeral NumeralData{TNumeral.value = v}:+ Token TimeGrain grain:+ _) -> Token Duration <$> nPlusOneHalf grain (floor v)+ _ -> Nothing+ }++ruleCompositeDuration :: Rule+ruleCompositeDuration = Rule+ { name = "composite <duration>"+ , pattern =+ [ Predicate isNatural+ , dimension TimeGrain+ , dimension Duration+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = v}:+ Token TimeGrain g:+ Token Duration dd@DurationData{TDuration.grain = dg}:+ _) | g > dg -> Just $ Token Duration $ duration g (floor v) <> dd+ _ -> Nothing+ }++ruleCompositeDurationCommasAnd :: Rule+ruleCompositeDurationCommasAnd = Rule+ { name = "composite <duration> (with ,/और)"+ , pattern =+ [ Predicate isNatural+ , dimension TimeGrain+ , regex ",|और"+ , dimension Duration+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = v}:+ Token TimeGrain g:+ _:+ Token Duration dd@DurationData{TDuration.grain = dg}:+ _) | g > dg -> Just $ Token Duration $ duration g (floor v) <> dd+ _ -> Nothing+ }++ruleNAndHalfDuration :: Rule+ruleNAndHalfDuration = Rule+ { name = "डेढ़|ढाई <duration>"+ , pattern =+ [ regex "(डेढ़|ढाई)"+ , dimension TimeGrain+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):+ Token TimeGrain grain:+ _) -> do+ h <- case Text.toLower match of+ "डेढ़" -> Just 1+ "ढाई" -> Just 2+ _ -> Nothing+ Token Duration <$> nPlusOneHalf grain h+ _ -> Nothing+ }+ rules :: [Rule] rules = [ ruleDurationPandrahMinat@@ -111,4 +215,10 @@ , ruleAadha , ruleDurationEkSaal , ruleDurationPreciseImprecise+ , rulePauneDuration+ , ruleSavaDuration+ , ruleSaadeDuration+ , ruleCompositeDuration+ , ruleCompositeDurationCommasAnd+ , ruleNAndHalfDuration ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-} {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -13,7 +12,10 @@ , isGrain , isNatural , minutesFromHourMixedFraction- , timesOneAndAHalf+ , nPlusOneHalf+ , secondsFromHourMixedFraction+ , timesOneQuarter+ , timesThreeQuarter ) where import Prelude@@ -42,11 +44,33 @@ minutesFromHourMixedFraction h n d = duration TG.Minute $ fromIntegral $ 60 * h + quot (n * 60) d -timesOneAndAHalf :: TG.Grain -> Int -> Maybe DurationData-timesOneAndAHalf grain = case grain of+nPlusOneHalf :: TG.Grain -> Int -> Maybe DurationData+nPlusOneHalf grain = case grain of TG.Minute -> Just . duration TG.Second . (30+) . (60*) TG.Hour -> Just . duration TG.Minute . (30+) . (60*) TG.Day -> Just . duration TG.Hour . (12+) . (24*) TG.Month -> Just . duration TG.Day . (15+) . (30*) TG.Year -> Just . duration TG.Month . (6+) . (12*)+ _ -> const Nothing++secondsFromHourMixedFraction :: Integer -> Integer -> Integer -> DurationData+secondsFromHourMixedFraction m s d =+ duration TG.Second $ fromIntegral $ 60 * m + quot (s * 60) d++timesOneQuarter :: TG.Grain -> Int -> Maybe DurationData+timesOneQuarter grain = case grain of+ TG.Minute -> Just . duration TG.Second . (15+) . (60*)+ TG.Hour -> Just . duration TG.Minute . (15+) . (60*)+ TG.Day -> Just . duration TG.Hour . (6+) . (24*)+ TG.Month -> Just . duration TG.Day . (7+) . (30*)+ TG.Year -> Just . duration TG.Month . (3+) . (12*)+ _ -> const Nothing++timesThreeQuarter :: TG.Grain -> Int -> Maybe DurationData+timesThreeQuarter grain = case grain of+ TG.Minute -> Just . duration TG.Second . (45+) . (60*)+ TG.Hour -> Just . duration TG.Minute . (45+) . (60*)+ TG.Day -> Just . duration TG.Hour . (18+) . (24*)+ TG.Month -> Just . duration TG.Day . (21+) . (30*)+ TG.Year -> Just . duration TG.Month . (9+) . (12*) _ -> const Nothing
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -0,0 +1,58 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}++module Duckling.Duration.KA.Corpus+ ( corpus+ ) where++import Prelude+import Data.String++import Duckling.Duration.Types+import Duckling.Testing.Types+import Duckling.TimeGrain.Types (Grain(..))++import Duckling.Locale+import Duckling.Resolve++corpus :: Corpus+corpus = (testContext {locale = makeLocale KA Nothing},+ testOptions, allExamples)++allExamples :: [Example]+allExamples = concat+ [ examples (DurationData 1 Second)+ [ "ერთი წამი"+ , "1 წამი"+ ]+ , examples (DurationData 2 Minute)+ [ "2 წუთი"+ , "ორი წუთი"+ ]+ , examples (DurationData 30 Day)+ [ "30 დღე"+ ]+ , examples (DurationData 7 Week)+ [ "შვიდი კვირა"+ ]+ , examples (DurationData 1 Month)+ [ "1 თვე"+ , "ერთი თვე"+ ]+ , examples (DurationData 3 Quarter)+ [ "3 კვარტალი"+ ]+ , examples (DurationData 27 Month)+ [ "2 წელი და 3 თვე"+ , "2 წელი, 3 თვე"+ ]+ , examples (DurationData 31719604 Second)+ [ "1 წელი, 2 დღე, 3 საათი და 4 წამი"+ ]+ ]
@@ -0,0 +1,155 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE NoRebindableSyntax #-}+{-# LANGUAGE OverloadedStrings #-}++module Duckling.Duration.KA.Rules+ ( rules+ ) where++import Data.Semigroup ((<>))+import Data.String+import Prelude+import qualified Data.Text as Text++import Duckling.Dimensions.Types+import Duckling.Duration.Helpers+import Duckling.Duration.Types (DurationData(..))+import Duckling.Numeral.Helpers (parseInt, parseInteger)+import Duckling.Numeral.Types (NumeralData(..))+import Duckling.Regex.Types+import Duckling.Types+import qualified Duckling.Duration.Types as TDuration+import qualified Duckling.Numeral.Types as TNumeral+import qualified Duckling.TimeGrain.Types as TG++ruleCompositeDuration :: Rule+ruleCompositeDuration = Rule+ { name = "composite <duration>"+ , pattern =+ [ Predicate isNatural+ , dimension TimeGrain+ , regex ",|და"+ , dimension Duration+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = v}:+ Token TimeGrain g:_:+ Token Duration dd@DurationData{TDuration.grain = dg}:+ _) | g > dg -> Just . Token Duration $ duration g (floor v) <> dd+ _ -> Nothing+ }++ruleCompositeDuration1 :: Rule+ruleCompositeDuration1 = Rule+ { name = "composite <duration>"+ , pattern =+ [ dimension TimeGrain+ , regex ",|და"+ , dimension Duration+ ]+ , prod = \case+ (Token TimeGrain g:_:+ Token Duration dd@DurationData{TDuration.grain = dg}:+ _) | g > dg -> Just . Token Duration $ duration g 1 <> dd+ _ -> Nothing+ }++ruleDurationYear :: Rule+ruleDurationYear = Rule+ { name = "<integer> year"+ , pattern =+ [ Predicate isNatural+ , regex "წელიწად(ის)?(ი)?(ში)?|წლი(ის)?(ში)?|წელშ?ი"+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = v}:_) ->+ Just . Token Duration . duration TG.Month $ 12 * floor v+ _ -> Nothing+ }++ruleDurationAndHalfYear :: Rule+ruleDurationAndHalfYear = Rule+ { name = "<integer> and an half year"+ , pattern =+ [ Predicate isNatural+ , regex "წელიწადნახევა?(რის)?(რი)?(რში)?|წლინახევრ(ის)?(არში)?"+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = v}:_) ->+ Just . Token Duration . duration TG.Month $ 6 + 12 * floor v+ _ -> Nothing+ }++ruleDurationAndHalfYear1 :: Rule+ruleDurationAndHalfYear1 = Rule+ { name = "<integer> and an half year"+ , pattern =+ [ regex "წელიწადნახევა?(რის)?(რი)?(რში)?|წლინახევრ(ის)?(არში)?"+ ]+ , prod = const $ Just . Token Duration . duration TG.Month $ 18+ }++ruleDurationAndHalfMonth :: Rule+ruleDurationAndHalfMonth = Rule+ { name = "<integer> and an half month"+ , pattern =+ [ Predicate isNatural+ , regex "თვენახევა?(რის)?(რი)?(რში)?"+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = v}:_) ->+ Just . Token Duration . duration TG.Day $ 15 + 30 * floor v+ _ -> Nothing+ }++ruleDurationAndHalfMonth1 :: Rule+ruleDurationAndHalfMonth1 = Rule+ { name = "month and an half month"+ , pattern =+ [ regex "თვენახევა?(რის)?(რი)?(რში)?"+ ]+ , prod = const $ Just . Token Duration . duration TG.Day $ 45+ }++ruleDurationAndHalfWeek :: Rule+ruleDurationAndHalfWeek = Rule+ { name = "<integer> and an half week"+ , pattern =+ [ Predicate isNatural+ , regex "თვენახევა?(რის)?(რი)?(რში)?"+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = v}:_) ->+ Just . Token Duration . duration TG.Day $ 3 + 7 * floor v+ _ -> Nothing+ }++ruleDurationAndHalfWeek1 :: Rule+ruleDurationAndHalfWeek1 = Rule+ { name = "week and an half week"+ , pattern =+ [ regex "კვირანახევა?(რის)?(რი)?(რში)?"+ ]+ , prod = const $ Just . Token Duration . duration TG.Day $ 10+ }++rules :: [Rule]+rules =+ [ ruleCompositeDuration+ , ruleCompositeDuration1+ , ruleDurationAndHalfYear+ , ruleDurationAndHalfYear1+ , ruleDurationAndHalfMonth+ , ruleDurationAndHalfMonth1+ , ruleDurationAndHalfWeek+ , ruleDurationAndHalfWeek1+ , ruleDurationYear+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -0,0 +1,67 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}++module Duckling.Duration.MN.Corpus+ ( corpus+ ) where++import Data.String+import Prelude++import Duckling.Duration.Types+import Duckling.Locale+import Duckling.Resolve+import Duckling.Testing.Types+import Duckling.TimeGrain.Types (Grain(..))++corpus :: Corpus+corpus = (testContext {locale = makeLocale MN Nothing}, testOptions, allExamples)++allExamples :: [Example]+allExamples = concat+ [ examples (DurationData 1 Second)+ [ "1 сек"+ , "1 секунд"+ , "секунд"+ , "1\""+ ]+ , examples (DurationData 15 Minute)+ [ "15 мин"+ , "15'"+ ]+ , examples (DurationData 30 Minute)+ [ "30 минут"+ ]+ , examples (DurationData 5400 Second)+ [ "5400 секунд"+ ]+ , examples (DurationData 8 Hour)+ [ "8 цаг"+ , "8 ц"+ ]+ , examples (DurationData 15 Day)+ [ "15 өдөр"+ ]+ , examples (DurationData 7 Week)+ [ "7 долоо хоног"+ ]+ , examples (DurationData 1 Month)+ [ "1 сар"+ , "сар"+ ]+ , examples (DurationData 6 Month)+ [ "6 сар"+ ]+ , examples (DurationData 2 Year)+ [ "2 жил"+ ]+ , examples (DurationData 12 Hour)+ [ "12 цаг"+ ]+ ]
@@ -0,0 +1,117 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE NoRebindableSyntax #-}+{-# LANGUAGE OverloadedStrings #-}++module Duckling.Duration.MN.Rules+ ( rules+ ) where++import Data.HashMap.Strict (HashMap)+import Data.String+import Data.Text (Text)+import Prelude+import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text++import Duckling.Dimensions.Types+import Duckling.Duration.Helpers+import Duckling.Numeral.Helpers (numberWith)+import Duckling.Numeral.Types (NumeralData(..), isInteger)+import Duckling.Duration.Types (DurationData (DurationData))+import Duckling.Regex.Types+import Duckling.Types+import Duckling.TimeGrain.Types+import qualified Duckling.Numeral.Types as TNumeral++grainsMap :: HashMap Text Grain+grainsMap = HashMap.fromList+ [ ("жил" , Year)+ , ("сар", Month)+ , ("өдөр" , Day)+ , ("цаг" , Hour)+ , ("минут", Minute)+ ]++-- TODO: Single-word composition (#110)+ruleHalves :: Rule+ruleHalves = Rule+ { name = "half of a grain"+ , pattern =+ [ regex "хагас\\s?(жил|сар|өдөр|цаг|минут)"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (x:_)):_) -> do+ grain <- HashMap.lookup (Text.toLower x) grainsMap+ Token Duration <$> nPlusOneHalf grain 0+ _ -> Nothing+ }++ruleNumeralQuotes :: Rule+ruleNumeralQuotes = Rule+ { name = "<integer> + '\""+ , pattern =+ [ Predicate isNatural+ , regex "(['\"])"+ ]+ , prod = \tokens -> case tokens of+ (Token Numeral NumeralData{TNumeral.value = v}:+ Token RegexMatch (GroupMatch (x:_)):+ _) -> case x of+ "'" -> Just . Token Duration . duration Minute $ floor v+ "\"" -> Just . Token Duration . duration Second $ floor v+ _ -> Nothing+ _ -> Nothing+ }++ruleDurationPrecision :: Rule+ruleDurationPrecision = Rule+ { name = "about|exactly <duration>"+ , pattern =+ [ regex "(ойролцоогоор|яг)"+ , dimension Duration+ ]+ , prod = \tokens -> case tokens of+ (_:token:_) -> Just token+ _ -> Nothing+ }++ruleGrainAsDuration :: Rule+ruleGrainAsDuration = Rule+ { name = "a <unit-of-duration>"+ , pattern =+ [ dimension TimeGrain+ ]+ , prod = \tokens -> case tokens of+ (Token TimeGrain grain:_) -> Just . Token Duration $ duration grain 1+ _ -> Nothing+ }++rulePositiveDuration :: Rule+rulePositiveDuration = Rule+ { name = "<positive-numeral> <time-grain>"+ , pattern =+ [ numberWith TNumeral.value $ and . sequence [not . isInteger, (>0)]+ , dimension TimeGrain+ ]+ , prod = \tokens -> case tokens of+ (Token Numeral NumeralData{TNumeral.value = v}:+ Token TimeGrain grain:+ _) -> Just . Token Duration . duration Second . floor $ inSeconds grain v+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ rulePositiveDuration+ , ruleDurationPrecision+ , ruleNumeralQuotes+ , ruleGrainAsDuration+ , ruleHalves+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -58,6 +57,21 @@ , examples (DurationData 45 Minute) [ "3 kwartier" ]+ , examples (DurationData 90 Minute)+ [ "anderhalf uur"+ ]+ , examples (DurationData 75 Minute)+ [ "een uur en een kwartier"+ , "een uur en 15 minuten"+ , "een uur, 15 minuten"+ , "een uur 15 minuten"+ ]+ , examples (DurationData 165 Minute)+ [ "twee uur en drie kwartier"+ , "twee uur, 3 kwartier"+ , "twee uur, 45 minuten"+ , "twee uur 45 minuten"+ ] , examples (DurationData 1 Hour) [ "een uur" , "één uur"@@ -66,6 +80,7 @@ ] , examples (DurationData 30 Day) [ "30 dagen"+ , "4 weken en 2 dagen" ] , examples (DurationData 7 Day) [ "7 dagen"
@@ -2,12 +2,12 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE LambdaCase #-} module Duckling.Duration.NL.Rules ( rules ) where@@ -19,10 +19,12 @@ import Duckling.Dimensions.Types import Duckling.Duration.Helpers+import Duckling.Duration.Types (DurationData(..)) import Duckling.Numeral.Helpers (parseInt, parseInteger) import Duckling.Numeral.Types (NumeralData(..)) import Duckling.Regex.Types import Duckling.Types+import qualified Duckling.Duration.Types as TDuration import qualified Duckling.Numeral.Types as TNumeral import qualified Duckling.TimeGrain.Types as TG @@ -103,6 +105,48 @@ _ -> Nothing } +ruleDurationOneAndHalfHour :: Rule+ruleDurationOneAndHalfHour = Rule+ { name = "1 and an half hour"+ , pattern = [ regex "anderhalf uur"]+ , prod = \_ -> Just . Token Duration $ duration TG.Minute 90+ }++-- | NOTE: Oxford comma is not supported.+ruleCompositeDurationCommasAnd :: Rule+ruleCompositeDurationCommasAnd = Rule+ { name = "composite <duration> (with ,/and)"+ , pattern =+ [ Predicate isNatural+ , dimension TimeGrain+ , regex ",|en|plus"+ , dimension Duration+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = v}:+ Token TimeGrain g:+ _:+ Token Duration dd@DurationData{TDuration.grain = dg}:+ _) | g > dg -> Just . Token Duration $ duration g (floor v) <> dd+ _ -> Nothing+ }++ruleCompositeDuration :: Rule+ruleCompositeDuration = Rule+ { name = "composite <duration>"+ , pattern =+ [ Predicate isNatural+ , dimension TimeGrain+ , dimension Duration+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = v}:+ Token TimeGrain g:+ Token Duration dd@DurationData{TDuration.grain = dg}:+ _) | g > dg -> Just . Token Duration $ duration g (floor v) <> dd+ _ -> Nothing+ }+ ruleDurationPrecision :: Rule ruleDurationPrecision = Rule { name = "about|exactly <duration>"@@ -119,10 +163,13 @@ rules = [ ruleDurationQuarterOfAnHour , ruleDurationKwartier+ , ruleCompositeDurationCommasAnd+ , ruleCompositeDuration , ruleDurationHalfAnHour , ruleDurationThreeQuartersOfAnHour , ruleDurationDotNumeralHours , ruleDurationAndHalfHour+ , ruleDurationOneAndHalfHour , ruleDurationPrecision , ruleNumeralQuotes ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -31,6 +30,7 @@ , "1 sekund" , "jeden sekundzie" , "pojedynczy sekundach"+ , "mniej więcej jedną sekundę" ] , examples (DurationData 30 Minute) [ "pol godziny"
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -96,7 +95,7 @@ ruleAboutDuration = Rule { name = "about <duration>" , pattern =- [ regex "(oko(l|ł)o|miej wi(ę|e)cej|jakie(s|ś))"+ [ regex "(oko(l|ł)o|mniej wi(ę|e)cej|jakie(s|ś))" , dimension Duration ] , prod = \tokens -> case tokens of
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -50,7 +49,7 @@ , prod = \tokens -> case tokens of (Token RegexMatch (GroupMatch (x:_)):_) -> do grain <- HashMap.lookup (Text.toLower x) grainsMap- Token Duration <$> timesOneAndAHalf grain 0+ Token Duration <$> nPlusOneHalf grain 0 _ -> Nothing }
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,11 +2,10 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.-+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} module Duckling.Duration.TR.Rules@@ -44,7 +43,7 @@ ruleDurationThreeQuartersOfAnHour :: Rule ruleDurationThreeQuartersOfAnHour = Rule { name = "three-quarters of an hour"- , pattern = [regex "(3/4\\s?sa(at)?|üçe \231eyrek sa(at)?)"]+ , pattern = [regex "(3/4\\s?sa(at)?|üç \231eyrek sa(at)?)"] , prod = \_ -> Just . Token Duration $ duration TG.Minute 45 } @@ -90,7 +89,7 @@ { name = "<integer> and an half hour" , pattern = [ Predicate isNatural- , regex "buçeuk sa(at)?"+ , regex "buçuk sa(at)?" ] , prod = \tokens -> case tokens of (Token Numeral NumeralData{TNumeral.value = v}:_) ->@@ -103,7 +102,7 @@ ruleDurationPrecision = Rule { name = "<duration> about|exactly" , pattern =- [ regex "(gibi|civar\305nda|yaklaş\305k|tam( olarak)?)"+ [ regex "(yaklaşık|tam(\\solarak)?)" , dimension Duration ] , prod = \tokens -> case tokens of@@ -111,6 +110,18 @@ _ -> Nothing } +ruleDurationPrecision2 :: Rule+ruleDurationPrecision2 = Rule+ { name = "<duration> about|exactly"+ , pattern =+ [ dimension Duration+ , regex "gibi|civarında"+ ]+ , prod = \case+ (token:_:_) -> Just token+ _ -> Nothing+ }+ rules :: [Rule] rules = [ ruleDurationQuarterOfAnHour@@ -120,5 +131,6 @@ , ruleDurationDotNumeralHours , ruleDurationAndHalfHour , ruleDurationPrecision+ , ruleDurationPrecision2 , ruleNumeralQuotes ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE DeriveAnyClass #-}
@@ -0,0 +1,78 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}++module Duckling.Duration.UK.Corpus+ ( corpus+ , negativeCorpus+ ) where++import Prelude+import Data.String++import Duckling.Duration.Types+import Duckling.Locale+import Duckling.Resolve+import Duckling.Testing.Types+import Duckling.TimeGrain.Types (Grain(..))++context :: Context+context = testContext {locale = makeLocale UK Nothing}++corpus :: Corpus+corpus = (context, testOptions, allExamples)++negativeCorpus :: NegativeCorpus+negativeCorpus = (context, testOptions, examples)+ where+ examples =+ [ "в дні"+ , "секретар"+ , "хвилини"+ ]++allExamples :: [Example]+allExamples = concat+ [ examples (DurationData 1 Second)+ [ "1 секунда"+ , "одна сек"+ ]+ , examples (DurationData 2 Minute)+ [ "2 хв"+ , "дві хвилини"+ ]+ , examples (DurationData 30 Day)+ [ "30 днів"+ ]+ , examples (DurationData 7 Week)+ [ "сім тижнів"+ ]+ , examples (DurationData 1 Month)+ [ "1 місяць"+ ]+ , examples (DurationData 2 Year)+ [ "2 роки"+ ]+ , examples (DurationData 30 Minute)+ [ "півгодини"+ , "1/2 години"+ ]+ , examples (DurationData 12 Hour)+ [ "пів дня"+ ]+ , examples (DurationData 90 Minute)+ [ "півтори години"+ ]+ , examples (DurationData 27 Month)+ [ "2 роки і 3 місяці"+ , "2 роки, 3 місяці"+ ]+ , examples (DurationData 31719604 Second)+ [ "1 рік, 2 дня, 3 години і 4 секунди"+ ]+ ]
@@ -0,0 +1,144 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE OverloadedStrings #-}++module Duckling.Duration.UK.Rules+ ( rules ) where++import Control.Monad (join)+import Data.Semigroup ((<>))+import Data.String+import Prelude+import qualified Data.Text as Text++import Duckling.Dimensions.Types+import Duckling.Duration.Helpers+import Duckling.Duration.Types (DurationData(..))+import Duckling.Numeral.Helpers (parseInt, parseInteger)+import Duckling.Numeral.Types (NumeralData(..))+import Duckling.Regex.Types+import Duckling.Types+import qualified Duckling.Duration.Types as TDuration+import qualified Duckling.Numeral.Types as TNumeral+import qualified Duckling.TimeGrain.Types as TG++ruleHalfAnHour :: Rule+ruleHalfAnHour = Rule+ { name = "half an hour"+ , pattern =+ [ regex "(1/2\\s?|пів\\s?)години?"+ ]+ , prod = \_ -> Just . Token Duration $ duration TG.Minute 30+ }++ruleNumeralnumberHours :: Rule+ruleNumeralnumberHours = Rule+ { name = "number.number hours"+ , pattern =+ [ regex "(\\d+)\\.(\\d+) години?"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (h:m:_)):_) -> do+ hh <- parseInteger h+ mnum <- parseInteger m+ let mden = 10 ^ Text.length m+ Just . Token Duration $ minutesFromHourMixedFraction hh mnum mden+ _ -> Nothing+ }++ruleIntegerAndAnHalfHours :: Rule+ruleIntegerAndAnHalfHours = Rule+ { name = "<integer> and an half hours"+ , pattern =+ [ Predicate isNatural+ , regex "з половиною години"+ ]+ , prod = \tokens -> case tokens of+ (Token Numeral NumeralData{TNumeral.value = v}:_) ->+ Just . Token Duration . duration TG.Minute $ 30 + 60 * floor v+ _ -> Nothing+ }++ruleAboutDuration :: Rule+ruleAboutDuration = Rule+ { name = "about <duration>"+ , pattern =+ [ regex "близько"+ , dimension Duration+ ]+ , prod = \tokens -> case tokens of+ (_:token:_) -> Just token+ _ -> Nothing+ }++ruleExactlyDuration :: Rule+ruleExactlyDuration = Rule+ { name = "exactly <duration>"+ , pattern =+ [ regex "рівно"+ , dimension Duration+ ]+ , prod = \tokens -> case tokens of+ (_:token:_) -> Just token+ _ -> Nothing+ }++ruleDurationHalfATimeGrain :: Rule+ruleDurationHalfATimeGrain = Rule+ { name = "half a <time-grain>"+ , pattern =+ [ regex "(1/2|пів)"+ , dimension TimeGrain+ ]+ , prod = \tokens -> case tokens of+ (_:Token TimeGrain grain:_) -> Token Duration <$> nPlusOneHalf grain 0+ _ -> Nothing+ }++ruleDurationOneGrainAndHalf :: Rule+ruleDurationOneGrainAndHalf = Rule+ { name = "one and a hald <unit-of-duration>"+ , pattern =+ [ regex "півтори"+ , dimension TimeGrain+ ]+ , prod = \tokens -> case tokens of+ (_:Token TimeGrain grain:_) -> Token Duration <$> nPlusOneHalf grain 1+ _ -> Nothing+ }++ruleCompositeDurationCommasAnd :: Rule+ruleCompositeDurationCommasAnd = Rule+ { name = "composite <duration> (with ,/and)"+ , pattern =+ [ Predicate isNatural+ , dimension TimeGrain+ , regex ",|і"+ , dimension Duration+ ]+ , prod = \tokens -> case tokens of+ (Token Numeral NumeralData{TNumeral.value = v}:+ Token TimeGrain g:+ _:+ Token Duration dd@DurationData{TDuration.grain = dg}:+ _) | g > dg -> Just . Token Duration $ duration g (floor v) <> dd+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleAboutDuration+ , ruleExactlyDuration+ , ruleHalfAnHour+ , ruleIntegerAndAnHalfHours+ , ruleNumeralnumberHours+ , ruleDurationHalfATimeGrain+ , ruleDurationOneGrainAndHalf+ , ruleCompositeDurationCommasAnd+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -48,4 +47,60 @@ [ "10 月" , "十 月" ]+ , examples (DurationData 30 Minute)+ [ "30分鐘"+ , "半個鐘"+ , "半小時"+ , "三十分鐘"+ , "卅分鐘"+ ]+ , examples (DurationData 12 Hour)+ [ "半日"+ , "半天"+ , "十二小時"+ , "十二個鐘"+ ]+ , examples (DurationData 90 Minute)+ [ "一個半小時"+ , "個半小時"+ , "個半鐘"+ , "一個半鐘"+ , "1.5小時"+ , "一個小時三十分鐘"+ , "一小時零三十分鐘"+ ]+ , examples (DurationData 130 Minute)+ [ "兩小時十分"+ , "一百三十分鐘"+ ]+ , examples (DurationData 3615 Second)+ [ "一小時零十五秒"+ , "一個鐘零十五秒"+ ]+ , examples (DurationData 45 Day)+ [ "一個半月"+ , "個半月"+ ]+ , examples (DurationData 27 Month)+ [ "兩年零三個月"+ , "廿七個月"+ ]+ , examples (DurationData 330 Second)+ [ "五個半分鐘"+ , "五點五分鐘"+ , "5.5分鐘"+ , "五分三十秒"+ , "五分半鐘"+ , "五分半"+ ]+ , examples (DurationData 90 Second)+ [ "一分半鐘"+ , "一分半"+ , "分半鐘"+ , "分半"+ ]+ , examples (DurationData 15 Minute)+ [ "3個字"+ , "三個字"+ ] ]
@@ -0,0 +1,301 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE NoRebindableSyntax #-}+{-# LANGUAGE OverloadedStrings #-}++module Duckling.Duration.ZH.Rules+ ( rules+ ) where++import Prelude+import qualified Data.Text as Text++import Duckling.Dimensions.Types+import Duckling.Duration.Helpers+import Duckling.Duration.Types (DurationData(..))+import Duckling.Numeral.Helpers (parseInteger, decimalsToDouble)+import Duckling.Numeral.Types (NumeralData(..))+import Duckling.Regex.Types+import Duckling.Types+import qualified Duckling.Duration.Types as TDuration+import qualified Duckling.Numeral.Types as TNumeral+import qualified Duckling.TimeGrain.Types as TG++ruleDurationNFiveMinutes :: Rule+ruleDurationNFiveMinutes = Rule+ { name = "number of five minutes"+ , pattern =+ [ Predicate isNatural+ , regex "個字"+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = v}:_) ->+ Just $ Token Duration $ duration TG.Minute $ floor v * 5+ _ -> Nothing+ }++ruleDurationHalfATimeGrain :: Rule+ruleDurationHalfATimeGrain = Rule+ { name = "half a <time-grain>"+ , pattern =+ [ regex "半"+ , dimension TimeGrain+ ]+ , prod = \case+ (_:Token TimeGrain grain:_) -> Token Duration <$> nPlusOneHalf grain 0+ _ -> Nothing+ }++ruleDurationOneGrainAndHalf :: Rule+ruleDurationOneGrainAndHalf = Rule+ { name = "a <unit-of-duration> and a half"+ , pattern =+ [ regex "一個半|個半"+ , dimension TimeGrain+ ]+ , prod = \case+ (_:Token TimeGrain grain:_) -> Token Duration <$> nPlusOneHalf grain 1+ _ -> Nothing+ }++ruleDurationOneGrainAndHalf2 :: Rule+ruleDurationOneGrainAndHalf2 = Rule+ { name = "a <unit-of-duration> and a half"+ , pattern =+ [ dimension TimeGrain+ , regex "半(鐘)?"+ ]+ , prod = \case+ (Token TimeGrain grain:_) -> Token Duration <$> nPlusOneHalf grain 1+ _ -> Nothing+ }++ruleDurationAndHalfGrain :: Rule+ruleDurationAndHalfGrain = Rule+ { name = "<integer> and a half <unit-of-duration>"+ , pattern =+ [ Predicate isNatural+ , dimension TimeGrain+ , regex "半(鐘)?"+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = v}:Token TimeGrain grain:_) -> do+ let vv = floor v+ Token Duration <$> nPlusOneHalf grain vv+ _ -> Nothing+ }++ruleDurationAndHalfGrain2 :: Rule+ruleDurationAndHalfGrain2 = Rule+ { name = "<integer> and a half <unit-of-duration>"+ , pattern =+ [ Predicate isNatural+ , regex "個半"+ , dimension TimeGrain+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = v}:_:Token TimeGrain grain:_) -> do+ let vv = floor v+ Token Duration <$> nPlusOneHalf grain vv+ _ -> Nothing+ }++ruleDurationDotNumeralHours :: Rule+ruleDurationDotNumeralHours = Rule+ { name = "number.number hours"+ , pattern =+ [ regex "(\\d+)\\.(\\d+)"+ , Predicate $ isGrain TG.Hour+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (h:m:_)):_) -> do+ hh <- parseInteger h+ mnum <- parseInteger m+ let mden = 10 ^ Text.length m+ Just $ Token Duration $ minutesFromHourMixedFraction hh mnum mden+ _ -> Nothing+ }++ruleDurationDotNumeralHours2 :: Rule+ruleDurationDotNumeralHours2 = Rule+ { name = "number.number hours"+ , pattern =+ [ Predicate isNatural+ , regex "點"+ , Predicate isNatural+ , Predicate $ isGrain TG.Hour+ ]+ , prod = \tokens -> case tokens of+ (Token Numeral NumeralData{TNumeral.value = m}:+ _:+ Token Numeral NumeralData{TNumeral.value = s}:+ _) -> Just+ $ Token Duration+ $ duration TG.Minute+ $ floor ((m + decimalsToDouble s) * 60)+ _ -> Nothing+ }++ruleDurationDotNumeralMinutes :: Rule+ruleDurationDotNumeralMinutes = Rule+ { name = "number.number minutes"+ , pattern =+ [ regex "(\\d+)\\.(\\d+)"+ , Predicate $ isGrain TG.Minute+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (m:s:_)):_) -> do+ mm <- parseInteger m+ ss <- parseInteger s+ let sden = 10 ^ Text.length s+ Just $ Token Duration $ secondsFromHourMixedFraction mm ss sden+ _ -> Nothing+ }++ruleDurationDotNumeralMinutes2 :: Rule+ruleDurationDotNumeralMinutes2 = Rule+ { name = "number.number minutes"+ , pattern =+ [ Predicate isNatural+ , regex "點"+ , Predicate isNatural+ , Predicate $ isGrain TG.Minute+ ]+ , prod = \tokens -> case tokens of+ (Token Numeral NumeralData{TNumeral.value = m}:+ _:+ Token Numeral NumeralData{TNumeral.value = s}:+ _) -> Just+ $ Token Duration+ $ duration TG.Second+ $ floor ((m + decimalsToDouble s) * 60)+ _ -> Nothing+ }++ruleDurationHoursAndMinutes :: Rule+ruleDurationHoursAndMinutes = Rule+ { name = "<integer> hours and <integer> minutes"+ , pattern =+ [ Predicate isNatural+ , Predicate $ isGrain TG.Hour+ , Predicate isNatural+ , Predicate $ isGrain TG.Minute+ ]+ , prod = \case+ (Token Numeral h:+ _:+ Token Numeral m:+ _) -> Just+ $ Token Duration+ $ duration TG.Minute+ $ floor (TNumeral.value m) + 60 * floor (TNumeral.value h)+ _ -> Nothing+ }++ruleDurationMinutesAndSeconds :: Rule+ruleDurationMinutesAndSeconds = Rule+ { name = "<integer> minutes and <integer> seconds"+ , pattern =+ [ Predicate isNatural+ , Predicate $ isGrain TG.Minute+ , Predicate isNatural+ , Predicate $ isGrain TG.Second+ ]+ , prod = \case+ (Token Numeral m:+ _:+ Token Numeral s:+ _) -> Just+ $ Token Duration+ $ duration TG.Second+ $ floor (TNumeral.value s) + 60 * floor (TNumeral.value m)+ _ -> Nothing+ }++ruleDurationHoursAndSeconds :: Rule+ruleDurationHoursAndSeconds = Rule+ { name = "<integer> hours and <integer> seconds"+ , pattern =+ [ Predicate isNatural+ , Predicate $ isGrain TG.Hour+ , Predicate isNatural+ , Predicate $ isGrain TG.Second+ ]+ , prod = \case+ (Token Numeral h:+ _:+ Token Numeral s:+ _) -> Just+ $ Token Duration+ $ duration TG.Second+ $ floor (TNumeral.value s) + 3600 * floor (TNumeral.value h)+ _ -> Nothing+ }++ruleDurationHoursAndMinutesAndSeconds :: Rule+ruleDurationHoursAndMinutesAndSeconds = Rule+ { name = "<integer> hours and <integer> minutes and <integer> seconds"+ , pattern =+ [ Predicate isNatural+ , Predicate $ isGrain TG.Hour+ , Predicate isNatural+ , Predicate $ isGrain TG.Minute+ , Predicate isNatural+ , Predicate $ isGrain TG.Second+ ]+ , prod = \case+ (Token Numeral h:+ _:+ Token Numeral m:+ _:+ Token Numeral s:+ _) -> Just+ $ Token Duration+ $ duration TG.Second+ $ floor (TNumeral.value s)+ + 60 * floor (TNumeral.value m)+ + 3600 * floor (TNumeral.value h)+ _ -> Nothing+ }++ruleCompositeDurationAnd :: Rule+ruleCompositeDurationAnd = Rule+ { name = "composite <duration> and <duration>"+ , pattern =+ [ dimension Duration+ , regex "零"+ , dimension Duration+ ]+ , prod = \case+ (Token Duration DurationData{TDuration.value = v, TDuration.grain = g}:+ _:+ Token Duration dd@DurationData{TDuration.grain = dg}:+ _) | g > dg -> Just $ Token Duration $ duration g v <> dd+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleDurationNFiveMinutes+ , ruleDurationHalfATimeGrain+ , ruleDurationOneGrainAndHalf+ , ruleDurationOneGrainAndHalf2+ , ruleDurationAndHalfGrain+ , ruleDurationAndHalfGrain2+ , ruleDurationDotNumeralHours+ , ruleDurationDotNumeralHours2+ , ruleDurationDotNumeralMinutes+ , ruleDurationDotNumeralMinutes2+ , ruleDurationHoursAndMinutes+ , ruleDurationMinutesAndSeconds+ , ruleDurationHoursAndSeconds+ , ruleDurationHoursAndMinutesAndSeconds+ , ruleCompositeDurationAnd+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -0,0 +1,64 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}++module Duckling.Email.DE.Corpus+ ( corpus+ , negativeCorpus+ ) where++import Data.String+import Prelude+import qualified Data.Text as Text++import Duckling.Email.Types+import Duckling.Locale+import Duckling.Resolve+import Duckling.Testing.Types++context :: Context+context = testContext {locale = makeLocale DE Nothing}++negativeCorpus :: NegativeCorpus+negativeCorpus = (context, testOptions, examples)+ where+ examples =+ [ "fitness at 6.40"+ , "class at 12.00"+ , "tonight at 9.15"+ , " dot 2@abci"+ , "x@ dot x"+ , "x@ x dot "+ , "abc@x dot "+ , Text.replicate 10000 "a at a"+ ]++corpus :: Corpus+corpus = (context, testOptions, allExamples)++allExamples :: [Example]+allExamples = concat+ [ examples (EmailData "alice@exAmple.io")+ [ "alice at exAmple.io"+ ]+ , examples (EmailData "yo+yo@blah.org")+ [ "yo+yo at blah.org"+ ]+ , examples (EmailData "1234+abc@x.net")+ [ "1234+abc at x.net"+ ]+ , examples (EmailData "jean-jacques@stuff.co.uk")+ [ "jean-jacques at stuff.co.uk"+ ]+ , examples (EmailData "asdf+ab.c@gmail.com")+ [ "asdf+ab punkt c at gmail punkt com"+ ]+ , examples (EmailData "asdf.k@fb.com")+ [ "asdf punkt k@fb punkt com"+ ]+ ]
@@ -0,0 +1,41 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE OverloadedStrings #-}++module Duckling.Email.DE.Rules+ ( rules ) where++import Data.String+import Prelude+import qualified Data.Text as Text++import Duckling.Dimensions.Types+import Duckling.Email.Types (EmailData (..))+import Duckling.Regex.Types+import Duckling.Types+import qualified Duckling.Email.Types as TEmail++ruleEmailSpelledOut :: Rule+ruleEmailSpelledOut = Rule+ { name = "email spelled out"+ , pattern =+ [ regex "([\\w_+-]+(?:(?: punkt |\\.)[\\w_+-]+){0,10})(?: at |@)([a-zA-Z]+(?:(?:\\.| punkt )[\\w_-]+){1,10})"+ ]+ , prod = \xs -> case xs of+ (Token RegexMatch (GroupMatch (m1:m2:_)):_) ->+ Just $ Token Email EmailData+ { TEmail.value = Text.concat [replaceDots m1, "@", replaceDots m2] }+ where replaceDots = Text.replace " punkt " "."+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleEmailSpelledOut+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -0,0 +1,39 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}++module Duckling.Email.IS.Corpus+ ( corpus+ ) where++import Data.String+import Prelude++import Duckling.Email.Types+import Duckling.Locale+import Duckling.Resolve+import Duckling.Testing.Types++corpus :: Corpus+corpus = (testContext {locale = makeLocale IS Nothing}, testOptions, allExamples)++allExamples :: [Example]+allExamples = concat+ [ examples (EmailData "alice@exAmple.io")+ [ "alice ingi exAmple.io"+ ]+ , examples (EmailData "yo+yo@blah.org")+ [ "yo+yo ingi blah.org"+ ]+ , examples (EmailData "1234+abc@x.net")+ [ "1234+abc ingi x.net"+ ]+ , examples (EmailData "jean-jacques@stuff.co.uk")+ [ "jean-jacques ingi stuff.co.uk"+ ]+ ]
@@ -0,0 +1,39 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE OverloadedStrings #-}++module Duckling.Email.IS.Rules+ ( rules ) where++import Data.String+import qualified Data.Text as Text+import Prelude++import Duckling.Dimensions.Types+import Duckling.Email.Types (EmailData (..))+import qualified Duckling.Email.Types as TEmail+import Duckling.Regex.Types+import Duckling.Types++ruleEmailSpelledOut :: Rule+ruleEmailSpelledOut = Rule+ { name = "email spelled out"+ , pattern =+ [ regex "([\\w\\._+-]+) ingi ([\\w_-]+(\\.[\\w_-]+)+)"+ ]+ , prod = \xs -> case xs of+ (Token RegexMatch (GroupMatch (m1:m2:_)):_) ->+ Just $ Token Email EmailData {TEmail.value = Text.concat [m1, "@", m2]}+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleEmailSpelledOut+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE DeriveAnyClass #-}@@ -32,4 +31,7 @@ resolve _ _ x = Just (x, False) instance ToJSON EmailData where- toJSON EmailData {value} = object [ "value" .= value ]+ toJSON EmailData {value} = object+ [ "value" .= value+ , "type" .= ("value" :: Text)+ ]
@@ -2,15 +2,12 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.-+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE NoRebindableSyntax #-} - module Duckling.Engine ( parseAndResolve , lookupRegexAnywhere@@ -92,8 +89,9 @@ -- on here (substring, rangeToText, translateRange) = Document.byteStringFromPos doc position- nodes = mapMaybe (f . Array.elems) $ Foldable.toList $- matchFun regex substring+ nodes = mapMaybe (f . Array.elems)+ $ Foldable.toList+ $ matchFun regex substring f :: [(Int, Int)] -> Maybe Node f [] = Nothing f ((0,0):_) = Nothing
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. module Duckling.Engine.Regex
@@ -2,40 +2,76 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE NoRebindableSyntax #-}- module Duckling.Locale ( Lang(..) , Locale(..)- , Region(AU,BE,BZ,CA,CN,GB,HK,IE,IN,JM,MO,NZ,PH,TT,TW,US,ZA)+ , Region+ ( AU+ , BE+ , BZ+ , CL+ , CN+ , CO+ , EG+ , GB+ , HK+ , IE+ , IN+ , JM+ , MO+ , MX+ , NZ+ , PE+ , PH+ , TT+ , TW+ , US+ , VE+ , ZA+ ) , allLocales , makeLocale ) where -import Data.Hashable import Data.HashMap.Strict (HashMap)+import qualified Data.HashMap.Strict as HashMap import Data.HashSet (HashSet)+import qualified Data.HashSet as HashSet+import Data.Hashable import GHC.Generics import Prelude import TextShow (TextShow)-import qualified Data.HashMap.Strict as HashMap-import qualified Data.HashSet as HashSet import qualified TextShow as TS -import Duckling.Region hiding (NL)-import qualified Duckling.Region as R (Region(NL))+import Duckling.Region hiding+ ( AR+ , CA+ , ES+ , NL+ )+import qualified Duckling.Region as R+ ( Region+ ( AR+ , CA+ , ES+ , NL+ )+ ) -- | ISO 639-1 Language. -- See https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes data Lang- = AR+ = AF+ | AR | BG+ | BN+ | CA | CS | DA | DE@@ -43,6 +79,8 @@ | EN | ES | ET+ | FA+ | FI | FR | GA | HE@@ -50,10 +88,16 @@ | HR | HU | ID+ | IS | IT | JA | KA+ | KN+ | KM | KO+ | LO+ | ML+ | MN | MY | NB | NE@@ -62,8 +106,12 @@ | PT | RO | RU+ | SK | SV+ | SW | TA+ | TE+ | TH | TR | UK | VI@@ -92,8 +140,11 @@ locales = HashMap.lookupDefault HashSet.empty lang allLocales allLocales :: HashMap Lang (HashSet Region)-allLocales = HashMap.fromList- [ (EN, HashSet.fromList [AU, BZ, CA, GB, IN, IE, JM, NZ, PH, ZA, TT, US])- , (NL, HashSet.fromList [BE, R.NL])- , (ZH, HashSet.fromList [CN, HK, MO, TW])- ]+allLocales =+ HashMap.fromList+ [ (AR, HashSet.fromList [EG])+ , (EN, HashSet.fromList [AU, BZ, R.CA, GB, IN, IE, JM, NZ, PH, ZA, TT, US])+ , (ES, HashSet.fromList [R.AR, CL, CO, R.ES, MX, PE, VE])+ , (NL, HashSet.fromList [BE, R.NL])+ , (ZH, HashSet.fromList [CN, HK, MO, TW])+ ]
@@ -0,0 +1,152 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}++module Duckling.Numeral.AF.Corpus+ ( corpus+ ) where++import Data.String+import Prelude++import Duckling.Locale+import Duckling.Numeral.Types+import Duckling.Resolve+import Duckling.Testing.Types++corpus :: Corpus+corpus =+ ( testContext {locale = makeLocale AF Nothing}+ , testOptions+ , allExamples+ )++allExamples :: [Example]+allExamples = concat+ [ examples (NumeralValue 0)+ [ "nul"+ , "geen"+ , "niks"+ ]+ , examples (NumeralValue 1)+ [ "een"+ ]+ , examples (NumeralValue 2)+ [ "twee"+ ]+ , examples (NumeralValue 3)+ [ "drie"+ ]+ , examples (NumeralValue 4)+ [ "vier"+ ]+ , examples (NumeralValue 5)+ [ "vyf"+ ]+ , examples (NumeralValue 6)+ [ "ses"+ ]+ , examples (NumeralValue 7)+ [ "sewe"+ ]+ , examples (NumeralValue 8)+ [ "agt"+ , "ag"+ ]+ , examples (NumeralValue 9)+ [ "nege"+ ]+ , examples (NumeralValue 10)+ [ "tien"+ ]+ , examples (NumeralValue 11)+ [ "elf"+ ]+ , examples (NumeralValue 12)+ [ "twaalf"+ , "dosyn"+ ]+ , examples (NumeralValue 14)+ [ "veertien"+ ]+ , examples (NumeralValue 15)+ [ "vyftien"+ ]+ , examples (NumeralValue 16)+ [ "sestien"+ ]+ , examples (NumeralValue 17)+ [ "sewentien"+ ]+ , examples (NumeralValue 19)+ [ "negentien"+ , "neentien"+ ]+ , examples (NumeralValue 20)+ [ "twintig"+ ]+ , examples (NumeralValue 22)+ [ "twee en twintig"+ ]+ , examples (NumeralValue 24)+ [ "vier en twintig"+ ]+ , examples (NumeralValue 26)+ [ "ses en twintig"+ ]+ , examples (NumeralValue 28)+ [ "agt en twintig"+ ]+ , examples (NumeralValue 33)+ [ "drie en dertig"+ ]+ , examples (NumeralValue 34)+ [ "vier en dertig"+ ]+ , examples (NumeralValue 50)+ [ "vyftig"+ ]+ , examples (NumeralValue 55)+ [ "vyf en vyftig"+ ]+ , examples (NumeralValue 1.1)+ [ "1,1"+ , "1,10"+ , "01,10"+ ]+ , examples (NumeralValue 0.77)+ [ "0,77"+ , ",77"+ ]+ , examples (NumeralValue 300)+ [ "3 honderd"+ , "drie honderd"+ ]+ , examples (NumeralValue 5000)+ [ "5 duisend"+ , "vyf duisend"+ ]+ , examples (NumeralValue 144)+ [ "een honderd vier en veertig"+ , "honderd vier en veertig"+ ]+ , examples (NumeralValue 122)+ [ "een honderd twee en twintig"+ , "honderd twee en twintig"+ ]+ , examples (NumeralValue 20000)+ [ "twintig duisend"+ ]+ , examples (NumeralValue 0.2)+ [ "0,2"+ , "1/5"+ , "2/10"+ , "3/15"+ , "20/100"+ ]+ ]
@@ -0,0 +1,210 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE NoRebindableSyntax #-}++module Duckling.Numeral.AF.Rules+ ( rules+ ) where++import Control.Applicative ((<|>))+import Data.HashMap.Strict (HashMap)+import Data.Maybe+import Data.String+import Data.Text (Text)+import Prelude+import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text++import Duckling.Dimensions.Types+import Duckling.Numeral.Helpers+import Duckling.Numeral.Types (NumeralData(..))+import Duckling.Regex.Types+import Duckling.Types+import qualified Duckling.Numeral.Types as TNumeral++zeroAndTenMap :: HashMap Text Integer+zeroAndTenMap = HashMap.fromList+ [ ( "nul" , 0 )+ , ( "geen", 0 )+ , ( "niks", 0 )+ , ( "zero", 0 )+ , ( "tien", 10 )+ ]++oneToNineMap :: HashMap Text Integer+oneToNineMap = HashMap.fromList+ [ ( "een" , 1 )+ , ( "twee", 2 )+ , ( "drie", 3 )+ , ( "vier", 4 )+ , ( "vyf" , 5 )+ , ( "ses" , 6 )+ , ( "sewe", 7 )+ , ( "agt" , 8 )+ , ( "ag" , 8 )+ , ( "nege", 9 )+ ]++ruleNumeral :: Rule+ruleNumeral = Rule+ { name = "number (0..10)"+ , pattern =+ [ regex . Text.unpack $+ Text.concat [ "(", Text.intercalate "|"+ ((HashMap.keys zeroAndTenMap) ++ (HashMap.keys oneToNineMap)), ")" ]+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ let x = Text.toLower match in+ (HashMap.lookup x oneToNineMap >>= integer) <|>+ (HashMap.lookup x zeroAndTenMap >>= integer)+ _ -> Nothing+ }++elevenToNineteenMap :: HashMap Text Integer+elevenToNineteenMap = HashMap.fromList+ [ ( "elf" , 11 )+ , ( "twaalf" , 12 )+ , ( "dertien" , 13 )+ , ( "veertien" , 14 )+ , ( "vyftien" , 15 )+ , ( "sestien" , 16 )+ , ( "sewentien", 17 )+ , ( "agtien" , 18 )+ , ( "negentien", 19 )+ , ( "neentien" , 19 )+ ]++ruleElevenToNineteen :: Rule+ruleElevenToNineteen = Rule+ { name = "number (11..19)"+ , pattern =+ [ regex "(elf|twaalf|dertien|veertien|vyftien|sestien|sewentien|agtien|neg?entien)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup (Text.toLower match) elevenToNineteenMap >>= integer+ _ -> Nothing+ }++tensMap :: HashMap Text Integer+tensMap = HashMap.fromList+ [ ( "twin" , 20 )+ , ( "der" , 30 )+ , ( "veer" , 40 )+ , ( "vyf" , 50 )+ , ( "ses" , 60 )+ , ( "sewen", 70 )+ , ( "tag" , 80 )+ , ( "negen", 90 )+ , ( "neen" , 90 )+ ]++ruleTens :: Rule+ruleTens = Rule+ { name = "integer (20,30..90)"+ , pattern =+ [ regex "(twin|der|veer|vyf|ses|sewen|tag|neg?en)tig"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup (Text.toLower match) tensMap >>= integer+ _ -> Nothing+ }++ruleCompositeTens :: Rule+ruleCompositeTens = Rule+ { name = "integer ([3-9][1-9])"+ , pattern =+ [ numberBetween 1 10+ , regex "en"+ , oneOf [20, 30..90]+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = units}:+ _:+ Token Numeral NumeralData{TNumeral.value = tens}:+ _) -> double $ tens + units+ _ -> Nothing+ }++ruleDecimals :: Rule+ruleDecimals = Rule+ { name = "decimal number"+ , pattern =+ [ regex "(\\d*\\,\\d+)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) -> parseDecimal False match+ _ -> Nothing+ }++rulePowersOfTen :: Rule+rulePowersOfTen = Rule+ { name = "powers of tens"+ , pattern =+ [ regex "(honderd|duisend)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) -> case Text.toLower match of+ "honderd" -> double 1e2 >>= withGrain 2 >>= withMultipliable+ "duisend" -> double 1e3 >>= withGrain 3 >>= withMultipliable+ _ -> Nothing+ _ -> Nothing+ }++ruleDozen :: Rule+ruleDozen = Rule+ { name = "a dozen of"+ , pattern =+ [ regex "dosyn"+ ]+ , prod = \_ -> integer 12 >>= withMultipliable >>= notOkForAnyTime+ }++ruleSum :: Rule+ruleSum = Rule+ { name = "intersect 2 numbers"+ , pattern =+ [ Predicate $ and . sequence [hasGrain, isPositive]+ , Predicate $ and . sequence [not . isMultipliable, isPositive]+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = val1, TNumeral.grain = Just g}:+ Token Numeral NumeralData{TNumeral.value = val2}:+ _) | (10 ** fromIntegral g) > val2 -> double $ val1 + val2+ _ -> Nothing+ }++ruleMultiply :: Rule+ruleMultiply = Rule+ { name = "compose by multiplication"+ , pattern =+ [ dimension Numeral+ , Predicate isMultipliable+ ]+ , prod = \case+ (token1:token2:_) -> multiply token1 token2+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleNumeral+ , ruleDozen+ , ruleDecimals+ , rulePowersOfTen+ , ruleElevenToNineteen+ , ruleTens+ , ruleCompositeTens+ , ruleSum+ , ruleMultiply+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -28,106 +27,155 @@ [ examples (NumeralValue 0) [ "0" , "صفر"+ , "٠"+ , "٠٫٠" ] , examples (NumeralValue 1) [ "1" , "واحد"+ , "١"+ , "١٫٠" ] , examples (NumeralValue 4) [ "4" , "أربعة" , "أربع" , "اربعه"+ , "٤"+ , "٤٫٠" ] , examples (NumeralValue 6) [ "6" , "ستة" , "ست" , "سته"+ , "٦"+ , "٦٫٠" ] , examples (NumeralValue 10) [ "10" , "عشرة" , "عشره"+ , "١٠"+ , "١٠٫٠" ] , examples (NumeralValue 11) [ "11" , "إحدى عشرة" , "إحدى عشر" , "احد عشر"+ , "١١"+ , "١١٫٠" ] , examples (NumeralValue 12) [ "12" , "إثنتى عشر" , "إثنى عشر"+ , "١٢"+ , "١٢٫٠" ] , examples (NumeralValue 14) [ "14" , "أربع عشر"+ , "١٤"+ , "١٤٫٠" ] , examples (NumeralValue 16) [ "16" , "ستة عشر"+ , "١٦"+ , "١٦٫٠" ] , examples (NumeralValue 17) [ "17" , "سبع عشر"+ , "١٧"+ , "١٧٫٠" ] , examples (NumeralValue 18) [ "18" , "ثمان عشرة"+ , "١٨"+ , "١٨٫٠" ] , examples (NumeralValue 20) [ "عشرون" , "عشرين"+ , "٢٠"+ , "٢٠٫٠" ] , examples (NumeralValue 21) [ "واحدة و عشرون" , "21"+ , "٢١"+ , "٢١٫٠" ] , examples (NumeralValue 24) [ "أربعة و عشرون" , "24"+ , "٢٤"+ , "٢٤٫٠" ] , examples (NumeralValue 26) [ "ستة و عشرون" , "26"+ , "٢٦"+ , "٢٦٫٠" ] , examples (NumeralValue 20) [ "عشرون" , "عشرين"+ , "٢٠" ] , examples (NumeralValue 30) [ "ثلاثون" , "ثلاثين"+ , "٣٠"+ , "٣٠٫٠" ] , examples (NumeralValue 33) [ "33" , "ثلاث و ثلاثون"+ , "٣٣"+ , "٣٣٫٠" ] , examples (NumeralValue 40) [ "اربعون" , "أربعين"+ , "٤٠"+ , "٤٠٫٠" ] , examples (NumeralValue 200) [ "مائتين" , "مائتان"+ , "٢٠٠"+ , "٢٠٠٫٠" ] , examples (NumeralValue 300) [ "ثلاثمائة"+ , "٣٠٠"+ , "٣٠٠٫٠" ] , examples (NumeralValue 350) [ "ثلاثمائة وخمسين"+ , "٣٥٠"+ , "٣٥٠٫٠" ] , examples (NumeralValue 500) [ "خمسمائة"+ , "٥٠٠"+ , "٥٠٠٫٠" ] , examples (NumeralValue 525) [ "خمسمائة و خمسة و عشرون" , "525"+ , "٥٢٥"+ , "٥٢٥٫٠" ] , examples (NumeralValue 700) [ "سبعمائة"+ , "٧٠٠"+ , "٧٠٠٫٠" ] , examples (NumeralValue 1.1) [ "1.1"@@ -135,40 +183,78 @@ , "01.10" , "1 فاصلة 1" , "واحد فاصلة واحد"+ , "١١/١٠"+ , "١٫١"+ , "١٫١٠" ] , examples (NumeralValue 0.77) [ "0.77" , ".77"+ , "٧٧/١٠٠"+ , "٫٧٧"+ , "٠٫٧٧"+ , "٠٫٧٧٠" ] , examples (NumeralValue 2000) [ "2000" , "الفان"+ , "٢٠٠٠" , "الفين" ] , examples (NumeralValue 100000) [ "100000" , "100 الف"+ , "١٠٠٠٠٠"+ , "١٠٠٠٠٠٫٠٠"+ , "١٠٠٬٠٠٠"+ , "١٠٠٬٠٠٠٫٠" ] , examples (NumeralValue 10000) [ "10000" , "10 آلاف"+ , "١٠٠٠٠"+ , "١٠٠٠٠٫٠٠"+ , "١٠٬٠٠٠"+ , "١٠٬٠٠٠٫٠٠" ] , examples (NumeralValue 1000000) [ "1000000" , "مليون"+ , "١٠٠٠٠٠٠"+ , "١٠٠٠٠٠٠٫٠٠"+ , "١٬٠٠٠٬٠٠٠"+ , "١٬٠٠٠٬٠٠٠٫٠٠" ] , examples (NumeralValue 2000000) [ "2000000" , "2 مليون" , "مليونان" , "مليونين"+ , "٢٠٠٠٠٠٠"+ , "٢٠٠٠٠٠٠٫٠٠"+ , "٢٬٠٠٠٬٠٠٠"+ , "٢٬٠٠٠٬٠٠٠٫٠٠" ] , examples (NumeralValue 3000000) [ "3 ملايين" , "3000000" , "3 مليون"+ , "٣٠٠٠٠٠٠"+ , "٣٠٠٠٠٠٠٫٠٠"+ , "٣٬٠٠٠٬٠٠٠"+ , "٣٬٠٠٠٬٠٠٠٫٠٠" ] , examples (NumeralValue (-1200000)) [ "-1200000"+ , "-١٢٠٠٠٠٠"+ , "-١٢٠٠٠٠٠٫٠٠"+ , "-١٬٢٠٠٬٠٠٠"+ , "-١٬٢٠٠٬٠٠٠٫٠٠"+ ]+ , examples (NumeralValue (-1.2))+ [ "-١٢/١٠"+ , "-1.2"+ , "-١٫٢"+ , "-١٫٢٠" ] ]
@@ -0,0 +1,257 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}++module Duckling.Numeral.AR.EG.Corpus (allExamples) where++import Data.String+import Prelude++import Duckling.Numeral.Types+import Duckling.Testing.Types++allExamples :: [Example]+allExamples = concat+ [ examples (NumeralValue 0)+ [ "0"+ , "صفر"+ , "٠"+ , "٠٫٠"+ ]+ , examples (NumeralValue 1)+ [ "1"+ , "واحد"+ , "١"+ , "١٫٠"+ ]+ , examples (NumeralValue 4)+ [ "4"+ , "أربع"+ , "اربعه"+ , "٤"+ , "٤٫٠"+ ]+ , examples (NumeralValue 6)+ [ "6"+ , "ستة"+ , "ست"+ , "سته"+ , "٦"+ , "٦٫٠"+ ]+ , examples (NumeralValue 10)+ [ "10"+ , "عشرة"+ , "عشره"+ , "١٠"+ , "١٠٫٠"+ ]+ , examples (NumeralValue 11)+ [ "11"+ , "حداشر"+ , "١١"+ , "١١٫٠"+ ]+ , examples (NumeralValue 12)+ [ "12"+ , "إتناشر"+ , "١٢"+ , "١٢٫٠"+ ]+ , examples (NumeralValue 14)+ [ "14"+ , "اربعتاشر"+ , "١٤"+ , "١٤٫٠"+ ]+ , examples (NumeralValue 16)+ [ "16"+ , "ستاشر"+ , "١٦"+ , "١٦٫٠"+ ]+ , examples (NumeralValue 17)+ [ "17"+ , "سبعتاشر"+ , "١٧"+ , "١٧٫٠"+ ]+ , examples (NumeralValue 18)+ [ "18"+ , "تمنتاشر"+ , "١٨"+ , "١٨٫٠"+ ]+ , examples (NumeralValue 20)+ [ "عشرين"+ , "٢٠"+ , "٢٠٫٠"+ ]+ , examples (NumeralValue 21)+ [ "واحد و عشرين"+ , "21"+ , "٢١"+ , "٢١٫٠"+ ]+ , examples (NumeralValue 24)+ [ "أربعة و عشرين"+ , "24"+ , "٢٤"+ , "٢٤٫٠"+ ]+ , examples (NumeralValue 26)+ [ "ستة و عشرين"+ , "26"+ , "٢٦"+ , "٢٦٫٠"+ ]+ , examples (NumeralValue 20)+ [ "عشرين"+ , "٢٠"+ ]+ , examples (NumeralValue 30)+ [ "ثلاثين"+ , "٣٠"+ , "٣٠٫٠"+ ]+ , examples (NumeralValue 33)+ [ "33"+ , "تلاتة و تلاتين"+ , "٣٣"+ , "٣٣٫٠"+ ]+ , examples (NumeralValue 40)+ [ "أربعين"+ , "٤٠"+ , "٤٠٫٠"+ ]+ , examples (NumeralValue 200)+ [ "متين"+ , "٢٠٠"+ , "٢٠٠٫٠"+ ]+ , examples (NumeralValue 210)+ [ "متين وعشرة"+ , "٢١٠"+ , "٢١٠٫٠"+ ]+ , examples (NumeralValue 221)+ [ "متين واحد وعشرين"+ , "٢٢١"+ , "٢٢١٫٠"+ ]+ , examples (NumeralValue 263)+ [ "متين تلاتة وستين"+ , "٢٦٣"+ , "٢٦٣٫٠"+ ]+ , examples (NumeralValue 300)+ [ "تلتمية"+ , "٣٠٠"+ , "٣٠٠٫٠"+ ]+ , examples (NumeralValue 350)+ [ "تلتمية وخمسين"+ , "٣٥٠"+ , "٣٥٠٫٠"+ ]+ , examples (NumeralValue 500)+ [ "خمسمية"+ , "٥٠٠"+ , "٥٠٠٫٠"+ ]+ , examples (NumeralValue 525)+ [ "خمسمية خمسة و عشرين"+ , "525"+ , "٥٢٥"+ , "٥٢٥٫٠"+ ]+ , examples (NumeralValue 700)+ [ "سبعمية"+ , "٧٠٠"+ , "٧٠٠٫٠"+ ]+ , examples (NumeralValue 1.1)+ [ "1.1"+ , "1.10"+ , "01.10"+ , "1 فاصلة 1"+ , "واحد فاصلة واحد"+ , "١١/١٠"+ , "١٫١"+ , "١٫١٠"+ ]+ , examples (NumeralValue 0.77)+ [ "0.77"+ , ".77"+ , "٧٧/١٠٠"+ , "٫٧٧"+ , "٠٫٧٧"+ , "٠٫٧٧٠"+ ]+ , examples (NumeralValue 2000)+ [ "2000"+ , "٢٠٠٠"+ , "الفين"+ ]+ , examples (NumeralValue 100000)+ [ "100000"+ , "100 الف"+ , "١٠٠٠٠٠"+ , "١٠٠٠٠٠٫٠٠"+ , "١٠٠٬٠٠٠"+ , "١٠٠٬٠٠٠٫٠"+ ]+ , examples (NumeralValue 10000)+ [ "10000"+ , "10 آلاف"+ , "١٠٠٠٠"+ , "١٠٠٠٠٫٠٠"+ , "١٠٬٠٠٠"+ , "١٠٬٠٠٠٫٠٠"+ ]+ , examples (NumeralValue 1000000)+ [ "1000000"+ , "مليون"+ , "١٠٠٠٠٠٠"+ , "١٠٠٠٠٠٠٫٠٠"+ , "١٬٠٠٠٬٠٠٠"+ , "١٬٠٠٠٬٠٠٠٫٠٠"+ ]+ , examples (NumeralValue 2000000)+ [ "2000000"+ , "2 مليون"+ , "اتنين مليون"+ , "٢٠٠٠٠٠٠"+ , "٢٠٠٠٠٠٠٫٠٠"+ , "٢٬٠٠٠٬٠٠٠"+ , "٢٬٠٠٠٬٠٠٠٫٠٠"+ ]+ , examples (NumeralValue 3000000)+ [ "3 ملايين"+ , "3000000"+ , "3 مليون"+ , "٣٠٠٠٠٠٠"+ , "٣٠٠٠٠٠٠٫٠٠"+ , "٣٬٠٠٠٬٠٠٠"+ , "٣٬٠٠٠٬٠٠٠٫٠٠"+ ]+ , examples (NumeralValue (-1200000))+ [ "-1200000"+ , "-١٢٠٠٠٠٠"+ , "-١٢٠٠٠٠٠٫٠٠"+ , "-١٬٢٠٠٬٠٠٠"+ , "-١٬٢٠٠٬٠٠٠٫٠٠"+ ]+ , examples (NumeralValue (-1.2))+ [ "-١٢/١٠"+ , "-1.2"+ , "-١٫٢"+ , "-١٫٢٠"+ ]+ ]
@@ -0,0 +1,80 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE OverloadedStrings #-}+module Duckling.Numeral.AR.EG.Helpers+ ( digitsMap+ , numeralToStringMap+ , parseArabicDoubleAsText+ , parseArabicDoubleFromText+ , parseArabicIntAsText+ , parseArabicIntegerFromText+ ) where++import Control.Monad (join)+import Data.HashMap.Strict (HashMap)+import Data.Maybe (mapMaybe)+import Data.String+import Data.Text (Text)+import Duckling.Numeral.Helpers+ ( parseDouble+ , parseInteger+ )+import Prelude++import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text++numeralToStringMap :: HashMap Char String+numeralToStringMap =+ HashMap.fromList+ [ ('٠', "0")+ , ('١', "1")+ , ('٢', "2")+ , ('٣', "3")+ , ('٤', "4")+ , ('٥', "5")+ , ('٦', "6")+ , ('٧', "7")+ , ('٨', "8")+ , ('٩', "9")+ ]++digitsMap :: HashMap Text Integer+digitsMap =+ HashMap.fromList+ [ ("اتنين", 2)+ , ("تلات", 3)+ , ("اربع", 4)+ , ("أربع", 4)+ , ("خمس", 5)+ , ("ست", 6)+ , ("سبع", 7)+ , ("تمان", 8)+ , ("تسع", 9)+ ]++parseArabicIntAsText :: Text -> Text+parseArabicIntAsText =+ Text.pack+ . join+ . mapMaybe (`HashMap.lookup` numeralToStringMap)+ . Text.unpack++parseArabicIntegerFromText :: Text -> Maybe Integer+parseArabicIntegerFromText = parseInteger . parseArabicIntAsText++parseArabicDoubleAsText :: Text -> Text+parseArabicDoubleAsText =+ Text.pack+ . join+ . mapMaybe (`HashMap.lookup` HashMap.insert '٫' "." numeralToStringMap)+ . Text.unpack++parseArabicDoubleFromText :: Text -> Maybe Double+parseArabicDoubleFromText = parseDouble . parseArabicDoubleAsText
@@ -0,0 +1,343 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE NoRebindableSyntax #-}++module Duckling.Numeral.AR.EG.Rules (rules) where++import Data.Maybe+import Prelude+import qualified Data.HashMap.Strict as HashMap++import Duckling.Dimensions.Types+import Duckling.Numeral.AR.EG.Helpers+ ( digitsMap+ , parseArabicDoubleFromText+ , parseArabicIntegerFromText+ )+import Duckling.Numeral.Helpers+import Duckling.Numeral.Types (NumeralData (..))+import Duckling.Regex.Types+import Duckling.Types+import qualified Duckling.Numeral.Types as TNumeral++ruleInteger2 :: Rule+ruleInteger2 = Rule+ { name = "integer 2"+ , pattern =+ [ regex "[إأا]?تني[ي]?ن"+ ]+ , prod = \_ -> integer 2+ }++ruleInteger3 :: Rule+ruleInteger3 = Rule+ { name = "integer 3"+ , pattern =+ [ regex "تلات[هة]?"+ ]+ , prod = \_ -> integer 3+ }++ruleInteger8 :: Rule+ruleInteger8 = Rule+ { name = "integer 8"+ , pattern =+ [ regex "تمان(ي[هة])?"+ ]+ , prod = \_ -> integer 8+ }++ruleInteger11 :: Rule+ruleInteger11 = Rule+ { name = "integer 11"+ , pattern =+ [ regex "(إأا)?حداشر"+ ]+ , prod = \_ -> integer 11+ }++ruleInteger12 :: Rule+ruleInteger12 = Rule+ { name = "integer 12"+ , pattern =+ [ regex "[إأا]?[تط]ناشر"+ ]+ , prod = \_ -> integer 12+ }++ruleInteger13 :: Rule+ruleInteger13 = Rule+ { name = "integer 13"+ , pattern =+ [ regex "[تط]ل(ا)?[تط]اشر"+ ]+ , prod = \_ -> integer 13+ }++ruleInteger14 :: Rule+ruleInteger14 = Rule+ { name = "integer 14"+ , pattern =+ [ regex "[إأا]ربع[تط]اشر"+ ]+ , prod = \_ -> integer 14+ }++ruleInteger15 :: Rule+ruleInteger15 = Rule+ { name = "integer 15"+ , pattern =+ [ regex "خمس[تط]اشر"+ ]+ , prod = \_ -> integer 15+ }++ruleInteger16 :: Rule+ruleInteger16 = Rule+ { name = "integer 16"+ , pattern =+ [ regex "س[تط]اشر"+ ]+ , prod = \_ -> integer 16+ }++ruleInteger17 :: Rule+ruleInteger17 = Rule+ { name = "integer 17"+ , pattern =+ [ regex "سبع[تط]اشر"+ ]+ , prod = \_ -> integer 17+ }++ruleInteger18 :: Rule+ruleInteger18 = Rule+ { name = "integer 18"+ , pattern =+ [ regex "[تط]من[تط]اشر"+ ]+ , prod = \_ -> integer 18+ }++ruleInteger19 :: Rule+ruleInteger19 = Rule+ { name = "integer 19"+ , pattern =+ [ regex "تسع[تط]اشر"+ ]+ , prod = \_ -> integer 19+ }++ruleInteger30_80 :: Rule+ruleInteger30_80 = Rule+ { name = "integer (30, 80)"+ , pattern =+ [ regex "([تط]لا[تط]|[تط]مان)(ين)"+ ]+ , prod = \tokens -> case tokens of+ Token RegexMatch (GroupMatch (match:_)):_ ->+ (* 10) <$> HashMap.lookup match digitsMap >>= integer+ _ -> Nothing+ }++ruleInteger100 :: Rule+ruleInteger100 = Rule+ { name = "integer (100)"+ , pattern =+ [ regex "مي[هةت]"+ ]+ , prod = const $ integer 100+ }++ruleInteger200 :: Rule+ruleInteger200 = Rule+ { name = "integer (200)"+ , pattern =+ [ regex "م(ي)?تين"+ ]+ , prod = const $ integer 200+ }++ruleInteger300 :: Rule+ruleInteger300 = Rule+ { name = "integer (300)"+ , pattern =+ [ regex "([تط]و?لا?[تط]و?)مي[هةت]"+ ]+ , prod = const $ integer 300+ }++ruleInteger400 :: Rule+ruleInteger400 = Rule+ { name = "integer (400)"+ , pattern =+ [ regex "(رو?بعو?)مي[هةت]"+ ]+ , prod = const $ integer 400+ }++ruleInteger500 :: Rule+ruleInteger500 = Rule+ { name = "integer (500)"+ , pattern =+ [ regex "(خو?مسو?)مي[هةت]"+ ]+ , prod = const $ integer 500+ }++ruleInteger600 :: Rule+ruleInteger600 = Rule+ { name = "integer (600)"+ , pattern =+ [ regex "(سو?تو?)مي[هةت]"+ ]+ , prod = const $ integer 600+ }++ruleInteger700 :: Rule+ruleInteger700 = Rule+ { name = "integer (700)"+ , pattern =+ [ regex "(سو?بعو?)مي[هةت]"+ ]+ , prod = const $ integer 700+ }++ruleInteger800 :: Rule+ruleInteger800 = Rule+ { name = "integer (800)"+ , pattern =+ [ regex "([تط]و?منو?)مي[هةت]"+ ]+ , prod = const $ integer 800+ }++ruleInteger900 :: Rule+ruleInteger900 = Rule+ { name = "integer (900)"+ , pattern =+ [ regex "([تط]و?سعو?)مي[هةت]"+ ]+ , prod = const $ integer 900+ }++ruleInteger101_999 :: Rule+ruleInteger101_999 = Rule+ { name = "integer 101..999"+ , pattern =+ [ oneOf [100, 200 .. 900]+ , regex "\\s"+ , oneOf $ map (+) [10, 20 .. 90] <*> [1..9]+ ]+ , prod = \tokens -> case tokens of+ (Token Numeral NumeralData{TNumeral.value = v1}:+ _:+ Token Numeral NumeralData{TNumeral.value = v2}:+ _) -> double $ v1 + v2+ _ -> Nothing+ }+++ruleInteger3000 :: Rule+ruleInteger3000 = Rule+ { name = "integer (3000)"+ , pattern =+ [ regex "([تط]لا?[تط])( ?[اآ])?لاف"+ ]+ , prod = const $ integer 3000+ }++ruleInteger4000 :: Rule+ruleInteger4000 = Rule+ { name = "integer (4000)"+ , pattern =+ [ regex "[أا]ربع(ت| ?[اآ])لاف"+ ]+ , prod = const $ integer 4000+ }++ruleInteger5000 :: Rule+ruleInteger5000 = Rule+ { name = "integer (5000)"+ , pattern =+ [ regex "خمس(ت| ?[اآ])لاف"+ ]+ , prod = const $ integer 5000+ }++ruleInteger6000 :: Rule+ruleInteger6000 = Rule+ { name = "integer (6000)"+ , pattern =+ [ regex "س(ت| ?[اآ])لاف"+ ]+ , prod = const $ integer 6000+ }++ruleInteger7000 :: Rule+ruleInteger7000 = Rule+ { name = "integer (7000)"+ , pattern =+ [ regex "سبع(ت| ?[اآ])لاف"+ ]+ , prod = const $ integer 7000+ }++ruleInteger8000 :: Rule+ruleInteger8000 = Rule+ { name = "integer (8000)"+ , pattern =+ [ regex "[تط]م[ا]?ن(ت| ?[اآ])لاف"+ ]+ , prod = const $ integer 8000+ }++ruleInteger9000 :: Rule+ruleInteger9000 = Rule+ { name = "integer (9000)"+ , pattern =+ [ regex "([تط]سع)(ت| ?[اآ])لاف"+ ]+ , prod = const $ integer 9000+ }++rules :: [Rule]+rules =+ [ ruleInteger2+ , ruleInteger3+ , ruleInteger8+ , ruleInteger11+ , ruleInteger12+ , ruleInteger13+ , ruleInteger14+ , ruleInteger15+ , ruleInteger16+ , ruleInteger17+ , ruleInteger18+ , ruleInteger19+ , ruleInteger30_80+ , ruleInteger100+ , ruleInteger200+ , ruleInteger300+ , ruleInteger400+ , ruleInteger500+ , ruleInteger600+ , ruleInteger700+ , ruleInteger800+ , ruleInteger900+ , ruleInteger101_999+ , ruleInteger3000+ , ruleInteger4000+ , ruleInteger5000+ , ruleInteger6000+ , ruleInteger7000+ , ruleInteger8000+ , ruleInteger9000+ ]
@@ -0,0 +1,80 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE OverloadedStrings #-}+module Duckling.Numeral.AR.Helpers+ ( digitsMap+ , numeralToStringMap+ , parseArabicDoubleAsText+ , parseArabicDoubleFromText+ , parseArabicIntAsText+ , parseArabicIntegerFromText+ ) where++import Control.Monad (join)+import Data.HashMap.Strict (HashMap)+import Data.Maybe (mapMaybe)+import Data.String+import Data.Text (Text)+import Duckling.Numeral.Helpers+ ( parseDouble+ , parseInteger+ )+import Prelude++import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text++numeralToStringMap :: HashMap Char String+numeralToStringMap =+ HashMap.fromList+ [ ('٠', "0")+ , ('١', "1")+ , ('٢', "2")+ , ('٣', "3")+ , ('٤', "4")+ , ('٥', "5")+ , ('٦', "6")+ , ('٧', "7")+ , ('٨', "8")+ , ('٩', "9")+ ]++digitsMap :: HashMap Text Integer+digitsMap =+ HashMap.fromList+ [ ("عشر", 2)+ , ("ثلاث", 3)+ , ("اربع", 4)+ , ("أربع", 4)+ , ("خمس", 5)+ , ("ست", 6)+ , ("سبع", 7)+ , ("ثمان", 8)+ , ("تسع", 9)+ ]++parseArabicIntAsText :: Text -> Text+parseArabicIntAsText =+ Text.pack+ . join+ . mapMaybe (`HashMap.lookup` numeralToStringMap)+ . Text.unpack++parseArabicIntegerFromText :: Text -> Maybe Integer+parseArabicIntegerFromText = parseInteger . parseArabicIntAsText++parseArabicDoubleAsText :: Text -> Text+parseArabicDoubleAsText =+ Text.pack+ . join+ . mapMaybe (`HashMap.lookup` HashMap.insert '٫' "." numeralToStringMap)+ . Text.unpack++parseArabicDoubleFromText :: Text -> Maybe Double+parseArabicDoubleFromText = parseDouble . parseArabicDoubleAsText
@@ -2,26 +2,25 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-} {-# LANGUAGE OverloadedStrings #-}--module Duckling.Numeral.AR.Rules- ( rules- ) where+{-# LANGUAGE NoRebindableSyntax #-} -import Data.HashMap.Strict (HashMap)+module Duckling.Numeral.AR.Rules (rules) where import Data.Maybe-import Data.String-import Data.Text (Text) import Prelude import qualified Data.HashMap.Strict as HashMap import qualified Data.Text as Text import Duckling.Dimensions.Types+import Duckling.Numeral.AR.Helpers+ ( digitsMap+ , parseArabicDoubleFromText+ , parseArabicIntegerFromText+ ) import Duckling.Numeral.Helpers import Duckling.Numeral.Types (NumeralData (..)) import Duckling.Regex.Types@@ -62,19 +61,6 @@ , prod = \_ -> integer 12 } -digitsMap :: HashMap Text Integer-digitsMap = HashMap.fromList- [ ("عشر", 2)- , ("ثلاث", 3)- , ("اربع", 4)- , ("أربع", 4)- , ("خمس", 5)- , ("ست", 6)- , ("سبع", 7)- , ("ثمان", 8)- , ("تسع", 9)- ]- ruleInteger19 :: Rule ruleInteger19 = Rule { name = "integer (20..90)"@@ -342,9 +328,62 @@ _ -> Nothing } +ruleIntegerNumeric :: Rule+ruleIntegerNumeric = Rule+ { name = "Arabic integer numeric"+ , pattern =+ [ regex "([٠-٩]{1,18})"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ parseArabicIntegerFromText match >>= integer+ _ -> Nothing+ }++ruleFractionsNumeric :: Rule+ruleFractionsNumeric = Rule+ { name = "Arabic fractional number numeric"+ , pattern =+ [ regex "([٠-٩]+)/([٠-٩]+)"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (numerator:denominator:_)):_) -> do+ n <- parseArabicIntegerFromText numerator >>= integer+ d <- parseArabicIntegerFromText denominator >>= integer+ divide n d >>= notOkForAnyTime+ _ -> Nothing+ }++ruleArabicDecimal :: Rule+ruleArabicDecimal = Rule+ { name = "Arabic decimal number with Arabic decimal separator"+ , pattern =+ [ regex "([٠-٩]*٫[٠-٩]+)"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ parseArabicDoubleFromText match >>= double+ _ -> Nothing+ }++ruleArabicCommas :: Rule+ruleArabicCommas = Rule+ { name = "Arabic number with commas and optional Arabic decimal separator"+ , pattern =+ [ regex "([٠-٩]{1,3}(٬[٠-٩]{3}){1,5}(٫[٠-٩]+)?)"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ parseArabicDoubleFromText (Text.replace "٬" Text.empty match) >>=+ double+ _ -> Nothing+ }+ rules :: [Rule] rules =- [ ruleDecimalNumeral+ [ ruleIntegerNumeric+ , ruleFractionsNumeric+ , ruleDecimalNumeral , ruleDecimalWithThousandsSeparator , ruleInteger , ruleInteger11@@ -369,4 +408,6 @@ , ruleNumeralsPrefixWithMinus , rulePowersOfTen , ruleInteger200+ , ruleArabicDecimal+ , ruleArabicCommas ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -0,0 +1,101 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}++module Duckling.Numeral.BN.Corpus+ ( corpus+ ) where++import Data.String+import Prelude++import Duckling.Locale+import Duckling.Numeral.Types+import Duckling.Resolve+import Duckling.Testing.Types++corpus :: Corpus+corpus = (testContext {locale = makeLocale BN Nothing}, testOptions,+ allExamples)++allExamples :: [Example]+allExamples = concat+ [ examples (NumeralValue 0)+ [ "শূন্য"+ , "০"+ ]+ , examples (NumeralValue 1)+ [ "এক"+ ]+ , examples (NumeralValue 2)+ [ "দুই"+ ]+ , examples (NumeralValue 3)+ [ "তিন"+ ]+ , examples (NumeralValue 4)+ [ "চার"+ ]+ , examples (NumeralValue 5)+ [ "পাঁচ"+ ]+ , examples (NumeralValue 6)+ [ "ছয়"+ ]+ , examples (NumeralValue 7)+ [ "সাত"+ ]+ , examples (NumeralValue 8)+ [ "আট"+ ]+ , examples (NumeralValue 9)+ [ "নয়"+ ]+ , examples (NumeralValue 10)+ [ "দশ"+ ]+ , examples (NumeralValue 11)+ [ "এগারো"+ ]+ , examples (NumeralValue 15)+ [ "পনেরো"+ ]+ , examples (NumeralValue 17)+ [ "সতেরো"+ ]+ , examples (NumeralValue 20)+ [ "কুড়ি"+ ]+ , examples (NumeralValue 22)+ [ "বাইশ"+ ]+ , examples (NumeralValue 24)+ [ "চব্বিশ"+ ]+ , examples (NumeralValue 25)+ [ "পঁচিশ"+ ]+ , examples (NumeralValue 26)+ [ "ছাব্বিশ"+ ]+ , examples (NumeralValue 28)+ [ "আঠাশ"+ ]+ , examples (NumeralValue 30)+ [ "তিরিশ"+ ]+ , examples (NumeralValue 40)+ [ "চল্লিশ"+ ]+ , examples (NumeralValue 50)+ [ "পঞ্চাশ"+ ]+ , examples (NumeralValue 70)+ [ "সত্তর"+ ]+ ]
@@ -0,0 +1,169 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE NoRebindableSyntax #-}+{-# LANGUAGE LambdaCase #-}++module Duckling.Numeral.BN.Rules+ ( rules+ ) where++import Data.HashMap.Strict (HashMap)+import Data.Maybe+import Data.String+import Data.Text (Text)+import Prelude+import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text++import Duckling.Dimensions.Types+import Duckling.Numeral.Helpers+import Duckling.Numeral.Types (NumeralData (..))+import Duckling.Regex.Types+import Duckling.Types+import qualified Duckling.Numeral.Types as TNumeral++bengaliMap :: HashMap Char Char+bengaliMap = HashMap.fromList+ [ ( '০', '0' )+ , ( '১', '1' )+ , ( '২', '2' )+ , ( '৩', '3' )+ , ( '৪', '4' )+ , ( '৫', '5' )+ , ( '৬', '6' )+ , ( '৭', '7' )+ , ( '৮', '8' )+ , ( '৯', '9' )+ ]++bengaliToArab :: Char -> Char+bengaliToArab c = HashMap.lookupDefault c c bengaliMap++ruleBengali :: Rule+ruleBengali = Rule+ { name = "bengali forms"+ , pattern =+ [ regex "([০১২৩৪৫৬৭৮৯]{1,18})"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ toInteger <$> parseInt (Text.map bengaliToArab match) >>= integer+ _ -> Nothing+}++ruleNumeralMap :: HashMap Text Integer+ruleNumeralMap = HashMap.fromList+ [ ( "শূন্য", 0 )+ , ( "এক", 1 )+ , ( "দুই" , 2 )+ , ( "তিন", 3 )+ , ( "চার", 4 )+ , ( "পাঁচ", 5 )+ , ( "ছয়", 6 )+ , ( "সাত", 7 )+ , ( "আট", 8 )+ , ( "নয়" , 9 )+ , ( "দশ", 10 )+ ]++ruleNumeral :: Rule+ruleNumeral = Rule+ { name = "number (0..10)"+ , pattern =+ [ regex "(শূন্য|এক|দুই|তিন|চার|পাঁচ|ছয়|সাত|আট|নয়|দশ)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup match ruleNumeralMap >>= integer+ _ -> Nothing+}++elevenToNineteenMap :: HashMap Text Integer+elevenToNineteenMap = HashMap.fromList+ [ ( "এগারো", 11 )+ , ( "বারো", 12 )+ , ( "তেরো", 13 )+ , ( "চৌদ্দ", 14 )+ , ( "পনেরো", 15 )+ , ( "ষোল", 16 )+ , ( "সতেরো", 17 )+ , ( "আঠারো", 18 )+ , ( "উনিশ", 19 )+ ]++ruleElevenToNineteen :: Rule+ruleElevenToNineteen = Rule+ { name = "number (11..19)"+ , pattern =+ [ regex "(এগারো|বারো|তেরো|চৌদ্দ|পনেরো|ষোল|সতেরো|আঠারো|উনিশ)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup match elevenToNineteenMap >>= integer+ _ -> Nothing+}++twentyoneToTwentynineMap :: HashMap Text Integer+twentyoneToTwentynineMap = HashMap.fromList+ [ ( "একুশ", 21 )+ , ( "বাইশ", 22 )+ , ( "তেইশ", 23 )+ , ( "চব্বিশ", 24 )+ , ( "পঁচিশ", 25 )+ , ( "ছাব্বিশ", 26 )+ , ( "সাতাশ", 27 )+ , ( "আঠাশ", 28 )+ , ( "ঊনত্রিশ", 29 )+ ]++ruleTwentyoneToTwentynine :: Rule+ruleTwentyoneToTwentynine = Rule+ { name = "number (21..29)"+ , pattern =+ [ regex "(একুশ|বাইশ|তেইশ|চব্বিশ|পঁচিশ|ছাব্বিশ|সাতাশ|আঠাশ|ঊনত্রিশ)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup match twentyoneToTwentynineMap >>= integer+ _ -> Nothing+}++tensMap :: HashMap Text Integer+tensMap = HashMap.fromList+ [ ( "কুড়ি", 20 )+ , ( "তিরিশ", 30 )+ , ( "চল্লিশ", 40 )+ , ( "পঞ্চাশ", 50 )+ , ( "ষাট", 60 )+ , ( "সত্তর", 70 )+ , ( "আশি", 80 )+ , ( "নব্বই", 90 )+ ]++ruleTens :: Rule+ruleTens = Rule+ { name = "integer (20..90)"+ , pattern =+ [ regex "(কুড়ি|তিরিশ|চল্লিশ|পঞ্চাশ|ষাট|সত্তর|আশি|নব্বই)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup match tensMap >>= integer+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleBengali+ , ruleNumeral+ , ruleElevenToNineteen+ , ruleTwentyoneToTwentynine+ , ruleTens+ ]
@@ -0,0 +1,162 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}++module Duckling.Numeral.CA.Corpus (corpus) where++import Data.String+import Prelude++import Duckling.Locale+import Duckling.Numeral.Types+import Duckling.Resolve+import Duckling.Testing.Types++corpus :: Corpus+corpus =+ (testContext { locale = makeLocale CA Nothing }, testOptions, allExamples)++allExamples :: [Example]+allExamples =+ concat+ [ examples (NumeralValue 1)+ [ "1"+ , "u"+ , "un"+ , "una"+ ]+ , examples (NumeralValue 11)+ [ "onze"+ ]+ , examples (NumeralValue 12)+ [ "dotze"+ ]+ , examples (NumeralValue 13)+ [ "tretze"+ ]+ , examples (NumeralValue 14)+ [ "catorze"+ ]+ , examples (NumeralValue 15)+ [ "quinze"+ ]+ , examples (NumeralValue 16)+ [ "setze"+ ]+ , examples (NumeralValue 17)+ [ "disset"+ , "dèsset"+ ]+ , examples (NumeralValue 18)+ [ "divuit"+ , "dihuit"+ , "devuit"+ ]+ , examples (NumeralValue 19)+ [ "dinou"+ , "dènou"+ , "denou"+ ]+ , examples (NumeralValue 20)+ [ "vint"+ ]+ , examples (NumeralValue 21)+ [ "vint-i-un"+ , "vint i un"+ ]+ , examples (NumeralValue 22)+ [ "vint-i-dos"+ , "vint i dos"+ ]+ , examples (NumeralValue 23)+ [ "vint-i-tres"+ , "vint i tres"+ ]+ , examples (NumeralValue 37)+ [ "trenta-set"+ ]+ , examples (NumeralValue 40)+ [ "quaranta"+ ]+ , examples (NumeralValue 70)+ [ "setanta"+ ]+ , examples (NumeralValue 78)+ [ "Setanta-vuit"+ ]+ , examples (NumeralValue 80)+ [ "vuitanta"+ ]+ , examples (NumeralValue 33)+ [ "33"+ , "trenta-tres"+ , "trenta-3"+ ]+ , examples (NumeralValue 100000)+ [ "100000"+ , "100K"+ , "100k"+ ]+ , examples (NumeralValue 300)+ [ "tres-cents"+ ]+ , examples (NumeralValue 243)+ [ "243"+ ]+ , examples (NumeralValue 85)+ [ "vuitanta-cinc"+ ]+ , examples (NumeralValue 3000000)+ [ "3M"+ , "3000K"+ , "3000000"+ ]+ , examples (NumeralValue 1200000)+ [ "1200000"+ , "1200K"+ ]+ , examples (NumeralValue (-1200000))+ [ "-1200000"+ , "-1200K"+ ]+ , examples (NumeralValue 1.5)+ [ "1 coma cinc"+ , "una coma cinc"+ , "u coma cinc"+ ]+ , examples (NumeralValue 1)+ [ "zero u"+ , "zero un"+ ]+ , examples (NumeralValue 2)+ [ "zero dos"+ ]+ , examples (NumeralValue 3)+ [ "zero tres"+ ]+ , examples (NumeralValue 4)+ [ "zero quatre"+ ]+ , examples (NumeralValue 5)+ [ "zero cinc"+ ]+ , examples (NumeralValue 6)+ [ "zero sis"+ ]+ , examples (NumeralValue 7)+ [ "zero set"+ ]+ , examples (NumeralValue 8)+ [ "zero vuit"+ ]+ , examples (NumeralValue 9)+ [ "zero nou"+ ]+ ]++-- Ull, revisar la xifra amb decimals
@@ -0,0 +1,300 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}++module Duckling.Numeral.CA.Rules (rules) where++import Data.HashMap.Strict (HashMap)+import qualified Data.HashMap.Strict as HashMap+import Data.Maybe+import Data.String+import Data.Text (Text)+import qualified Data.Text as Text+import Prelude++import Duckling.Dimensions.Types+import Duckling.Numeral.Helpers+import Duckling.Numeral.Types (NumeralData(..))+import qualified Duckling.Numeral.Types as TNumeral+import Duckling.Regex.Types+import Duckling.Types++zeroToFifteenMap :: HashMap Text Integer+zeroToFifteenMap =+ HashMap.fromList+ [ ("zero", 0)+ , ("u", 1)+ , ("un", 1)+ , ("una", 1)+ , ("dos", 2)+ , ("dues", 2)+ , ("tres", 3)+ , ("quatre", 4)+ , ("cinc", 5)+ , ("sis", 6)+ , ("set", 7)+ , ("vuit", 8)+ , ("nou", 9)+ , ("deu", 10)+ , ("onze", 11)+ , ("dotze", 12)+ , ("tretze", 13)+ , ("catorze", 14)+ , ("quinze", 15)+ ]++ruleZeroToFifteen :: Rule+ruleZeroToFifteen = Rule+ { name = "number (0..15)"+ , pattern =+ [ regex+ "(zero|u(na|n)?|d(o|ue)s|tres|quatre|cinc|sis|set|vuit|nou|deu|onze|dotze|tretze|catorze|quinze)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup (Text.toLower match) zeroToFifteenMap >>= integer+ _ -> Nothing+ }++ruleNumeralsPrefixWithNegativeOrMinus :: Rule+ruleNumeralsPrefixWithNegativeOrMinus = Rule+ { name = "numbers prefix with -, negative or minus"+ , pattern = [regex "-|menys", Predicate isPositive]+ , prod = \case+ (_ : Token Numeral NumeralData { TNumeral.value = v } : _) ->+ double $ negate v+ _ -> Nothing+ }++tensMap :: HashMap Text Integer+tensMap =+ HashMap.fromList+ [ ("vint", 20)+ , ("trenta", 30)+ , ("quaranta", 40)+ , ("cinquanta", 50)+ , ("seixanta", 60)+ , ("setanta", 70)+ , ("vuitanta", 80)+ , ("noranta", 90)+ ]++ruleTens :: Rule+ruleTens = Rule+ { name = "number (20..90)"+ , pattern =+ [ regex+ "(vint|(tre|quara|cinqua|seixa|seta|vuita|nora)nta)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)) : _) ->+ HashMap.lookup (Text.toLower match) tensMap >>= integer+ _ -> Nothing+ }++sixteenToTwentyNineMap :: HashMap Text Integer+sixteenToTwentyNineMap =+ HashMap.fromList+ [ ("setze", 16)+ , ("disset", 17)+ , ("dèsset", 17)+ , ("devuit", 18)+ , ("divuit", 18)+ , ("dihuit", 18)+ , ("dinou", 19)+ , ("dènou", 19)+ , ("denou", 19)+ , ("vint-i-u", 21)+ , ("vint-i-una", 21)+ , ("vint-i-dos", 22)+ , ("vint-i-tres", 23)+ , ("vint-i-quatre", 24)+ , ("vint-i-cinc", 25)+ , ("vint-i-sis", 26)+ , ("vint-i-set", 27)+ , ("vint-i-vuit", 28)+ , ("vint-i-nou", 29)+ ]++ruleLowerTensWithOnes :: Rule+ruleLowerTensWithOnes = Rule+ { name = "number (16..19 21..29)"+ , pattern =+ [ regex+ "(setze|d(i|e|è)sset|d(e|i)(v|h)uit|d(i|e|è)nou|vint-i-u(na)?|vint-i-dos|vint-i-tres|vint-i-quatre|vint-i-cinc|vint-i-sis|vint-i-set|vint-i-vuit|vint-i-nou)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup (Text.toLower match) sixteenToTwentyNineMap >>= integer+ _ -> Nothing+ }++ruleHigherTensWithOnes :: Rule+ruleHigherTensWithOnes = Rule+ { name = "number (31..39 41..49 51..59 61..69 71..79 81..89 91..99)"+ , pattern =+ [oneOf [30, 40, 50, 60, 70, 80, 90], regex "-", numberBetween 1 9]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = v1}:+ _:+ Token Numeral NumeralData{TNumeral.value = v2}:+ _) -> double $ v1 + v2+ _ -> Nothing+ }++ruleNumeralsSuffixesKMG :: Rule+ruleNumeralsSuffixesKMG = Rule+ { name = "numbers suffixes (K, M, G)"+ , pattern = [dimension Numeral, regex "([kmg])(?=[\\W\\$€]|$)"]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = v}:+ Token RegexMatch (GroupMatch (match:_)):+ _) ->+ case Text.toLower match of+ "k" -> double $ v * 1e3+ "m" -> double $ v * 1e6+ "g" -> double $ v * 1e9+ _ -> Nothing+ _ -> Nothing+ }++oneHundredToThousandMap :: HashMap Text Integer+oneHundredToThousandMap =+ HashMap.fromList+ [ ("cent", 100)+ , ("cents", 100)+ , ("dos-cents", 200)+ , ("tres-cents", 300)+ , ("quatre-cents", 400)+ , ("cinc-cents", 500)+ , ("sis-cents", 600)+ , ("set-cents", 700)+ , ("vuit-cents", 800)+ , ("nou-cents", 900)+ , ("mil", 1000)+ ]++ruleTwenties :: Rule+ruleTwenties = Rule+ { name = "number (21..29)"+ , pattern =+ [oneOf [20], regex "(-i-| i )", numberBetween 1 10]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = v1}:+ _:+ Token Numeral NumeralData{TNumeral.value = v2}:+ _) -> double $ v1 + v2+ _ -> Nothing+ }++ruleHundreds :: Rule+ruleHundreds = Rule+ { name = "number 100..1000 "+ , pattern =+ [ regex+ "(cent(s)?|dos-cents|tres-cents|quatre-cents|cinc-cents|sis-cents|set-cents|vuit-cents|nou-cents|mil)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup (Text.toLower match) oneHundredToThousandMap >>= integer+ _ -> Nothing+ }++-- Afegeixo regex "-" perque les centenes s'escriuen dos-cent, tres-cent+ruleNumerals :: Rule+ruleNumerals = Rule+ { name = "numbers 200..999"+ , pattern =+ [ numberBetween 2 10+ , regex "-"+ , numberWith TNumeral.value (== 100)+ , numberBetween 0 100+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = v1}:+ _:+ Token Numeral NumeralData{TNumeral.value = v2}:+ _) -> double $ 100 * v1 + v2+ _ -> Nothing+ }++ruleNumeralDotNumeral :: Rule+ruleNumeralDotNumeral = Rule+ { name = "number dot number"+ , pattern = [dimension Numeral, regex "coma", Predicate $ not . hasGrain]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = v1}:+ _:+ Token Numeral NumeralData{TNumeral.value = v2}:+ _) -> double $ v1 + decimalsToDouble v2+ _ -> Nothing+ }++ruleBelowTenWithTwoDigits :: Rule+ruleBelowTenWithTwoDigits = Rule+ { name = "integer (0-9) with two digits"+ , pattern =+ [ regex "zero|0"+ , numberBetween 1 10+ ]+ , prod = \case+ (_:Token Numeral NumeralData{TNumeral.value = v}:_) -> double v+ _ -> Nothing+ }++ruleDecimalWithThousandsSeparator :: Rule+ruleDecimalWithThousandsSeparator = Rule+ { name = "decimal with thousands separator ."+ , pattern = [regex "(\\d+(\\.\\d\\d\\d)+,\\d+)"]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ let fmt = Text.replace "," "." . Text.replace "." Text.empty $ match+ in parseDouble fmt >>= double+ _ -> Nothing+ }++ruleDecimalNumeral :: Rule+ruleDecimalNumeral = Rule+ { name = "decimal number ,"+ , pattern = [regex "(\\d*,\\d+)"]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ parseDecimal False match+ _ -> Nothing+ }++ruleIntegerWithThousandsSeparator :: Rule+ruleIntegerWithThousandsSeparator = Rule+ { name = "integer with thousands separator ."+ , pattern = [regex "(\\d{1,3}(\\.\\d\\d\\d){1,5})"]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ parseDouble (Text.replace "." Text.empty match) >>= double+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleBelowTenWithTwoDigits+ , ruleZeroToFifteen+ , ruleTens+ , ruleTwenties+ , ruleLowerTensWithOnes+ , ruleHigherTensWithOnes+ , ruleHundreds++ , ruleNumeralDotNumeral+ , ruleNumerals+ , ruleNumeralsPrefixWithNegativeOrMinus+ , ruleNumeralsSuffixesKMG+ , ruleDecimalNumeral+ , ruleDecimalWithThousandsSeparator+ , ruleIntegerWithThousandsSeparator+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -142,14 +141,16 @@ rulePowersOfTen = Rule { name = "powers of tens" , pattern =- [ regex "(hundrede?|tusinde?|million(er)?)"+ [ regex "(hundrede?|tohundrede|tusinde?|totusinde|million(er)?)" ] , prod = \tokens -> case tokens of (Token RegexMatch (GroupMatch (match:_)):_) -> case Text.toLower match of "hundred" -> double 1e2 >>= withGrain 2 >>= withMultipliable "hundrede" -> double 1e2 >>= withGrain 2 >>= withMultipliable+ "tohundrede" -> double (2 * 1e2) >>= withGrain 2 >>= withMultipliable "tusind" -> double 1e3 >>= withGrain 3 >>= withMultipliable "tusinde" -> double 1e3 >>= withGrain 3 >>= withMultipliable+ "totusinde" -> double (2 * 1e3) >>= withGrain 3 >>= withMultipliable "million" -> double 1e6 >>= withGrain 6 >>= withMultipliable "millioner" -> double 1e6 >>= withGrain 6 >>= withMultipliable _ -> Nothing
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -58,6 +57,10 @@ , examples (NumeralValue 14) [ "14" , "vierzehn"+ ]+ , examples (NumeralValue 15)+ [ "15"+ , "fünfzehn" ] , examples (NumeralValue 16) [ "16"
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -90,7 +89,7 @@ ruleInteger3 = Rule { name = "integer ([2-9][1-9])" , pattern =- [ regex "(ein|zwei|drei|vier|fünf|sechs|sieben|acht|neun)und(zwanzig|dreissig|vierzig|fünfzig|sechzig|siebzig|achtzig|neunzig)"+ [ regex "(ein|zwei|drei|vier|fünf|sechs|sieben|acht|neun)und(zwanzig|dreissig|dreißig|vierzig|fünfzig|sechzig|siebzig|achtzig|neunzig)" ] , prod = \tokens -> case tokens of (Token RegexMatch (GroupMatch (m1:m2:_)):_) -> do@@ -108,6 +107,7 @@ v2 <- case Text.toLower m2 of "zwanzig" -> Just 20 "dreissig" -> Just 30+ "dreißig" -> Just 30 "vierzig" -> Just 40 "fünfzig" -> Just 50 "sechzig" -> Just 60@@ -255,7 +255,7 @@ ruleZeroToNineteen = Rule { name = "integer (0..19)" , pattern =- [ regex "(keine[rn]|keine?s?|null|nichts|eins?(er)?|zwei|dreizehn|drei|vierzehn|vier|fünf|sechzehn|sechs|siebzehn|sieben|achtzehn|acht|neunzehn|neun|elf|zwölf|füfzehn)"+ [ regex "(keine[rn]|keine?s?|null|nichts|eins?(er)?|zwei|dreizehn|drei|vierzehn|vier|fünfzehn|fünf|sechzehn|sechs|siebzehn|sieben|achtzehn|acht|neunzehn|neun|elf|zwölf)" ] , prod = \tokens -> case tokens of (Token RegexMatch (GroupMatch (match:_)):_) ->@@ -267,6 +267,7 @@ tensMap = HashMap.fromList [ ( "zwanzig" , 20 ) , ( "dreissig", 30 )+ , ( "dreißig" , 30 ) , ( "vierzig" , 40 ) , ( "fünfzig" , 50 ) , ( "sechzig" , 60 )@@ -280,7 +281,7 @@ ruleInteger2 = Rule { name = "integer (20..90)" , pattern =- [ regex "(zwanzig|dreissig|vierzig|fünfzig|sechzig|siebzig|achtzig|neunzig)"+ [ regex "(zwanzig|dreissig|dreißig|vierzig|fünfzig|sechzig|siebzig|achtzig|neunzig)" ] , prod = \tokens -> case tokens of (Token RegexMatch (GroupMatch (match:_)):_) ->
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -115,6 +114,9 @@ , "3000000" , "3,000,000" , "3 million"+ , "30 lakh"+ , "30 lkh"+ , "30 l" ] , examples (NumeralValue 1.2e6) [ "1,200,000"@@ -122,6 +124,8 @@ , "1.2M" , "1200k" , ".0012G"+ , "12 lakhs"+ , "12 lkhs" ] , examples (NumeralValue 5000) [ "5 thousand"@@ -140,6 +144,11 @@ , "-1200K" , "-.0012G" ]+ , examples (NumeralValue (-3200000))+ [ "-3,200,000"+ , "-3200000"+ , "minus three million two hundred thousand"+ ] , examples (NumeralValue 122) [ "one twenty two" , "ONE TwentY tWO"@@ -156,6 +165,8 @@ ] , examples (NumeralValue 31256721) [ "thirty-one million two hundred fifty-six thousand seven hundred twenty-one"+ , "three crore twelve lakh fifty-six thousand seven hundred twenty-one"+ , "three cr twelve lac fifty-six thousand seven hundred twenty-one" ] , examples (NumeralValue 2400) [ "two hundred dozens"@@ -167,5 +178,10 @@ , examples (NumeralValue 3000000000) [ "three billions" , "three thousand millions"+ , "three hundred crores"+ , "three hundred Cr"+ , "three hundred koti"+ , "three hundred krores"+ , "three hundred Kr" ] ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -17,7 +16,6 @@ import Control.Applicative ((<|>)) import Data.HashMap.Strict (HashMap) import Data.Maybe-import Data.String import Data.Text (Text) import Prelude import qualified Data.HashMap.Strict as HashMap@@ -127,19 +125,32 @@ _ -> Nothing } +powersOfTensMap :: HashMap Text Int+powersOfTensMap = HashMap.fromList+ [ ("hundred", 2)+ , ("thousand", 3)+ , ("lakh", 5)+ , ("lkh", 5)+ , ("l", 5)+ , ("lac", 5)+ , ("million", 6)+ , ("cr", 7)+ , ("crore", 7)+ , ("krore", 7)+ , ("kr", 7)+ , ("koti", 7)+ , ("billion", 9)+ , ("trillion", 12)+ ]+ rulePowersOfTen :: Rule rulePowersOfTen = Rule { name = "powers of tens"- , pattern =- [ regex "(hundred|thousand|million|billion)s?"- ]+ , pattern = [regex "(hundred|thousand|l(ac|(a?kh)?)|million|((k|c)r(ore)?|koti)|billion)s?"] , prod = \tokens -> case tokens of- (Token RegexMatch (GroupMatch (match:_)):_) -> case Text.toLower match of- "hundred" -> double 1e2 >>= withGrain 2 >>= withMultipliable- "thousand" -> double 1e3 >>= withGrain 3 >>= withMultipliable- "million" -> double 1e6 >>= withGrain 6 >>= withMultipliable- "billion" -> double 1e9 >>= withGrain 9 >>= withMultipliable- _ -> Nothing+ (Token RegexMatch (GroupMatch (match : _)) : _) -> do+ grain <- HashMap.lookup (Text.toLower match) powersOfTensMap+ double (10 ^ grain) >>= withGrain grain >>= withMultipliable _ -> Nothing } @@ -148,10 +159,12 @@ { name = "integer 21..99" , pattern = [ oneOf [20,30..90]+ , regex "[\\s\\-]+" , numberBetween 1 10 ] , prod = \tokens -> case tokens of (Token Numeral NumeralData{TNumeral.value = tens}:+ _: Token Numeral NumeralData{TNumeral.value = units}: _) -> double $ tens + units _ -> Nothing@@ -312,7 +325,7 @@ ruleMultiply = Rule { name = "compose by multiplication" , pattern =- [ dimension Numeral+ [ Predicate isPositive , Predicate isMultipliable ] , prod = \tokens -> case tokens of
@@ -0,0 +1,32 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}+module Duckling.Numeral.ES.AR.Corpus (allExamples) where++import Data.String+import Prelude++import Duckling.Numeral.Types+import Duckling.Testing.Types++allExamples :: [Example]+allExamples =+ concat+ [ examples (NumeralValue 1) ["1"]+ , examples (NumeralValue 33) ["33"]+ , examples (NumeralValue 1.1) ["1,1", "1,10", "01,10"]+ , examples (NumeralValue 0.77) ["0,77", ",77"]+ , examples (NumeralValue 100000) ["100.000", "100000"]+ , examples (NumeralValue 243) ["243"]+ , examples (NumeralValue 3000000) ["3000000", "3.000.000"]+ , examples (NumeralValue 1200000) ["1.200.000", "1200000"]+ , examples+ (NumeralValue (-1200000))+ ["- 1.200.000", "menos 1.200.000", "-1,2M", "-,0012G"]+ , examples (NumeralValue 1.5) ["1,5"]+ ]
@@ -0,0 +1,58 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE OverloadedStrings #-}+module Duckling.Numeral.ES.AR.Rules (rules) where++import Data.Maybe+import Data.String+import qualified Data.Text as Text+import Prelude++import Duckling.Dimensions.Types+import Duckling.Numeral.Helpers+import Duckling.Regex.Types+import Duckling.Types++ruleDecimalWithThousandsSeparator :: Rule+ruleDecimalWithThousandsSeparator = Rule+ { name = "decimal with thousands separator ."+ , pattern = [regex "(\\d+(\\.\\d\\d\\d)+,\\d+)"]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match : _)) : _) ->+ let fmt = Text.replace "," "." $ Text.replace "." Text.empty match+ in parseDouble fmt >>= double+ _ -> Nothing+ }++ruleDecimalNumeral :: Rule+ruleDecimalNumeral = Rule+ { name = "decimal number ,"+ , pattern = [regex "(\\d*,\\d+)"]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match : _)) : _) ->+ parseDecimal False match+ _ -> Nothing+ }++ruleIntegerWithThousandsSeparator :: Rule+ruleIntegerWithThousandsSeparator = Rule+ { name = "integer with thousands separator ."+ , pattern = [regex "(\\d{1,3}(\\.\\d\\d\\d){1,5})"]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match : _)) : _) ->+ parseDouble (Text.replace "." Text.empty match) >>= double+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleDecimalNumeral+ , ruleDecimalWithThousandsSeparator+ , ruleIntegerWithThousandsSeparator+ ]
@@ -0,0 +1,32 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}+module Duckling.Numeral.ES.CL.Corpus (allExamples) where++import Data.String+import Prelude++import Duckling.Numeral.Types+import Duckling.Testing.Types++allExamples :: [Example]+allExamples =+ concat+ [ examples (NumeralValue 1) ["1"]+ , examples (NumeralValue 33) ["33"]+ , examples (NumeralValue 1.1) ["1,1", "1,10", "01,10"]+ , examples (NumeralValue 0.77) ["0,77", ",77"]+ , examples (NumeralValue 100000) ["100.000", "100000"]+ , examples (NumeralValue 243) ["243"]+ , examples (NumeralValue 3000000) ["3000000", "3.000.000"]+ , examples (NumeralValue 1200000) ["1.200.000", "1200000"]+ , examples+ (NumeralValue (-1200000))+ ["- 1.200.000", "menos 1.200.000", "-1,2M", "-,0012G"]+ , examples (NumeralValue 1.5) ["1,5"]+ ]
@@ -0,0 +1,58 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE OverloadedStrings #-}+module Duckling.Numeral.ES.CL.Rules (rules) where++import Data.Maybe+import Data.String+import qualified Data.Text as Text+import Prelude++import Duckling.Dimensions.Types+import Duckling.Numeral.Helpers+import Duckling.Regex.Types+import Duckling.Types++ruleDecimalWithThousandsSeparator :: Rule+ruleDecimalWithThousandsSeparator = Rule+ { name = "decimal with thousands separator ."+ , pattern = [regex "(\\d+(\\.\\d\\d\\d)+,\\d+)"]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match : _)) : _) ->+ let fmt = Text.replace "," "." $ Text.replace "." Text.empty match+ in parseDouble fmt >>= double+ _ -> Nothing+ }++ruleDecimalNumeral :: Rule+ruleDecimalNumeral = Rule+ { name = "decimal number ,"+ , pattern = [regex "(\\d*,\\d+)"]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match : _)) : _) ->+ parseDecimal False match+ _ -> Nothing+ }++ruleIntegerWithThousandsSeparator :: Rule+ruleIntegerWithThousandsSeparator = Rule+ { name = "integer with thousands separator ."+ , pattern = [regex "(\\d{1,3}(\\.\\d\\d\\d){1,5})"]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match : _)) : _) ->+ parseDouble (Text.replace "." Text.empty match) >>= double+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleDecimalNumeral+ , ruleDecimalWithThousandsSeparator+ , ruleIntegerWithThousandsSeparator+ ]
@@ -0,0 +1,32 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}+module Duckling.Numeral.ES.CO.Corpus (allExamples) where++import Data.String+import Prelude++import Duckling.Numeral.Types+import Duckling.Testing.Types++allExamples :: [Example]+allExamples =+ concat+ [ examples (NumeralValue 1) ["1"]+ , examples (NumeralValue 33) ["33"]+ , examples (NumeralValue 1.1) ["1,1", "1,10", "01,10"]+ , examples (NumeralValue 0.77) ["0,77", ",77"]+ , examples (NumeralValue 100000) ["100.000", "100000"]+ , examples (NumeralValue 243) ["243"]+ , examples (NumeralValue 3000000) ["3000000", "3.000.000"]+ , examples (NumeralValue 1200000) ["1.200.000", "1200000"]+ , examples+ (NumeralValue (-1200000))+ ["- 1.200.000", "menos 1.200.000", "-1,2M", "-,0012G"]+ , examples (NumeralValue 1.5) ["1,5"]+ ]
@@ -0,0 +1,58 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE OverloadedStrings #-}+module Duckling.Numeral.ES.CO.Rules (rules) where++import Data.Maybe+import Data.String+import qualified Data.Text as Text+import Prelude++import Duckling.Dimensions.Types+import Duckling.Numeral.Helpers+import Duckling.Regex.Types+import Duckling.Types++ruleDecimalWithThousandsSeparator :: Rule+ruleDecimalWithThousandsSeparator = Rule+ { name = "decimal with thousands separator ."+ , pattern = [regex "(\\d+(\\.\\d\\d\\d)+,\\d+)"]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match : _)) : _) ->+ let fmt = Text.replace "," "." $ Text.replace "." Text.empty match+ in parseDouble fmt >>= double+ _ -> Nothing+ }++ruleDecimalNumeral :: Rule+ruleDecimalNumeral = Rule+ { name = "decimal number ,"+ , pattern = [regex "(\\d*,\\d+)"]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match : _)) : _) ->+ parseDecimal False match+ _ -> Nothing+ }++ruleIntegerWithThousandsSeparator :: Rule+ruleIntegerWithThousandsSeparator = Rule+ { name = "integer with thousands separator ."+ , pattern = [regex "(\\d{1,3}(\\.\\d\\d\\d){1,5})"]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match : _)) : _) ->+ parseDouble (Text.replace "." Text.empty match) >>= double+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleDecimalNumeral+ , ruleDecimalWithThousandsSeparator+ , ruleIntegerWithThousandsSeparator+ ]
@@ -2,17 +2,14 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}--module Duckling.Numeral.ES.Corpus- ( corpus ) where+module Duckling.Numeral.ES.Corpus (corpus) where -import Prelude import Data.String+import Prelude import Duckling.Locale import Duckling.Numeral.Types@@ -20,91 +17,50 @@ import Duckling.Testing.Types corpus :: Corpus-corpus = (testContext {locale = makeLocale ES Nothing}, testOptions, allExamples)+corpus =+ (testContext { locale = makeLocale ES Nothing }, testOptions, allExamples) allExamples :: [Example]-allExamples = concat- [ examples (NumeralValue 1)- [ "1"- , "uno"- , "una"- ]- , examples (NumeralValue 11)- [ "once"- ]- , examples (NumeralValue 16)- [ "dieciséis"- , "dieciseis"- , "Diesiseis"- , "diez y seis"- ]- , examples (NumeralValue 21)- [ "veintiuno"- , "veinte y uno"- ]- , examples (NumeralValue 23)- [ "veintitrés"- , "veinte y tres"- ]- , examples (NumeralValue 70)- [ "setenta"- ]- , examples (NumeralValue 78)- [ "Setenta y ocho"- ]- , examples (NumeralValue 80)- [ "ochenta"- ]- , examples (NumeralValue 33)- [ "33"- , "treinta y tres"- , "treinta y 3"- ]- , examples (NumeralValue 1.1)- [ "1,1"- , "1,10"- , "01,10"- ]- , examples (NumeralValue 0.77)- [ "0,77"- , ",77"- ]- , examples (NumeralValue 100000)- [ "100.000"- , "100000"- , "100K"- , "100k"- ]- , examples (NumeralValue 300)- [ "trescientos"- ]- , examples (NumeralValue 243)- [ "243"- ]- , examples (NumeralValue 3000000)- [ "3M"- , "3000K"- , "3000000"- , "3.000.000"- ]- , examples (NumeralValue 1200000)- [ "1.200.000"- , "1200000"- , "1,2M"- , "1200K"- , ",0012G"- ]- , examples (NumeralValue (-1200000))- [ "- 1.200.000"- , "-1200000"- , "menos 1.200.000"- , "-1,2M"- , "-1200K"- , "-,0012G"- ]- , examples (NumeralValue 1.5)- [ "1 punto cinco"- , "una punto cinco"- , "1,5"- ]- ]+allExamples =+ concat+ [ examples (NumeralValue 1) ["1", "uno", "una"]+ , examples (NumeralValue 11) ["once"]+ , examples+ (NumeralValue 16)+ ["dieciséis", "dieciseis", "Diesiseis", "diez y seis"]+ , examples (NumeralValue 21) ["veintiuno", "veinte y uno"]+ , examples (NumeralValue 22) ["veintidós"]+ , examples (NumeralValue 23) ["veintitrés", "veinte y tres"]+ , examples (NumeralValue 70) ["setenta"]+ , examples (NumeralValue 78) ["Setenta y ocho"]+ , examples (NumeralValue 80) ["ochenta"]+ , examples (NumeralValue 33) ["33", "treinta y tres", "treinta y 3"]+ , examples (NumeralValue 100000) ["100000", "100K", "100k"]+ , examples (NumeralValue 300) ["trescientos"]+ , examples (NumeralValue 243) ["243"]+ , examples (NumeralValue 3000000) ["3M", "3000K", "3000000"]+ , examples (NumeralValue 1200000) ["1200000", "1200K"]+ , examples (NumeralValue (-1200000)) ["-1200000", "-1200K"]+ , examples (NumeralValue 1.5) ["1 punto cinco", "una punto cinco"]+ , examples (NumeralValue 1) ["cero uno", "zero uno"]+ , examples (NumeralValue 2) ["cero dos", "zero dos"]+ , examples (NumeralValue 3)+ [+ "cero tres",+ "cero trés",+ "zero tres",+ "zero trés"+ ]+ , examples (NumeralValue 4) ["cero cuatro", "zero cuatro"]+ , examples (NumeralValue 5) ["cero cinco", "zero cinco"]+ , examples (NumeralValue 6)+ [+ "cero seis",+ "cero séis",+ "zero seis",+ "zero séis"+ ]+ , examples (NumeralValue 7) ["cero siete", "zero siete"]+ , examples (NumeralValue 8) ["cero ocho", "zero ocho"]+ , examples (NumeralValue 9) ["cero nueve", "zero nueve"]+ ]
@@ -0,0 +1,32 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}+module Duckling.Numeral.ES.ES.Corpus (allExamples) where++import Data.String+import Prelude++import Duckling.Numeral.Types+import Duckling.Testing.Types++allExamples :: [Example]+allExamples =+ concat+ [ examples (NumeralValue 1) ["1"]+ , examples (NumeralValue 33) ["33"]+ , examples (NumeralValue 1.1) ["1,1", "1,10", "01,10"]+ , examples (NumeralValue 0.77) ["0,77", ",77"]+ , examples (NumeralValue 100000) ["100.000", "100000"]+ , examples (NumeralValue 243) ["243"]+ , examples (NumeralValue 3000000) ["3000000", "3.000.000"]+ , examples (NumeralValue 1200000) ["1.200.000", "1200000"]+ , examples+ (NumeralValue (-1200000))+ ["- 1.200.000", "menos 1.200.000", "-1,2M", "-,0012G"]+ , examples (NumeralValue 1.5) ["1,5"]+ ]
@@ -0,0 +1,67 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE OverloadedStrings #-}+module Duckling.Numeral.ES.ES.Rules+ ( rules+ , rulesBackwardCompatible+ ) where++import qualified Data.HashMap.Strict as HashMap+import Data.Maybe+import Data.String+import qualified Data.Text as Text+import Prelude++import Duckling.Dimensions.Types+import Duckling.Numeral.Helpers+import Duckling.Numeral.Types (NumeralData(..))+import qualified Duckling.Numeral.Types as TNumeral+import Duckling.Regex.Types+import Duckling.Types++ruleDecimalWithThousandsSeparator :: Rule+ruleDecimalWithThousandsSeparator = Rule+ { name = "decimal with thousands separator ."+ , pattern = [regex "(\\d+(\\.\\d\\d\\d)+,\\d+)"]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match : _)) : _) ->+ let fmt = Text.replace "," "." $ Text.replace "." Text.empty match+ in parseDouble fmt >>= double+ _ -> Nothing+ }++ruleDecimalNumeral :: Rule+ruleDecimalNumeral = Rule+ { name = "decimal number ,"+ , pattern = [regex "(\\d*,\\d+)"]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match : _)) : _) ->+ parseDecimal False match+ _ -> Nothing+ }++ruleIntegerWithThousandsSeparator :: Rule+ruleIntegerWithThousandsSeparator = Rule+ { name = "integer with thousands separator ."+ , pattern = [regex "(\\d{1,3}(\\.\\d\\d\\d){1,5})"]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match : _)) : _) ->+ parseDouble (Text.replace "." Text.empty match) >>= double+ _ -> Nothing+ }++rulesBackwardCompatible :: [Rule]+rulesBackwardCompatible =+ [ ruleDecimalNumeral+ , ruleDecimalWithThousandsSeparator+ , ruleIntegerWithThousandsSeparator+ ]++rules :: [Rule]+rules = rulesBackwardCompatible
@@ -0,0 +1,32 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}+module Duckling.Numeral.ES.MX.Corpus (allExamples) where++import Data.String+import Prelude++import Duckling.Numeral.Types+import Duckling.Testing.Types++allExamples :: [Example]+allExamples =+ concat+ [ examples (NumeralValue 1) ["1"]+ , examples (NumeralValue 33) ["33"]+ , examples (NumeralValue 1.1) ["1.1", "1.10", "01.10"]+ , examples (NumeralValue 0.77) ["0.77", ".77"]+ , examples (NumeralValue 100000) ["100,000", "100000"]+ , examples (NumeralValue 243) ["243"]+ , examples (NumeralValue 3000000) ["3000000", "3,000,000"]+ , examples (NumeralValue 1200000) ["1,200,000", "1200000"]+ , examples+ (NumeralValue (-1200000))+ ["- 1,200,000", "menos 1,200,000", "-1.2M", "-.0012G"]+ , examples (NumeralValue 1.5) ["1.5"]+ ]
@@ -0,0 +1,58 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE OverloadedStrings #-}+module Duckling.Numeral.ES.MX.Rules (rules) where++import qualified Data.HashMap.Strict as HashMap+import Data.Maybe+import Data.String+import qualified Data.Text as Text+import Prelude++import Duckling.Dimensions.Types+import Duckling.Numeral.Helpers+import Duckling.Regex.Types+import Duckling.Types++ruleDecimalWithThousandsSeparator :: Rule+ruleDecimalWithThousandsSeparator = Rule+ { name = "decimal with thousands separator"+ , pattern = [regex "(\\d+(\\,\\d\\d\\d)+\\.\\d+)"]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match : _)) : _) ->+ parseDouble (Text.replace "," Text.empty match) >>= double+ _ -> Nothing+ }++ruleDecimalNumeral :: Rule+ruleDecimalNumeral = Rule+ { name = "decimal number ."+ , pattern = [regex "(\\d*\\.\\d+)"]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match : _)) : _) ->+ parseDecimal False match+ _ -> Nothing+ }++ruleIntegerWithThousandsSeparator :: Rule+ruleIntegerWithThousandsSeparator = Rule+ { name = "integer with thousands separator ,"+ , pattern = [regex "(\\d{1,3}(\\,\\d\\d\\d){1,5})"]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match : _)) : _) ->+ parseDouble (Text.replace "," Text.empty match) >>= double+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleDecimalNumeral+ , ruleDecimalWithThousandsSeparator+ , ruleIntegerWithThousandsSeparator+ ]
@@ -0,0 +1,32 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}+module Duckling.Numeral.ES.PE.Corpus (allExamples) where++import Data.String+import Prelude++import Duckling.Numeral.Types+import Duckling.Testing.Types++allExamples :: [Example]+allExamples =+ concat+ [ examples (NumeralValue 1) ["1"]+ , examples (NumeralValue 33) ["33"]+ , examples (NumeralValue 1.1) ["1,1", "1,10", "01,10"]+ , examples (NumeralValue 0.77) ["0,77", ",77"]+ , examples (NumeralValue 100000) ["100.000", "100000"]+ , examples (NumeralValue 243) ["243"]+ , examples (NumeralValue 3000000) ["3000000", "3.000.000"]+ , examples (NumeralValue 1200000) ["1.200.000", "1200000"]+ , examples+ (NumeralValue (-1200000))+ ["- 1.200.000", "menos 1.200.000", "-1,2M", "-,0012G"]+ , examples (NumeralValue 1.5) ["1,5"]+ ]
@@ -0,0 +1,58 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE OverloadedStrings #-}+module Duckling.Numeral.ES.PE.Rules (rules) where++import Data.Maybe+import Data.String+import qualified Data.Text as Text+import Prelude++import Duckling.Dimensions.Types+import Duckling.Numeral.Helpers+import Duckling.Regex.Types+import Duckling.Types++ruleDecimalWithThousandsSeparator :: Rule+ruleDecimalWithThousandsSeparator = Rule+ { name = "decimal with thousands separator ."+ , pattern = [regex "(\\d+(\\.\\d\\d\\d)+,\\d+)"]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match : _)) : _) ->+ let fmt = Text.replace "," "." $ Text.replace "." Text.empty match+ in parseDouble fmt >>= double+ _ -> Nothing+ }++ruleDecimalNumeral :: Rule+ruleDecimalNumeral = Rule+ { name = "decimal number ,"+ , pattern = [regex "(\\d*,\\d+)"]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match : _)) : _) ->+ parseDecimal False match+ _ -> Nothing+ }++ruleIntegerWithThousandsSeparator :: Rule+ruleIntegerWithThousandsSeparator = Rule+ { name = "integer with thousands separator ."+ , pattern = [regex "(\\d{1,3}(\\.\\d\\d\\d){1,5})"]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match : _)) : _) ->+ parseDouble (Text.replace "." Text.empty match) >>= double+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleDecimalNumeral+ , ruleDecimalWithThousandsSeparator+ , ruleIntegerWithThousandsSeparator+ ]
@@ -2,161 +2,138 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE LambdaCase #-} -module Duckling.Numeral.ES.Rules- ( rules- ) where+module Duckling.Numeral.ES.Rules (rules) where +import qualified Data.HashMap.Strict as HashMap import Data.Maybe import Data.String-import Prelude-import qualified Data.HashMap.Strict as HashMap import qualified Data.Text as Text+import Prelude import Duckling.Dimensions.Types import Duckling.Numeral.Helpers-import Duckling.Numeral.Types (NumeralData (..))+import Duckling.Numeral.Types (NumeralData(..))+import qualified Duckling.Numeral.Types as TNumeral import Duckling.Regex.Types import Duckling.Types-import qualified Duckling.Numeral.Types as TNumeral ruleNumeralsPrefixWithNegativeOrMinus :: Rule ruleNumeralsPrefixWithNegativeOrMinus = Rule { name = "numbers prefix with -, negative or minus"- , pattern =- [ regex "-|menos"- , Predicate isPositive- ]- , prod = \tokens -> case tokens of- (_:Token Numeral NumeralData{TNumeral.value = v}:_) ->- double $ v * (- 1)- _ -> Nothing- }--ruleDecimalWithThousandsSeparator :: Rule-ruleDecimalWithThousandsSeparator = Rule- { name = "decimal with thousands separator"- , pattern =- [ regex "(\\d+(\\.\\d\\d\\d)+,\\d+)"- ]- , prod = \tokens -> case tokens of- (Token RegexMatch (GroupMatch (match:_)):- _) -> let fmt = Text.replace "," "." $ Text.replace "." Text.empty match- in parseDouble fmt >>= double- _ -> Nothing- }--ruleDecimalNumeral :: Rule-ruleDecimalNumeral = Rule- { name = "decimal number"- , pattern =- [ regex "(\\d*,\\d+)"- ]+ , pattern = [regex "-|menos", Predicate isPositive] , prod = \tokens -> case tokens of- (Token RegexMatch (GroupMatch (match:_)):_) ->- parseDecimal False match+ (_ : Token Numeral NumeralData { TNumeral.value = v } : _) ->+ double $ v * (-1) _ -> Nothing } byTensMap :: HashMap.HashMap Text.Text Integer-byTensMap = HashMap.fromList- [ ( "veinte" , 20 )- , ( "treinta" , 30 )- , ( "cuarenta" , 40 )- , ( "cincuenta" , 50 )- , ( "sesenta" , 60 )- , ( "setenta" , 70 )- , ( "ochenta" , 80 )- , ( "noventa" , 90 )- ]+byTensMap =+ HashMap.fromList+ [ ("veinte", 20)+ , ("treinta", 30)+ , ("cuarenta", 40)+ , ("cincuenta", 50)+ , ("sesenta", 60)+ , ("setenta", 70)+ , ("ochenta", 80)+ , ("noventa", 90)+ ] ruleNumeral2 :: Rule ruleNumeral2 = Rule { name = "number (20..90)" , pattern =- [ regex "(veinte|treinta|cuarenta|cincuenta|sesenta|setenta|ochenta|noventa)"- ]+ [ regex+ "(veinte|treinta|cuarenta|cincuenta|sesenta|setenta|ochenta|noventa)"+ ] , prod = \tokens -> case tokens of- (Token RegexMatch (GroupMatch (match:_)):_) ->+ (Token RegexMatch (GroupMatch (match : _)) : _) -> HashMap.lookup (Text.toLower match) byTensMap >>= integer _ -> Nothing } zeroToFifteenMap :: HashMap.HashMap Text.Text Integer-zeroToFifteenMap = HashMap.fromList- [ ( "zero" , 0 )- , ( "cero" , 0 )- , ( "un" , 1 )- , ( "una" , 1 )- , ( "uno" , 1 )- , ( "dos" , 2 )- , ( "trés" , 3 )- , ( "tres" , 3 )- , ( "cuatro" , 4 )- , ( "cinco" , 5 )- , ( "seis" , 6 )- , ( "séis" , 6 )- , ( "siete" , 7 )- , ( "ocho" , 8 )- , ( "nueve" , 9 )- , ( "diez" , 10 )- , ( "dies" , 10 )- , ( "once" , 11 )- , ( "doce" , 12 )- , ( "trece" , 13 )- , ( "catorce" , 14 )- , ( "quince" , 15 )- ]+zeroToFifteenMap =+ HashMap.fromList+ [ ("zero", 0)+ , ("cero", 0)+ , ("un", 1)+ , ("una", 1)+ , ("uno", 1)+ , ("dos", 2)+ , ("trés", 3)+ , ("tres", 3)+ , ("cuatro", 4)+ , ("cinco", 5)+ , ("seis", 6)+ , ("séis", 6)+ , ("siete", 7)+ , ("ocho", 8)+ , ("nueve", 9)+ , ("diez", 10)+ , ("dies", 10)+ , ("once", 11)+ , ("doce", 12)+ , ("trece", 13)+ , ("catorce", 14)+ , ("quince", 15)+ ] ruleNumeral :: Rule ruleNumeral = Rule { name = "number (0..15)" , pattern =- [ regex "((c|z)ero|un(o|a)?|dos|tr(é|e)s|cuatro|cinco|s(e|é)is|siete|ocho|nueve|die(z|s)|once|doce|trece|catorce|quince)"- ]+ [ regex+ "((c|z)ero|un(o|a)?|dos|tr(é|e)s|cuatro|cinco|s(e|é)is|siete|ocho|nueve|die(z|s)|once|doce|trece|catorce|quince)"+ ] , prod = \tokens -> case tokens of- (Token RegexMatch (GroupMatch (match:_)):_) ->+ (Token RegexMatch (GroupMatch (match : _)) : _) -> HashMap.lookup (Text.toLower match) zeroToFifteenMap >>= integer _ -> Nothing } sixteenToTwentyNineMap :: HashMap.HashMap Text.Text Integer-sixteenToTwentyNineMap = HashMap.fromList- [ ( "dieciseis" , 16 )- , ( "diesiséis" , 16 )- , ( "diesiseis" , 16 )- , ( "dieciséis" , 16 )- , ( "diecisiete" , 17 )- , ( "dieciocho" , 18 )- , ( "diecinueve" , 19 )- , ( "veintiuno" , 21 )- , ( "veintiuna" , 21 )- , ( "veintidos" , 22 )- , ( "veintitrés" , 23 )- , ( "veintitres" , 23 )- , ( "veinticuatro" , 24 )- , ( "veinticinco" , 25 )- , ( "veintiséis" , 26 )- , ( "veintiseis" , 26 )- , ( "veintisiete" , 27 )- , ( "veintiocho" , 28 )- , ( "veintinueve" , 29 )- ]+sixteenToTwentyNineMap =+ HashMap.fromList+ [ ("dieciseis", 16)+ , ("diesiséis", 16)+ , ("diesiseis", 16)+ , ("dieciséis", 16)+ , ("diecisiete", 17)+ , ("dieciocho", 18)+ , ("diecinueve", 19)+ , ("veintiuno", 21)+ , ("veintiuna", 21)+ , ("veintidos", 22)+ , ("veintidós", 22)+ , ("veintitrés", 23)+ , ("veintitres", 23)+ , ("veinticuatro", 24)+ , ("veinticinco", 25)+ , ("veintiséis", 26)+ , ("veintiseis", 26)+ , ("veintisiete", 27)+ , ("veintiocho", 28)+ , ("veintinueve", 29)+ ] ruleNumeral5 :: Rule ruleNumeral5 = Rule { name = "number (16..19 21..29)" , pattern =- [ regex "(die(c|s)is(é|e)is|diecisiete|dieciocho|diecinueve|veintiun(o|a)|veintidos|veintitr(é|e)s|veinticuatro|veinticinco|veintis(é|e)is|veintisiete|veintiocho|veintinueve)"- ]+ [ regex+ "(die(c|s)is(é|e)is|diecisiete|dieciocho|diecinueve|veintiun(o|a)|veintid(o|ó)s|veintitr(é|e)s|veinticuatro|veinticinco|veintis(é|e)is|veintisiete|veintiocho|veintinueve|treinta)"+ ] , prod = \tokens -> case tokens of- (Token RegexMatch (GroupMatch (match:_)):_) ->+ (Token RegexMatch (GroupMatch (match : _)) : _) -> HashMap.lookup (Text.toLower match) sixteenToTwentyNineMap >>= integer _ -> Nothing }@@ -164,13 +141,9 @@ ruleNumeral3 :: Rule ruleNumeral3 = Rule { name = "number (16..19)"- , pattern =- [ numberWith TNumeral.value (== 10)- , regex "y"- , numberBetween 6 10- ]+ , pattern = [numberWith TNumeral.value (== 10), regex "y", numberBetween 6 10] , prod = \tokens -> case tokens of- (_:_:Token Numeral NumeralData{TNumeral.value = v}:_) ->+ (_ : _ : Token Numeral NumeralData { TNumeral.value = v } : _) -> double $ 10 + v _ -> Nothing }@@ -178,14 +151,10 @@ ruleNumeralsSuffixesKMG :: Rule ruleNumeralsSuffixesKMG = Rule { name = "numbers suffixes (K, M, G)"- , pattern =- [ dimension Numeral- , regex "([kmg])(?=[\\W\\$€]|$)"- ]+ , pattern = [dimension Numeral, regex "([kmg])(?=[\\W\\$€]|$)"] , prod = \tokens -> case tokens of- (Token Numeral NumeralData{TNumeral.value = v}:- Token RegexMatch (GroupMatch (match:_)):- _) -> case Text.toLower match of+ (Token Numeral NumeralData { TNumeral.value = v } : Token RegexMatch (GroupMatch (match : _)) : _) ->+ case Text.toLower match of "k" -> double $ v * 1e3 "m" -> double $ v * 1e6 "g" -> double $ v * 1e9@@ -194,30 +163,31 @@ } oneHundredToThousandMap :: HashMap.HashMap Text.Text Integer-oneHundredToThousandMap = HashMap.fromList- [ ( "cien" , 100 )- , ( "cientos" , 100 )- , ( "ciento" , 100 )- , ( "doscientos" , 200 )- , ( "trescientos" , 300 )- , ( "cuatrocientos" , 400 )- , ( "quinientos" , 500 )- , ( "seiscientos" , 600 )- , ( "setecientos" , 700 )- , ( "ochocientos" , 800 )- , ( "novecientos" , 900 )- , ( "mil" , 1000 )- ]-+oneHundredToThousandMap =+ HashMap.fromList+ [ ("cien", 100)+ , ("cientos", 100)+ , ("ciento", 100)+ , ("doscientos", 200)+ , ("trescientos", 300)+ , ("cuatrocientos", 400)+ , ("quinientos", 500)+ , ("seiscientos", 600)+ , ("setecientos", 700)+ , ("ochocientos", 800)+ , ("novecientos", 900)+ , ("mil", 1000)+ ] ruleNumeral6 :: Rule ruleNumeral6 = Rule { name = "number 100..1000 " , pattern =- [ regex "(cien(to)?s?|doscientos|trescientos|cuatrocientos|quinientos|seiscientos|setecientos|ochocientos|novecientos|mil)"- ]+ [ regex+ "(cien(to)?s?|doscientos|trescientos|cuatrocientos|quinientos|seiscientos|setecientos|ochocientos|novecientos|mil)"+ ] , prod = \tokens -> case tokens of- (Token RegexMatch (GroupMatch (match:_)):_) ->+ (Token RegexMatch (GroupMatch (match : _)) : _) -> HashMap.lookup (Text.toLower match) oneHundredToThousandMap >>= integer _ -> Nothing }@@ -226,15 +196,10 @@ ruleNumeral4 = Rule { name = "number (21..29 31..39 41..49 51..59 61..69 71..79 81..89 91..99)" , pattern =- [ oneOf [70, 20, 60, 50, 40, 90, 30, 80]- , regex "y"- , numberBetween 1 10- ]+ [oneOf [70, 20, 60, 50, 40, 90, 30, 80], regex "y", numberBetween 1 10] , prod = \tokens -> case tokens of- (Token Numeral NumeralData{TNumeral.value = v1}:- _:- Token Numeral NumeralData{TNumeral.value = v2}:- _) -> double $ v1 + v2+ (Token Numeral NumeralData { TNumeral.value = v1 } : _ : Token Numeral NumeralData { TNumeral.value = v2 } : _) ->+ double $ v1 + v2 _ -> Nothing } @@ -242,51 +207,47 @@ ruleNumerals = Rule { name = "numbers 200..999" , pattern =- [ numberBetween 2 10- , numberWith TNumeral.value (== 100)- , numberBetween 0 100- ]+ [ numberBetween 2 10+ , numberWith TNumeral.value (== 100)+ , numberBetween 0 100+ ] , prod = \tokens -> case tokens of- (Token Numeral NumeralData{TNumeral.value = v1}:- _:- Token Numeral NumeralData{TNumeral.value = v2}:- _) -> double $ 100 * v1 + v2+ (Token Numeral NumeralData { TNumeral.value = v1 } : _ : Token Numeral NumeralData { TNumeral.value = v2 } : _) ->+ double $ 100 * v1 + v2 _ -> Nothing } ruleNumeralDotNumeral :: Rule ruleNumeralDotNumeral = Rule { name = "number dot number"- , pattern =- [ dimension Numeral- , regex "punto"- , Predicate $ not . hasGrain- ]+ , pattern = [dimension Numeral, regex "punto", Predicate $ not . hasGrain] , prod = \tokens -> case tokens of- (Token Numeral NumeralData{TNumeral.value = v1}:- _:- Token Numeral NumeralData{TNumeral.value = v2}:- _) -> double $ v1 + decimalsToDouble v2+ (Token Numeral NumeralData { TNumeral.value = v1 } : _ : Token Numeral NumeralData { TNumeral.value = v2 } : _) ->+ double $ v1 + decimalsToDouble v2 _ -> Nothing } -ruleIntegerWithThousandsSeparator :: Rule-ruleIntegerWithThousandsSeparator = Rule- { name = "integer with thousands separator ."+ruleBelowTenWithTwoDigits :: Rule+ruleBelowTenWithTwoDigits = Rule+ {+ name = "integer (0-9) with two digits" , pattern =- [ regex "(\\d{1,3}(\\.\\d\\d\\d){1,5})"- ]- , prod = \tokens -> case tokens of- (Token RegexMatch (GroupMatch (match:_)):_) ->- parseDouble (Text.replace "." Text.empty match) >>= double+ [+ regex "((c|z)ero)|0"+ , numberBetween 1 10+ ]+ , prod = \case+ (+ _:+ Token Numeral NumeralData { TNumeral.value = v }:+ _+ ) -> double v _ -> Nothing } rules :: [Rule] rules =- [ ruleDecimalNumeral- , ruleDecimalWithThousandsSeparator- , ruleIntegerWithThousandsSeparator+ [ ruleBelowTenWithTwoDigits , ruleNumeral , ruleNumeral2 , ruleNumeral3
@@ -0,0 +1,32 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}+module Duckling.Numeral.ES.VE.Corpus (allExamples) where++import Data.String+import Prelude++import Duckling.Numeral.Types+import Duckling.Testing.Types++allExamples :: [Example]+allExamples =+ concat+ [ examples (NumeralValue 1) ["1"]+ , examples (NumeralValue 33) ["33"]+ , examples (NumeralValue 1.1) ["1,1", "1,10", "01,10"]+ , examples (NumeralValue 0.77) ["0,77", ",77"]+ , examples (NumeralValue 100000) ["100.000", "100000"]+ , examples (NumeralValue 243) ["243"]+ , examples (NumeralValue 3000000) ["3000000", "3.000.000"]+ , examples (NumeralValue 1200000) ["1.200.000", "1200000"]+ , examples+ (NumeralValue (-1200000))+ ["- 1.200.000", "menos 1.200.000", "-1,2M", "-,0012G"]+ , examples (NumeralValue 1.5) ["1,5"]+ ]
@@ -0,0 +1,58 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE OverloadedStrings #-}+module Duckling.Numeral.ES.VE.Rules (rules) where++import Data.Maybe+import Data.String+import qualified Data.Text as Text+import Prelude++import Duckling.Dimensions.Types+import Duckling.Numeral.Helpers+import Duckling.Regex.Types+import Duckling.Types++ruleDecimalWithThousandsSeparator :: Rule+ruleDecimalWithThousandsSeparator = Rule+ { name = "decimal with thousands separator ."+ , pattern = [regex "(\\d+(\\.\\d\\d\\d)+,\\d+)"]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match : _)) : _) ->+ let fmt = Text.replace "," "." $ Text.replace "." Text.empty match+ in parseDouble fmt >>= double+ _ -> Nothing+ }++ruleDecimalNumeral :: Rule+ruleDecimalNumeral = Rule+ { name = "decimal number ,"+ , pattern = [regex "(\\d*,\\d+)"]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match : _)) : _) ->+ parseDecimal False match+ _ -> Nothing+ }++ruleIntegerWithThousandsSeparator :: Rule+ruleIntegerWithThousandsSeparator = Rule+ { name = "integer with thousands separator ."+ , pattern = [regex "(\\d{1,3}(\\.\\d\\d\\d){1,5})"]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match : _)) : _) ->+ parseDouble (Text.replace "." Text.empty match) >>= double+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleDecimalNumeral+ , ruleDecimalWithThousandsSeparator+ , ruleIntegerWithThousandsSeparator+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -0,0 +1,102 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}++module Duckling.Numeral.FA.Corpus+ ( corpus+ ) where++import Data.String+import Prelude++import Duckling.Locale+import Duckling.Numeral.Types+import Duckling.Resolve+import Duckling.Testing.Types++corpus :: Corpus+corpus = (testContext {locale = makeLocale FA Nothing}, testOptions, allExamples)++allExamples :: [Example]+allExamples = concat+ [ examples (NumeralValue 0)+ [ "0"+ , "۰"+ , "صفر"+ ]+ , examples (NumeralValue 1)+ [ "1"+ , "۱"+ , "یک"+ ]+ , examples (NumeralValue 11)+ [ "یازده"+ ]+ , examples (NumeralValue 17)+ [ "هفده"+ ]+ , examples (NumeralValue 21)+ [ "بیست و یک"+ ]+ , examples (NumeralValue 23)+ [ "بیست و سه"+ ]+ , examples (NumeralValue 70)+ [ "هفتاد"+ ]+ , examples (NumeralValue 71)+ [ "هفتاد و یک"+ ]+ , examples (NumeralValue 78)+ [ "هفتاد و هشت"+ ]+ , examples (NumeralValue 73)+ [ "هفتاد و سه"+ ]+ , examples (NumeralValue 80)+ [ "هشتاد"+ ]+ , examples (NumeralValue 81)+ [ "هشتاد و یک"+ ]+ , examples (NumeralValue 82)+ [ "هشتاد و دو"+ ]+ , examples (NumeralValue 90)+ [ "نود"+ ]+ , examples (NumeralValue 91)+ [ "نود و یک"+ ]+ , examples (NumeralValue 92)+ [ "نود و دو"+ ]+ , examples (NumeralValue 99)+ [ "نود و نه"+ ]+ , examples (NumeralValue 33)+ [ "33"+ , "۳۳"+ , "سی و سه"+ ]+ , examples (NumeralValue 118)+ [ "صد و هجده"+ ]+ , examples (NumeralValue 4020)+ [ "چهار هزار و بیست"+ ]+ , examples (NumeralValue 100000)+ [ "صد هزار"+ , "100000"+ , "۱۰۰۰۰۰"+ ]+ , examples (NumeralValue 3000000)+ [ "سه میلیون"+ , "3000000"+ ]+ ]
@@ -0,0 +1,254 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree. An additional grant+-- of patent rights can be found in the PATENTS file in the same directory.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE NoRebindableSyntax #-}++module Duckling.Numeral.FA.Rules+ ( rules ) where++import Control.Monad (join)+import Data.HashMap.Strict (HashMap)+import Data.Maybe+import Data.String+import Data.Text (Text)+import Prelude+import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text++import Duckling.Dimensions.Types+import Duckling.Numeral.Helpers+import Duckling.Numeral.Types (NumeralData (..))+import Duckling.Regex.Types+import Duckling.Types+import qualified Duckling.Numeral.Types as TNumeral++zeroNineteenMap :: HashMap Text Integer+zeroNineteenMap = HashMap.fromList+ [ ("صفر", 0)+ , ("یک", 1)+ , ("دو", 2)+ , ("سه", 3)+ , ("چهار", 4)+ , ("پنج", 5)+ , ("شش", 6)+ , ("شیش", 6)+ , ("هفت", 7)+ , ("هشت", 8)+ , ("نه", 9)+ , ("ده", 10)+ , ("یازده", 11)+ , ("دوازده", 12)+ , ("سیزده", 13)+ , ("چهارده", 14)+ , ("پانزده", 15)+ , ("پونزده", 15)+ , ("شانزده", 16)+ , ("شونزده", 16)+ , ("هفده", 17)+ , ("هیفده", 17)+ , ("هجده", 18)+ , ("هیجده", 18)+ , ("نوزده", 19)+ ]++ruleToNineteen :: Rule+ruleToNineteen = Rule+ { name = "integer (0..19)"+ , pattern =+ [ regex "(صفر|یک|سه|چهارده|چهار|پنج|شی?ش|هفت|هشت|نه|یازده|دوازده|سیزده|پ(ا|و)نزده|ش(ا|و)نزده|هی?فده|هی?جده|نوزده|ده|دو)"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ let x = Text.toLower match in+ (HashMap.lookup x zeroNineteenMap >>= integer)+ _ -> Nothing+ }++tensMap :: HashMap Text Integer+tensMap = HashMap.fromList+ [ ( "بیست" , 20 )+ , ( "سی" , 30 )+ , ( "چهل" , 40 )+ , ( "پنجاه" , 50 )+ , ( "شصت" , 60 )+ , ( "هفتاد" , 70 )+ , ( "هشتاد" , 80 )+ , ( "نود" , 90 )+ , ( "صد" , 100 )+ , ( "دویست" , 200 )+ , ( "سیصد" , 300 )+ , ( "سی صد" , 300 )+ , ( "چهارصد" , 400 )+ , ( "چهار صد" , 400 )+ , ( "پانصد" , 500 )+ , ( "پونصد" , 500 )+ , ( "شیشصد" , 600 )+ , ( "شیش صد" , 600 )+ , ( "ششصد" , 600 )+ , ( "شش صد" , 600 )+ , ( "هفتصد" , 700 )+ , ( "هفت صد" , 700 )+ , ( "هشتصد" , 800 )+ , ( "هشت صد" , 800 )+ , ( "نهصد" , 900 )+ , ( "نه صد" , 900 )+ ]++ruleTens :: Rule+ruleTens = Rule+ { name = "integer (20..90)"+ , pattern =+ [ regex "(دویست|(سی|چهار|پان|پون|شی?ش|هفت|هشت|نه)? ?صد|بیست|سی|چهل|پنجاه|شصت|هفتاد|هشتاد|نود)"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup (Text.toLower match) tensMap >>= integer+ _ -> Nothing+ }++rulePowersOfTen :: Rule+rulePowersOfTen = Rule+ { name = "powers of tens"+ , pattern =+ [ regex "(هزار|میلیون|ملیون|میلیارد)"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) -> case Text.toLower match of+ "هزار" -> double 1e3 >>= withGrain 2 >>= withMultipliable+ "میلیون" -> double 1e6 >>= withGrain 3 >>= withMultipliable+ "ملیون" -> double 1e6 >>= withGrain 6 >>= withMultipliable+ "میلیارد" -> double 1e9 >>= withGrain 9 >>= withMultipliable+ _ -> Nothing+ _ -> Nothing+ }++ruleCompositeTens :: Rule+ruleCompositeTens = Rule+ { name = "integer 21..99"+ , pattern =+ [ oneOf [20,30..90]+ , regex "و"+ , numberBetween 1 10+ ]+ , prod = \tokens -> case tokens of+ (Token Numeral NumeralData{TNumeral.value = tens}:+ _:+ Token Numeral NumeralData{TNumeral.value = units}:+ _) -> double $ tens + units+ _ -> Nothing+ }++ruleCompositeHundred :: Rule+ruleCompositeHundred = Rule+ { name = "integer 21..99"+ , pattern =+ [ oneOf [100,200..900]+ , regex "و"+ , numberBetween 1 100+ ]+ , prod = \tokens -> case tokens of+ (Token Numeral NumeralData{TNumeral.value = tens}:+ _:+ Token Numeral NumeralData{TNumeral.value = units}:+ _) -> double $ tens + units+ _ -> Nothing+ }++ruleSum :: Rule+ruleSum = Rule+ { name = "intersect 2 numbers"+ , pattern =+ [ Predicate $ and . sequence [hasGrain, isPositive]+ , Predicate $ and . sequence [not . isMultipliable, isPositive]+ ]+ , prod = \tokens -> case tokens of+ (Token Numeral NumeralData{TNumeral.value = val1, TNumeral.grain = Just g}:+ Token Numeral NumeralData{TNumeral.value = val2}:+ _) | (10 ** fromIntegral g) > val2 -> double $ val1 + val2+ _ -> Nothing+ }++ruleSumAnd :: Rule+ruleSumAnd = Rule+ { name = "intersect 2 numbers (with and)"+ , pattern =+ [ Predicate $ and . sequence [hasGrain, isPositive]+ , regex "و"+ , Predicate $ and . sequence [not . isMultipliable, isPositive]+ ]+ , prod = \tokens -> case tokens of+ (Token Numeral NumeralData{TNumeral.value = val1, TNumeral.grain = Just g}:+ _:+ Token Numeral NumeralData{TNumeral.value = val2}:+ _) | (10 ** fromIntegral g) > val2 -> double $ val1 + val2+ _ -> Nothing+ }++ruleMultiply :: Rule+ruleMultiply = Rule+ { name = "compose by multiplication"+ , pattern =+ [ dimension Numeral+ , Predicate isMultipliable+ ]+ , prod = \tokens -> case tokens of+ (token1:token2:_) -> multiply token1 token2+ _ -> Nothing+ }++numeralToStringMap :: HashMap Char String+numeralToStringMap =+ HashMap.fromList+ [ ('۰', "0")+ , ('۱', "1")+ , ('۲', "2")+ , ('۳', "3")+ , ('۴', "4")+ , ('۵', "5")+ , ('۶', "6")+ , ('۷', "7")+ , ('۸', "8")+ , ('۹', "9")+ ]++parseIntAsText :: Text -> Text+parseIntAsText =+ Text.pack+ . join+ . mapMaybe (`HashMap.lookup` numeralToStringMap)+ . Text.unpack++parseIntegerFromText :: Text -> Maybe Integer+parseIntegerFromText = parseInteger . parseIntAsText++ruleIntegerNumeric :: Rule+ruleIntegerNumeric = Rule+ { name = "Persian integer numeric"+ , pattern =+ [ regex "([۰-۹]{1,18})"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ parseIntegerFromText match >>= integer+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleIntegerNumeric+ , ruleToNineteen+ , ruleTens+ , rulePowersOfTen+ , ruleCompositeTens+ , ruleCompositeHundred+ , ruleSum+ , ruleSumAnd+ , ruleMultiply+ ]
@@ -0,0 +1,122 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.++{-# LANGUAGE OverloadedStrings #-}++module Duckling.Numeral.FI.Corpus+ ( corpus+ ) where++import Data.String+import Prelude++import Duckling.Locale+import Duckling.Numeral.Types+import Duckling.Resolve+import Duckling.Testing.Types++context :: Context+context = testContext {locale = makeLocale FI Nothing}++corpus :: Corpus+corpus = (context, testOptions, allExamples)++allExamples :: [Example]+allExamples = concat+ [ examples (NumeralValue 0)+ [ "0"+ , "nolla"+ ]+ , examples (NumeralValue 1)+ [ "1"+ , "yksi"+ ]+ , examples (NumeralValue 2)+ [ "kaksi"+ ]+ , examples (NumeralValue 3)+ [ "kolme"+ ]+ , examples (NumeralValue 4)+ [ "neljä"+ ]+ , examples (NumeralValue 5)+ [ "viisi"+ ]+ , examples (NumeralValue 6)+ [ "kuusi"+ ]+ , examples (NumeralValue 7)+ [ "seitsemän"+ ]+ , examples (NumeralValue 8)+ [ "kahdeksan"+ ]+ , examples (NumeralValue 9)+ [ "yhdeksän"+ ]+ , examples (NumeralValue 10)+ [ "10"+ , "kymmenen"+ ]+ , examples (NumeralValue 11)+ [ "yksitoista"+ ]+ , examples (NumeralValue 12)+ [ "kaksitoista"+ ]+ , examples (NumeralValue 13)+ [ "kolmetoista"+ ]+ , examples (NumeralValue 14)+ [ "neljätoista"+ ]+ , examples (NumeralValue 15)+ [ "viisitoista"+ ]+ , examples (NumeralValue 16)+ [ "kuusitoista"+ ]+ , examples (NumeralValue 17)+ [ "seitsemäntoista"+ ]+ , examples (NumeralValue 18)+ [ "kahdeksantoista"+ ]+ , examples (NumeralValue 19)+ [ "yhdeksäntoista"+ ]+ , examples (NumeralValue 20)+ [ "20"+ , "kaksikymmentä"+ ]+ , examples (NumeralValue 24)+ [ "24"+ , "kaksikymmentäneljä"+ ]+ , examples (NumeralValue 35)+ [ "kolmekymmentäviisi"+ ]+ , examples (NumeralValue 42)+ [ "neljäkymmentäkaksi"+ ]+ , examples (NumeralValue 52)+ [ "viisikymmentäkaksi"+ ]+ , examples (NumeralValue 62)+ [ "kuusikymmentäkaksi"+ ]+ , examples (NumeralValue 72)+ [ "seitsemänkymmentäkaksi"+ ]+ , examples (NumeralValue 82)+ [ "kahdeksankymmentäkaksi"+ ]+ , examples (NumeralValue 99)+ [ "99"+ , "yhdeksänkymmentäyhdeksän"+ ]+ ]
@@ -0,0 +1,141 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.++{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE NoRebindableSyntax #-}++module Duckling.Numeral.FI.Rules+ ( rules+ ) where++import Data.HashMap.Strict (HashMap)+import Data.Maybe+import Data.String+import Data.Text (Text)+import Prelude+import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text++import Duckling.Dimensions.Types+import Duckling.Numeral.Helpers+import Duckling.Numeral.Types (NumeralData(..))+import Duckling.Regex.Types+import Duckling.Types+import qualified Duckling.Numeral.Types as TNumeral++ruleIntegerNumeric :: Rule+ruleIntegerNumeric = Rule+ { name = "integer (numeric)"+ , pattern =+ [ regex "(\\d{1,18})"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) -> do+ v <- parseInt match+ integer $ toInteger v+ _ -> Nothing+ }++numeralMap :: HashMap Text Integer+numeralMap = HashMap.fromList+ [ ( "nolla", 0 )+ , ( "yksi", 1 )+ , ( "kaksi", 2 )+ , ( "kolme", 3 )+ , ( "neljä", 4 )+ , ( "viisi", 5 )+ , ( "kuusi", 6 )+ , ( "seitsemän", 7 )+ , ( "kahdeksan", 8 )+ , ( "yhdeksän", 9 )+ , ( "kymmenen", 10 )+ ]++ruleNumeral :: Rule+ruleNumeral = Rule+ { name = "number (0..10)"+ , pattern =+ [ regex "(nolla|yksi|kaksi|kolme|neljä|viisi|kuusi|seitsemän|kahdeksan|yhdeksän|kymmenen)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup (Text.toLower match) numeralMap >>= integer+ _ -> Nothing+ }++elevenToNineteenMap :: HashMap Text Integer+elevenToNineteenMap = HashMap.fromList+ [ ( "yksitoista", 11 )+ , ( "kaksitoista", 12 )+ , ( "kolmetoista", 13 )+ , ( "neljätoista", 14 )+ , ( "viisitoista", 15 )+ , ( "kuusitoista", 16 )+ , ( "seitsemäntoista", 17 )+ , ( "kahdeksantoista", 18 )+ , ( "yhdeksäntoista", 19 )+ ]++ruleElevenToNineteen :: Rule+ruleElevenToNineteen = Rule+ { name = "number (11..19)"+ , pattern =+ [ regex "(yksitoista|kaksitoista|kolmetoista|neljätoista|viisitoista|kuusitoista|seitsemäntoista|kahdeksantoista|yhdeksäntoista)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup (Text.toLower match) elevenToNineteenMap >>= integer+ _ -> Nothing+ }++tensMap :: HashMap Text Integer+tensMap = HashMap.fromList+ [ ( "kaksikymmentä", 20 )+ , ( "kolmekymmentä", 30 )+ , ( "neljäkymmentä", 40 )+ , ( "viisikymmentä", 50 )+ , ( "kuusikymmentä", 60 )+ , ( "seitsemänkymmentä", 70 )+ , ( "kahdeksankymmentä", 80 )+ , ( "yhdeksänkymmentä", 90 )+ ]++ruleTens :: Rule+ruleTens = Rule+ { name = "integer (20,30..90)"+ , pattern =+ [ regex "(kaksikymmentä|kolmekymmentä|neljäkymmentä|viisikymmentä|kuusikymmentä|seitsemänkymmentä|kahdeksankymmentä|yhdeksänkymmentä)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup (Text.toLower match) tensMap >>= integer+ _ -> Nothing+ }++ruleCompositeTens :: Rule+ruleCompositeTens = Rule+ { name = "integer ([2-9][1-9])"+ , pattern =+ [ regex "(kaksikymmentä|kolmekymmentä|neljäkymmentä|viisikymmentä|kuusikymmentä|seitsemänkymmentä|kahdeksankymmentä|yhdeksänkymmentä)(yksi|kaksi|kolme|neljä|viisi|kuusi|seitsemän|kahdeksan|yhdeksän)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (m1:m2:_)):_) -> do+ v1 <- HashMap.lookup (Text.toLower m1) tensMap+ v2 <- HashMap.lookup (Text.toLower m2) numeralMap+ integer $ v1 + v2+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleIntegerNumeric+ , ruleNumeral+ , ruleElevenToNineteen+ , ruleTens+ , ruleCompositeTens+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -125,5 +124,12 @@ , "-1,2M" , "-1200K" , "-,0012G"+ ]+ , examples (NumeralValue 6.7)+ [ "6,7"+ ]+ , examples (NumeralValue 6700.54)+ [ "6.700,54"+ , "6 700,54" ] ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -57,10 +56,12 @@ { name = "numbers 22..29 32..39 .. 52..59" , pattern = [ oneOf [20, 50, 40, 30]+ , regex "[\\s\\-]+" , numberBetween 2 10 ] , prod = \tokens -> case tokens of (Token Numeral NumeralData{TNumeral.value = v1}:+ _: Token Numeral NumeralData{TNumeral.value = v2}: _) -> double $ v1 + v2 _ -> Nothing@@ -117,10 +118,12 @@ { name = "numbers 62..69 .. 92..99" , pattern = [ oneOf [60, 80]+ , regex "[\\s\\-]+" , numberBetween 2 20 ] , prod = \tokens -> case tokens of (Token Numeral NumeralData{TNumeral.value = v1}:+ _: Token Numeral NumeralData{TNumeral.value = v2}: _) -> double $ v1 + v2 _ -> Nothing@@ -166,10 +169,12 @@ { name = "number (17..19)" , pattern = [ numberWith TNumeral.value (== 10)+ , regex "[\\s\\-]+" , numberBetween 7 10 ] , prod = \tokens -> case tokens of (_:+ _: Token Numeral NumeralData{TNumeral.value = v}: _) -> double $ 10 + v _ -> Nothing@@ -224,7 +229,7 @@ { name = "numbers 21 31 41 51" , pattern = [ oneOf [20, 50, 40, 30]- , regex "et"+ , regex "-?et-?" , numberWith TNumeral.value (== 1) ] , prod = \tokens -> case tokens of
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-} @@ -69,6 +68,10 @@ [ "1.1" , "1.10" , "01.10"+ ]+ , examples (NumeralValue 0.5)+ [ "חצי"+ , "0.5" ] , examples (NumeralValue 0.77) [ "0.77"
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-} {-# LANGUAGE OverloadedStrings #-}@@ -344,6 +343,15 @@ _ -> Nothing } +ruleHalf :: Rule+ruleHalf = Rule+ { name = "half"+ , pattern =+ [ regex "חצי"+ ]+ , prod = \_ -> double 0.5+ }+ rules :: [Rule] rules = [ ruleCommas@@ -373,4 +381,5 @@ , ruleNumeralsPrefixWithNegativeOrMinus , rulePowersOfTen , ruleSingle+ , ruleHalf ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -83,5 +82,22 @@ , examples (NumeralValue 50) [ "५०" , "पचास"+ ]+ , examples (NumeralValue 300)+ [ "तीन सौ"+ ]+ , examples (NumeralValue 81)+ [ "इक्यासी"+ ]+ , examples (NumeralValue 150)+ [ "एक सौ पचास"+ ]+ , examples (NumeralValue 1000)+ [ "हज़ार"+ , "एक हज़ार"+ , "हज़ार" -- हज़ार using a different character scheme+ ]+ , examples (NumeralValue 1520)+ [ "एक हज़ार पाँच सौ बीस" ] ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -16,7 +15,6 @@ import Data.HashMap.Strict (HashMap) import Data.Maybe-import Data.String import Data.Text (Text) import Prelude import qualified Data.HashMap.Strict as HashMap@@ -58,36 +56,20 @@ _ -> Nothing } -ruleNumeralMap :: HashMap Text Integer-ruleNumeralMap = HashMap.fromList+ruleZeroToNinetyNineMap :: HashMap Text Integer+ruleZeroToNinetyNineMap = HashMap.fromList [ ( "शून्य", 0 ) , ( "एक", 1 )- , ( "दो" , 2 )+ , ( "दो", 2 ) , ( "तीन", 3 ) , ( "चार", 4 ) , ( "पाँच", 5 )+ , ( "छः", 6 ) , ( "छह", 6 ) , ( "सात", 7 ) , ( "आठ", 8 )- , ( "नौ" , 9 )- , ( "दस", 10 )- ]--ruleNumeral :: Rule-ruleNumeral = Rule- { name = "number (0..10)"- , pattern =- [ regex "(शून्य|एक|दो|तीन|चार|पाँच|छह|सात|आठ|नौ|दस)"- ]- , prod = \tokens -> case tokens of- (Token RegexMatch (GroupMatch (match:_)):_) ->- HashMap.lookup match ruleNumeralMap >>= integer- _ -> Nothing- }--elevenToNineteenMap :: HashMap Text Integer-elevenToNineteenMap = HashMap.fromList- [ ( "ग्यारह", 11 )+ , ( "नौ", 9 )+ , ( "ग्यारह", 11 ) , ( "बारह", 12 ) , ( "तेरह", 13 ) , ( "चौदह", 14 )@@ -96,23 +78,7 @@ , ( "सत्रह", 17 ) , ( "अठारह", 18 ) , ( "उन्नीस", 19 )- ]--ruleElevenToNineteen :: Rule-ruleElevenToNineteen = Rule- { name = "number (11..19)"- , pattern =- [ regex "(ग्यारह|बारह|तेरह|चौदह|पन्द्रह|सोलह|सत्रह|अठारह|उन्नीस)"- ]- , prod = \tokens -> case tokens of- (Token RegexMatch (GroupMatch (match:_)):_) ->- HashMap.lookup match elevenToNineteenMap >>= integer- _ -> Nothing- }--twentyoneToTwentynineMap :: HashMap Text Integer-twentyoneToTwentynineMap = HashMap.fromList- [ ( "इक्कीस", 21 )+ , ( "इक्कीस", 21 ) , ( "बाईस", 22 ) , ( "तेईस", 23 ) , ( "चौबीस", 24 )@@ -121,23 +87,88 @@ , ( "सत्ताईस", 27 ) , ( "अट्ठाईस", 28 ) , ( "उनतीस", 29 )+ , ( "इकतीस", 31 )+ , ( "इकत्तीस", 31 )+ , ( "बत्तीस", 32 )+ , ( "तैंतीस", 33 )+ , ( "चौंतीस", 34 )+ , ( "पैंतीस", 35 )+ , ( "छत्तीस", 36 )+ , ( "सैंतीस", 37 )+ , ( "अड़तीस", 38 )+ , ( "उनतालीस", 39 )+ , ( "इकतालीस", 41 )+ , ( "बयालीस", 42 )+ , ( "तैंतालीस", 43 )+ , ( "चौवालीस", 44 )+ , ( "पैंतालीस", 45 )+ , ( "छियालीस", 46 )+ , ( "सैंतालीस", 47 )+ , ( "अड़तालीस", 48 )+ , ( "उनचास", 49 )+ , ( "इक्यावन", 51 )+ , ( "बावन", 52 )+ , ( "तिरेपन", 53 )+ , ( "चौवन", 54 )+ , ( "पचपन", 55 )+ , ( "छप्पन", 56 )+ , ( "सत्तावन", 57 )+ , ( "अट्ठावन", 58 )+ , ( "उनसठ", 59 )+ , ( "इकसठ", 61 )+ , ( "बासठ", 62 )+ , ( "तिरेसठ", 63 )+ , ( "चौंसठ", 64 )+ , ( "पैंसठ", 65 )+ , ( "छियासठ", 66 )+ , ( "सड़सठ", 67 )+ , ( "अड़सठ", 68 )+ , ( "उनहत्तर", 69 )+ , ( "इकहत्तर", 71 )+ , ( "बहत्तर", 72 )+ , ( "तिहत्तर", 73 )+ , ( "चौहत्तर", 74 )+ , ( "पचहत्तर", 75 )+ , ( "छिहत्तर", 76 )+ , ( "सतहत्तर", 77 )+ , ( "अठहत्तर", 78 )+ , ( "उनासी", 79 )+ , ( "इक्यासी", 81 )+ , ( "बयासी", 82 )+ , ( "तिरासी", 83 )+ , ( "चौरासी", 84 )+ , ( "पचासी", 85 )+ , ( "छियासी", 86 )+ , ( "सतासी", 87 )+ , ( "अट्ठासी", 88 )+ , ( "नवासी", 89 )+ , ( "इक्यानवे", 91 )+ , ( "बानवे", 92 )+ , ( "तिरानवे", 93 )+ , ( "चौरानवे", 94 )+ , ( "पचानवे", 95 )+ , ( "छियानवे", 96 )+ , ( "सत्तानवे", 97 )+ , ( "अट्ठानवे", 98 )+ , ( "निन्यानवे", 99 ) ] -ruleTwentyoneToTwentynine :: Rule-ruleTwentyoneToTwentynine = Rule- { name = "number (21..29)"+ruleZeroToNinetyNine :: Rule+ruleZeroToNinetyNine = Rule+ { name = "number (0..99)" , pattern =- [ regex "(इक्कीस|बाईस|तेईस|चौबीस|पच्चीस|छब्बीस|सत्ताईस|अट्ठाईस|उनतीस)"+ [ regex "(शून्य|एक|दो|तीन|चार|पाँच|छे|छह|सात|आठ|नौ|ग्यारह|बारह|तेरह|चौदह|पन्द्रह|सोलह|सत्रह|अठारह|उन्नीस|इक्कीस|बाईस|तेईस|चौबीस|पच्चीस|छब्बीस|सत्ताईस|अट्ठाईस|उनतीस|इकतीस|बत्तीस|तैंतीस|चौंतीस|पैंतीस|छत्तीस|सैंतीस|अड़तीस|उनतालीस|इकतालीस|बयालीस|तैंतालीस|चौवालीस|पैंतालीस|छियालीस|सैंतालीस|अड़तालीस|उनचास|इक्यावन|बावन|तिरेपन|चौवन|पचपन|छप्पन|सत्तावन|अट्ठावन|उनसठ|इकसठ|बासठ|तिरेसठ|चौंसठ|पैंसठ|छियासठ|सड़सठ|अड़सठ|उनहत्तर|इकहत्तर|बहत्तर|तिहत्तर|चौहत्तर|पचहत्तर|छिहत्तर|सतहत्तर|अठहत्तर|उनासी|इक्यासी|बयासी|तिरासी|चौरासी|पचासी|छियासी|सतासी|अट्ठासी|नवासी|इक्यानवे|बानवे|तिरानवे|चौरानवे|पचानवे|छियानवे|सत्तानवे|अट्ठानवे|निन्यानवे)" ] , prod = \tokens -> case tokens of (Token RegexMatch (GroupMatch (match:_)):_) ->- HashMap.lookup match twentyoneToTwentynineMap >>= integer+ HashMap.lookup match ruleZeroToNinetyNineMap >>= integer _ -> Nothing } tensMap :: HashMap Text Integer tensMap = HashMap.fromList- [ ( "बीस", 20 )+ [ ("दस", 10)+ , ( "बीस", 20 ) , ( "तीस", 30 ) , ( "चालीस", 40 ) , ( "पचास", 50 )@@ -151,7 +182,7 @@ ruleTens = Rule { name = "integer (20,30..90)" , pattern =- [ regex "(बीस|तीस|चालीस|पचास|साठ|सत्तर|अस्सी|नब्बे)"+ [ regex "(दस|बीस|तीस|चालीस|पचास|साठ|सत्तर|अस्सी|नब्बे)" ] , prod = \tokens -> case tokens of (Token RegexMatch (GroupMatch (match:_)):_) ->@@ -159,12 +190,72 @@ _ -> Nothing } +rulePowersOfTen :: Rule+rulePowersOfTen = Rule+ { name = "powers of tens"+ , pattern = [regex "(सौ|हज़ार|हज़ार)"]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match : _)) : _) ->+ case Text.toLower match of+ "सौ" -> double 1e2 >>= withGrain 2 >>= withMultipliable+ "हज़ार" -> double 1e3 >>= withGrain 3 >>= withMultipliable+ "हज़ार" -> double 1e3 >>= withGrain 3 >>= withMultipliable+ _ -> Nothing+ _ -> Nothing+ } +ruleMultiply :: Rule+ruleMultiply = Rule+ { name = "compose by multiplication"+ , pattern =+ [ Predicate isPositive+ , Predicate isMultipliable+ ]+ , prod = \tokens -> case tokens of+ (token1:token2:_) -> multiply token1 token2+ _ -> Nothing+ }++ruleCompositeHundreds :: Rule+ruleCompositeHundreds = Rule+ { name = "integer 100s.."+ , pattern =+ [ oneOf [100,200..5000]+ , regex "[\\s\\-]+"+ , numberBetween 1 99+ ]+ , prod = \tokens -> case tokens of+ (Token Numeral NumeralData{TNumeral.value = hundreds}:+ _:+ Token Numeral NumeralData{TNumeral.value = remaining}:+ _) -> double $ hundreds + remaining+ _ -> Nothing+ }+++ruleCompositeThousands :: Rule+ruleCompositeThousands = Rule+ { name = "integer 100s.."+ , pattern =+ [ oneOf [1000,2000..50000]+ , regex "[\\s\\-]+"+ , numberBetween 1 999+ ]+ , prod = \tokens -> case tokens of+ (Token Numeral NumeralData{TNumeral.value = thousands}:+ _:+ Token Numeral NumeralData{TNumeral.value = remaining}:+ _) -> double $ thousands + remaining+ _ -> Nothing+ }+ rules :: [Rule] rules = [ ruleDevanagari- , ruleNumeral- , ruleElevenToNineteen- , ruleTwentyoneToTwentynine+ , ruleZeroToNinetyNine , ruleTens+ , rulePowersOfTen+ , ruleMultiply+ , ruleCompositeHundreds+ , ruleCompositeThousands ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-} {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -0,0 +1,79 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}++module Duckling.Numeral.IS.Corpus+ ( corpus+ ) where++import Data.String+import Prelude++import Duckling.Locale+import Duckling.Numeral.Types+import Duckling.Resolve+import Duckling.Testing.Types++context :: Context+context = testContext{locale = makeLocale IS Nothing}++corpus :: Corpus+corpus = (context, testOptions, allExamples)++allExamples :: [Example]+allExamples = concat+ [ examples (NumeralValue 0)+ [ "0"+ , "núll"+ , "null"+ ]+ , examples (NumeralValue 1)+ [ "1"+ , "einn"+ ]+ , examples (NumeralValue 2)+ [ "tveir"+ ]+ , examples (NumeralValue 3)+ [ "þrír"+ ]+ , examples (NumeralValue 4)+ [ "fjórir"+ ]+ , examples (NumeralValue 5)+ [ "fimm"+ ]+ , examples (NumeralValue 6)+ [ "sex"+ ]+ , examples (NumeralValue 7)+ [ "sjö"+ ]+ , examples (NumeralValue 8)+ [ "átta"+ ]+ , examples (NumeralValue 9)+ [ "níu"+ ]+ , examples (NumeralValue 10)+ [ "tíu"+ ]+ , examples (NumeralValue 11)+ [ "ellefu"+ ]+ , examples (NumeralValue 15)+ [ "fimmtán"+ ]+ , examples (NumeralValue 17)+ [ "sautján"+ ]+ , examples (NumeralValue 20)+ [ "20"+ , "tuttugu"+ ]+ ]
@@ -0,0 +1,73 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE NoRebindableSyntax #-}++module Duckling.Numeral.IS.Rules+ ( rules+ ) where++import Data.HashMap.Strict (HashMap)+import Data.Maybe+import Data.String+import Data.Text (Text)+import Prelude+import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text++import Duckling.Dimensions.Types+import Duckling.Numeral.Helpers+import Duckling.Numeral.Types (NumeralData (..))+import Duckling.Regex.Types+import Duckling.Types+import qualified Duckling.Numeral.Types as TNumeral++zeroToTwentyMap:: HashMap Text Integer+zeroToTwentyMap = HashMap.fromList+ [ ( "núll", 0 )+ , ( "null", 0 )+ , ( "einn", 1 )+ , ( "tveir", 2 )+ , ( "þrír", 3 )+ , ( "fjórir", 4 )+ , ( "fimm", 5 )+ , ( "sex", 6 )+ , ( "sjö", 7 )+ , ( "átta", 8 )+ , ( "níu", 9 )+ , ( "tíu", 10 )+ , ( "ellefu", 11 )+ , ( "tólf", 12 )+ , ( "þrettán", 13 )+ , ( "fjórtán", 14 )+ , ( "fimmtán", 15 )+ , ( "sextán", 16 )+ , ( "sautján", 17 )+ , ( "átján", 18 )+ , ( "nítján", 19 )+ , ( "tuttugu", 20 )+ ]++ruleZeroToTwenty :: Rule+ruleZeroToTwenty = Rule+ { name = "number (0..20)"+ , pattern =+ [ regex "(n[úu]ll|einn|tveir|þrír|fjórir|fimm(tán)?|sex(tán)?|sjö|átta|níu|tíu|ellefu|tólf|þrettán|fjórtán|sautján|átján|nítján|tuttugu)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup (Text.toLower match) zeroToTwentyMap >>= integer+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleZeroToTwenty+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -129,12 +128,14 @@ , "100000" , "100K" , "100k"+ , "100 000" ] , examples (NumeralValue 3000000) [ "3M" , "3000K" , "3000000" , "3.000.000"+ , "3 000 000" ] , examples (NumeralValue 1200000) [ "1.200.000"@@ -151,5 +152,12 @@ , "-1,2M" , "-1200K" , "-,0012G"+ ]+ , examples (NumeralValue 6.7)+ [ "6,7"+ ]+ , examples (NumeralValue 6700.54)+ [ "6.700,54"+ , "6 700,54" ] ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -43,11 +42,11 @@ ruleDecimalWithThousandsSeparator = Rule { name = "decimal with thousands separator" , pattern =- [ regex "(\\d+(\\.\\d\\d\\d)+,\\d+)"+ [ regex "(\\d+(([\\. ])\\d\\d\\d)+,\\d+)" ] , prod = \tokens -> case tokens of- (Token RegexMatch (GroupMatch (match:_)):- _) -> let fmt = Text.replace "," "." $ Text.replace "." Text.empty match+ (Token RegexMatch (GroupMatch (match:_:sep:_)):+ _) -> let fmt = Text.replace "," "." $ Text.replace sep Text.empty match in parseDouble fmt >>= double _ -> Nothing }@@ -304,11 +303,12 @@ ruleIntegerWithThousandsSeparator = Rule { name = "integer with thousands separator ." , pattern =- [ regex "(\\d{1,3}(\\.\\d\\d\\d){1,5})"+ [ regex "(\\d{1,3}(([\\. ])\\d\\d\\d){1,5})" ] , prod = \tokens -> case tokens of- (Token RegexMatch (GroupMatch (match:_)):_) ->- parseDouble (Text.replace "." Text.empty match) >>= double+ (Token RegexMatch (GroupMatch (match:_:sep:_)):+ _) -> let fmt = Text.replace sep Text.empty match+ in parseDouble fmt >>= double _ -> Nothing }
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,14 +2,15 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-} +-- /Note/: All commented-out tests are failing due to https://github.com/facebook/duckling/issues/541 module Duckling.Numeral.KA.Corpus- ( corpus ) where+ ( corpus+ ) where import Data.String import Prelude@@ -19,14 +20,19 @@ import Duckling.Resolve import Duckling.Testing.Types +context :: Context+context = testContext {locale = makeLocale KA Nothing}+ corpus :: Corpus-corpus = (testContext {locale = makeLocale KA Nothing}, testOptions, allExamples)+corpus = (context, testOptions, allExamples) allExamples :: [Example] allExamples = concat [ examples (NumeralValue 0) [ "0"+ , "ნოლი" , "ნული"+ , "ნოლ" ] , examples (NumeralValue 1) [ "1"@@ -35,9 +41,380 @@ , examples (NumeralValue 2) [ "2" , "ორი"+ , "წყვილი"+ , "წყვილები" ] , examples (NumeralValue 3) [ "3" , "სამი"+ , "ცოტა"+ , "რამდენიმე"+ , "რამოდენიმე" ]+ , examples (NumeralValue 4)+ [ "4"+ , "ოთხი"+ ]+ , examples (NumeralValue 5)+ [ "5"+ , "ხუთი"+ ]+ , examples (NumeralValue 6)+ [ "6"+ , "ექვსი"+ ]+ , examples (NumeralValue 7)+ [ "7"+ , "შვიდი"+ ]+ , examples (NumeralValue 8)+ [ "8"+ , "რვა"+ ]+ , examples (NumeralValue 9)+ [ "9"+ , "ცხრა"+ ]+ , examples (NumeralValue 10)+ [ "10"+ , "ათი"+ ]+ , examples (NumeralValue 11)+ [ "11"+ , "თერთმეტი"+ ]+ , examples (NumeralValue 12)+ [ "12"+ , "თორმეტი"+ ]+ , examples (NumeralValue 13)+ [ "13"+ , "ცამეტი"+ ]+ , examples (NumeralValue 14)+ [ "14"+ , "თოთხმეტი"+ ]+ , examples (NumeralValue 15)+ [ "15"+ , "თხუთმეტი"+ ]+ , examples (NumeralValue 16)+ [ "16"+ , "თექვსმეტი"+ ]+ , examples (NumeralValue 17)+ [ "17"+ , "ჩვიდმეტი"+ ]+ , examples (NumeralValue 18)+ [ "18"+ , "თვრამეტი"+ ]+ , examples (NumeralValue 19)+ [ "19"+ , "ცხრამეტი"+ ]+ , examples (NumeralValue 20)+ [ "20"+ , "ოცი"+ ]+ , examples (NumeralValue 21)+ [ "21"+ -- , "ოცდაერთი"+ ]+ , examples (NumeralValue 22)+ [ "22"+ -- , "ოცდაორი"+ ]+ , examples (NumeralValue 23)+ [ "23"+ -- , "ოცდასამი"+ ]+ , examples (NumeralValue 24)+ [ "24"+ -- , "ოცდაოთხი"+ ]+ , examples (NumeralValue 25)+ [ "25"+ -- , "ოცდახუთი"+ ]+ , examples (NumeralValue 26)+ [ "26"+ -- , "ოცდაექვსი"+ ]+ , examples (NumeralValue 27)+ [ "27"+ -- , "ოცდაშვიდი"+ ]+ , examples (NumeralValue 30)+ [ "30"+ , "ოცდაათი"+ ]+ , examples (NumeralValue 31)+ [ "31"+ -- , "ოცდათერთმეტი"+ ]+ , examples (NumeralValue 38)+ [ "38"+ -- , "ოცდათვრამეტი"+ ]+ , examples (NumeralValue 39)+ [ "39"+ -- , "ოცდაცხრამეტი"+ ]+ , examples (NumeralValue 40)+ [ "40"+ , "ორმოცი"+ ]+ , examples (NumeralValue 42)+ [ "42"+ -- , "ორმოცდაორი"+ ]+ , examples (NumeralValue 47)+ [ "47"+ -- , "ორმოცდაშვიდი"+ ]+ , examples (NumeralValue 99)+ [ "99"+ --, "ოთხმოცდაცხრამეტი"+ ]+ , examples (NumeralValue 100)+ [ "100"+ , "ასი"+ ]+ , examples (NumeralValue 101)+ [ "101"+ , "ას ერთი"+ ]+ , examples (NumeralValue 102)+ [ "102"+ , "ას ორი"+ ]+ , examples (NumeralValue 121)+ [ "121"+ --, "ას ოცდაერთი"+ ]+ , examples (NumeralValue 200)+ [ "200"+ , "ორასი"+ ]+ , examples (NumeralValue 201)+ [ "201"+ , "ორას ერთი"+ ]+ , examples (NumeralValue 250)+ [ "250"+ , "ორას ორმოცდაათი"+ ]+ , examples (NumeralValue 300)+ [ "300"+ , "სამასი"+ ]+ , examples (NumeralValue 310)+ [ "310"+ , "სამას ათი"+ ]+ , examples (NumeralValue 415)+ [ "415"+ , "ოთხას თხუთმეტი"+ ]+ , examples (NumeralValue 600)+ [ "600"+ , "ექვსასი"+ ]+ , examples (NumeralValue 909)+ [ "909"+ , "ცხრაას ცხრა"+ ]+ , examples (NumeralValue 999)+ [ "999"+ --, "ცხრაას ოთხმოცდაცხრამეტი"+ ]+ , examples (NumeralValue 1000)+ [ "1000"+ , "ათასი"+ ]+ , examples (NumeralValue 1001)+ [ "1001"+ , "ათას ერთი"+ ]+ , examples (NumeralValue 2000)+ [ "2000"+ , "ორი ათასი"+ ]+ , examples (NumeralValue 2010)+ [ "2010"+ , "ორი ათას ათი"+ ]+ , examples (NumeralValue 7892)+ [ "7892"+ --, "შვიდი ათას რვაას ოთხმოცდათორმეტი"+ ]+ , examples (NumeralValue 10000)+ [ "10000"+ , "ათი ათასი"+ ]+ , examples (NumeralValue 121000)+ [ "121000"+ --, "ას ოცდაერთი ათასი"+ ]+ , examples (NumeralValue 120000)+ [ "120000"+ , "ას ოცი ათასი"+ ]+ , examples (NumeralValue 124000)+ [ "124000"+ --, "ას ოცდაოთხი ათასი"+ ]+ , examples (NumeralValue 999000)+ [ "999000"+ --, "ცხრაას ოთხმოცდაცხრამეტი ათასი"+ ]+ , examples (NumeralValue 999900)+ [ "999900"+ --, "ცხრაას ოთხმოცდაცხრამეტი ათას ცხრაასი"+ ]+ , examples (NumeralValue 999990)+ [ "999990"+ --, "ცხრაას ოთხმოცდაცხრამეტი ათას ცხრაას ოთხმოცდაათი"+ ]+ , examples (NumeralValue 999999)+ [ "999999"+ -- , "ცხრაას ოთხმოცდაცხრამეტი ათას ცხრაას ოთხმოცდაცხრამეტი"+ ]+ , examples (NumeralValue 1000000)+ [ "1000000"+ , "ერთი მილიონი"+ ]+ , examples (NumeralValue 2000000)+ [ "2000000"+ , "ორი მილიონი"+ ]+ , examples (NumeralValue 999000999)+ [ "999000999"+ -- , "ცხრაას ოთხმოცდაცხრამეტი მილიონ ცხრაას ოთხმოცდაცხრამეტი"+ ]+ , examples (NumeralValue 999999999)+ [ "999999999"+ -- , "ცხრაას ოთხმოცდაცხრამეტი მილიონ ცხრაას ოთხმოცდაცხრამეტი ათას ცხრაას ოთხმოცდაცხრამეტი"+ ]+ , examples (NumeralValue 1174315110)+ [ "1174315110"+ -- , "ერთი მილიარდ ას სამოცდათოთხმეტი მილიონ სამას თხუთმეტი ათას ას ათი"+ ]+ , examples (NumeralValue 1174315119)+ [ "1174315119"+ -- , "ერთი მილიარდ ას სამოცდათოთხმეტი მილიონ სამას თხუთმეტი ათას ას ცხრამეტი"+ ]+ , examples (NumeralValue 15174315110)+ [ "15174315110"+ -- , "თხუთმეტი მილიარდ ას სამოცდათოთხმეტი მილიონ სამას თხუთმეტი ათას ას ათი"+ ]+ , examples (NumeralValue 35174315119)+ [ "35174315119"+ -- , "ოცდათხუთმეტი მილიარდ ას სამოცდათოთხმეტი მილიონ სამას თხუთმეტი ათას ას ცხრამეტი"+ ]+ , examples (NumeralValue 935174315119)+ [ "935174315119"+ -- , "ცხრაას ოცდათხუთმეტი მილიარდ ას სამოცდათოთხმეტი მილიონ სამას თხუთმეტი ათას ას ცხრამეტი"+ ]+ , examples (NumeralValue 33)+ [ "33"+ -- , "ოცდაცამეტი"+ , "0033"+ ]+ , examples (NumeralValue 24)+ [ "24"+ -- , "ოცდაოთხი"+ ]+ , examples (NumeralValue 1.1)+ [ "1.1"+ , "1.10"+ , "01.10"+ , "1 მთელი 1"+ , "ერთი მთელი ერთი"+ ]+ , examples (NumeralValue 0.77)+ [ ".77"+ , "0.77"+ -- , "ნოლი მთელი სამოცდაჩვიდმეტი"+ -- , "ნული მთელი სამოცდაჩვიდმეტი"+ ]+ , examples (NumeralValue 100000)+ [ "100,000"+ , "100,000.0"+ , "100000"+ , "100k"+ -- , "ასი ათასი"+ ]+ , examples (NumeralValue 0.2)+ [ "1/5"+ , "2/10"+ , "3/15"+ , "20/100"+ ]+ , examples (NumeralValue 3e6)+ [ "3M"+ , "3000K"+ , "3000000"+ , "3,000,000"+ , "3 მილიონი"+ -- , "სამი მილიონი"+ ]+ , examples (NumeralValue 1.2e6)+ [ "1,200,000"+ , "1200000"+ , "1.2M"+ , "1200k"+ , ".0012G"+ ]+ , examples (NumeralValue 5000)+ [ "5 ათასი"+ -- , "ხუთი ათასი"+ ]+ , examples (NumeralValue (-504))+ [ "-504"+ -- , "მინუს ხუთას ოთხი"+ -- , "მინუს 504"+ ]+ , examples (NumeralValue (-1.2e6))+ [ "- 1,200,000"+ , "-1200000"+ -- , "მინუს 1,200,000"+ -- , "მინუს 1200000"+ , "-1.2M"+ , "-1200K"+ , "-.0012G"+ ]+{-+ , examples (NumeralValue 122)+ [ "ას ოცდაორი"+ , "ასოცდაორი"+ ]+ , examples (NumeralValue 2e5)+ [ "ორასი ათასი"+ ]+ , examples (NumeralValue 21011)+ [ "ოცდაერთიათას თერთმეტი"+ ]+ , examples (NumeralValue 721012)+ [ "შვიდას ოცდაერთი ათას თორმეტი"+ ]+ , examples (NumeralValue 31256721)+ [ "ოცდათერთმეტი მილიონ ორას ორმოცდათექვსმეტი ათას შვიდას ოცდაერთი"+ ]+ , examples (NumeralValue 2400)+ [ "ორიათას ოთხასი"+ , "ორიათასოთხასი"+ ]+ , examples (NumeralValue 2200000)+ [ "ორი მთელი ორი მილიონი"+ , "ორი მილიონ ორასი ათას"+ ]+ , examples (NumeralValue 3000000000)+ [ "სამი მილიარდი"+ , "3 მილიარდი"+ ]+-} ]
@@ -2,17 +2,19 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE NoRebindableSyntax #-} {-# LANGUAGE OverloadedStrings #-} module Duckling.Numeral.KA.Rules ( rules ) where +import Control.Applicative ((<|>)) import Data.HashMap.Strict (HashMap) import Data.Maybe import Data.String@@ -28,34 +30,376 @@ import Duckling.Types import qualified Duckling.Numeral.Types as TNumeral -ruleNumeralMap :: HashMap Text Integer-ruleNumeralMap = HashMap.fromList- [ ( "ნული", 0 )- , ( "ერთი", 1 )- , ( "ორი", 2 )- , ( "სამი", 3 )- , ( "ოთხი", 4 )- , ( "ხუთი", 5)- , ( "ექვსი", 6)- , ( "შვიდი", 7)- , ( "რვა", 8)- , ( "ცხრა", 9)- , ( "ათი", 10)+zeroNineteenMap :: HashMap Text Integer+zeroNineteenMap = HashMap.fromList+ [ ( "ნოლ" , 0 )+ , ( "ნულ" , 0 )+ , ( "ნული" , 0 )+ , ( "ნოლ" , 0 )+ , ( "ნოლი" , 0 )+ , ( "ერთი" , 1 )+ , ( "ორი" , 2 )+ , ( "ორ" , 2 )+ , ( "სამი" , 3 )+ , ( "სამ" , 3 )+ , ( "ოთხი" , 4 )+ , ( "ოთხ" , 4 )+ , ( "ხუთი" , 5 )+ , ( "ხუთ" , 5 )+ , ( "ექვსი" , 6 )+ , ( "ექვს" , 6 )+ , ( "შვიდი" , 7 )+ , ( "შვიდ" , 7 )+ , ( "რვა" , 8 )+ , ( "რვ" , 8 )+ , ( "ცხრა" , 9 )+ , ( "ცხრ" , 9 )+ , ( "ათი" , 10 )+ , ( "აათი" , 10 )+ , ( "თერთმეტი" , 11 )+ , ( "თერთმეტ" , 11 )+ , ( "თორმეტი" , 12 )+ , ( "თორმეტ" , 12 )+ , ( "ცამეტი" , 13 )+ , ( "ცამეტ" , 13 )+ , ( "თოთხმეტი" , 14 )+ , ( "თოთხმეტ" , 14 )+ , ( "თხუთმეტი" , 15 )+ , ( "თხუთმეტ" , 15 )+ , ( "თექვსმეტი" , 16 )+ , ( "თექვსმეტ" , 16 )+ , ( "ჩვიდმეტი" , 17 )+ , ( "ჩვიდმეტ" , 17 )+ , ( "თვრამეტი" , 18 )+ , ( "თვრამეტ" , 18 )+ , ( "ცხრამეტი" , 19 )+ , ( "ცხრამეტ" , 19 ) ] -ruleNumeral :: Rule-ruleNumeral = Rule- { name = "number (0..10)"+informalMap :: HashMap Text Integer+informalMap = HashMap.fromList+ [ ( "ერთი" , 1 )+ , ( "წყვილი" , 2 )+ , ( "წყვილები" , 2 )+ , ( "ცოტა" , 3 )+ , ( "რამდენიმე" , 3 )+ , ( "რამოდენიმე" , 3 )+ ]++ruleToNineteen :: Rule+ruleToNineteen = Rule+ { name = "integer (0..19)" , pattern =- [ regex "(ნული|ერთი|ორი|სამი|ოთხი|ხუთი|ექვსი|შვიდი|რვა|ცხრა|ათი)"+ [ regex "(წყვილ(ებ)?ი|ცოტა|რამდენიმე|რამოდენიმე|ნოლი?|ნული?|ერთი|ორი?|სამი?|ოთხი?|ხუთი?|ექვსი?|შვიდი?|რვა|თერთმეტი?|თორმეტი?|ცამეტი?|თოთხმეტი?|თხუთმეტი?|თექვსმეტი?|ჩვიდმეტი?|თვრამეტი?|ცხრამეტი?|ცხრა|ა?ათი)" ]- , prod = \tokens -> case tokens of+ , prod = \case (Token RegexMatch (GroupMatch (match:_)):_) ->- HashMap.lookup (Text.toLower match) ruleNumeralMap >>= integer+ let x = Text.toLower match in+ (HashMap.lookup x zeroNineteenMap >>= integer) <|>+ (HashMap.lookup x informalMap >>= integer >>= notOkForAnyTime) _ -> Nothing } +tensMap :: HashMap Text Integer+tensMap = HashMap.fromList+ [ ( "ოცი" , 20 )+ , ( "ოცდა" , 20 )+ , ( "ოც" , 20 )+ , ( "ოცდაათ" , 30 )+ , ( "ოცდაათი" , 30 )+ , ( "ორმოც" , 40 )+ , ( "ორმოცი" , 40 )+ , ( "ორმოცდა" , 40 )+ , ( "ორმოცდაათ" , 50 )+ , ( "ორმოცდაათი" , 50 )+ , ( "სამოც" , 60 )+ , ( "სამოცი" , 60 )+ , ( "სამოცდა" , 60 )+ , ( "სამოცდაათ" , 70 )+ , ( "სამოცდაათი" , 70 )+ , ( "ოთხმოც" , 80 )+ , ( "ოთხმოცი" , 80 )+ , ( "ოთხმოცდა" , 80 )+ , ( "ოთხმოცდაათ" , 90 )+ , ( "ოთხმოცდაათი" , 90 )+ ]++ruleTens :: Rule+ruleTens = Rule+ { name = "integer (20..90)"+ , pattern =+ [ regex "(ოცდაათი?|ორმოცდაათი?|სამოცდაათი?|ოთხმოცდაათი?|ოცდა|ორმოცდა|სამოცდა|ოთხმოცდა|ოცი?|ორმოცი?|სამოცი?|ოთხმოცი?)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup (Text.toLower match) tensMap >>= integer+ _ -> Nothing+ }++hundredsMap :: HashMap Text Integer+hundredsMap = HashMap.fromList+ [ ( "ასი" , 100 )+ , ( "ორასი" , 200 )+ , ( "სამასი" , 300 )+ , ( "ოთხასი" , 400 )+ , ( "ხუთასი" , 500 )+ , ( "ექვსასი" , 600 )+ , ( "შვიდასი" , 700 )+ , ( "რვაასი" , 800 )+ , ( "ცხრაასი" , 900 )+ , ( "ას" , 100 )+ , ( "ორას" , 200 )+ , ( "სამას" , 300 )+ , ( "ოთხას" , 400 )+ , ( "ხუთას" , 500 )+ , ( "ექვსას" , 600 )+ , ( "შვიდას" , 700 )+ , ( "რვაას" , 800 )+ , ( "ცხრაას" , 900 )+ , ( "ორ ას" , 200 )+ , ( "სამ ას" , 300 )+ , ( "ოთხ ას" , 400 )+ , ( "ხუთ ას" , 500 )+ , ( "ექვს ას" , 600 )+ , ( "შვიდ ას" , 700 )+ , ( "რვა ას" , 800 )+ , ( "ცხრა ას" , 900 )+ , ( "ორ ასი" , 200 )+ , ( "სამ ასი" , 300 )+ , ( "ოთხ ასი" , 400 )+ , ( "ხუთ ასი" , 500 )+ , ( "ექვს ასი" , 600 )+ , ( "შვიდ ასი" , 700 )+ , ( "რვა ასი" , 800 )+ , ( "ცხრა ასი" , 900 )+ ]++ruleHundreds :: Rule+ruleHundreds = Rule+ { name = "integer (800..900)"+ , pattern =+ [ regex "(ასი?|ორ ?ასი?|სამ ?ასი?|ოთხ ?ასი?|ხუთ ?ასი?|ექვს ?ასი?|შვიდ ?ასი?|რვა ?ასი?|ცხრა ?ასი?)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup (Text.toLower match) hundredsMap >>= integer+ _ -> Nothing+ }++rulePowersOfTen :: Rule+rulePowersOfTen = Rule+ { name = "powers of tens"+ , pattern =+ [ regex "(ათასი?|მილიონი?|მილიარდი?)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) -> case Text.toLower match of+ "ათასი" -> double 1e3 >>= withGrain 3 >>= withMultipliable+ "ათას" -> double 1e3 >>= withGrain 3 >>= withMultipliable+ "მილიონი" -> double 1e6 >>= withGrain 6 >>= withMultipliable+ "მილიონ" -> double 1e6 >>= withGrain 6 >>= withMultipliable+ "მილიარდი" -> double 1e9 >>= withGrain 9 >>= withMultipliable+ "მილიარდ" -> double 1e9 >>= withGrain 9 >>= withMultipliable+ _ -> Nothing+ _ -> Nothing+ }++ruleCompositeTens :: Rule+ruleCompositeTens = Rule+ { name = "integer 21..99"+ , pattern =+ [ oneOf [20,40..90]+ , numberBetween 1 20+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = tens}:+ Token Numeral NumeralData{TNumeral.value = units}:+ _) -> double $ tens + units+ _ -> Nothing+ }++ruleCompositeHundreds :: Rule+ruleCompositeHundreds = Rule+ { name = "integer 100..999"+ , pattern =+ [ oneOf [100,200..900]+ , oneOf [20,40..90]+ , numberBetween 1 20+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = hundreds}:+ Token Numeral NumeralData{TNumeral.value = tens}:+ Token Numeral NumeralData{TNumeral.value = units}:+ _) -> double $ hundreds + tens + units+ _ -> Nothing+ }++ruleCompositeHundredsAndUnits :: Rule+ruleCompositeHundredsAndUnits = Rule+ { name = "integer 100..999"+ , pattern =+ [ oneOf [100,200..900]+ , numberBetween 1 20+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = hundreds}:+ Token Numeral NumeralData{TNumeral.value = units}:+ _) -> double $ hundreds + units+ _ -> Nothing+ }++ruleCompositeHundredsAndTens :: Rule+ruleCompositeHundredsAndTens = Rule+ { name = "integer 100..999"+ , pattern =+ [ oneOf [100,200..900]+ , oneOf [10,20..90]+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = hundreds}:+ Token Numeral NumeralData{TNumeral.value = tens}:+ _) -> double $ hundreds + tens+ _ -> Nothing+ }++ruleDotSpelledOut :: Rule+ruleDotSpelledOut = Rule+ { name = "one point 2"+ , pattern =+ [ dimension Numeral+ , regex "წერტილი|მთელი"+ , Predicate $ not . hasGrain+ ]+ , prod = \case+ (Token Numeral nd1:_:Token Numeral nd2:_) ->+ double $ TNumeral.value nd1 + decimalsToDouble (TNumeral.value nd2)+ _ -> Nothing+ }++ruleLeadingDotSpelledOut :: Rule+ruleLeadingDotSpelledOut = Rule+ { name = "point 77"+ , pattern =+ [ regex "წერტილი|მთელი"+ , Predicate $ not . hasGrain+ ]+ , prod = \case+ (_:Token Numeral nd:_) -> double . decimalsToDouble $ TNumeral.value nd+ _ -> Nothing+ }++ruleDecimals :: Rule+ruleDecimals = Rule+ { name = "decimal number"+ , pattern =+ [ regex "(\\d*\\.\\d+)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) -> parseDecimal True match+ _ -> Nothing+ }++ruleCommas :: Rule+ruleCommas = Rule+ { name = "comma-separated numbers"+ , pattern =+ [ regex "(\\d+(,\\d\\d\\d)+(\\.\\d+)?)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ parseDouble (Text.replace "," Text.empty match) >>= double+ _ -> Nothing+ }++ruleSuffixes :: Rule+ruleSuffixes = Rule+ { name = "suffixes (K,M,G))"+ , pattern =+ [ dimension Numeral+ , regex "(k|m|g)(?=[\\W$€¢£]|$)"+ ]+ , prod = \case+ (Token Numeral nd : Token RegexMatch (GroupMatch (match : _)):_) -> do+ x <- case Text.toLower match of+ "k" -> Just 1e3+ "m" -> Just 1e6+ "g" -> Just 1e9+ _ -> Nothing+ double $ TNumeral.value nd * x+ _ -> Nothing+ }++ruleNegative :: Rule+ruleNegative = Rule+ { name = "negative numbers"+ , pattern =+ [ regex "(-|მინუს|მინ)(?!\\s*-)"+ , Predicate isPositive+ ]+ , prod = \case+ (_:Token Numeral nd:_) -> double (TNumeral.value nd * (-1))+ _ -> Nothing+ }++ruleSum :: Rule+ruleSum = Rule+ { name = "intersect 2 numbers"+ , pattern =+ [ Predicate $ and . sequence [hasGrain, isPositive]+ , Predicate $ and . sequence [not . isMultipliable, isPositive]+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = val1, TNumeral.grain = Just g}:+ Token Numeral NumeralData{TNumeral.value = val2}:+ _) | (10 ** fromIntegral g) > val2 -> double $ val1 + val2+ _ -> Nothing+ }++ruleSumAnd :: Rule+ruleSumAnd = Rule+ { name = "intersect 2 numbers (with and)"+ , pattern =+ [ Predicate $ and . sequence [hasGrain, isPositive]+ , regex "და"+ , Predicate $ and . sequence [not . isMultipliable, isPositive]+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = val1, TNumeral.grain = Just g}:+ _:+ Token Numeral NumeralData{TNumeral.value = val2}:+ _) | (10 ** fromIntegral g) > val2 -> double $ val1 + val2+ _ -> Nothing+ }++ruleMultiply :: Rule+ruleMultiply = Rule+ { name = "compose by multiplication"+ , pattern =+ [ dimension Numeral+ , Predicate isMultipliable+ ]+ , prod = \case+ (token1:token2:_) -> multiply token1 token2+ _ -> Nothing+ }+ rules :: [Rule] rules =- [ ruleNumeral+ [ ruleToNineteen+ , ruleHundreds+ , ruleCompositeHundreds+ , ruleCompositeHundredsAndUnits+ , ruleCompositeHundredsAndTens+ , ruleTens+ , rulePowersOfTen+ , ruleCompositeTens+ , ruleDotSpelledOut+ , ruleLeadingDotSpelledOut+ , ruleDecimals+ , ruleCommas+ , ruleSuffixes+ , ruleNegative+ , ruleSum+ , ruleSumAnd+ , ruleMultiply ]
@@ -0,0 +1,107 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}++module Duckling.Numeral.KM.Corpus+ ( corpus+ ) where++import Data.String+import Prelude++import Duckling.Locale+import Duckling.Numeral.Types+import Duckling.Resolve+import Duckling.Testing.Types++context :: Context+context = testContext {locale = makeLocale KM Nothing}++corpus :: Corpus+corpus = (context, testOptions, allExamples)++allExamples :: [Example]+allExamples = concat+ [ examples (NumeralValue 0)+ [ "0"+ , "០"+ , "សូន្យ"+ ]+ , examples (NumeralValue 1)+ [ "1"+ , "១"+ , "មួយ"+ ]+ , examples (NumeralValue 2)+ [ "2"+ , "២"+ , "ពីរ"+ ]+ , examples (NumeralValue 3)+ [ "3"+ , "៣"+ , "បី"+ ]+ , examples (NumeralValue 4)+ [ "4"+ , "៤"+ , "បួន"+ ]+ , examples (NumeralValue 5)+ [ "5"+ , "៥"+ , "ប្រាំ"+ ]+ , examples (NumeralValue 6)+ [ "6"+ , "៦"+ , "ប្រាំមួយ"+ ]+ , examples (NumeralValue 7)+ [ "7"+ , "៧"+ , "ប្រាំពីរ"+ ]+ , examples (NumeralValue 8)+ [ "8"+ , "៨"+ , "ប្រាំបី"+ ]+ , examples (NumeralValue 9)+ [ "9"+ , "៩"+ , "ប្រាំបួន"+ ]+ , examples (NumeralValue 10)+ [ "ដប់"+ ]+ , examples (NumeralValue 11)+ [ "ដប់មួយ"+ ]+ , examples (NumeralValue 22)+ [ "ម្ភៃពីរ"+ ]+ , examples (NumeralValue 33)+ [ "សាមបី"+ ]+ , examples (NumeralValue 99)+ [ "កៅប្រាំបួន"+ ]+ , examples (NumeralValue 320)+ [ "បីរយម្ភៃ"+ ]+ , examples (NumeralValue 6078)+ [ "ប្រាំមួយពាន់ចិតប្រាំបី"+ ]+ , examples (NumeralValue 5689443)+ [ "ប្រាំលានប្រាំមួយសែនប្រាំបីម៉ឺនប្រាំបួនពាន់បួនរយសែបី"+ ]+ , examples (NumeralValue 800000000)+ [ "ប្រាំបីរយលាន"+ ]+ ]
@@ -0,0 +1,163 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE NoRebindableSyntax #-}++module Duckling.Numeral.KM.Rules+ ( rules+ ) where++import Data.HashMap.Strict (HashMap)+import Data.Maybe+import Data.String+import Data.Text (Text)+import Prelude+import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text++import Duckling.Dimensions.Types+import Duckling.Numeral.Helpers+import Duckling.Numeral.Types (NumeralData (..))+import Duckling.Regex.Types+import Duckling.Types+import qualified Duckling.Numeral.Types as TNumeral++ruleNumeralMap :: HashMap Text Integer+ruleNumeralMap = HashMap.fromList+ [ ( "០", 0 )+ , ( "១", 1 )+ , ( "២", 2 )+ , ( "៣", 3 )+ , ( "៤", 4 )+ , ( "៥", 5 )+ , ( "៦", 6 )+ , ( "៧", 7 )+ , ( "៨", 8 )+ , ( "៩", 9 )+ , ( "សូន្យ", 0 )+ , ( "មួយ", 1 )+ , ( "ពីរ", 2 )+ , ( "បី", 3 )+ , ( "បួន", 4 )+ , ( "ប្រាំ", 5 )+ , ( "ប្រាំមួយ", 6 )+ , ( "ប្រាំពីរ", 7 )+ , ( "ប្រាំបី", 8 )+ , ( "ប្រាំបួន", 9 )+ ]++ruleNumeral :: Rule+ruleNumeral = Rule+ { name = "integer (0..9)"+ -- ត្រូវដាក់ពាក្យ ប្រាំមួយ ប្រាំពីរ ប្រាំបី និងប្រាំបួន នៅខាងមុខលេខប្រាំ។ បើមិនដូច្នោះទេ វាមិនអាចផ្គូរផ្គងត្រូវទេ។+ , pattern =+ [ regex "(០|១|២|៣|៤|៥|៦|៧|៨|៩|ប្រាំបួន|ប្រាំបី|ប្រាំពីរ|ប្រាំមួយ|ប្រាំ|បួន|បី|ពីរ|មួយ|សូន្យ)"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup match ruleNumeralMap >>= integer+ _ -> Nothing+ }++ruleTensMap :: HashMap Text Integer+ruleTensMap = HashMap.fromList+ -- លេខ ១០ ២០ ៣០ ៤០ ៥០ ៦០ ៧០ ៨០ ៩០ អត់ត្រូវបានបញ្ចូលទេ ព្រោះមិនទាន់អាចរក+ -- វិធីដកលេខ ០ ចេញ នៅពេលផ្គំុជាមួយលេខដទៃ។+ -- ពពួក "សិប" ក៏មិនត្រូវបានបញ្ចូលដែរ ព្រោះមិនទាន់រកឃើញវិធីផ្គូរផ្គងត្រូវ។+ [ ( "ដប់", 10 )+ , ( "ម្ភៃ", 20 )+ , ( "សាម", 30 )+ , ( "សែ", 40 )+ , ( "ហា", 50 )+ , ( "ហុក", 60 )+ , ( "ចិត", 70 )+ , ( "ប៉ែត", 80 )+ , ( "កៅ", 90 )+ ]++ruleTens :: Rule+ruleTens = Rule+ { name = "integer (10..90)"+ , pattern =+ [ regex "(កៅ|ប៉ែត|ចិត|ហុក|ហា|សែ|សាម|ម្ភៃ|ដប់)"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup match ruleTensMap >>= integer+ _ -> Nothing+ }++ruleCompositeTens :: Rule+ruleCompositeTens = Rule+ { name = "integer (11..99)"+ , pattern =+ [ oneOf [10, 20 .. 90]+ , oneOf [1 .. 9]+ ]+ , prod = \tokens -> case tokens of+ (Token Numeral NumeralData{TNumeral.value = v1}:+ Token Numeral NumeralData{TNumeral.value = v2}:+ _) -> double $ v1 + v2+ _ -> Nothing+ }++rulePowersOfTen :: Rule+rulePowersOfTen = Rule+ { name = "powers of tens"+ , pattern =+ [ regex "(រយ|ពាន់|ម៉ឺន|សែន|លាន)"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) -> case match of+ "រយ" -> double 1e2 >>= withGrain 2 >>= withMultipliable+ "ពាន់" -> double 1e3 >>= withGrain 3 >>= withMultipliable+ "ម៉ឺន" -> double 1e4 >>= withGrain 4 >>= withMultipliable+ "សែន" -> double 1e5 >>= withGrain 5 >>= withMultipliable+ "លាន" -> double 1e6 >>= withGrain 6 >>= withMultipliable+ _ -> Nothing+ _ -> Nothing+ }++-- សម្រាប់ផ្គុំពីរលេខ ដែលចាប់ពីខ្ទង់រយទៅ និងខ្ទង់រាយ+ruleSum :: Rule+ruleSum = Rule+ { name = "intersect 2 numbers"+ , pattern =+ [ Predicate $ and . sequence [hasGrain, isPositive]+ , Predicate $ and . sequence [not . isMultipliable, isPositive]+ ]+ , prod = \tokens -> case tokens of+ (Token Numeral NumeralData{TNumeral.value = val1, TNumeral.grain = Just g}:+ Token Numeral NumeralData{TNumeral.value = val2}:+ _) | (10 ** fromIntegral g) > val2 -> double $ val1 + val2+ _ -> Nothing+ }++-- សម្រាប់លេខចាប់ពីខ្ទង់រយទៅ+ruleMultiply :: Rule+ruleMultiply = Rule+ { name = "compose by multiplication"+ , pattern =+ [ dimension Numeral+ , Predicate isMultipliable+ ]+ , prod = \tokens -> case tokens of+ (token1:token2:_) -> multiply token1 token2+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleNumeral+ , ruleTens+ , ruleCompositeTens+ , rulePowersOfTen+ , ruleSum+ , ruleMultiply+ ]
@@ -0,0 +1,67 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}++module Duckling.Numeral.KN.Corpus+ ( corpus+ ) where++import Data.String+import Prelude++import Duckling.Locale+import Duckling.Numeral.Types+import Duckling.Resolve+import Duckling.Testing.Types++corpus :: Corpus+corpus = (testContext {locale = makeLocale KN Nothing}, testOptions, allExamples)++allExamples :: [Example]+allExamples = concat+ [ examples (NumeralValue 0)+ [ "ಸೊನ್ನೆ"+ , "೦"+ ]+ , examples (NumeralValue 1)+ [ "ಒಂದು"+ , "೧"+ ]+ , examples (NumeralValue 2)+ [ "ಎರಡು"+ , "೨"+ ]+ , examples (NumeralValue 3)+ [ "ಮೂರು"+ , "೩"+ ]+ , examples (NumeralValue 4)+ [ "ನಾಲ್ಕು"+ , "೪"+ ]+ , examples (NumeralValue 5)+ [ "ಐದು"+ , "೫"+ ]+ , examples (NumeralValue 6)+ [ "ಆರು"+ , "೬"+ ]+ , examples (NumeralValue 7)+ [ "ಏಳು"+ , "೭"+ ]+ , examples (NumeralValue 8)+ [ "ಎಂಟು"+ , "೮"+ ]+ , examples (NumeralValue 9)+ [ "ಒಂಬತ್ತು"+ , "೯"+ ]+ ]
@@ -0,0 +1,90 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE NoRebindableSyntax #-}++module Duckling.Numeral.KN.Rules+ ( rules+ ) where++import Data.HashMap.Strict (HashMap)+import Data.Maybe+import Data.Text (Text)+import Prelude+import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text++import Duckling.Dimensions.Types+import Duckling.Numeral.Helpers+import Duckling.Regex.Types+import Duckling.Types++ankiMap :: HashMap Char Char+ankiMap = HashMap.fromList+ [ ('೦', '0')+ , ('೧', '1')+ , ('೨', '2')+ , ('೩', '3')+ , ('೪', '4')+ , ('೫', '5')+ , ('೬', '6')+ , ('೭', '7')+ , ('೮', '8')+ , ('೯', '9')+ ]++ankiToArab :: Char -> Char+ankiToArab c = HashMap.lookupDefault c c ankiMap++ruleAnki :: Rule+ruleAnki = Rule+ { name = "anki forms"+ , pattern =+ [ regex "([೦೧೨೩೪೫೬೭೮೯]{1,10})"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ toInteger <$> parseInt (Text.map ankiToArab match) >>= integer+ _ -> Nothing+ }++ruleNumeralMap :: [(Text, Integer)]+ruleNumeralMap =+ [ ("ಸೊನ್ನೆ", 0)+ , ("ಒಂದು", 1)+ , ("ಎರಡು", 2)+ , ("ಮೂರು", 3)+ , ("ನಾಲ್ಕು", 4)+ , ("ಐದು", 5)+ , ("ಆರು", 6)+ , ("ಏಳು", 7)+ , ("ಎಂಟು", 8)+ , ("ಒಂಬತ್ತು", 9)+ ]++ruleNumerals :: [Rule]+ruleNumerals =+ map constructRule ruleNumeralMap+ where+ constructRule :: (Text, Integer) -> Rule+ constructRule (s, i) = Rule+ { name = "number: " `mappend` s+ , pattern =+ [ regex $ Text.unpack s+ ]+ , prod = const $ integer i+ }+++rules :: [Rule]+rules =+ [ ruleAnki+ ]+ ++ ruleNumerals
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -0,0 +1,89 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}++module Duckling.Numeral.LO.Corpus+ ( corpus ) where++import Data.String+import Prelude++import Duckling.Locale+import Duckling.Numeral.Types+import Duckling.Resolve+import Duckling.Testing.Types++corpus :: Corpus+corpus = (testContext {locale = makeLocale LO Nothing}, testOptions, allExamples)++allExamples :: [Example]+allExamples = concat+ [ examples (NumeralValue 0)+ [ "ສູນ"+ ]+ , examples (NumeralValue 1)+ [ "ໜຶ່ງ"+ ]+ , examples (NumeralValue 2)+ [ "ສອງ"+ ]+ , examples (NumeralValue 3)+ [ "ສາມ"+ ]+ , examples (NumeralValue 4)+ [ "ສີ່"+ ]+ , examples (NumeralValue 5)+ [ "ຫ້າ"+ ]+ , examples (NumeralValue 6)+ [ "ຫົກ"+ ]+ , examples (NumeralValue 7)+ [ "ເຈັດ"+ ]+ , examples (NumeralValue 8)+ [ "ແປດ"+ ]+ , examples (NumeralValue 9)+ [ "ເກົ້າ"+ ]+ , examples (NumeralValue 11)+ [ "ສິບເອັດ"+ ]+ , examples (NumeralValue 15)+ [ "ສິບຫ້າ"+ ]+ , examples (NumeralValue 17)+ [ "ສິບເຈັດ"+ ]+ , examples (NumeralValue 22)+ [ "ຊາວສອງ"+ ]+ , examples (NumeralValue 24)+ [ "ຊາວສີ່"+ ]+ , examples (NumeralValue 26)+ [ "ຊາວຫົກ"+ ]+ , examples (NumeralValue 28)+ [ "ຊາວແປດ"+ ]+ , examples (NumeralValue 34)+ [ "ສາມສິບສີ່"+ ]+ , examples (NumeralValue 10)+ [ "ສິບ"+ ]+ , examples (NumeralValue 20)+ [ "ຊາວ"+ ]+ , examples (NumeralValue 50)+ [ "ຫ້າສິບ"+ ]+ ]
@@ -0,0 +1,153 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE NoRebindableSyntax #-}++module Duckling.Numeral.LO.Rules+ ( rules+ ) where++import Data.HashMap.Strict (HashMap)+import Data.Maybe+import Data.String+import Data.Text (Text)+import Prelude+import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text++import Duckling.Dimensions.Types+import Duckling.Numeral.Helpers+import Duckling.Numeral.Types (NumeralData (..))+import Duckling.Regex.Types+import Duckling.Types+import qualified Duckling.Numeral.Types as TNumeral++ruleNumeralMap :: HashMap Text Integer+ruleNumeralMap = HashMap.fromList+ [ ( "ສູນ", 0 )+ , ( "ໜຶ່ງ", 1 )+ , ( "ສອງ", 2 )+ , ( "ສາມ", 3 )+ , ( "ສີ່", 4 )+ , ( "ຫ້າ", 5)+ , ( "ຫົກ", 6)+ , ( "ເຈັດ", 7)+ , ( "ແປດ", 8)+ , ( "ເກົ້າ", 9)+ , ( "ສິບ", 10)+ ]++ruleNumeral :: Rule+ruleNumeral = Rule+ { name = "number (0..10)"+ , pattern =+ [ regex "(ສູນ|ໜຶ່ງ|ສອງ|ສາມ|ສີ່|ຫ້າ|ຫົກ|ເຈັດ|ແປດ|ເກົ້າ|ສິບ)"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup (Text.toLower match) ruleNumeralMap >>= integer+ _ -> Nothing+ }++elevenToNineteenMap :: HashMap Text Integer+elevenToNineteenMap = HashMap.fromList+ [ ( "ສິບເອັດ", 11 )+ , ( "ສິບສອງ", 12 )+ , ( "ສິບສາມ", 13 )+ , ( "ສິບສີ່", 14 )+ , ( "ສິບຫ້າ", 15 )+ , ( "ສິບຫົກ", 16 )+ , ( "ສິບເຈັດ", 17 )+ , ( "ສິບແປດ", 18 )+ , ( "ສິບເກົ້າ", 19 )+ ]++ruleElevenToNineteen :: Rule+ruleElevenToNineteen = Rule+ { name = "number (11..19)"+ , pattern =+ [ regex "(ສິບເອັດ|ສິບສອງ|ສິບສາມ|ສິບສີ່|ສິບຫ້າ|ສິບຫົກ|ສິບເຈັດ|ສິບແປດ|ສິບເກົ້າ)"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup (Text.toLower match) elevenToNineteenMap >>= integer+ _ -> Nothing+ }++twentyoneToTwentynineMap :: HashMap Text Integer+twentyoneToTwentynineMap = HashMap.fromList+ [ ( "ຊາວເອັດ", 21 )+ , ( "ຊາວສອງ", 22 )+ , ( "ຊາວສາມ", 23 )+ , ( "ຊາວສີ່", 24 )+ , ( "ຊາວຫ້າ", 25 )+ , ( "ຊາວຫົກ", 26 )+ , ( "ຊາວເຈັດ", 27 )+ , ( "ຊາວແປດ", 28 )+ , ( "ຊາວເກົ້າ", 29 )+ ]++ruleTwentyoneToTwentynine :: Rule+ruleTwentyoneToTwentynine = Rule+ { name = "number (21..29)"+ , pattern =+ [ regex "(ຊາວເອັດ|ຊາວສອງ|ຊາວສາມ|ຊາວສີ່|ຊາວຫ້າ|ຊາວຫົກ|ຊາວເຈັດ|ຊາວແປດ|ຊາວເກົ້າ)"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup (Text.toLower match) twentyoneToTwentynineMap >>= integer+ _ -> Nothing+ }++tensMap :: HashMap Text Integer+tensMap = HashMap.fromList+ [ ( "ຊາວ", 20 )+ , ( "ສາມສິບ", 30 )+ , ( "ສິບສີ່", 40 )+ , ( "ຫ້າສິບ", 50 )+ , ( "ຫົກສິບ", 60 )+ , ( "ເຈັດສິບ", 70 )+ , ( "ແປດສິບ", 80 )+ , ( "ເກົ້າສິບ", 90 )+ ]++ruleTens :: Rule+ruleTens = Rule+ { name = "integer (20,30..90)"+ , pattern =+ [ regex "(ຊາວ|ສາມສິບ|ສິບສີ່|ຫ້າສິບ|ຫົກສິບ|ເຈັດສິບ|ແປດສິບ|ເກົ້າສິບ)"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup (Text.toLower match) tensMap >>= integer+ _ -> Nothing+ }++ruleCompositeTens :: Rule+ruleCompositeTens = Rule+ { name = "integer ([3-9][1-9])"+ , pattern =+ [ regex "(ສາມສິບ|ສິບສີ່|ຫ້າສິບ|ຫົກສິບ|ເຈັດສິບ|ແປດສິບ|ເກົ້າສິບ)(ໜຶ່ງ|ສອງ|ສາມ|ສີ່|ຫ້າ|ຫົກ|ເຈັດ|ແປດ|ເກົ້າ)"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (m1:m2:_)):_) -> do+ v1 <- HashMap.lookup (Text.toLower m1) tensMap+ v2 <- HashMap.lookup (Text.toLower m2) ruleNumeralMap+ integer $ v1 + v2+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleNumeral+ , ruleElevenToNineteen+ , ruleTwentyoneToTwentynine+ , ruleTens+ , ruleCompositeTens+ ]
@@ -0,0 +1,100 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}++module Duckling.Numeral.ML.Corpus+ ( corpus+ ) where++import Data.String+import Prelude++import Duckling.Locale+import Duckling.Numeral.Types+import Duckling.Resolve+import Duckling.Testing.Types+++context :: Context+context = testContext {locale = makeLocale ML Nothing}++corpus :: Corpus+corpus = (context, testOptions, allExamples)++allExamples :: [Example]+allExamples = concat+ [ examples (NumeralValue 0)+ [ "പൂജ്യം"+ ]+ , examples (NumeralValue 1)+ [ "ഒന്ന്"+ ]+ , examples (NumeralValue 2)+ [ "രണ്ട്"+ ]+ , examples (NumeralValue 3)+ [ "മുന്ന്"+ ]+ , examples (NumeralValue 4)+ [ "നാല്"+ ]+ , examples (NumeralValue 5)+ [ "അഞ്ച്"+ ]+ , examples (NumeralValue 6)+ [ "ആറ്"+ ]+ , examples (NumeralValue 7)+ [ "ഏഴ്"+ ]+ , examples (NumeralValue 8)+ [ "എട്ട്"+ ]+ , examples (NumeralValue 9)+ [ "ഒൻപത്"+ ]+ , examples (NumeralValue 10)+ [ "പത്ത്"+ ]+ , examples (NumeralValue 11)+ [ "പതിനൊന്ന്"+ ]+ , examples (NumeralValue 12)+ [ "പന്ത്രണ്ട്"+ ]+ , examples (NumeralValue 13)+ [ "പതിമൂന്ന്"+ ]+ , examples (NumeralValue 19)+ [ "പത്തൊമ്പത്"+ ]+ , examples (NumeralValue 20)+ [ "ഇരുപത്"+ ]+ , examples (NumeralValue 21)+ [ "ഇരുപത്തിഒന്ന്"+ ]+ , examples (NumeralValue 22)+ [ "ഇരുപത്തിരണ്ട്"+ ]+ , examples (NumeralValue 26)+ [ "ഇരുപത്തിആറ്"+ ]+ , examples (NumeralValue 30)+ [ "മുപ്പത്"+ ]+ , examples (NumeralValue 33)+ [ "മുപ്പത്തിമുന്ന്"+ ]+ , examples (NumeralValue 50)+ [ "അമ്പത്"+ ]+ , examples (NumeralValue 51)+ [ "അമ്പത്തിഒന്ന്"+ ]+ ]
@@ -0,0 +1,138 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE NoRebindableSyntax #-}+{-# LANGUAGE LambdaCase #-}++module Duckling.Numeral.ML.Rules+ ( rules+ ) where++import Data.HashMap.Strict (HashMap)+import Data.Maybe+import Data.String+import Data.Text (Text)+import Prelude+import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text++import Duckling.Dimensions.Types+import Duckling.Numeral.Helpers+import Duckling.Numeral.Types (NumeralData (..))+import Duckling.Regex.Types+import Duckling.Types+import qualified Duckling.Numeral.Types as TNumeral+++zeroToNineMap :: HashMap Text Integer+zeroToNineMap = HashMap.fromList+ [ ( "പൂജ്യം", 0 )+ , ( "ഒന്ന്", 1 )+ , ( "രണ്ട്", 2 )+ , ( "മുന്ന്", 3 )+ , ( "നാല്", 4 )+ , ( "അഞ്ച്", 5 )+ , ( "ആറ്", 6 )+ , ( "ഏഴ്", 7 )+ , ( "എട്ട്", 8 )+ , ( "ഒൻപത്", 9 )+ ]++ruleZeroToNine :: Rule+ruleZeroToNine = Rule+ { name = "integer (0..9)"+ , pattern =+ [ regex "(പൂജ്യം|ഒന്ന്|രണ്ട്|മുന്ന്|നാല്|അഞ്ച്|ആറ്|ഏഴ്|എട്ട്|ഒൻപത്)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup (Text.toLower match) zeroToNineMap >>= integer+ _ -> Nothing+ }++tenToNineteenMap :: HashMap Text Integer+tenToNineteenMap = HashMap.fromList+ [ ( "പത്ത്", 10 )+ , ( "പതിനൊന്ന്", 11 )+ , ( "പന്ത്രണ്ട്", 12 )+ , ( "പതിമൂന്ന്", 13 )+ , ( "പതിനാല്", 14 )+ , ( "പതിനഞ്ച്", 15 )+ , ( "പതിനാറ്", 16 )+ , ( "പതിനേഴ്", 17 )+ , ( "പതിനെട്ട്", 18 )+ , ( "പത്തൊമ്പത്", 19 )+ ]++ruleTenToNineteen :: Rule+ruleTenToNineteen = Rule+ { name = "integer (10..19)"+ , pattern =+ [+ regex "(പത്ത്|പതിനൊന്ന്|പന്ത്രണ്ട്|പതിമൂന്ന്|പതിനാല്|പതിനഞ്ച്|പതിനാറ്|പതിനേഴ്|പതിനെട്ട്|പത്തൊമ്പത്)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup (Text.toLower match) tenToNineteenMap >>= integer+ _ -> Nothing+ }++tensMap :: HashMap Text Integer+tensMap = HashMap.fromList+ [ ( "ഇരുപത്", 20 )+ , ( "ഇരുപത്തി", 20 )+ , ( "മുപ്പത്", 30 )+ , ( "മുപ്പത്തി", 30 )+ , ( "നാല്പത്", 40 )+ , ( "നാല്പത്തി", 40 )+ , ( "അമ്പത്", 50 )+ , ( "അമ്പത്തി", 50 )+ , ( "അറുപത്", 60 )+ , ( "അറുപത്തി", 60 )+ , ( "എഴുപത്", 70 )+ , ( "എഴുപത്തി", 70 )+ , ( "എൺപത്", 80 )+ , ( "എൺപത്തി", 80 )+ , ( "തൊണ്ണൂറ്", 90 )+ , ( "തൊണ്ണൂറ്റി", 90 )+ ]++ruleTens :: Rule+ruleTens = Rule+ { name = "integer (20..90)"+ , pattern =+ [ regex "(ഇരുപത്|മുപ്പത്|നാല്പത്|അമ്പത്|അറുപത്|എഴുപത്|എൺപത്|തൊണ്ണൂറ്)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup (Text.toLower match) tensMap >>= integer+ _ -> Nothing+ }++ruleCompositeTens :: Rule+ruleCompositeTens = Rule+ { name = "integer ([2-9][1-9])"+ , pattern =+ [ regex "(ഇരുപത്തി|മുപ്പത്തി|നാല്പത്തി|അമ്പത്തി|അറുപത്തി|എഴുപത്തി|എൺപത്തി|തൊണ്ണൂറ്റി)(ഒന്ന്|രണ്ട്|മുന്ന്|നാല്|അഞ്ച്|ആറ്|ഏഴ്|എട്ട്|ഒൻപത്)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (m1:m2:_)):_) -> do+ v1 <- HashMap.lookup (Text.toLower m1) tensMap+ v2 <- HashMap.lookup (Text.toLower m2) zeroToNineMap+ integer $ v1 + v2+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleZeroToNine+ , ruleTenToNineteen+ , ruleCompositeTens+ , ruleTens+ ]
@@ -0,0 +1,104 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}++module Duckling.Numeral.MN.Corpus+ ( corpus+ ) where++import Data.String+import Prelude++import Duckling.Locale+import Duckling.Numeral.Types+import Duckling.Resolve+import Duckling.Testing.Types++context :: Context+context = testContext {locale = makeLocale MN Nothing}++corpus :: Corpus+corpus = (context, testOptions, allExamples)++allExamples :: [Example]+allExamples = concat+ [ examples (NumeralValue 0)+ [ "0"+ , "нойл"+ , "тэг"+ ]+ , examples (NumeralValue 1)+ [ "1"+ , "нэг"+ ]+ , examples (NumeralValue 2)+ [ "хоёр"+ ]+ , examples (NumeralValue 3)+ [ "гурав"+ ]+ , examples (NumeralValue 4)+ [ "дөрөв"+ ]+ , examples (NumeralValue 5)+ [ "тав"+ ]+ , examples (NumeralValue 6)+ [ "зургаа"+ ]+ , examples (NumeralValue 7)+ [ "долоо"+ ]+ , examples (NumeralValue 8)+ [ "найм"+ ]+ , examples (NumeralValue 9)+ [ "ес"+ ]+ , examples (NumeralValue 11)+ [ "арван нэг"+ ]+ , examples (NumeralValue 15)+ [ "арван тав"+ ]+ , examples (NumeralValue 17)+ [ "арван долоо"+ ]+ , examples (NumeralValue 20)+ [ "20"+ , "хорь"+ ]+ , examples (NumeralValue 22)+ [ "хорин хоёр"+ ]+ , examples (NumeralValue 24)+ [ "24"+ , "хорин дөрөв"+ ]+ , examples (NumeralValue 26)+ [ "хорин зургаа"+ ]+ , examples (NumeralValue 28)+ [ "хорин найм"+ ]+ , examples (NumeralValue 10)+ [ "арав"+ ]+ , examples (NumeralValue 20)+ [ "хорь"+ ]+ , examples (NumeralValue 50)+ [ "тавь"+ ]+ , examples (NumeralValue 34)+ [ "гучин дөрөв"+ ]+ , examples (NumeralValue 99)+ [ "ерэн ес"+ ]+ ]
@@ -0,0 +1,319 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE NoRebindableSyntax #-}+{-# LANGUAGE OverloadedStrings #-}++module Duckling.Numeral.MN.Rules+ ( rules+ ) where++import Data.HashMap.Strict (HashMap)+import Data.Maybe+import Data.Text (Text)+import Prelude+import Data.String+import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text++import Duckling.Dimensions.Types+import Duckling.Numeral.Helpers+import Duckling.Numeral.Types (NumeralData (..))+import Duckling.Regex.Types+import Duckling.Types+import qualified Duckling.Numeral.Types as TNumeral++ruleNumeralsPrefixWithNegativeOrMinus :: Rule+ruleNumeralsPrefixWithNegativeOrMinus = Rule+ { name = "numbers prefix with -, negative or minus"+ , pattern =+ [ regex "-|хасах|сөрөг"+ , Predicate isPositive+ ]+ , prod = \tokens -> case tokens of+ (_:Token Numeral NumeralData{TNumeral.value = v}:_) ->+ double $ v * (- 1)+ _ -> Nothing+ }++ruleFew :: Rule+ruleFew = Rule+ { name = "few"+ , pattern =+ [ regex "хэдхэн"+ ]+ , prod = \_ -> integer 3+ }++ruleTen :: Rule+ruleTen = Rule+ { name = "ten"+ , pattern =+ [ regex "арав"+ ]+ , prod = \_ -> integer 10 >>= withGrain 1+ }++ruleDecimalWithThousandsSeparator :: Rule+ruleDecimalWithThousandsSeparator = Rule+ { name = "decimal with thousands separator"+ , pattern =+ [ regex "(\\d+(\\.\\d\\d\\d)+\\,\\d+)"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):+ _) -> let fmt = Text.replace "," "." $ Text.replace "." Text.empty match+ in parseDouble fmt >>= double+ _ -> Nothing+ }+++-- TODO: Single-word composition (#110)+ruleInteger3 :: Rule+ruleInteger3 = Rule+ { name = "integer ([2-9][1-9])"+ , pattern =+ [ regex "(хорин|гучин|дөчин|тавин|жаран|далан|наян|ерэн) ?(нэг|хоёр|гурав|дөрөв|тав|зургаа|долоо|найм|ес)"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (m1:m2:_)):_) -> do+ v1 <- case Text.toLower m1 of+ "хорин" -> Just 20+ "гучин" -> Just 30+ "дөчин" -> Just 40+ "тавин" -> Just 50+ "жаран" -> Just 60+ "далан" -> Just 70+ "наян" -> Just 80+ "ерэн" -> Just 90+ _ -> Nothing+ v2 <- case Text.toLower m2 of+ "нэг" -> Just 1+ "хоёр" -> Just 2+ "гурав" -> Just 3+ "дөрөв" -> Just 4+ "тав" -> Just 5+ "зургаа" -> Just 6+ "долоо" -> Just 7+ "найм" -> Just 8+ "ес" -> Just 9+ _ -> Nothing+ integer $ v1 + v2+ _ -> Nothing+ }++ruleNumeralsUnd :: Rule+ruleNumeralsUnd = Rule+ { name = "numbers und"+ , pattern =+ [ oneOf [20, 30 .. 90]+ , numberBetween 1 10+ ]+ , prod = \tokens -> case tokens of+ (Token Numeral NumeralData{TNumeral.value = v1}:+ Token Numeral NumeralData{TNumeral.value = v2}:+ _) -> double $ v1 + v2+ _ -> Nothing+ }++ruleMultiply :: Rule+ruleMultiply = Rule+ { name = "compose by multiplication"+ , pattern =+ [ dimension Numeral+ , Predicate isMultipliable+ ]+ , prod = \tokens -> case tokens of+ (token1:token2:_) -> multiply token1 token2+ _ -> Nothing+ }++ruleIntersect :: Rule+ruleIntersect = Rule+ { name = "intersect"+ , pattern =+ [ Predicate hasGrain+ , Predicate $ and . sequence [not . isMultipliable, isPositive]+ ]+ , prod = \tokens -> case tokens of+ (Token Numeral NumeralData{TNumeral.value = val1, TNumeral.grain = Just g}:+ Token Numeral NumeralData{TNumeral.value = val2}:+ _) | (10 ** fromIntegral g) > val2 -> double $ val1 + val2+ _ -> Nothing+ }++ruleNumeralsSuffixesKMG :: Rule+ruleNumeralsSuffixesKMG = Rule+ { name = "numbers suffixes (K, M, G)"+ , pattern =+ [ dimension Numeral+ , regex "([kmg])(?=[\\W\\$€]|$)"+ ]+ , prod = \tokens -> case tokens of+ (Token Numeral NumeralData{TNumeral.value = v}:+ Token RegexMatch (GroupMatch (match:_)):+ _) -> case Text.toLower match of+ "k" -> double $ v * 1e3+ "m" -> double $ v * 1e6+ "g" -> double $ v * 1e9+ _ -> Nothing+ _ -> Nothing+ }++ruleCouple :: Rule+ruleCouple = Rule+ { name = "couple"+ , pattern =+ [ regex "хос"+ ]+ , prod = \_ -> integer 2+ }+++rulePowersOfTen :: Rule+rulePowersOfTen = Rule+ { name = "powers of tens"+ , pattern =+ [ regex "(зуу?|мянга?|сая?)"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) -> case Text.toLower match of+ "зуу" -> double 1e2 >>= withGrain 2 >>= withMultipliable+ "зуун" -> double 1e2 >>= withGrain 2 >>= withMultipliable+ "мянга" -> double 1e3 >>= withGrain 3 >>= withMultipliable+ "мянган" -> double 1e3 >>= withGrain 3 >>= withMultipliable+ "сая" -> double 1e6 >>= withGrain 6 >>= withMultipliable+ "саяын" -> double 1e6 >>= withGrain 6 >>= withMultipliable+ _ -> Nothing+ _ -> Nothing+ }++zeroNineteenMap :: HashMap Text Integer+zeroNineteenMap = HashMap.fromList+ [ ("нуль", 0)+ , ("тэг", 0)+ , ("нойл", 0)+ , ("нэг", 1)+ , ("ганц", 1)+ , ("хоёр", 2)+ , ("гурав", 3)+ , ("дөрөв", 4)+ , ("тав", 5)+ , ("зургаа", 6)+ , ("долоо", 7)+ , ("найм", 8)+ , ("ес", 9)+ , ("арван", 10)+ , ("арав", 10)+ , ("арван нэг", 11)+ , ("арван хоёр", 12)+ , ("арван гурав", 13)+ , ("арван дөрөв", 14)+ , ("арван тав", 15)+ , ("арван зургаа", 16)+ , ("арван долоо", 17)+ , ("арван найм", 18)+ , ("арван ес", 19)+ ]++-- TODO: Single-word composition (#110)+ruleZeroToNineteen :: Rule+ruleZeroToNineteen = Rule+ { name = "integer (0..19)"+ , pattern =+ [ regex "(нуль|тэг|нойл|нэг|ганц|хоёр|гурав|дөрөв|тав|зургаа|долоо|найм|ес|арван нэг|арван хоёр|арван гурав|арван дөрөв|арван тав|арван зургаа|арван долоо|арван найм|арван ес|арав|арван)"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup (Text.toLower match) zeroNineteenMap >>= integer+ _ -> Nothing+ }++tensMap :: HashMap Text Integer+tensMap = HashMap.fromList+ [ ( "хорь" , 20 )+ , ( "гуч", 30 )+ , ( "дөч" , 40 )+ , ( "тавь" , 50 )+ , ( "жар" , 60 )+ , ( "дал" , 70 )+ , ( "ная" , 80 )+ , ( "ер" , 90 )+ ]++-- TODO: Single-word composition (#110)+ruleInteger2 :: Rule+ruleInteger2 = Rule+ { name = "integer (20..90)"+ , pattern =+ [ regex "(хорь|гуч|дөч|тавь|жар|дал|ная|ер)"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup (Text.toLower match) tensMap >>= integer+ _ -> Nothing+ }++ruleNumeralDotNumeral :: Rule+ruleNumeralDotNumeral = Rule+ { name = "number dot number"+ , pattern =+ [ dimension Numeral+ , regex "цэг"+ , Predicate $ not . hasGrain+ ]+ , prod = \tokens -> case tokens of+ (Token Numeral NumeralData{TNumeral.value = v1}:+ _:+ Token Numeral NumeralData{TNumeral.value = v2}:+ _) -> double $ v1 + decimalsToDouble v2+ _ -> Nothing+ }++ruleDecimalNumeral :: Rule+ruleDecimalNumeral = Rule+ { name = "decimal number"+ , pattern =+ [ regex "(\\d*\\.\\d+)"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) -> parseDecimal True match+ _ -> Nothing+ }++ruleIntegerWithThousandsSeparator :: Rule+ruleIntegerWithThousandsSeparator = Rule+ { name = "integer with thousands separator ."+ , pattern =+ [ regex "(\\d{1,3}(\\.\\d\\d\\d){1,5})"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ parseDouble (Text.replace "." Text.empty match) >>= double+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleCouple+ , ruleDecimalNumeral+ , ruleDecimalWithThousandsSeparator+ , ruleFew+ , ruleInteger2+ , ruleInteger3+ , ruleIntegerWithThousandsSeparator+ , ruleIntersect+ , ruleMultiply+ , ruleNumeralDotNumeral+ , ruleNumeralsPrefixWithNegativeOrMinus+ , ruleNumeralsSuffixesKMG+ , ruleNumeralsUnd+ , rulePowersOfTen+ , ruleTen+ , ruleZeroToNineteen+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -90,12 +89,14 @@ , "100000" , "100K" , "100k"+ , "100 000" ] , examples (NumeralValue 3000000) [ "3M" , "3000K" , "3000000" , "3.000.000"+ , "3 000 000" ] , examples (NumeralValue 1200000) [ "1.200.000"@@ -103,6 +104,7 @@ , "1,2M" , "1200K" , ",0012G"+ , "1 200 000" ] , examples (NumeralValue (-1200000)) [ "- 1.200.000"@@ -112,15 +114,313 @@ , "-1,2M" , "-1200K" , "-,0012G"+ , "-1 200 000" ] , examples (NumeralValue 5000) [ "5 tusen" , "fem tusen"+ , "5 000" ] , examples (NumeralValue 100) [ "hundre" ] , examples (NumeralValue 5020) [ "fem tusen og tjue"+ ]+ , examples (NumeralValue 1e9)+ [ "en milliard"+ ]+ , examples (NumeralValue 1e12)+ [ "en billion"+ ]+ , examples (NumeralValue 1e15)+ [ "en billiard"+ ]+ , examples (NumeralValue 1e18)+ [ "en trillion"+ ]+ , examples (NumeralValue 1e21)+ [ "en trilliard"+ ]+ , examples (NumeralValue 1e24)+ [ "en kvadrillion"+ ]+ , examples (NumeralValue 1e27)+ [ "en kvadrilliard"+ ]+ , examples (NumeralValue 6e10)+ [ "seksti milliarder"+ , "60 milliarder"+ ]+ , examples (NumeralValue 3e12)+ [ "tre billioner"+ , "3 billioner"+ ]+ , examples (NumeralValue 4e17)+ [ "fire hundre billiarder"+ , "400 billiarder"+ ]+ , examples (NumeralValue 2e18)+ [ "to trillioner"+ , "2 trillioner"+ ]+ , examples (NumeralValue 1.8e22)+ [ "atten trilliarder"+ , "18 trilliarder"+ ]+ , examples (NumeralValue 1.8e22)+ [ "atten trilliarder"+ , "18 trilliarder"+ ]+ , examples (NumeralValue 4.11e26)+ [ "fire hundre og elleve kvadrillioner"+ , "411 kvadrillioner"+ ]+ , examples (NumeralValue 9e27)+ [ "ni kvadrilliarder"+ , "9 kvadrilliarder"+ ]+ , examples (NumeralValue 21)+ [ "tjueen"+ , "tjueén"+ ]+ , examples (NumeralValue 22)+ [ "tjueto"+ ]+ , examples (NumeralValue 23)+ [ "tjuetre"+ ]+ , examples (NumeralValue 24)+ [ "tjuefire"+ ]+ , examples (NumeralValue 25)+ [ "tjuefem"+ ]+ , examples (NumeralValue 26)+ [ "tjueseks"+ ]+ , examples (NumeralValue 27)+ [ "tjuesju"+ , "tjuesyv"+ ]+ , examples (NumeralValue 28)+ [ "tjueåtte"+ ]+ , examples (NumeralValue 29)+ [ "tjueni"+ ]+ , examples (NumeralValue 31)+ [ "trettien"+ , "trettién"+ ]+ , examples (NumeralValue 32)+ [ "trettito"+ ]+ , examples (NumeralValue 33)+ [ "trettitre"+ ]+ , examples (NumeralValue 34)+ [ "trettifire"+ ]+ , examples (NumeralValue 35)+ [ "trettifem"+ ]+ , examples (NumeralValue 36)+ [ "trettiseks"+ ]+ , examples (NumeralValue 37)+ [ "trettisju"+ , "trettisyv"+ ]+ , examples (NumeralValue 38)+ [ "trettiåtte"+ ]+ , examples (NumeralValue 39)+ [ "trettini"+ ]+ , examples (NumeralValue 41)+ [ "førtien"+ , "førtién"+ ]+ , examples (NumeralValue 42)+ [ "førtito"+ ]+ , examples (NumeralValue 43)+ [ "førtitre"+ ]+ , examples (NumeralValue 44)+ [ "førtifire"+ ]+ , examples (NumeralValue 45)+ [ "førtifem"+ ]+ , examples (NumeralValue 46)+ [ "førtiseks"+ ]+ , examples (NumeralValue 47)+ [ "førtisju"+ , "førtisyv"+ ]+ , examples (NumeralValue 48)+ [ "førtiåtte"+ ]+ , examples (NumeralValue 49)+ [ "førtini"+ ]+ , examples (NumeralValue 51)+ [ "femtien"+ , "femtién"+ ]+ , examples (NumeralValue 52)+ [ "femtito"+ ]+ , examples (NumeralValue 53)+ [ "femtitre"+ ]+ , examples (NumeralValue 54)+ [ "femtifire"+ ]+ , examples (NumeralValue 55)+ [ "femtifem"+ ]+ , examples (NumeralValue 56)+ [ "femtiseks"+ ]+ , examples (NumeralValue 57)+ [ "femtisju"+ , "femtisyv"+ ]+ , examples (NumeralValue 58)+ [ "femtiåtte"+ ]+ , examples (NumeralValue 59)+ [ "femtini"+ ]+ , examples (NumeralValue 61)+ [ "sekstien"+ , "sekstién"+ ]+ , examples (NumeralValue 62)+ [ "sekstito"+ ]+ , examples (NumeralValue 63)+ [ "sekstitre"+ ]+ , examples (NumeralValue 64)+ [ "sekstifire"+ ]+ , examples (NumeralValue 65)+ [ "sekstifem"+ ]+ , examples (NumeralValue 66)+ [ "sekstiseks"+ ]+ , examples (NumeralValue 67)+ [ "sekstisju"+ , "sekstisyv"+ ]+ , examples (NumeralValue 68)+ [ "sekstiåtte"+ ]+ , examples (NumeralValue 69)+ [ "sekstini"+ ]+ , examples (NumeralValue 71)+ [ "syttien"+ , "søttien"+ , "søttién"+ , "søttién"+ ]+ , examples (NumeralValue 72)+ [ "syttito"+ , "søttito"+ ]+ , examples (NumeralValue 73)+ [ "syttitre"+ , "søttitre"+ ]+ , examples (NumeralValue 74)+ [ "syttifire"+ , "søttifire"+ ]+ , examples (NumeralValue 75)+ [ "syttifem"+ , "søttifem"+ ]+ , examples (NumeralValue 76)+ [ "syttiseks"+ , "søttiseks"+ ]+ , examples (NumeralValue 77)+ [ "syttisju"+ , "syttisju"+ , "søttisyv"+ , "søttisyv"+ ]+ , examples (NumeralValue 78)+ [ "søttiåtte"+ , "søttiåtte"+ ]+ , examples (NumeralValue 79)+ [ "søttini"+ , "søttini"+ ]+ , examples (NumeralValue 81)+ [ "åttien"+ , "åttién"+ ]+ , examples (NumeralValue 82)+ [ "åttito"+ ]+ , examples (NumeralValue 83)+ [ "åttitre"+ ]+ , examples (NumeralValue 84)+ [ "åttifire"+ ]+ , examples (NumeralValue 85)+ [ "åttifem"+ ]+ , examples (NumeralValue 86)+ [ "åttiseks"+ ]+ , examples (NumeralValue 87)+ [ "åttisju"+ , "åttisyv"+ ]+ , examples (NumeralValue 88)+ [ "åttiåtte"+ ]+ , examples (NumeralValue 89)+ [ "åttini"+ ]+ , examples (NumeralValue 91)+ [ "nittien"+ , "nittién"+ ]+ , examples (NumeralValue 92)+ [ "nittito"+ ]+ , examples (NumeralValue 93)+ [ "nittitre"+ ]+ , examples (NumeralValue 94)+ [ "nittifire"+ ]+ , examples (NumeralValue 95)+ [ "nittifem"+ ]+ , examples (NumeralValue 96)+ [ "nittiseks"+ ]+ , examples (NumeralValue 97)+ [ "nittisju"+ , "nittisyv"+ ]+ , examples (NumeralValue 98)+ [ "nittiåtte"+ ]+ , examples (NumeralValue 99)+ [ "nittini" ] ]
@@ -2,11 +2,11 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} module Duckling.Numeral.NB.Rules@@ -36,7 +36,7 @@ , regex "og" , Predicate $ and . sequence [not . isMultipliable, isPositive] ]- , prod = \tokens -> case tokens of+ , prod = \case (Token Numeral NumeralData{TNumeral.value = val1, TNumeral.grain = Just g}: _: Token Numeral NumeralData{TNumeral.value = val2}:@@ -51,7 +51,7 @@ [ regex "-|minus|negativ" , Predicate isPositive ]- , prod = \tokens -> case tokens of+ , prod = \case (_:Token Numeral nd:_) -> double (TNumeral.value nd * (-1)) _ -> Nothing }@@ -71,7 +71,7 @@ , pattern = [ regex "(\\d+(\\.\\d\\d\\d)+\\,\\d+)" ]- , prod = \tokens -> case tokens of+ , prod = \case (Token RegexMatch (GroupMatch (match:_)): _) -> let fmt = Text.replace "," "." $ Text.replace "." Text.empty match in parseDouble fmt >>= double@@ -85,7 +85,7 @@ [ dimension Numeral , Predicate isMultipliable ]- , prod = \tokens -> case tokens of+ , prod = \case (token1:token2:_) -> multiply token1 token2 _ -> Nothing }@@ -96,7 +96,7 @@ , pattern = [ regex "(\\d*,\\d+)" ]- , prod = \tokens -> case tokens of+ , prod = \case (Token RegexMatch (GroupMatch (match:_)): _) -> parseDecimal False match _ -> Nothing@@ -109,7 +109,7 @@ [ oneOf [70, 20, 60, 50, 40, 90, 30, 80] , numberBetween 1 10 ]- , prod = \tokens -> case tokens of+ , prod = \case (Token Numeral NumeralData{TNumeral.value = v1}: Token Numeral NumeralData{TNumeral.value = v2}: _) -> double $ v1 + v2@@ -132,7 +132,7 @@ [ Predicate hasGrain , Predicate $ and . sequence [not . isMultipliable, isPositive] ]- , prod = \tokens -> case tokens of+ , prod = \case (Token Numeral NumeralData{TNumeral.value = val1, TNumeral.grain = Just g}: Token Numeral NumeralData{TNumeral.value = val2}: _) | (10 ** fromIntegral g) > val2 -> double $ val1 + val2@@ -146,7 +146,7 @@ [ dimension Numeral , regex "([kmg])(?=[\\W\\$€]|$)" ]- , prod = \tokens -> case tokens of+ , prod = \case (Token Numeral NumeralData{TNumeral.value = v}: Token RegexMatch (GroupMatch (match:_)): _) -> case Text.toLower match of@@ -161,9 +161,9 @@ rulePowersOfTen = Rule { name = "powers of tens" , pattern =- [ regex "(hundre(de)?|tusen?|million(er)?)"+ [ regex "(hundre(de)?|tusen?|million(er)?|milliard(?:er)?|billion(?:er)?|billiard(?:er)?|trillion(?:er)?|trilliard(?:er)?|kvadrillion(?:er)?|kvadrilliard(?:er)?)" ]- , prod = \tokens -> case tokens of+ , prod = \case (Token RegexMatch (GroupMatch (match:_)):_) -> case Text.toLower match of "hundre" -> double 1e2 >>= withGrain 2 >>= withMultipliable "hundrede" -> double 1e2 >>= withGrain 2 >>= withMultipliable@@ -171,6 +171,20 @@ "tusen" -> double 1e3 >>= withGrain 3 >>= withMultipliable "million" -> double 1e6 >>= withGrain 6 >>= withMultipliable "millioner" -> double 1e6 >>= withGrain 6 >>= withMultipliable+ "milliard" -> double 1e9 >>= withGrain 9 >>= withMultipliable+ "milliarder" -> double 1e9 >>= withGrain 9 >>= withMultipliable+ "billion" -> double 1e12 >>= withGrain 12 >>= withMultipliable+ "billioner" -> double 1e12 >>= withGrain 12 >>= withMultipliable+ "billiard" -> double 1e15 >>= withGrain 15 >>= withMultipliable+ "billiarder" -> double 1e15 >>= withGrain 15 >>= withMultipliable+ "trillion" -> double 1e18 >>= withGrain 18 >>= withMultipliable+ "trillioner" -> double 1e18 >>= withGrain 18 >>= withMultipliable+ "trilliard" -> double 1e21 >>= withGrain 21 >>= withMultipliable+ "trilliarder" -> double 1e21 >>= withGrain 21 >>= withMultipliable+ "kvadrillion" -> double 1e24 >>= withGrain 24 >>= withMultipliable+ "kvadrillioner" -> double 1e24 >>= withGrain 24 >>= withMultipliable+ "kvadrilliard" -> double 1e27 >>= withGrain 27 >>= withMultipliable+ "kvadrilliarder" -> double 1e27 >>= withGrain 27 >>= withMultipliable _ -> Nothing _ -> Nothing }@@ -208,7 +222,7 @@ , ( "seks" , 6 ) , ( "sju" , 7 ) , ( "syv" , 7 )- , ( "otte" , 8 )+ , ( "åtte" , 8 ) , ( "ni" , 9 ) , ( "ti" , 10 ) , ( "elleve" , 11 )@@ -229,12 +243,137 @@ , pattern = [ regex "(intet|ingen|null|en|ett|én|to|tretten|tre|fire|femten|fem|seksten|seks|syv|sju|åtte|nitten|ni|ti|elleve|tolv|fjorten|sytten|søtten|atten)" ]- , prod = \tokens -> case tokens of+ , prod = \case (Token RegexMatch (GroupMatch (match:_)):_) -> HashMap.lookup (Text.toLower match) zeroToNineteenMap >>= integer _ -> Nothing } +twentyToHundredMap :: HashMap Text Integer+twentyToHundredMap = HashMap.fromList+ [ ("tjueen", 21)+ , ("tjueén", 21)+ , ("tjueto", 22)+ , ("tjuetre", 23)+ , ("tjuefire", 24)+ , ("tjuefem", 25)+ , ("tjueseks", 26)+ , ("tjuesju", 27)+ , ("tjuesyv", 27)+ , ("tjueåtte", 28)+ , ("tjueni", 29)+ , ("trettien", 31)+ , ("trettién", 31)+ , ("trettito", 32)+ , ("trettitre", 33)+ , ("trettifire", 34)+ , ("trettifem", 35)+ , ("trettiseks", 36)+ , ("trettisju", 37)+ , ("trettisyv", 37)+ , ("trettiåtte", 38)+ , ("trettini", 39)+ , ("førtien", 41)+ , ("førtién", 41)+ , ("førtito", 42)+ , ("førtitre", 43)+ , ("førtifire", 44)+ , ("førtifem", 45)+ , ("førtiseks", 46)+ , ("førtisju", 47)+ , ("førtisyv", 47)+ , ("førtiåtte", 48)+ , ("førtini", 49)+ , ("femtien", 51)+ , ("femtién", 51)+ , ("femtito", 52)+ , ("femtitre", 53)+ , ("femtifire", 54)+ , ("femtifem", 55)+ , ("femtiseks", 56)+ , ("femtisju", 57)+ , ("femtisyv", 57)+ , ("femtiåtte", 58)+ , ("femtini", 59)+ , ("sekstien", 61)+ , ("sekstién", 61)+ , ("sekstito", 62)+ , ("sekstitre", 63)+ , ("sekstifire", 64)+ , ("sekstifem", 65)+ , ("sekstiseks", 66)+ , ("sekstisju", 67)+ , ("sekstisyv", 67)+ , ("sekstiåtte", 68)+ , ("sekstini", 69)+ , ("syttien", 71)+ , ("syttién", 71)+ , ("syttito", 72)+ , ("syttitre", 73)+ , ("syttifire", 74)+ , ("syttifem", 75)+ , ("syttiseks", 76)+ , ("syttisju", 77)+ , ("syttisyv", 77)+ , ("syttiåtte", 78)+ , ("syttini", 79)+ , ("søttien", 71)+ , ("søttién", 71)+ , ("søttito", 72)+ , ("søttitre", 73)+ , ("søttifire", 74)+ , ("søttifem", 75)+ , ("søttiseks", 76)+ , ("søttisju", 77)+ , ("søttisyv", 77)+ , ("søttiåtte", 78)+ , ("søttini", 79)+ , ("åttien", 81)+ , ("åttién", 81)+ , ("åttito", 82)+ , ("åttitre", 83)+ , ("åttifire", 84)+ , ("åttifem", 85)+ , ("åttiseks", 86)+ , ("åttisju", 87)+ , ("åttisyv", 87)+ , ("åttiåtte", 88)+ , ("åttini", 89)+ , ("nittien", 91)+ , ("nittién", 91)+ , ("nittito", 92)+ , ("nittitre", 93)+ , ("nittifire", 94)+ , ("nittifem", 95)+ , ("nittiseks", 96)+ , ("nittisju", 97)+ , ("nittisyv", 97)+ , ("nittiåtte", 98)+ , ("nittini", 99)+ ]++ruleInteger4 :: Rule+ruleInteger4 = Rule+ { name = "integer (21..99)"+ , pattern =+ [ regex "(tjueen|tjueén|tjueto|tjuetre|tjuefire|tjuefem|tjueseks|tjuesju|tjuesyv|tjueåtte|tjueni\+ \|trettien|trettién|trettito|trettitre|trettifire|trettifem|trettiseks|trettisju|trettisyv|trettiåtte|trettini\+ \|førtien|førtién|førtito|førtitre|førtifire|førtifem|førtiseks|førtisju|førtisyv|førtiåtte|førtini\+ \|femtien|femtién|femtito|femtitre|femtifire|femtifem|femtiseks|femtisju|femtisyv|femtiåtte|femtini\+ \|sekstien|sekstién|sekstito|sekstitre|sekstifire|sekstifem|sekstiseks|sekstisju|sekstisyv|sekstiåtte|sekstini\+ \|syttien|syttién|syttito|syttitre|syttifire|syttifem|syttiseks|syttisju|syttisyv|syttiåtte|syttini\+ \|søttien|søttién|søttito|søttitre|søttifire|søttifem|søttiseks|søttisju|søttisyv|søttiåtte|søttini\+ \|åttien|åttién|åttito|åttitre|åttifire|åttifem|åttiseks|åttisju|åttisyv|åttiåtte|åttini\+ \|nittien|nittién|nittito|nittitre|nittifire|nittifem|nittiseks|nittisju|nittisyv|nittiåtte|nittini\+ \)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup (Text.toLower match) twentyToHundredMap >>= integer+ _ -> Nothing+ }++ tensMap :: HashMap Text Integer tensMap = HashMap.fromList [ ( "tyve" , 20 )@@ -256,7 +395,7 @@ , pattern = [ regex "(tyve|tjue|tredve|tretti|førti|femti|seksti|sytti|søtti|åtti|nitti)" ]- , prod = \tokens -> case tokens of+ , prod = \case (Token RegexMatch (GroupMatch (match:_)):_) -> HashMap.lookup (Text.toLower match) tensMap >>= integer _ -> Nothing@@ -270,7 +409,7 @@ , regex "komma" , Predicate $ not . hasGrain ]- , prod = \tokens -> case tokens of+ , prod = \case (Token Numeral nd1:_:Token Numeral nd2:_) -> double $ TNumeral.value nd1 + decimalsToDouble (TNumeral.value nd2) _ -> Nothing@@ -280,11 +419,12 @@ ruleIntegerWithThousandsSeparator = Rule { name = "integer with thousands separator ." , pattern =- [ regex "(\\d{1,3}(\\.\\d\\d\\d){1,5})"+ [ regex "(\\d{1,3}((?:\\.| )\\d\\d\\d){1,5})" ]- , prod = \tokens -> case tokens of- (Token RegexMatch (GroupMatch (match:_)):_) ->- parseDouble (Text.replace "." Text.empty match) >>= double+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) -> parseDouble+ (Text.replace " " Text.empty $ Text.replace "." Text.empty $ match)+ >>= double _ -> Nothing } @@ -298,6 +438,7 @@ , ruleInteger , ruleInteger2 , ruleInteger3+ , ruleInteger4 , ruleIntegerWithThousandsSeparator , ruleIntersect , ruleIntersectWithAnd
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -77,6 +76,14 @@ [ "0,77" , ",77" ]+ , examples (NumeralValue 100000)+ [ "100.000"+ , "100.000,0"+ , "100000"+ , "100K"+ , "100k"+ , "honderd duizend"+ ] , examples (NumeralValue 300) [ "3 honderd" , "drie honderd"@@ -84,6 +91,8 @@ , examples (NumeralValue 5000) [ "5 duizend" , "vijf duizend"+ , "5.000"+ , "5.000,00" ] , examples (NumeralValue 144) [ "gros"@@ -95,6 +104,9 @@ ] , examples (NumeralValue 20000) [ "twintig duizend"+ , "20.000"+ , "20000"+ , "20.000,00" ] , examples (NumeralValue 0.2) [ "1/5"
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -63,7 +62,7 @@ ruleDecimalWithThousandsSeparator = Rule { name = "decimal with thousands separator" , pattern =- [ regex "(\\d+(\\.\\d\\d\\d)+,\\d+)"+ [ regex "(\\d+(\\.\\d\\d\\d)+(,\\d+)?)" ] , prod = \tokens -> case tokens of (Token RegexMatch (GroupMatch (match:_)):@@ -148,7 +147,7 @@ { name = "numbers en" , pattern = [ numberBetween 1 10- , regex "en"+ , regex "-?en-?" , oneOf [20, 30 .. 90] ] , prod = \tokens -> case tokens of
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -98,6 +97,22 @@ , examples (NumeralValue 5000) [ "5 tysięcy" , "pięć tysięcy"+ ]+ , examples (NumeralValue 79)+ [ "siedemdziesiąt dziewięć"+ , "siedemdziesięciu dziewięciu"+ ]+ , examples (NumeralValue 84)+ [ "osiemdziesiąt cztery"+ , "osiemdziesiat cztery"+ , "osiemdziesięciu czterem"+ , "osiemdziesieciu czterem"+ ]+ , examples (NumeralValue 92)+ [ "dziewięćdziesiąt dwa"+ , "dziewiecdziesiat dwa"+ , "dziewięćdziesięciu dwóm"+ , "dziewiecdziesieciu dwom" ] , examples (NumeralValue 122) [ "sto dwadzieścia dwa"
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -61,6 +60,33 @@ , prod = \_ -> integer 60 } +ruleSeventy :: Rule+ruleSeventy = Rule+ { name = "seventy"+ , pattern =+ [ regex "siedemdziesi((a|ą)t|(e|ę)ci(u|oma))"+ ]+ , prod = \_ -> integer 70+ }++ruleEighty :: Rule+ruleEighty = Rule+ { name = "eighty"+ , pattern =+ [ regex "osiemdziesi((a|ą)t|(e|ę)ci(u|oma))"+ ]+ , prod = \_ -> integer 80+ }++ruleNinety :: Rule+ruleNinety = Rule+ { name = "ninety"+ , pattern =+ [ regex "dziewi(e|ę)(c|ć)dziesi((a|ą)|(e|ę))(t|ci(u|oma))"+ ]+ , prod = \_ -> integer 90+ }+ ruleIntersectWithAnd :: Rule ruleIntersectWithAnd = Rule { name = "intersect (with and)"@@ -553,6 +579,7 @@ , ruleDozen , ruleEight , ruleEighteen+ , ruleEighty , ruleEleven , ruleFifteen , ruleFifty@@ -568,6 +595,7 @@ , ruleMultiply , ruleNine , ruleNineteen+ , ruleNinety , ruleNumeral , ruleNumeral2 , ruleNumeral3@@ -583,6 +611,7 @@ , ruleOne , ruleSeven , ruleSeventeen+ , ruleSeventy , ruleSingle , ruleSix , ruleSixteen
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -20,8 +19,11 @@ import Duckling.Resolve import Duckling.Testing.Types +context :: Context+context = testContext {locale = makeLocale RO Nothing}+ corpus :: Corpus-corpus = (testContext {locale = makeLocale RO Nothing}, testOptions, allExamples)+corpus = (context, testOptions, allExamples) allExamples :: [Example] allExamples = concat@@ -164,6 +166,10 @@ [ "7 milioane" , "sapte milioane" , "șapte milioane"+ ]+ , examples (NumeralValue 21000000)+ [ "21 de milioane"+ , "douazeci si unu de milioane" ] , examples (NumeralValue 1000000000) [ "un miliard"
@@ -2,11 +2,11 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} module Duckling.Numeral.RO.Rules@@ -23,7 +23,7 @@ import Duckling.Dimensions.Types import Duckling.Numeral.Helpers-import Duckling.Numeral.Types (NumeralData (..))+import Duckling.Numeral.Types (NumeralData(..)) import Duckling.Regex.Types import Duckling.Types import qualified Duckling.Numeral.Types as TNumeral@@ -35,7 +35,7 @@ [ regex "-|minus" , Predicate isPositive ]- , prod = \tokens -> case tokens of+ , prod = \case (_:Token Numeral nd:_) -> double (TNumeral.value nd * (-1)) _ -> Nothing }@@ -46,7 +46,7 @@ , pattern = [ regex "(\\d+(\\.\\d\\d\\d)+,\\d+)" ]- , prod = \tokens -> case tokens of+ , prod = \case (Token RegexMatch (GroupMatch (match:_)): _) -> let fmt = Text.replace "," "." $ Text.replace "." Text.empty match in parseDouble fmt >>= double@@ -59,9 +59,8 @@ , pattern = [ regex "(\\d*,\\d+)" ]- , prod = \tokens -> case tokens of- (Token RegexMatch (GroupMatch (match:_)):- _) -> parseDecimal False match+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) -> parseDecimal False match _ -> Nothing } @@ -72,7 +71,7 @@ [ oneOf [20, 30 .. 90] , numberBetween 1 10 ]- , prod = \tokens -> case tokens of+ , prod = \case (Token Numeral NumeralData{TNumeral.value = v1}: Token Numeral NumeralData{TNumeral.value = v2}: _) -> double $ v1 + v2@@ -86,11 +85,24 @@ [ dimension Numeral , Predicate isMultipliable ]- , prod = \tokens -> case tokens of+ , prod = \case (token1:token2:_) -> multiply token1 token2 _ -> Nothing } +ruleMultiplyDe :: Rule+ruleMultiplyDe = Rule+ { name = "compose by multiplication"+ , pattern =+ [ numberWith TNumeral.value (>= 20)+ , regex "de"+ , Predicate isMultipliable+ ]+ , prod = \case+ (token1:_:token2:_) -> multiply token1 token2+ _ -> Nothing+ }+ ruleIntersect :: Rule ruleIntersect = Rule { name = "intersect"@@ -98,7 +110,7 @@ [ Predicate hasGrain , Predicate $ and . sequence [not . isMultipliable, isPositive] ]- , prod = \tokens -> case tokens of+ , prod = \case (Token Numeral NumeralData{TNumeral.value = val1, TNumeral.grain = Just g}: Token Numeral NumeralData{TNumeral.value = val2}: _) | (10 ** fromIntegral g) > val2 -> double $ val1 + val2@@ -110,10 +122,10 @@ { name = "intersect (cu și)" , pattern = [ Predicate hasGrain- , regex "(s|ș)i"+ , regex "[sș]i" , Predicate $ and . sequence [not . isMultipliable, isPositive] ]- , prod = \tokens -> case tokens of+ , prod = \case (Token Numeral NumeralData{TNumeral.value = val1, TNumeral.grain = Just g}: _: Token Numeral NumeralData{TNumeral.value = val2}:@@ -128,7 +140,7 @@ [ Predicate isPositive , regex "neg(ativ)?" ]- , prod = \tokens -> case tokens of+ , prod = \case (Token Numeral NumeralData{TNumeral.value = v}: _) -> double $ v * (-1) _ -> Nothing@@ -140,7 +152,7 @@ , pattern = [ regex "(sut(a|e|ă)?|milio(n|ane)?|miliar(de?)?|mi[ei]?)" ]- , prod = \tokens -> case tokens of+ , prod = \case (Token RegexMatch (GroupMatch (match:_)):_) -> case Text.toLower match of "suta" -> double 1e2 >>= withGrain 2 >>= withMultipliable "sute" -> double 1e2 >>= withGrain 2 >>= withMultipliable@@ -199,7 +211,7 @@ , pattern = [ regex "(zero|nimic|nici(\\s?o|\\sun(a|ul?))|una|unul?|doi|dou(a|ă)|trei|patru|cinci|(s|ș)ase|(s|ș)apte|opt|nou(a|ă)|zec[ei]|(i|î)nt(a|â)i|un|o)" ]- , prod = \tokens -> case tokens of+ , prod = \case (Token RegexMatch (GroupMatch (match:_)):_) -> HashMap.lookup (Text.toLower match) zeroTenMap >>= integer _ -> Nothing@@ -231,7 +243,7 @@ , pattern = [ regex "(cin|sapti|opti)(s|ș)pe|(cinci|(s|ș)apte|opt)sprezece|(un|doi|trei|pai|(s|ș)ai|nou(a|ă))((s|ș)pe|sprezece)" ]- , prod = \tokens -> case tokens of+ , prod = \case (Token RegexMatch (GroupMatch (e1:_:e2:_:r:_)):_) -> do match <- case () of _ | not $ Text.null e1 -> Just e1@@ -246,9 +258,9 @@ ruleInteger2 = Rule { name = "integer (20..90)" , pattern =- [ regex "(dou(a|ă)|trei|patru|cinci|(s|ș)ai|(s|ș)apte|opt|nou(a|ă))\\s?zeci"+ [ regex "(dou[aă]|trei|patru|cinci|[sș]ai|[sș]apte|opt|nou[aă])\\s?zeci" ]- , prod = \tokens -> case tokens of+ , prod = \case (Token RegexMatch (GroupMatch (match:_)):_) -> do unit <- HashMap.lookup (Text.toLower match) zeroTenMap integer (unit * 10) >>= withGrain 2 >>= withMultipliable@@ -261,7 +273,7 @@ , pattern = [ regex "(\\d{1,3}(\\.\\d\\d\\d){1,5})" ]- , prod = \tokens -> case tokens of+ , prod = \case (Token RegexMatch (GroupMatch (match:_)): _) -> let fmt = Text.replace "." Text.empty match in parseDouble fmt >>= double@@ -280,6 +292,7 @@ , ruleIntersect , ruleIntersectCuI , ruleMultiply+ , ruleMultiplyDe , ruleNumeralsPrefixWithOrMinus , ruleNumeralsSuffixesWithNegativ , rulePowersOfTen
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -56,6 +55,7 @@ , examples (NumeralValue 33) [ "33" , "тридцать три"+ , "тридцати три" , "0033" ] , examples (NumeralValue 11)@@ -84,11 +84,33 @@ ] , examples (NumeralValue 444) [ "четыреста сорок четыре"+ , "четыреста сорока четыре" , "444" ] , examples (NumeralValue 525) [ "пятьсот двадцать пять"+ , "пятьсот двадцати пять" , "525"+ ]+ , examples (NumeralValue 555)+ [ "пятьсот пятьдесят пять"+ , "пятьсот пятидесяти пять"+ ]+ , examples (NumeralValue 565)+ [ "пятьсот шестьдесят пять"+ , "пятьсот шестидесяти пять"+ ]+ , examples (NumeralValue 575)+ [ "пятьсот семьдесят пять"+ , "пятьсот семидесяти пять"+ ]+ , examples (NumeralValue 585)+ [ "пятьсот восемьдесят пять"+ , "пятьсот восьмидесяти пять"+ ]+ , examples (NumeralValue 595)+ [ "пятьсот девяносто пять"+ , "пятьсот девяноста пять" ] , examples (NumeralValue 1.5) [ "1.5"
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -31,20 +30,32 @@ tensMap :: HashMap Text Integer tensMap = HashMap.fromList [ ( "двадцать", 20)+ , ( "двадцати", 20) , ( "тридцать", 30)+ , ( "тридцати", 30) , ( "сорок", 40)+ , ( "сорока", 40) , ( "пятьдесят", 50)+ , ( "пятидесяти", 50) , ( "шестьдесят", 60)+ , ( "шестидесяти", 60)+ , ( "шестидесят", 60) , ( "семьдесят", 70)+ , ( "семидесяти", 70)+ , ( "семидесят", 70) , ( "восемьдесят", 80)+ , ( "восьмидесяти", 80)+ , ( "восьмидесят", 80)+ , ( "восемьдесяти", 80) , ( "девяносто", 90)+ , ( "девяноста", 90) ] ruleInteger5 :: Rule ruleInteger5 = Rule { name = "integer (20..90)" , pattern =- [ regex "(двадцать|тридцать|сорок|пятьдесят|шестьдесят|семьдесят|восемьдесят|девяносто)"+ [ regex "(двадцат(ь|и)|тридцат(ь|и)|сорока?|пят(ь|и)десяти?|шест(ь|и)десяти?|сем(ь|и)десяти?|вос(е|ь)м(ь|и)десяти?|девяност(о|а))" ] , prod = \tokens -> case tokens of (Token RegexMatch (GroupMatch (match:_)):_) ->@@ -79,7 +90,7 @@ ruleInteger3 = Rule { name = "integer 2" , pattern =- [ regex "(два|две|двое|пара|пару|парочку|парочка)"+ [ regex "(дв(а|е|ух|ое)|пар(а|у|очк(у|а)))" ] , prod = \_ -> integer 2 }
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -0,0 +1,110 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree. An additional grant+-- of patent rights can be found in the PATENTS file in the same directory.+++{-# LANGUAGE OverloadedStrings #-}++module Duckling.Numeral.SK.Corpus+ ( corpus+ ) where++import Data.String+import Prelude++import Duckling.Locale+import Duckling.Numeral.Types+import Duckling.Resolve+import Duckling.Testing.Types++corpus :: Corpus+corpus =+ ( testContext {locale = makeLocale SK Nothing}+ , testOptions+ , allExamples+ )++allExamples :: [Example]+allExamples = concat+ [ examples (NumeralValue 0)+ [ "0"+ , "nula"+ ]+ , examples (NumeralValue 1)+ [ "1"+ , "jeden"+ , "jedna"+ ]+ , examples (NumeralValue 2)+ [ "2"+ , "dva"+ , "dve"+ ]+ , examples (NumeralValue 7)+ [ "7"+ , "sedem"+ ]+ , examples (NumeralValue 14)+ [ "14"+ , "štrnásť"+ ]+ , examples (NumeralValue 16)+ [ "16"+ , "šestnásť"+ ]+ , examples (NumeralValue 17)+ [ "17"+ , "sedemnásť"+ ]+ , examples (NumeralValue 18)+ [ "18"+ , "osemnásť"+ ]+ , examples (NumeralValue 20)+ [ "20"+ , "dvadsať"+ ]+ , examples (NumeralValue 1.1)+ [ "1,1"+ , "1,10"+ , "01,10"+ ]+ , examples (NumeralValue 0.77)+ [ "0,77"+ , ",77"+ ]+ , examples (NumeralValue 100000)+ [ "100.000"+ , "100000"+ , "100K"+ , "100k"+ ]+ , examples (NumeralValue 3000000)+ [ "3M"+ , "3000K"+ , "3000000"+ , "3.000.000"+ ]+ , examples (NumeralValue 1200000)+ [ "1.200.000"+ , "1200000"+ , "1,2M"+ , "1200K"+ , ",0012G"+ ]+ , examples (NumeralValue (-1200000))+ [ "- 1.200.000"+ , "-1200000"+ , "mínus 1.200.000"+ , "-1,2M"+ , "-1200K"+ , "-,0012G"+ ]+ , examples (NumeralValue 5000)+ [ "5 tisíc"+ , "päť tisíc"+ ]+ ]
@@ -0,0 +1,309 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree. An additional grant+-- of patent rights can be found in the PATENTS file in the same directory.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}++module Duckling.Numeral.SK.Rules+ ( rules+ ) where++import Data.HashMap.Strict (HashMap)+import Data.Maybe+import Data.String+import Data.Text (Text)+import Prelude+import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text++import Duckling.Dimensions.Types+import Duckling.Numeral.Helpers+import Duckling.Numeral.Types (NumeralData (..))+import Duckling.Regex.Types+import Duckling.Types+import qualified Duckling.Numeral.Types as TNumeral++ruleIntersectWithAnd :: Rule+ruleIntersectWithAnd = Rule+ { name = "intersect (with and)"+ , pattern =+ [ Predicate hasGrain+ , regex "a"+ , Predicate $ and . sequence [not . isMultipliable, isPositive]+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = val1, TNumeral.grain = Just g}:+ _:+ Token Numeral NumeralData{TNumeral.value = val2}:+ _) | (10 ** fromIntegral g) > val2 -> double $ val1 + val2+ _ -> Nothing+ }++ruleNumeralsPrefixWithNegativeOrMinus :: Rule+ruleNumeralsPrefixWithNegativeOrMinus = Rule+ { name = "numbers prefix with -, negative or minus"+ , pattern =+ [ regex "-|mínus|záporné"+ , Predicate isPositive+ ]+ , prod = \case+ (_:+ Token Numeral NumeralData{TNumeral.value = v}:+ _) -> double $ v * (-1)+ _ -> Nothing+ }++ruleFew :: Rule+ruleFew = Rule+ { name = "few"+ , pattern =+ [ regex "(zo)?pár"+ ]+ , prod = \_ -> integer 3+ }++ruleDecimalWithThousandsSeparator :: Rule+ruleDecimalWithThousandsSeparator = Rule+ { name = "decimal with thousands separator"+ , pattern =+ [ regex "(\\d+(\\.\\d\\d\\d)+\\,\\d+)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):+ _) -> let fmt = Text.replace "," "." $ Text.replace "." Text.empty match+ in parseDouble fmt >>= double+ _ -> Nothing+ }++ruleDecimalNumeral :: Rule+ruleDecimalNumeral = Rule+ { name = "decimal number"+ , pattern =+ [ regex "(\\d*,\\d+)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):+ _) -> parseDecimal False match+ _ -> Nothing+ }++ruleIntegerCompositeTens :: Rule+ruleIntegerCompositeTens = Rule+ { name = "integer 21..99"+ , pattern =+ [ oneOf [20, 30..90]+ , numberBetween 1 10+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = tens}:+ Token Numeral NumeralData{TNumeral.value = units}:+ _) -> double $ tens + units+ _ -> Nothing+ }++ruleSingle :: Rule+ruleSingle = Rule+ { name = "single"+ , pattern =+ [ regex "jed(en|no|na)"+ ]+ , prod = \_ -> integer 1 >>= withGrain 1+ }++ruleSum :: Rule+ruleSum = Rule+ { name = "intersect"+ , pattern =+ [ Predicate hasGrain+ , Predicate $ and . sequence [not . isMultipliable, isPositive]+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = val1, TNumeral.grain = Just g}:+ Token Numeral NumeralData{TNumeral.value = val2}:+ _) | (10 ** fromIntegral g) > val2 -> double $ val1 + val2+ _ -> Nothing+ }++ruleMultiply :: Rule+ruleMultiply = Rule+ { name = "compose by multiplication"+ , pattern =+ [ dimension Numeral+ , Predicate isMultipliable+ ]+ , prod = \case+ (token1:token2:_) -> multiply token1 token2+ _ -> Nothing+ }++ruleNumeralsSuffixesKMG :: Rule+ruleNumeralsSuffixesKMG = Rule+ { name = "numbers suffixes (K, M, G)"+ , pattern =+ [ dimension Numeral+ , regex "([kmg])(?=[\\W\\$€]|$)"+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = v}:+ Token RegexMatch (GroupMatch (match:_)):+ _) -> case Text.toLower match of+ "k" -> double $ v * 1e3+ "m" -> double $ v * 1e6+ "g" -> double $ v * 1e9+ _ -> Nothing+ _ -> Nothing+ }++rulePowersOfTen :: Rule+rulePowersOfTen = Rule+ { name = "powers of tens"+ , pattern =+ [ regex "(sto(vky)?|tisíce?|milióny?)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) -> case Text.toLower match of+ "sto" -> double 1e2 >>= withGrain 2 >>= withMultipliable+ "stovky" -> double 1e2 >>= withGrain 2 >>= withMultipliable+ "tisíc" -> double 1e3 >>= withGrain 3 >>= withMultipliable+ "tisíce" -> double 1e3 >>= withGrain 3 >>= withMultipliable+ "milión" -> double 1e6 >>= withGrain 6 >>= withMultipliable+ "milióny" -> double 1e6 >>= withGrain 6 >>= withMultipliable+ _ -> Nothing+ _ -> Nothing+ }++ruleCouple :: Rule+ruleCouple = Rule+ { name = "couple, a pair"+ , pattern =+ [ regex "páry?"+ ]+ , prod = \_ -> integer 2+ }++ruleDozen :: Rule+ruleDozen = Rule+ { name = "dozen"+ , pattern =+ [ regex "tucet"+ ]+ , prod = \_ -> integer 12 >>= withGrain 1 >>= withMultipliable+ }++zeroToNineteenMap :: HashMap Text Integer+zeroToNineteenMap = HashMap.fromList+ [ ( "nula" , 0 )+ , ( "jeden" , 1 )+ , ( "jedna" , 1 )+ , ( "jedno" , 1 )+ , ( "dva" , 2 )+ , ( "dve" , 2 )+ , ( "tri" , 3 )+ , ( "štyri" , 4 )+ , ( "päť" , 5 )+ , ( "šesť" , 6 )+ , ( "sedem" , 7 )+ , ( "osem" , 8 )+ , ( "deväť" , 9 )+ , ( "desať" , 10 )+ , ( "jedenásť", 11 )+ , ( "dvanásť" , 12 )+ , ( "trinásť" , 13 )+ , ( "štrnásť" , 14 )+ , ( "pätnásť" , 15 )+ , ( "šestnásť", 16 )+ , ( "sedemnásť", 17 )+ , ( "osemnásť" , 18 )+ , ( "devätnásť", 19 )+ ]++ruleInteger :: Rule+ruleInteger = Rule+ { name = "integer (0..19)"+ -- e.g. jedenásť must be before jeden, otherwise jeden will always shadow jedenásť+ , pattern =+ [ regex "(nula|jed(enásť|en|na|no)|dv(anásť|a|e)|trinásť|tri|štrnásť|štyri|pätnásť|päť|šestnásť|šesť|sedemnásť|sedem|osemnásť|osem|devätnásť|deväť|desať)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup (Text.toLower match) zeroToNineteenMap >>= integer+ _ -> Nothing+ }++dozenMap :: HashMap Text Integer+dozenMap = HashMap.fromList+ [ ( "dvadsať" , 20)+ , ( "tridsať" , 30)+ , ( "štyridsať" , 40)+ , ( "päťdesiat" , 50)+ , ( "šesťdesiat" , 60)+ , ( "sedemdesiat" , 70)+ , ( "osemdesiat" , 80)+ , ( "devätdesiat" , 90)+ ]++ruleInteger2 :: Rule+ruleInteger2 = Rule+ { name = "integer (20..90)"+ , pattern =+ [ regex "((dva|tri|štyri)dsať|(päť|šesť|sedem|osem|devät)desiat)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup (Text.toLower match) dozenMap >>= integer+ _ -> Nothing+ }++ruleNumeralDotNumeral :: Rule+ruleNumeralDotNumeral = Rule+ { name = "number dot number"+ , pattern =+ [ dimension Numeral+ , regex "celá|celých|celé"+ , Predicate $ not . hasGrain+ ]+ , prod = \case+ (Token Numeral nd1:_:Token Numeral nd2:_) ->+ double $ TNumeral.value nd1 + decimalsToDouble (TNumeral.value nd2)+ _ -> Nothing+ }++ruleIntegerWithThousandsSeparator :: Rule+ruleIntegerWithThousandsSeparator = Rule+ { name = "integer with thousands separator ."+ , pattern =+ [ regex "(\\d{1,3}(\\.\\d\\d\\d){1,5})"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):+ _) -> let fmt = Text.replace "." Text.empty match+ in parseDouble fmt >>= double+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleCouple+ , ruleDecimalNumeral+ , ruleDecimalWithThousandsSeparator+ , ruleDozen+ , ruleFew+ , ruleInteger+ , ruleInteger2+ , ruleIntegerCompositeTens+ , ruleIntegerWithThousandsSeparator+ , ruleSum+ , ruleIntersectWithAnd+ , ruleMultiply+ , ruleNumeralDotNumeral+ , ruleNumeralsPrefixWithNegativeOrMinus+ , ruleNumeralsSuffixesKMG+ , rulePowersOfTen+ , ruleSingle+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -0,0 +1,86 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}++module Duckling.Numeral.SW.Corpus+ ( corpus ) where++import Data.String+import Prelude++import Duckling.Locale+import Duckling.Numeral.Types+import Duckling.Resolve+import Duckling.Testing.Types++corpus :: Corpus+corpus = (testContext {locale = makeLocale SW Nothing}, testOptions, allExamples)++allExamples :: [Example]+allExamples = concat+ [ examples (NumeralValue 0)+ [ "0"+ , "sufuri"+ , "zero"+ ]+ , examples (NumeralValue 1)+ [ "moja"+ ]+ , examples (NumeralValue 2)+ [ "mbili"+ ]+ , examples (NumeralValue 3)+ [ "tatu"+ ]+ , examples (NumeralValue 4)+ [ "nne"+ ]+ , examples (NumeralValue 5)+ [ "tano"+ ]+ , examples (NumeralValue 6)+ [ "sita"+ ]+ , examples (NumeralValue 7)+ [ "saba"+ ]+ , examples (NumeralValue 8)+ [ "nane"+ ]+ , examples (NumeralValue 9)+ [ "tisa"+ ]+ , examples (NumeralValue 10)+ [ "kumi"+ ]+ , examples (NumeralValue 20)+ [ "ishirini"+ ]+ , examples (NumeralValue 30)+ [ "thelathini"+ ]+ , examples (NumeralValue 40)+ [ "arubaini"+ , "arobaini"+ ]+ , examples (NumeralValue 50)+ [ "hamsini"+ ]+ , examples (NumeralValue 60)+ [ "sitini"+ ]+ , examples (NumeralValue 70)+ [ "sabini"+ ]+ , examples (NumeralValue 80)+ [ "themanini"+ ]+ , examples (NumeralValue 90)+ [ "tisini"+ ]+ ]
@@ -0,0 +1,104 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE NoRebindableSyntax #-}++module Duckling.Numeral.SW.Rules+ ( rules+ ) where++import Data.HashMap.Strict (HashMap)+import Data.Maybe+import Data.String+import Data.Text (Text)+import Prelude+import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text++import Duckling.Dimensions.Types+import Duckling.Numeral.Helpers+import Duckling.Numeral.Types (NumeralData (..))+import Duckling.Regex.Types+import Duckling.Types+import qualified Duckling.Numeral.Types as TNumeral++ruleNumeralMap :: HashMap Text Integer+ruleNumeralMap = HashMap.fromList+ [ ( "sufuri", 0 )+ , ( "zero", 0 )+ , ( "moja", 1 )+ , ( "mbili", 2 )+ , ( "tatu", 3 )+ , ( "nne", 4 )+ , ( "tano", 5)+ , ( "sita", 6)+ , ( "saba", 7)+ , ( "nane", 8)+ , ( "tisa", 9)+ , ( "kumi", 10)+ ]++ruleNumeral :: Rule+ruleNumeral = Rule+ { name = "number (0..10)"+ , pattern =+ [ regex "(sufuri|zero|moja|mbili|tatu|nne|tano|sita|saba|nane|tisa|kumi)"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup (Text.toLower match) ruleNumeralMap >>= integer+ _ -> Nothing+ }++tensMap :: HashMap Text Integer+tensMap = HashMap.fromList+ [ ( "ishirini", 20 )+ , ( "thelathini", 30 )+ , ( "arubaini", 40 )+ , ( "arobaini", 40 )+ , ( "hamsini", 50 )+ , ( "sitini", 60 )+ , ( "sabini", 70 )+ , ( "themanini", 80 )+ , ( "tisini", 90 )+ ]++ruleTens :: Rule+ruleTens = Rule+ { name = "integer (20,30..90)"+ , pattern =+ [ regex "(ishirini|thelathini|arubaini|arobaini|hamsini|sitini|sabini|themanini|tisini)"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup (Text.toLower match) tensMap >>= integer+ _ -> Nothing+ }+++ruleCompositeTens :: Rule+ruleCompositeTens = Rule+ { name = "integer 11..19 21..29 .. 91..99"+ , pattern = [oneOf [20,30..90]+ , regex "-?na-?"+ , numberBetween 1 10]+ , prod = \tokens -> case tokens of+ (Token Numeral NumeralData{TNumeral.value = v1}:+ Token Numeral NumeralData{TNumeral.value = v2}:+ _) -> double $ v1 + v2+ _ -> Nothing+ }+++rules :: [Rule]+rules =+ [ ruleNumeral+ , ruleTens+ , ruleCompositeTens+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -0,0 +1,123 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}++module Duckling.Numeral.TE.Corpus+ ( corpus+ ) where++import Data.String+import Prelude++import Duckling.Locale+import Duckling.Numeral.Types+import Duckling.Resolve+import Duckling.Testing.Types++corpus :: Corpus+corpus = (testContext {locale = makeLocale TE Nothing}, testOptions, allExamples)++allExamples :: [Example]+allExamples = concat+ [ examples (NumeralValue 0)+ [ "సున్న"+ ]+ , examples (NumeralValue 1)+ [ "ఒకటి"+ ]+ , examples (NumeralValue 2)+ [ "రెండు"+ ]+ , examples (NumeralValue 3)+ [ "మూడు"+ ]+ , examples (NumeralValue 4)+ [ "నాలుగు"+ ]+ , examples (NumeralValue 5)+ [ "ఐదు"+ ]+ , examples (NumeralValue 6)+ [ "ఆరు"+ ]+ , examples (NumeralValue 7)+ [ "ఏడు"+ ]+ , examples (NumeralValue 8)+ [ "ఎనిమిది"+ ]+ , examples (NumeralValue 9)+ [ "తొమ్మిది"+ ]+ , examples (NumeralValue 10)+ [ "పది"+ ]+ , examples (NumeralValue 11)+ [ "పదకొండు"+ ]+ , examples (NumeralValue 12)+ [ "పన్నెండు"+ ]+ , examples (NumeralValue 13)+ [ "పదమూడు"+ ]+ , examples (NumeralValue 14)+ [ "పద్నాల్గు"+ ]+ , examples (NumeralValue 15)+ [ "పదిహేను"+ ]+ , examples (NumeralValue 16)+ [ "పదహారు"+ ]+ , examples (NumeralValue 17)+ [ "పదిహేడు"+ ]+ , examples (NumeralValue 18)+ [ "పద్దెనిమిది"+ ]+ , examples (NumeralValue 19)+ [ "పంతొమ్మిది"+ ]+ , examples (NumeralValue 20)+ [ "ఇరవై"+ ]+ , examples (NumeralValue 30)+ [ "ముప్పై"+ ]+ , examples (NumeralValue 40)+ [ "నలబై"+ ]+ , examples (NumeralValue 50)+ [ "యాబై"+ ]+ , examples (NumeralValue 60)+ [ "అరవై"+ ]+ , examples (NumeralValue 70)+ [ "డెబ్బై"+ ]+ , examples (NumeralValue 80)+ [ "ఎనబై"+ ]+ , examples (NumeralValue 90)+ [ "తొంబై"+ ]+ , examples (NumeralValue 100)+ [ "వంద"+ ]+ , examples (NumeralValue 1000)+ [ "వెయ్యి"+ ]+ , examples (NumeralValue 100000)+ [ "లక్ష"+ ]+ , examples (NumeralValue 10000000)+ [ "కోటి"+ ]+ ]
@@ -0,0 +1,161 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE NoRebindableSyntax #-}++module Duckling.Numeral.TE.Rules+ ( rules+ ) where++import Data.HashMap.Strict (HashMap)+import Data.Maybe+import Data.Text (Text)+import Prelude+import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text++import Duckling.Dimensions.Types+import Duckling.Numeral.Helpers+import Duckling.Regex.Types+import Duckling.Types++teluguMap :: HashMap Char Char+teluguMap = HashMap.fromList+ [ ( '౦', '0' )+ , ( '౧', '1' )+ , ( '౨', '2' )+ , ( '౩', '3' )+ , ( '౪', '4' )+ , ( '౫', '5' )+ , ( '౬', '6' )+ , ( '౭', '7' )+ , ( '౮', '8' )+ , ( '౯', '9' )+ ]++teluguToArab :: Char -> Char+teluguToArab c = HashMap.lookupDefault c c teluguMap++ruleTelugu :: Rule+ruleTelugu = Rule+ { name = "telugu forms"+ , pattern =+ [ regex "([౦౧౨౩౪౫౬౭౮౯]{1,18})"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ toInteger <$> parseInt (Text.map teluguToArab match) >>= integer+ _ -> Nothing+ }++zeroToNineMap :: HashMap Text Integer+zeroToNineMap = HashMap.fromList+ [ ( "సున్న", 0 )+ , ( "ఒకటి", 1 )+ , ( "రెండు", 2 )+ , ( "మూడు", 3 )+ , ( "నాలుగు", 4 )+ , ( "ఐదు", 5 )+ , ( "ఆరు", 6 )+ , ( "ఏడు", 7 )+ , ( "ఎనిమిది", 8 )+ , ( "తొమ్మిది", 9 )+ ]++ruleZeroToNine :: Rule+ruleZeroToNine = Rule+ { name = "integer (0..9)"+ , pattern =+ [ regex "(సున్న|ఒకటి|రెండు|మూడు|నాలుగు|ఐదు|ఆరు|ఏడు|ఎనిమిది|తొమ్మిది)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup (Text.toLower match) zeroToNineMap >>= integer+ _ -> Nothing+ }++tenToNineteenMap :: HashMap Text Integer+tenToNineteenMap = HashMap.fromList+ [ ( "పది", 10 )+ , ( "పదకొండు", 11 )+ , ( "పన్నెండు", 12 )+ , ( "పదమూడు", 13 )+ , ( "పద్నాల్గు", 14 )+ , ( "పదిహేను", 15 )+ , ( "పదహారు", 16 )+ , ( "పదిహేడు", 17 )+ , ( "పద్దెనిమిది", 18 )+ , ( "పంతొమ్మిది", 19 )+ ]++ruleTenToNineteen :: Rule+ruleTenToNineteen = Rule+ { name = "integer (10..19)"+ , pattern =+ [ regex "(పదకొండు|పన్నెండు|పదమూడు|పద్నాల్గు|పదిహేను|పదహారు|పదిహేడు|పద్దెనిమిది|పంతొమ్మిది|పది)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup (Text.toLower match) tenToNineteenMap >>= integer+ _ -> Nothing+ }++tensMap :: HashMap Text Integer+tensMap = HashMap.fromList+ [ ( "ఇరవై", 20 )+ , ( "ముప్పై", 30 )+ , ( "నలబై", 40 )+ , ( "యాబై", 50 )+ , ( "అరవై", 60 )+ , ( "డెబ్బై", 70 )+ , ( "ఎనబై", 80 )+ , ( "తొంబై", 90 )+ ]++ruleTens :: Rule+ruleTens = Rule+ { name = "integer (20..90)"+ , pattern =+ [ regex "(ఇరవై|ముప్పై|నలబై|యాబై|అరవై|డెబ్బై|ఎనబై|తొంబై)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup match tensMap >>= integer+ _ -> Nothing+ }++hundredsMap :: HashMap Text Integer+hundredsMap = HashMap.fromList+ [ ( "వంద", 100 )+ , ( "వెయ్యి", 1000 )+ , ( "లక్ష", 100000 )+ , ( "కోటి", 10000000 )+ ]++rulehundreds :: Rule+rulehundreds = Rule+ { name = "integer (100,1000,100000,10000000)"+ , pattern =+ [ regex "(వంద|వెయ్యి|లక్ష|కోటి)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup (Text.toLower match) hundredsMap >>= integer+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleTelugu+ , ruleZeroToNine+ , ruleTenToNineteen+ , ruleTens+ , rulehundreds+ ]
@@ -0,0 +1,153 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}++module Duckling.Numeral.TH.Corpus+ ( corpus ) where++import Prelude+import Data.String++import Duckling.Locale+import Duckling.Numeral.Types+import Duckling.Resolve+import Duckling.Testing.Types++corpus :: Corpus+corpus = (testContext {locale = makeLocale TH Nothing}, testOptions, allExamples)++allExamples :: [Example]+allExamples = concat+ [+ examples (NumeralValue 0)+ [ "0"+ , "ไม่มี"+ , "ศูนย์"+ ]+ ,examples (NumeralValue 1)+ [ "1"+ , "หนึ่ง"+ ]+ , examples (NumeralValue 2)+ [ "2"+ , "สอง"+ ]+ , examples (NumeralValue 3)+ [ "3"+ , "สาม"+ ]+ , examples (NumeralValue 10)+ [ "10"+ , "สิบ"+ ]+ , examples (NumeralValue 12)+ [ "12"+ , "สิบสอง"+ , "โหล"+ ]+ , examples (NumeralValue 14)+ [ "14"+ , "สิบสี่"+ ]+ , examples (NumeralValue 16)+ [ "16"+ , "สิบหก"+ ]+ , examples (NumeralValue 17)+ [ "17"+ , "สิบเจ็ด"+ ]+ , examples (NumeralValue 18)+ [ "18"+ , "สิบแปด"+ ]+ , examples (NumeralValue 33)+ [ "33"+ , "0033"+ ]+ , examples (NumeralValue 24)+ [ "24"+ , "สองโหล"+ ]+ , examples (NumeralValue 1.1)+ [ "1.1"+ , "1.10"+ , "01.10"+ , "1 จุด 1"+ , "หนึ่งจุดหนึ่ง"+ ]+ , examples (NumeralValue 0.77)+ [ ".77"+ , "0.77"+ , "จุด 77"+ ]+ , examples (NumeralValue 100000)+ [ "100,000"+ , "100,000.0"+ , "100000"+ , "หนึ่งแสน"+ ]+ , examples (NumeralValue 0.2)+ [ "1/5"+ , "2/10"+ , "3/15"+ , "20/100"+ , "ศูนย์จุดสอง"+ ]+ , examples (NumeralValue 3e6)+ [ "3000000"+ , "3,000,000"+ , "3 ล้าน"+ , "สามล้าน"+ ]+ , examples (NumeralValue 1.2e6)+ [ "1,200,000"+ , "1200000"+ , "1.2 ล้าน"+ , "หนึ่งจุดสองล้าน"+ ]+ , examples (NumeralValue 5000)+ [ "ห้าพัน"+ ]+ , examples (NumeralValue (-504))+ [ "-504"+ ]+ , examples (NumeralValue (-1.2e6))+ [ "- 1,200,000"+ , "-1200000"+ , "ลบ 1,200,000"+ ]+ , examples (NumeralValue 122)+ [ "หนึ่งร้อยยี่สิบสอง"+ ]+ , examples (NumeralValue 2e5)+ [ "สองแสน"+ ]+ , examples (NumeralValue 21011)+ [ "สองหมื่นหนึ่งพันสิบเอ็ด"+ , "สองหมื่นหนึ่งพันสิบหนึ่ง"+ ]+ , examples (NumeralValue 721012)+ [ "เจ็ดแสนสองหมื่นหนึ่งพันสิบสอง"+ ]+ , examples (NumeralValue 31256721)+ [ "สามสิบเอ็ดล้านสองแสนห้าหมื่นหกพันเจ็ดร้อยยี่สิบเอ็ด"+ , "สามสิบหนึ่งล้านสองแสนห้าหมื่นหกพันเจ็ดร้อยยี่สิบหนึ่ง"+ ]+ , examples (NumeralValue 2400)+ [ "สองร้อยโหล"+ , "200 โหล"+ ]+ , examples (NumeralValue 2200000)+ [ "สองจุดสองล้าน"+ , "สองล้านสองแสน"+ ]+ , examples (NumeralValue 3000000000)+ [ "สามพันล้าน"+ ]+ ]
@@ -0,0 +1,460 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE NoRebindableSyntax #-}+{-# LANGUAGE OverloadedStrings #-}++module Duckling.Numeral.TH.Rules+ ( rules+ ) where++import Control.Applicative ((<|>))+import Data.HashMap.Strict (HashMap)+import Data.Maybe+import Data.String+import Data.Text (Text)+import Prelude+import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text++import Duckling.Dimensions.Types+import Duckling.Numeral.Helpers+import Duckling.Numeral.Types (NumeralData (..))+import Duckling.Regex.Types+import Duckling.Types+import qualified Duckling.Numeral.Types as TNumeral++ruleDozen :: Rule+ruleDozen = Rule+ { name = "a dozen of"+ , pattern =+ [ regex "โหล?( ของ)?"+ ]+ , prod = \_ -> integer 12 >>= withMultipliable >>= notOkForAnyTime+ }++zeroNineteenMap :: HashMap Text Integer+zeroNineteenMap = HashMap.fromList+ [ ( "ไม่มี", 0 )+ , ( "ศูนย์", 0 )+ , ( "หนึ่ง", 1 )+ , ( "เอ็ด", 1 )+ , ( "สอง", 2 )+ , ( "สาม", 3 )+ , ( "สี่", 4 )+ , ( "ห้า", 5 )+ , ( "หก", 6 )+ , ( "เจ็ด", 7 )+ , ( "แปด", 8 )+ , ( "เก้า", 9 )+ , ( "สิบ", 10 )+ , ( "สิบเอ็ด", 11 )+ , ( "สิบหนึ่ง", 11 )+ , ( "สิบสอง", 12 )+ , ( "สิบสาม", 13 )+ , ( "สิบสี่", 14 )+ , ( "สิบห้า", 15 )+ , ( "สิบหก", 16 )+ , ( "สิบเจ็ด", 17 )+ , ( "สิบแปด", 18 )+ , ( "สิบเก้า", 19 )+ ]++informalMap :: HashMap Text Integer+informalMap = HashMap.fromList+ [ ( "อันนึง", 1 )+ , ( "คู่นึง", 2 )+ , ( "คู่ของ", 2 )+ ]++ruleToNineteen :: Rule+ruleToNineteen = Rule+ { name = "integer (0..19)"+ -- e.g. fourteen must be before four, otherwise four will always shadow fourteen+ , pattern =+ [ regex "(ไม่มี|ศูนย์|สิบหนึ่ง|หนึ่ง|(คู่)s?( ของ)?|(คู่)s?( นึง)?|สิบเอ็ด|เอ็ด|สิบสอง|สิบสาม|สิบสี่|สิบห้า|สิบหก|สิบเจ็ด|สิบแปด|สิบเก้า|สอง|สาม|สี่|ห้า|หก|เจ็ด|แปด|เก้า|สิบ)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ let x = Text.toLower match in+ (HashMap.lookup x zeroNineteenMap >>= integer) <|>+ (HashMap.lookup x informalMap >>= integer >>= notOkForAnyTime)+ _ -> Nothing+ }++tensMap :: HashMap Text Integer+tensMap = HashMap.fromList+ [ ( "ยี่สิบ", 20 )+ , ( "สามสิบ", 30 )+ , ( "สี่สิบ", 40 )+ , ( "ห้าสิบ", 50 )+ , ( "หกสิบ", 60 )+ , ( "เจ็ดสิบ", 70 )+ , ( "แปดสิบ", 80 )+ , ( "เก้าสิบ", 90 )+ ]++ruleTens :: Rule+ruleTens = singleStringLookupRule tensMap "integer (20..90)" integer++digitsHundredTwentyToTwentyNineMap :: HashMap Text Integer+digitsHundredTwentyToTwentyNineMap = HashMap.fromList+ [ ( "ร้อยยี่สิบ", 120 )+ , ( "ร้อยยี่สิบเอ็ด", 121 )+ , ( "ร้อยยี่สิบหนึ่ง", 121 )+ , ( "ร้อยยี่สิบสอง", 122 )+ , ( "ร้อยยี่สิบสาม", 123 )+ , ( "ร้อยยี่สิบสี่", 124 )+ , ( "ร้อยยี่สิบห้า", 125 )+ , ( "ร้อยยี่สิบหก", 126 )+ , ( "ร้อยยี่สิบเจ็ด", 127 )+ , ( "ร้อยยี่สิบแปด", 128 )+ , ( "ร้อยยี่สิบเก้า", 129 )+ , ( "หนึ่งร้อยยี่สิบ", 120 )+ , ( "หนึ่งร้อยยี่สิบเอ็ด", 121 )+ , ( "หนึ่งร้อยยี่สิบหนึ่ง", 121 )+ , ( "หนึ่งร้อยยี่สิบสอง", 122 )+ , ( "หนึ่งร้อยยี่สิบสาม", 123 )+ , ( "หนึ่งร้อยยี่สิบสี่", 124 )+ , ( "หนึ่งร้อยยี่สิบห้า", 125 )+ , ( "หนึ่งร้อยยี่สิบหก", 126 )+ , ( "หนึ่งร้อยยี่สิบเจ็ด", 127 )+ , ( "หนึ่งร้อยยี่สิบแปด", 128 )+ , ( "หนึ่งร้อยยี่สิบเก้า", 129 )+ , ( "สองร้อยยี่สิบ", 220 )+ , ( "สองร้อยยี่สิบเอ็ด", 221 )+ , ( "สองร้อยยี่สิบหนึ่ง", 221 )+ , ( "สองร้อยยี่สิบสอง", 222 )+ , ( "สองร้อยยี่สิบสาม", 223 )+ , ( "สองร้อยยี่สิบสี่", 224 )+ , ( "สองร้อยยี่สิบห้า", 225 )+ , ( "สองร้อยยี่สิบหก", 226 )+ , ( "สองร้อยยี่สิบเจ็ด", 227 )+ , ( "สองร้อยยี่สิบแปด", 228 )+ , ( "สองร้อยยี่สิบเก้า", 229 )+ , ( "สามร้อยยี่สิบ", 320 )+ , ( "สามร้อยยี่สิบเอ็ด", 321 )+ , ( "สามร้อยยี่สิบหนึ่ง", 321 )+ , ( "สามร้อยยี่สิบสอง", 322 )+ , ( "สามร้อยยี่สิบสาม", 323 )+ , ( "สามร้อยยี่สิบสี่", 324 )+ , ( "สามร้อยยี่สิบห้า", 325 )+ , ( "สามร้อยยี่สิบหก", 326 )+ , ( "สามร้อยยี่สิบเจ็ด", 327 )+ , ( "สามร้อยยี่สิบแปด", 328 )+ , ( "สามร้อยยี่สิบเก้า", 329 )+ , ( "สี่ร้อยยี่สิบ", 420 )+ , ( "สี่ร้อยยี่สิบเอ็ด", 421 )+ , ( "สี่ร้อยยี่สิบหนึ่ง", 421 )+ , ( "สี่ร้อยยี่สิบสอง", 422 )+ , ( "สี่ร้อยยี่สิบสาม", 423 )+ , ( "สี่ร้อยยี่สิบสี่", 424 )+ , ( "สี่ร้อยยี่สิบห้า", 425 )+ , ( "สี่ร้อยยี่สิบหก", 426 )+ , ( "สี่ร้อยยี่สิบเจ็ด", 427 )+ , ( "สี่ร้อยยี่สิบแปด", 428 )+ , ( "สี่ร้อยยี่สิบเก้า", 429 )+ , ( "ห้าร้อยยี่สิบ", 520 )+ , ( "ห้าร้อยยี่สิบเอ็ด", 521 )+ , ( "ห้าร้อยยี่สิบหนึ่ง", 521 )+ , ( "ห้าร้อยยี่สิบสอง", 522 )+ , ( "ห้าร้อยยี่สิบสาม", 523 )+ , ( "ห้าร้อยยี่สิบสี่", 524 )+ , ( "ห้าร้อยยี่สิบห้า", 525 )+ , ( "ห้าร้อยยี่สิบหก", 526 )+ , ( "ห้าร้อยยี่สิบเจ็ด", 527 )+ , ( "ห้าร้อยยี่สิบแปด", 528 )+ , ( "ห้าร้อยยี่สิบเก้า", 529 )+ , ( "หกร้อยยี่สิบ", 620 )+ , ( "หกร้อยยี่สิบเอ็ด", 621 )+ , ( "หกร้อยยี่สิบหนึ่ง", 621 )+ , ( "หกร้อยยี่สิบสอง", 622 )+ , ( "หกร้อยยี่สิบสาม", 623 )+ , ( "หกร้อยยี่สิบสี่", 624 )+ , ( "หกร้อยยี่สิบห้า", 625 )+ , ( "หกร้อยยี่สิบหก", 626 )+ , ( "หกร้อยยี่สิบเจ็ด", 627 )+ , ( "หกร้อยยี่สิบแปด", 628 )+ , ( "หกร้อยยี่สิบเก้า", 629 )+ , ( "เจ็ดร้อยยี่สิบ", 720 )+ , ( "เจ็ดร้อยยี่สิบเอ็ด", 721 )+ , ( "เจ็ดร้อยยี่สิบหนึ่ง", 721 )+ , ( "เจ็ดร้อยยี่สิบสอง", 722 )+ , ( "เจ็ดร้อยยี่สิบสาม", 723 )+ , ( "เจ็ดร้อยยี่สิบสี่", 724 )+ , ( "เจ็ดร้อยยี่สิบห้า", 725 )+ , ( "เจ็ดร้อยยี่สิบหก", 726 )+ , ( "เจ็ดร้อยยี่สิบเจ็ด", 727 )+ , ( "เจ็ดร้อยยี่สิบแปด", 728 )+ , ( "เจ็ดร้อยยี่สิบเก้า", 729 )+ , ( "แปดร้อยยี่สิบ", 820 )+ , ( "แปดร้อยยี่สิบเอ็ด", 821 )+ , ( "แปดร้อยยี่สิบหนึ่ง", 821 )+ , ( "แปดร้อยยี่สิบสอง", 822 )+ , ( "แปดร้อยยี่สิบสาม", 823 )+ , ( "แปดร้อยยี่สิบสี่", 824 )+ , ( "แปดร้อยยี่สิบห้า", 825 )+ , ( "แปดร้อยยี่สิบหก", 826 )+ , ( "แปดร้อยยี่สิบเจ็ด", 827 )+ , ( "แปดร้อยยี่สิบแปด", 828 )+ , ( "แปดร้อยยี่สิบเก้า", 829 )+ , ( "เก้าร้อยยี่สิบ", 920 )+ , ( "เก้าร้อยยี่สิบเอ็ด", 921 )+ , ( "เก้าร้อยยี่สิบหนึ่ง", 921 )+ , ( "เก้าร้อยยี่สิบสอง", 922 )+ , ( "เก้าร้อยยี่สิบสาม", 923 )+ , ( "เก้าร้อยยี่สิบสี่", 924 )+ , ( "เก้าร้อยยี่สิบห้า", 925 )+ , ( "เก้าร้อยยี่สิบหก", 926 )+ , ( "เก้าร้อยยี่สิบเจ็ด", 927 )+ , ( "เก้าร้อยยี่สิบแปด", 928 )+ , ( "เก้าร้อยยี่สิบเก้า", 929 )+ ]++ruleXHundredTwentyToXHundredTwentyNine :: Rule+ruleXHundredTwentyToXHundredTwentyNine = singleStringLookupRule+ digitsHundredTwentyToTwentyNineMap "integer (x20,x21,...,x29)" integer++rulePowersOfTen :: Rule+rulePowersOfTen = Rule+ { name = "powers of tens"+ , pattern = [regex "(ร้อย|พัน|หมื่น|แสน|ล้าน|สิบล้าน|ร้อยล้าน|พันล้าน)"]+ , prod = \case+ (Token RegexMatch (GroupMatch (match : _)) : _) ->+ case Text.toLower match of+ "ร้อย" -> double 1e2 >>= withGrain 2 >>= withMultipliable+ "พัน" -> double 1e3 >>= withGrain 3 >>= withMultipliable+ "หมื่น" -> double 1e4 >>= withGrain 4 >>= withMultipliable+ "แสน" -> double 1e5 >>= withGrain 5 >>= withMultipliable+ "ล้าน" -> double 1e6 >>= withGrain 6 >>= withMultipliable+ "สิบล้าน" -> double 1e7 >>= withGrain 7 >>= withMultipliable+ "ร้อยล้าน" -> double 1e8 >>= withGrain 8 >>= withMultipliable+ "พันล้าน" -> double 1e9 >>= withGrain 9 >>= withMultipliable+ _ -> Nothing+ _ -> Nothing+ }++ruleCompositeTens :: Rule+ruleCompositeTens = Rule+ { name = "integer 21..99"+ , pattern =+ [ oneOf [20,30..90]+ , regex "[\\s\\-]+"+ , numberBetween 1 10+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = tens}:+ _:+ Token Numeral NumeralData{TNumeral.value = units}:+ _) -> double $ tens + units+ _ -> Nothing+ }++ruleSumTenDigits :: Rule+ruleSumTenDigits = Rule+ { name = "สามสิบสี่"+ , pattern =+ [ regex "(ยี่สิบ|สามสิบ|สี่สิบ|ห้าสิบ|หกสิบ|เจ็ดสิบ|แปดสิบ|เก้าสิบ)"+ , regex "(หนึ่ง|เอ็ด|สอง|สาม|สี่|ห้า|หก|เจ็ด|แปด|เก้า|สิบ)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (m1:_)):+ Token RegexMatch (GroupMatch (m2:_)):+ _) -> do+ let x1 = Text.toLower m1+ let x2 = Text.toLower m2+ hundreds <- HashMap.lookup x1 tensMap+ rest <- HashMap.lookup x2 zeroNineteenMap+ integer (hundreds + rest)+ _ -> Nothing+ }++ruleSkipHundreds1 :: Rule+ruleSkipHundreds1 = Rule+ { name = "one eleven"+ , pattern =+ [ regex "(หนึ่ง|สอง|สาม|สี่|ห้า|หก|เจ็ด|แปด|เก้า)"+ , regex "(สิบ|สิบเอ็ด|สิบสอง|สิบสาม|สิบสี่|สิบห้า|สิบหก|สิบเจ็ด|สิบแปด|สิบเก้า|ยี่สิบ|สามสิบ|สี่สิบ|ห้าสิบ|หกสิบ|เจ็ดสิบ|แปดสิบ|เก้าสิบ)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (m1:_)):+ Token RegexMatch (GroupMatch (m2:_)):+ _) -> do+ let x1 = Text.toLower m1+ let x2 = Text.toLower m2+ hundreds <- HashMap.lookup x1 zeroNineteenMap+ rest <- HashMap.lookup x2 zeroNineteenMap <|> HashMap.lookup x2 tensMap+ integer (hundreds * 100 + rest)+ _ -> Nothing+ }++ruleSkipHundreds2 :: Rule+ruleSkipHundreds2 = Rule+ { name = "one twenty two"+ , pattern =+ [ regex "(หนึ่ง|สอง|สาม|สี่|ห้า|หก|เจ็ด|แปด|เก้า)"+ , regex "(ยี่สิบ|สามสิบ|สี่สิบ|ห้าสิบ|หกสิบ|เจ็ดสิบ|แปดสิบ|เก้าสิบ)"+ , regex "(หนึ่ง|สอง|สาม|สี่|ห้า|หก|เจ็ด|แปด|เก้า)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (m1:_)):+ Token RegexMatch (GroupMatch (m2:_)):+ Token RegexMatch (GroupMatch (m3:_)):+ _) -> do+ let x1 = Text.toLower m1+ let x2 = Text.toLower m2+ let x3 = Text.toLower m3+ hundreds <- HashMap.lookup x1 zeroNineteenMap+ tens <- HashMap.lookup x2 tensMap+ rest <- HashMap.lookup x3 zeroNineteenMap+ integer (hundreds * 100 + tens + rest)+ _ -> Nothing+ }++ruleDotSpelledOut :: Rule+ruleDotSpelledOut = Rule+ { name = "one point 2"+ , pattern =+ [ dimension Numeral+ , regex "จุด"+ , Predicate $ not . hasGrain+ ]+ , prod = \case+ (Token Numeral nd1:_:Token Numeral nd2:_) ->+ double $ TNumeral.value nd1 + decimalsToDouble (TNumeral.value nd2)+ _ -> Nothing+ }++ruleLeadingDotSpelledOut :: Rule+ruleLeadingDotSpelledOut = Rule+ { name = "point 77"+ , pattern =+ [ regex "จุด"+ , Predicate $ not . hasGrain+ ]+ , prod = \case+ (_:Token Numeral nd:_) -> double $ decimalsToDouble $ TNumeral.value nd+ _ -> Nothing+ }++ruleDecimals :: Rule+ruleDecimals = Rule+ { name = "decimal number"+ , pattern =+ [ regex "(\\d*\\.\\d+)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) -> parseDecimal True match+ _ -> Nothing+ }++ruleCommas :: Rule+ruleCommas = Rule+ { name = "comma-separated numbers"+ , pattern =+ [ regex "(\\d+(,\\d\\d\\d)+(\\.\\d+)?)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ parseDouble (Text.replace "," Text.empty match) >>= double+ _ -> Nothing+ }++ruleSuffixes :: Rule+ruleSuffixes = Rule+ { name = "suffixes (กิโลกรัม,กรัม))"+ , pattern =+ [ dimension Numeral+ , regex "(กิโลกรัม|กรัม)(?=[\\W$€¢£]|$)"+ ]+ , prod = \case+ (Token Numeral nd : Token RegexMatch (GroupMatch (match : _)):_) -> do+ x <- case Text.toLower match of+ "กิโลกรัม" -> Just 1e3+ "กรัม" -> Just 1e1+ _ -> Nothing+ double $ TNumeral.value nd * x+ _ -> Nothing+ }++ruleNegative :: Rule+ruleNegative = Rule+ { name = "negative numbers"+ , pattern =+ [ regex "(-|ลบ)(?!\\s*-)"+ , Predicate isPositive+ ]+ , prod = \case+ (_:Token Numeral nd:_) -> double (TNumeral.value nd * (-1))+ _ -> Nothing+ }++ruleSum :: Rule+ruleSum = Rule+ { name = "intersect 2 numbers"+ , pattern =+ [ Predicate $ and . sequence [hasGrain, isPositive]+ , Predicate $ and . sequence [not . isMultipliable, isPositive]+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = val1, TNumeral.grain = Just g}:+ Token Numeral NumeralData{TNumeral.value = val2}:+ _) | (10 ** fromIntegral g) > val2 -> double $ val1 + val2+ _ -> Nothing+ }++ruleSumAnd :: Rule+ruleSumAnd = Rule+ { name = "intersect 2 numbers (with and)"+ , pattern =+ [ Predicate $ and . sequence [hasGrain, isPositive]+ , regex "และ"+ , Predicate $ and . sequence [not . isMultipliable, isPositive]+ ]+ , prod = \case+ (Token Numeral NumeralData{TNumeral.value = val1, TNumeral.grain = Just g}:+ _:+ Token Numeral NumeralData{TNumeral.value = val2}:+ _) | (10 ** fromIntegral g) > val2 -> double $ val1 + val2+ _ -> Nothing+ }++ruleMultiply :: Rule+ruleMultiply = Rule+ { name = "compose by multiplication"+ , pattern =+ [ dimension Numeral+ , Predicate isMultipliable+ ]+ , prod = \case+ (token1:token2:_) -> multiply token1 token2+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleXHundredTwentyToXHundredTwentyNine+ , ruleSkipHundreds1+ , ruleSkipHundreds2+ , ruleToNineteen+ , ruleTens+ , rulePowersOfTen+ , ruleCompositeTens+ , ruleSumTenDigits+ , ruleDotSpelledOut+ , ruleLeadingDotSpelledOut+ , ruleDecimals+ , ruleCommas+ , ruleSuffixes+ , ruleNegative+ , ruleSum+ , ruleSumAnd+ , ruleMultiply+ , ruleDozen+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -153,7 +152,7 @@ ruleNumeralSuffixesHalfsuffixText = Rule { name = "number suffixes (half-suffix text) (1..9)" , pattern =- [ regex "((bir?|iki|üç|dört|beş|altı|yedi|sekiz|dokuz)(buçuk))"+ [ regex "((bir?|iki|üçü?|dört|beş|altı|yedi|sekiz|dokuz)(buçuk))" ] , prod = \tokens -> case tokens of (Token RegexMatch (GroupMatch (match:_)):_) ->@@ -515,7 +514,7 @@ ruleInteger9 = Rule { name = "integer 11..19 21..29 31..39 41..49 51..59 61..69 71..79 81..89 91..99" , pattern =- [ regex "((on|yirmi|otuz|kırk|elli|atmış|altmış|yetmiş|seksen|doksan)(bir|bi|iki|üç|dört|beş|altı|yedi|sekiz|dokuz)(buçuk))"+ [ regex "((on|yirmi|otuz|kırk|elli|atmış|altmış|yetmiş|seksen|doksan)(bir|bi|iki|üçü?|dört|beş|altı|yedi|sekiz|dokuz)(buçuk))" ] , prod = \tokens -> case tokens of (Token RegexMatch (GroupMatch (match:_)):_) ->@@ -543,6 +542,7 @@ , ( "tek", 1) , ( "iki", 2) , ( "üç", 3)+ , ( "üçü", 3) , ( "dört", 4) , ( "beş", 5) , ( "altı", 6)@@ -555,7 +555,7 @@ ruleInteger = Rule { name = "integer (0..9)" , pattern =- [ regex "(yok|hi(ç)|s(ı)f(ı)r|bir?|[ty]ek|iki|(ü)(ç)|d(ö)rt|be(ş)|alt(ı)|yedi|sekiz|dokuz)"+ [ regex "(yok|hi(ç)|s(ı)f(ı)r|bir?|[ty]ek|iki|(ü)(ç)(ü)?|d(ö)rt|be(ş)|alt(ı)|yedi|sekiz|dokuz)" ] , prod = \tokens -> case tokens of (Token RegexMatch (GroupMatch (match:_)):_) ->
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE DeriveAnyClass #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -58,7 +57,7 @@ ] , examples (NumeralValue 100) [ "100"- , "tră"+ , "trăm" ] , examples (NumeralValue 1.1) [ "1,1"@@ -96,15 +95,22 @@ , "-1200K" , "-,0012G" ]+ , examples (NumeralValue 20)+ [ "hai chục"+ , "hai mươi"+ ] , examples (NumeralValue 5000) [ "5 nghìn" , "năm nghìn"+ , "năm ngàn" ] , examples (NumeralValue 200000) [ "hai trăm nghìn"+ , "hai trăm ngàn" ] , examples (NumeralValue 1000000000) [ "một tỷ"+ , "một tỉ" ] , examples (NumeralValue 21011) [ "hai mươi mốt nghìn không trăm mười một"
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -28,21 +27,20 @@ powersOfTenMap :: HashMap.HashMap Text.Text (Double, Int) powersOfTenMap = HashMap.fromList- [ ( "tră", (1e2, 2) )+ [ ( "chục", (1e1, 1) ) , ( "trăm", (1e2, 2) )- , ( "nghì", (1e3, 3) ) , ( "nghìn", (1e3, 3) )- , ( "triệ", (1e6, 6) )+ , ( "ngàn", (1e3, 3) ) , ( "triệu", (1e6, 6) )- , ( "t", (1e9, 9) ) , ( "tỷ", (1e9, 9) )+ , ( "tỉ", (1e9, 9) ) ] rulePowersOfTen :: Rule rulePowersOfTen = Rule { name = "powers of tens" , pattern =- [ regex "(trăm?|nghìn?|triệu?|tỷ?)"+ [ regex "(chục|trăm|nghìn|ngàn|triệu|t(ỷ|ỉ))" ] , prod = \tokens -> case tokens of (Token RegexMatch (GroupMatch (match:_)):_) -> do
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -36,67 +35,97 @@ , "一" , "一个" , "1个"+ , "壹" ] , examples (NumeralValue 2) [ "2" , "二個" , "二个"+ , "貳"+ , "一對"+ , "一雙" ] , examples (NumeralValue 10) [ "10" , "十"+ , "拾"+ , "五對"+ , "五雙" ] , examples (NumeralValue 11) [ "11" , "十一"+ , "拾壹" ] , examples (NumeralValue 20) [ "20" , "二十"+ , "貳拾"+ , "廿" ] , examples (NumeralValue 60) [ "60" , "六十"+ , "陸拾"+ , "五打" ] , examples (NumeralValue 33) [ "33" , "三十三"+ , "參拾參"+ , "卅三" ] , examples (NumeralValue 96) [ "96" , "九十六"+ , "玖拾陸"+ , "八打" ] , examples (NumeralValue 203) [ "203" , "二百零三"+ , "貳佰零參" ] , examples (NumeralValue 534) [ "534" , "五百三十四"+ , "伍佰參拾肆"+ , "五百卅四" ] , examples (NumeralValue 34567) [ "34567" , "34,567" , "三万四千五百六十七"+ , "三萬四千五百六十七"+ , "參萬肆仟伍佰陸拾柒" ] , examples (NumeralValue 10040) [ "10040" , "10,040" , "一万零四十"+ , "一萬零四十"+ , "壹萬零肆拾"+ , "一萬零卌" ] , examples (NumeralValue 1.1) [ "1.1" , "1.10" , "01.10"+ , "一點一"+ , "十份十一"+ , "一又十分一" ] , examples (NumeralValue 0.77) [ "0.77" , ".77"+ , "零點77" ] , examples (NumeralValue 34507) [ "34507" , "34,507" , "三万四千五百零七"+ , "三萬四千五百零七"+ , "參萬肆仟伍佰零柒" ] , examples (NumeralValue 100000) [ "100,000"@@ -104,18 +133,24 @@ , "100K" , "100k" , "十万"+ , "十萬"+ , "拾萬" ] , examples (NumeralValue 3000000) [ "3M" , "3000000" , "3,000,000" , "三百万"+ , "三百萬"+ , "參佰萬" ] , examples (NumeralValue 1040000) [ "1,040,000" , "1040000" , "1.04M" , "一百零四万"+ , "一百零四萬"+ , "壹佰零肆萬" ] , examples (NumeralValue 1200000) [ "1,200,000"@@ -123,6 +158,9 @@ , "1.2M" , ".0012G" , "一百二十万"+ , "一百二十萬"+ , "壹佰貳拾萬"+ , "百二萬" ] , examples (NumeralValue (-1200000)) [ "- 1,200,000"@@ -136,5 +174,25 @@ , "-1200K" , "-.0012G" , "负一百二十万"+ , "負一百二十萬"+ , "負壹佰貳拾萬"+ ]+ , examples (NumeralValue 0.5)+ [ "0.5"+ , "一半"+ , "一半半"+ , "1半"+ , "半个"+ , "半個"+ , "零點五"+ , "二分之一"+ , "二份一"+ ]+ , examples (NumeralValue 1100)+ [ "千一"+ , "一千一百"+ ]+ , examples (NumeralValue 19000)+ [ "萬九" ] ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -32,7 +31,7 @@ ruleInteger = Rule { name = "integer (0..10)" , pattern =- [ regex "(〇|零|一|二|两|兩|三|四|五|六|七|八|九|十)"+ [ regex "(〇|零|一|二|两|兩|三|四|五|六|七|八|九|十|壹|貳|參|肆|伍|陸|柒|捌|玖|拾)" ] , prod = \case (Token RegexMatch (GroupMatch (match:_)):_) ->@@ -45,20 +44,64 @@ [ ( "〇", 0 ) , ( "零", 0 ) , ( "一", 1 )+ , ( "壹", 1 ) , ( "兩", 2 ) , ( "两", 2 ) , ( "二", 2 )+ , ( "貳", 2 ) , ( "三", 3 )+ , ( "參", 3 ) , ( "四", 4 )+ , ( "肆", 4 ) , ( "五", 5 )+ , ( "伍", 5 ) , ( "六", 6 )+ , ( "陸", 6 ) , ( "七", 7 )+ , ( "柒", 7 ) , ( "八", 8 )+ , ( "捌", 8 ) , ( "九", 9 )+ , ( "玖", 9 ) , ( "十", 10 )+ , ( "拾", 10 ) ] +tensMap :: HashMap.HashMap Text Integer+tensMap = HashMap.fromList+ [ ( "廿" , 20 )+ , ( "卅" , 30 )+ , ( "卌" , 40 )+ ] +ruleTens :: Rule+ruleTens = Rule+ { name = "integer (20,30,40)"+ , pattern =+ [ regex "(廿|卅|卌)"+ ]+ , prod = \tokens -> case tokens of+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ HashMap.lookup (Text.toLower match) tensMap >>= integer+ _ -> Nothing+ }++ruleCompositeTens :: Rule+ruleCompositeTens = Rule+ { name = "integer 21..49"+ , pattern =+ [ oneOf [20,30,40]+ , regex "[\\s\\-]+"+ , numberBetween 1 10+ ]+ , prod = \tokens -> case tokens of+ (Token Numeral NumeralData{TNumeral.value = tens}:+ _:+ Token Numeral NumeralData{TNumeral.value = units}:+ _) -> double $ tens + units+ _ -> Nothing+ }+ ruleNumeralsPrefixWithNegativeOrMinus :: Rule ruleNumeralsPrefixWithNegativeOrMinus = Rule { name = "numbers prefix with -, negative or minus"@@ -94,6 +137,56 @@ _ -> Nothing } +ruleDotSpelledOut :: Rule+ruleDotSpelledOut = Rule+ { name = "one point 2"+ , pattern =+ [ dimension Numeral+ , regex "點"+ , Predicate $ not . hasGrain+ ]+ , prod = \tokens -> case tokens of+ (Token Numeral nd1:_:Token Numeral nd2:_) ->+ double $ TNumeral.value nd1 + decimalsToDouble (TNumeral.value nd2)+ _ -> Nothing+ }++ruleFraction :: Rule+ruleFraction = Rule+ { name = "fraction"+ , pattern =+ [ dimension Numeral+ , regex "分之|分|份"+ , dimension Numeral+ ]+ , prod = \tokens -> case tokens of+ (Token Numeral NumeralData{TNumeral.value = v1}:+ _:+ Token Numeral NumeralData{TNumeral.value = v2}:+ _) -> double $ v2 / v1+ _ -> Nothing+ }++ruleMixedFraction :: Rule+ruleMixedFraction = Rule+ { name = " mixed fraction"+ , pattern =+ [ dimension Numeral+ , regex "又"+ , dimension Numeral+ , regex "分之|分|份"+ , dimension Numeral+ ]+ , prod = \tokens -> case tokens of+ (Token Numeral NumeralData{TNumeral.value = v1}:+ _:+ Token Numeral NumeralData{TNumeral.value = v2}:+ _:+ Token Numeral NumeralData{TNumeral.value = v3}:+ _) -> double $ v3 / v2 + v1+ _ -> Nothing+ }+ ruleNumeral :: Rule ruleNumeral = Rule { name = "<number>个/個"@@ -106,16 +199,45 @@ _ -> Nothing } +ruleHalf :: Rule+ruleHalf = Rule+ { name = "half"+ , pattern =+ [ regex "(1|一)?半(半|个|個)?"+ ]+ , prod = \case+ (_:_) -> double 0.5 >>= withMultipliable+ _ -> Nothing+ }++ruleDozen :: Rule+ruleDozen = Rule+ { name = "a dozen of"+ , pattern =+ [ regex "打"+ ]+ , prod = \_ -> integer 12 >>= withMultipliable >>= notOkForAnyTime+ }++rulePair :: Rule+rulePair = Rule+ { name = "a pair"+ , pattern =+ [ regex "雙|對"+ ]+ , prod = \_ -> integer 2 >>= withMultipliable >>= notOkForAnyTime+ }+ numeralSuffixList :: [(Text, Maybe Token)] numeralSuffixList = [ ("K", double 1e3 >>= withGrain 3 >>= withMultipliable) , ("M", double 1e6 >>= withGrain 6 >>= withMultipliable) , ("G", double 1e9 >>= withGrain 9 >>= withMultipliable)- , ("十", double 1e1 >>= withGrain 1 >>= withMultipliable)- , ("百", double 1e2 >>= withGrain 2 >>= withMultipliable)- , ("千", double 1e3 >>= withGrain 3 >>= withMultipliable)- , ("万", double 1e4 >>= withGrain 4 >>= withMultipliable)- , ("亿", double 1e8 >>= withGrain 8 >>= withMultipliable)+ , ("十|拾", double 1e1 >>= withGrain 1 >>= withMultipliable)+ , ("百|佰", double 1e2 >>= withGrain 2 >>= withMultipliable)+ , ("千|仟", double 1e3 >>= withGrain 3 >>= withMultipliable)+ , ("万|萬", double 1e4 >>= withGrain 4 >>= withMultipliable)+ , ("亿|億", double 1e8 >>= withGrain 8 >>= withMultipliable) ] ruleNumeralSuffixes :: [Rule]@@ -197,6 +319,45 @@ | d == 1 = Just $ v1 + v2 | otherwise = Nothing +ruleHundredPrefix :: Rule+ruleHundredPrefix = Rule+ { name = "one hundred and <integer> (short form)"+ , pattern =+ [ regex "百|佰"+ , numberBetween 1 10+ ]+ , prod = \case+ (_:Token Numeral NumeralData{TNumeral.value = v}:_) ->+ double $ 100 + v*10+ _ -> Nothing+ }++ruleThousandPrefix :: Rule+ruleThousandPrefix = Rule+ { name = "one thousand and <integer> (short form)"+ , pattern =+ [ regex "千|仟"+ , numberBetween 1 10+ ]+ , prod = \case+ (_:Token Numeral NumeralData{TNumeral.value = v}:_) ->+ double $ 1000 + v*100+ _ -> Nothing+ }++ruleTenThousandPrefix :: Rule+ruleTenThousandPrefix = Rule+ { name = "ten thousand and <integer> (short form)"+ , pattern =+ [ regex "万|萬"+ , numberBetween 1 10+ ]+ , prod = \case+ (_:Token Numeral NumeralData{TNumeral.value = v}:_) ->+ double $ 10000 + v*1000+ _ -> Nothing+ }+ rules :: [Rule] rules = [ ruleDecimalNumeral@@ -208,5 +369,16 @@ , ruleNumeralsIntersectNonconsectiveUnit , ruleNumeralsPrefixWithNegativeOrMinus , ruleMultiply+ , ruleTens+ , ruleCompositeTens+ , ruleHalf+ , ruleDotSpelledOut+ , ruleDozen+ , rulePair+ , ruleFraction+ , ruleMixedFraction+ , ruleHundredPrefix+ , ruleThousandPrefix+ , ruleTenThousandPrefix ] ++ ruleNumeralSuffixes
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -0,0 +1,126 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}++module Duckling.Ordinal.CA.Corpus+ ( corpus ) where++import Data.String+import Prelude++import Duckling.Locale+import Duckling.Ordinal.Types+import Duckling.Resolve+import Duckling.Testing.Types++corpus :: Corpus+corpus = (testContext {locale = makeLocale CA Nothing}, testOptions, allExamples)++allExamples :: [Example]+allExamples = concat+ [ examples (OrdinalData 1)+ [ "primer"+ , "primera"+ , "primers"+ , "primeres"+ ]+ , examples (OrdinalData 2)+ [ "segon"+ , "segona"+ , "segons"+ , "segones"+ ]+ , examples (OrdinalData 3)+ [ "tercer"+ , "tercera"+ , "tercers"+ , "terceres"+ ]+ , examples (OrdinalData 4)+ [ "quart"+ , "quarta"+ , "quarts"+ , "quartes"+ ]+ , examples (OrdinalData 5)+ [ "cinquè"+ , "cinquena"+ , "cinquens"+ , "cinquenes"+ ]+ , examples (OrdinalData 6)+ [ "sisè"+ , "sisena"+ , "sisens"+ , "sisenes"+ ]+ , examples (OrdinalData 7)+ [ "setè"+ , "setena"+ , "setens"+ , "setenes"+ ]+ , examples (OrdinalData 8)+ [ "vuitè"+ , "vuitena"+ , "vuitens"+ , "vuitenes"+ ]+ , examples (OrdinalData 9)+ [ "novè"+ , "novena"+ , "novens"+ , "novenes"+ ]+ , examples (OrdinalData 10)+ [ "desè"+ , "desena"+ , "desens"+ , "desenes"+ ]+ , examples (OrdinalData 11)+ [ "onzè"+ , "onzena"+ ]+ , examples (OrdinalData 12)+ [ "dotzè"+ , "dotzena"+ ]+ , examples (OrdinalData 13)+ [ "tretzè"+ , "tretzena"+ ]+ , examples (OrdinalData 14)+ [ "catorzè"+ , "catorzena"+ ]+ , examples (OrdinalData 15)+ [ "quinzè"+ , "quinzena"+ ]+ , examples (OrdinalData 16)+ [ "setzè"+ , "setzena"+ ]+ , examples (OrdinalData 17)+ [ "dissetè"+ , "dissetena"+ ]+ , examples (OrdinalData 18)+ [ "divuitè"+ , "divuitena"+ ]+ , examples (OrdinalData 19)+ [ "dinovè"+ , "dinovena"+ ]+ , examples (OrdinalData 20)+ [ "vintè"+ , "vintena"+ ]+ ]
@@ -0,0 +1,104 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE LambdaCase #-}++module Duckling.Ordinal.CA.Rules+ ( rules ) where++import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text+import Prelude+import Data.String++import Duckling.Dimensions.Types+import Duckling.Ordinal.Helpers+import Duckling.Regex.Types+import Duckling.Types++ordinalsMap :: HashMap.HashMap Text.Text Int+ordinalsMap = HashMap.fromList+ [ ( "primer" , 1 )+ , ( "primers" , 1 )+ , ( "primera" , 1 )+ , ( "primeres" , 1 )+ , ( "segon" , 2 )+ , ( "segona" , 2 )+ , ( "segones" , 2 )+ , ( "segons" , 2 )+ , ( "tercer" , 3 )+ , ( "tercera" , 3 )+ , ( "tercers" , 3 )+ , ( "terceres" , 3 )+ , ( "quart" , 4 )+ , ( "quarta" , 4 )+ , ( "quarts" , 4 )+ , ( "quartes" , 4 )+ , ( "cinquè" , 5 )+ , ( "cinquena" , 5 )+ , ( "cinquens" , 5 )+ , ( "cinquenes" , 5 )+ , ( "sisè" , 6 )+ , ( "sisena" , 6 )+ , ( "sisens" , 6 )+ , ( "sisenes" , 6 )+ , ( "setè" , 7 )+ , ( "setena" , 7 )+ , ( "setens" , 7 )+ , ( "setenes" , 7 )+ , ( "vuitè" , 8 )+ , ( "vuitena" , 8 )+ , ( "vuitens" , 8 )+ , ( "vuitenes" , 8 )+ , ( "novè" , 9 )+ , ( "novena" , 9 )+ , ( "novens" , 9 )+ , ( "novenes" , 9 )+ , ( "desè" , 10 )+ , ( "desena" , 10 )+ , ( "desens" , 10 )+ , ( "desenes" , 10 )+ , ( "onzè" , 11 )+ , ( "onzena" , 11 )+ , ( "dotzè" , 12 )+ , ( "dotzena" , 12 )+ , ( "tretzè" , 13 )+ , ( "tretzena" , 13 )+ , ( "catorzè" , 14 )+ , ( "catorzena" , 14 )+ , ( "quinzè" , 15 )+ , ( "quinzena" , 15 )+ , ( "setzè" , 16 )+ , ( "setzena" , 16 )+ , ( "dissetè" , 17 )+ , ( "dissetena" , 17 )+ , ( "divuitè" , 18 )+ , ( "divuitena" , 18 )+ , ( "dinovè" , 19 )+ , ( "dinovena" , 19 )+ , ( "vintè" , 20 )+ , ( "vintena" , 20 )+ ]++ruleOrdinalsPrimero :: Rule+ruleOrdinalsPrimero = Rule+ { name = "ordinals (primero..10)"+ , pattern =+ [ regex "(primer(a|s|es)?|segon(a|s|es)?|tercer(a|s|es)?|quart(a|s|es)?|cinqu(è|(en(a|s|es)))|sis(è|en(a|s|es))|set(è|en(a|s|es))|vuit(è|en(a|s|es))|nov(è|en(a|s|es))|des(è|en(a|s|es))|onz(è|ena)|dotz(è|ena)|tretz(è|ena)|catorz(è|ena)|quinz(è|ena)|setz(è|ena)|disset(è|ena)|divuit(è|ena)|dinov(è|ena)|vint(è|ena))"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ ordinal <$> HashMap.lookup (Text.toLower match) ordinalsMap+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleOrdinalsPrimero+ ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -23,9 +22,24 @@ corpus = (testContext {locale = makeLocale DA Nothing}, testOptions, allExamples) allExamples :: [Example]-allExamples =- examples (OrdinalData 4)- [ "4."- , "fjerde"- , "Fjerde"- ]+allExamples = concat+ [ examples (OrdinalData 4)+ [ "4."+ , "fjerde"+ , "Fjerde"+ ]+ , examples (OrdinalData 41)+ [ "enogfyrrende"+ ]+ , examples (OrdinalData 78)+ [ "otteoghalvfjerdsindstyvende"+ ]+ , examples (OrdinalData 263)+ [ "to hundrede og treogtresindstyvende"+ , "tohundrede og treogtresindstyvende"+ ]+ , examples (OrdinalData 70)+ [ "halvfjerdsende"+ , "halvfjerdsindstyvende"+ ]+ ]
@@ -2,69 +2,151 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE NoRebindableSyntax #-} module Duckling.Ordinal.DA.Rules ( rules ) where -import qualified Data.Text as Text++import Data.HashMap.Strict (HashMap)+import Data.Text (Text) import Prelude-import Data.String+import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text import Duckling.Dimensions.Types-import Duckling.Numeral.Helpers (parseInt)+import Duckling.Numeral.Helpers (parseInt, numberWith)+import Duckling.Numeral.Types (NumeralData (..), getIntValue) import Duckling.Ordinal.Helpers+import Duckling.Ordinal.Types (OrdinalData (..)) import Duckling.Regex.Types import Duckling.Types+import qualified Duckling.Numeral.Types as TNumeral +ordinalsMap :: HashMap Text Int+ordinalsMap = HashMap.fromList+ [ ( "første", 1 )+ , ( "anden", 2 )+ , ( "tredje", 3 )+ , ( "fjerde", 4 )+ , ( "femte", 5 )+ , ( "sjette", 6 )+ , ( "syvende", 7 )+ , ( "ottende", 8 )+ , ( "niende", 9 )+ , ( "tiende", 10 )+ , ( "elfte", 11 )+ , ( "tolvte", 12 )+ , ( "trettende", 13 )+ , ( "fjortende", 14 )+ , ( "femtende", 15 )+ , ( "sekstende", 16 )+ , ( "syttende", 17 )+ , ( "attende", 18 )+ , ( "nittende", 19 )+ , ( "tyvende", 20 )+ , ( "tenogtyvende", 21 )+ , ( "toogtyvende", 22 )+ , ( "treogtyvende", 23 )+ , ( "fireogtyvende", 24 )+ , ( "femogtyvende", 25 )+ , ( "seksogtyvende", 26 )+ , ( "syvogtyvende", 27 )+ , ( "otteogtyvende", 28 )+ , ( "niogtyvende", 29 )+ , ( "tredivte", 30 )+ , ( "enogtredivte", 31 )+ ]++cardinalsMap :: HashMap Text Int+cardinalsMap = HashMap.fromList+ [ ( "tyvende", 20 )+ , ( "tredivte", 30 )+ , ( "fyrrende", 40 )+ , ( "fyrretyvende", 40 )+ , ( "halvtredsende", 50 )+ , ( "halvtredsindstyvende", 50 )+ , ( "tressende", 60 )+ , ( "tresindstyvende", 60 )+ , ( "halvfjerdsende", 70 )+ , ( "halvfjerdsindstyvende", 70 )+ , ( "firsende", 80 )+ , ( "firsindsstyvende", 80 )+ , ( "halvfemsende", 90 )+ , ( "halvfemsindstyvende", 90 )+ ]++oneValMap :: HashMap Text Int+oneValMap = HashMap.fromList+ [ ( "", 0 )+ , ( "enog", 1 )+ , ( "toog", 2 )+ , ( "treog", 3 )+ , ( "fireog", 4 )+ , ( "femog", 5 )+ , ( "seksog", 6 )+ , ( "syvog", 7 )+ , ( "otteog", 8 )+ , ( "niog", 9 )+ ]+ ruleOrdinalsFirstst :: Rule ruleOrdinalsFirstst = Rule- { name = "ordinals (first..31st)"+ { name = "ordinals (first..19st)" , pattern =- [ regex "(første|anden|tredje|fjerde|femte|sjette|syvende|ottende|niende|tiende|elfte|tolvte|trettende|fjortende|femtende|sekstende|syttende|attende|nittende|tyvende|tenogtyvende|toogtyvende|treogtyvende|fireogtyvende|femogtyvende|seksogtyvende|syvogtyvende|otteogtyvende|niogtyvende|tredivte|enogtredivte)"+ [ regex "(første|anden|tredje|fjerde|femte|sjette|syvende|ottende|niende|tiende|elfte|tolvte|trettende|fjortende|femtende|sekstende|syttende|attende|nittende)" ] , prod = \tokens -> case tokens of- (Token RegexMatch (GroupMatch (match:_)):_) -> case Text.toLower match of- "første" -> Just $ ordinal 1- "anden" -> Just $ ordinal 2- "tredje" -> Just $ ordinal 3- "fjerde" -> Just $ ordinal 4- "femte" -> Just $ ordinal 5- "sjette" -> Just $ ordinal 6- "syvende" -> Just $ ordinal 7- "ottende" -> Just $ ordinal 8- "niende" -> Just $ ordinal 9- "tiende" -> Just $ ordinal 10- "elfte" -> Just $ ordinal 11- "tolvte" -> Just $ ordinal 12- "trettende" -> Just $ ordinal 13- "fjortende" -> Just $ ordinal 14- "femtende" -> Just $ ordinal 15- "sekstende" -> Just $ ordinal 16- "syttende" -> Just $ ordinal 17- "attende" -> Just $ ordinal 18- "nittende" -> Just $ ordinal 19- "tyvende" -> Just $ ordinal 20- "tenogtyvende" -> Just $ ordinal 21- "toogtyvende" -> Just $ ordinal 22- "treogtyvende" -> Just $ ordinal 23- "fireogtyvende" -> Just $ ordinal 24- "femogtyvende" -> Just $ ordinal 25- "seksogtyvende" -> Just $ ordinal 26- "syvogtyvende" -> Just $ ordinal 27- "otteogtyvende" -> Just $ ordinal 28- "niogtyvende" -> Just $ ordinal 29- "tredivte" -> Just $ ordinal 30- "enogtredivte" -> Just $ ordinal 31- _ -> Nothing+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ ordinal <$> HashMap.lookup (Text.toLower match) ordinalsMap _ -> Nothing } +ruleSpelledOutOrdinals :: Rule+ruleSpelledOutOrdinals = Rule+ { name = "ordinals, 20 to 99, spelled-out"+ , pattern =+ [ regex (concat ["((?:en|to|tre|fire|fem|seks|syv|otte|ni)og)?",+ "(tyvende",+ "|tredivte",+ "|fyrr(?:etyv)?ende",+ "|halvtreds(?:indstyv)?ende",+ "|tres(?:indstyv|s)?ende",+ "|halvfjerds(?:indstyv)?ende",+ "|firs(?:indstyv)?ende",+ "|halvfems(?:indstyv)?ende)"])+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (ones:tens:_)):_) -> do+ oneVal <- HashMap.lookup (Text.toLower ones) oneValMap+ tenVal <- HashMap.lookup (Text.toLower tens) cardinalsMap+ Just $ ordinal (oneVal + tenVal)+ _ -> Nothing++ }++ruleSpelledOutBigOrdinals :: Rule+ruleSpelledOutBigOrdinals = Rule+ { name = "ordinals, above 99, spelled out"+ , pattern =+ [ numberWith TNumeral.value (> 99)+ , regex "og"+ , dimension Ordinal+ ]+ , prod = \case+ Token Numeral NumeralData {TNumeral.value=maybenumnum}:_:Token Ordinal (OrdinalData ordnum):_ ->+ case getIntValue maybenumnum of+ Just numnum -> Just $ ordinal (numnum + ordnum)+ Nothing -> Nothing+ _ -> Nothing+ }+ ruleOrdinalDigits :: Rule ruleOrdinalDigits = Rule { name = "ordinal (digits)"@@ -82,4 +164,6 @@ rules = [ ruleOrdinalDigits , ruleOrdinalsFirstst+ , ruleSpelledOutOrdinals+ , ruleSpelledOutBigOrdinals ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,19 +2,24 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} module Duckling.Ordinal.DE.Rules- ( rules ) where+ ( rules+ ) where -import qualified Data.Text as Text+import Data.Semigroup ((<>)) import Prelude import Data.String+import Data.Text (Text)+import qualified Data.HashMap.Strict as HashMap+import qualified Data.List as List+import qualified Data.Text as Text import Duckling.Dimensions.Types import Duckling.Numeral.Helpers (parseInt)@@ -22,64 +27,71 @@ import Duckling.Regex.Types import Duckling.Types +ordinalList :: [(Text, Int)]+ordinalList =+ [ ("erste", 1)+ , ("zweite", 2)+ , ("dritte", 3)+ , ("vierte", 4)+ , ("fünfte", 5)+ , ("sechste", 6)+ , ("siebte", 7)+ , ("achte", 8)+ , ("neunte", 9)+ , ("zehnte", 10)+ , ("elfte", 11)+ , ("zwölfte", 12)+ , ("dreizente", 13)+ , ("vierzehnte", 14)+ , ("fünfzehnte", 15)+ , ("sechzente", 16)+ , ("siebzehnte", 17)+ , ("achtzehnte", 18)+ , ("neunzehnte", 19)+ , ("zwanzigste", 20)+ , ("einundzwanzigste", 21)+ , ("zweiundzwanzigste", 22)+ , ("dreiundzwanzigste", 23)+ , ("vierundzwanzigste", 24)+ , ("fünfundzwanzigste", 25)+ , ("sechsundzwanzigste", 26)+ , ("siebenundzwanzigste", 27)+ , ("achtundzwanzigste", 28)+ , ("neunundzwanzigste", 29)+ , ("dreissigste", 30)+ , ("dreißigste", 30)+ , ("einunddreissigste", 31)+ , ("einunddreißigste", 31)+ ]+ ruleOrdinalsFirstth :: Rule ruleOrdinalsFirstth = Rule- { name = "ordinals (first..19th)"+ { name = "ordinal (1..31)" , pattern =- [ regex "(erste(r|s)?|zweite(r|s)|dritte(r|s)|vierte(r|s)|fuenfte(r|s)|sechste(r|s)|siebte(r|s)|achte(r|s)|neunte(r|s)|zehnte(r|s)|elfter|zwölfter|dreizenter|vierzehnter|fünfzehnter|sechzenter|siebzehnter|achtzehnter|neunzehnter)"+ [ regex $ Text.unpack construction ]- , prod = \tokens -> case tokens of- (Token RegexMatch (GroupMatch (match:_)):_) -> case Text.toLower match of- "erstes" -> Just $ ordinal 1- "erster" -> Just $ ordinal 1- "erste" -> Just $ ordinal 1- "zweiter" -> Just $ ordinal 2- "zweite" -> Just $ ordinal 2- "zweites" -> Just $ ordinal 2- "drittes" -> Just $ ordinal 3- "dritte" -> Just $ ordinal 3- "dritter" -> Just $ ordinal 3- "viertes" -> Just $ ordinal 4- "vierte" -> Just $ ordinal 4- "vierter" -> Just $ ordinal 4- "fünftes" -> Just $ ordinal 5- "fünfter" -> Just $ ordinal 5- "fünfte" -> Just $ ordinal 5- "sechste" -> Just $ ordinal 6- "sechstes" -> Just $ ordinal 6- "sechster" -> Just $ ordinal 6- "siebtes" -> Just $ ordinal 7- "siebte" -> Just $ ordinal 7- "siebter" -> Just $ ordinal 7- "achtes" -> Just $ ordinal 8- "achte" -> Just $ ordinal 8- "achter" -> Just $ ordinal 8- "neuntes" -> Just $ ordinal 9- "neunter" -> Just $ ordinal 9- "neunte" -> Just $ ordinal 9- "zehnte" -> Just $ ordinal 10- "zehnter" -> Just $ ordinal 10- "zehntes" -> Just $ ordinal 10- "elfter" -> Just $ ordinal 11- "zwölfter" -> Just $ ordinal 12- "dreizehnter" -> Just $ ordinal 13- "vierzehnter" -> Just $ ordinal 14- "fünfzehnter" -> Just $ ordinal 15- "sechzehnter" -> Just $ ordinal 16- "siebzehnter" -> Just $ ordinal 17- "achtzehnter" -> Just $ ordinal 18- "neunzehnter" -> Just $ ordinal 19- _ -> Nothing+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ ordinal <$> HashMap.lookup (Text.toLower match) ordinalMap _ -> Nothing }+ where+ ordinalMap :: HashMap.HashMap Text Int+ ordinalMap = HashMap.fromList ordinalList + construction :: Text+ construction =+ "("+ <> mconcat (List.intersperse "|" (fst <$> ordinalList))+ <> ")[rsn]?"+ ruleOrdinalDigits :: Rule ruleOrdinalDigits = Rule { name = "ordinal (digits)" , pattern = [ regex "(?<!\\d|\\.)0*(\\d+)(\\.(?!\\d)| ?(te(n|r|s)?)|(ste(n|r|s)?))" ]- , prod = \tokens -> case tokens of+ , prod = \case (Token RegexMatch (GroupMatch (match:_)):_) -> do v <- parseInt match Just $ ordinal v@@ -88,6 +100,6 @@ rules :: [Rule] rules =- [ ruleOrdinalDigits- , ruleOrdinalsFirstth+ [ ruleOrdinalsFirstth+ , ruleOrdinalDigits ]
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}@@ -33,6 +32,11 @@ [ "segundo" , "segunda" , "segundos"+ ]+ , examples (OrdinalData 3)+ [ "tercero"+ , "tercera"+ , "terceros" ] , examples (OrdinalData 10) [ "decimo"
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -80,7 +79,7 @@ ruleOrdinalsPrimero = Rule { name = "ordinals (primero..10)" , pattern =- [ regex "((primer|segund|cuart|quint|sext|s[eé]ptim|octav|noven|d[eé]cim)(os?|as?)|(prim|terc)er)"+ [ regex "((primer|segund|tercer|cuart|quint|sext|s[eé]ptim|octav|noven|d[eé]cim)(os?|as?)|(prim|terc)er)" ] , prod = \tokens -> case tokens of (Token RegexMatch (GroupMatch (match:_)):_) ->
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,66 +2,67 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} module Duckling.Ordinal.FR.Rules- ( rules ) where+ ( rules+ ) where import Data.HashMap.Strict ( HashMap)-import qualified Data.HashMap.Strict as HashMap+import Data.String import Data.Text (Text)-import qualified Data.Text as Text import Prelude-import Data.String+import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text import Duckling.Dimensions.Types import Duckling.Numeral.Helpers (parseInt) import Duckling.Ordinal.Helpers-import Duckling.Regex.Types+import Duckling.Regex.Types (GroupMatch (..)) import Duckling.Types -ruleOrdinalsPremierseiziemeMap :: HashMap Text Int-ruleOrdinalsPremierseiziemeMap = HashMap.fromList- [ ( "première" , 1 )- , ( "premiere" , 1 )- , ( "premier" , 1 )- , ( "deuxième" , 2 )- , ( "deuxieme" , 2 )- , ( "second" , 2 )- , ( "seconde" , 2 )- , ( "troisième" , 3 )- , ( "troisieme" , 3 )- , ( "quatrieme" , 4 )- , ( "quatrième" , 4 )- , ( "cinquieme" , 5 )- , ( "cinquième" , 5 )- , ( "sixième" , 6 )- , ( "sixieme" , 6 )- , ( "septieme" , 7 )- , ( "septième" , 7 )- , ( "huitième" , 8 )- , ( "huitieme" , 8 )- , ( "neuvieme" , 9 )- , ( "neuvième" , 9 )- , ( "dixième" , 10 )- , ( "dixieme" , 10 )- , ( "onzième" , 11 )- , ( "onzieme" , 11 )- , ( "douzieme" , 12 )- , ( "douzième" , 12 )- , ( "treizieme" , 13 )- , ( "treizième" , 13 )+ordinalsMap :: HashMap Text Int+ordinalsMap = HashMap.fromList+ [ ( "première", 1 )+ , ( "premiere", 1 )+ , ( "premier", 1 )+ , ( "deuxième", 2 )+ , ( "deuxieme", 2 )+ , ( "second", 2 )+ , ( "seconde", 2 )+ , ( "troisième", 3 )+ , ( "troisieme", 3 )+ , ( "quatrieme", 4 )+ , ( "quatrième", 4 )+ , ( "cinquieme", 5 )+ , ( "cinquième", 5 )+ , ( "sixième", 6 )+ , ( "sixieme", 6 )+ , ( "septieme", 7 )+ , ( "septième", 7 )+ , ( "huitième", 8 )+ , ( "huitieme", 8 )+ , ( "neuvieme", 9 )+ , ( "neuvième", 9 )+ , ( "dixième", 10 )+ , ( "dixieme", 10 )+ , ( "onzième", 11 )+ , ( "onzieme", 11 )+ , ( "douzieme", 12 )+ , ( "douzième", 12 )+ , ( "treizieme", 13 )+ , ( "treizième", 13 ) , ( "quatorzième", 14 )- , ( "quatorzieme" , 14 )- , ( "quinzième" , 15 )- , ( "quinzieme" , 15 )- , ( "seizieme" , 16 )- , ( "seizième" , 16 )+ , ( "quatorzieme", 14 )+ , ( "quinzième", 15 )+ , ( "quinzieme", 15 )+ , ( "seizieme", 16 )+ , ( "seizième", 16 ) ] ruleOrdinalsPremierseizieme :: Rule@@ -70,9 +71,9 @@ , pattern = [ regex "(premi(ere?|ère)|(deux|trois|quatr|cinqu|six|sept|huit|neuv|dix|onz|douz|treiz|quatorz|quinz|seiz)i(e|è)me|seconde?)" ]- , prod = \tokens -> case tokens of+ , prod = \case (Token RegexMatch (GroupMatch (match:_)):_) ->- ordinal <$> HashMap.lookup (Text.toLower match) ruleOrdinalsPremierseiziemeMap+ ordinal <$> HashMap.lookup (Text.toLower match) ordinalsMap _ -> Nothing } @@ -82,10 +83,8 @@ , pattern = [ regex "0*(\\d+) ?(ere?|ère|ème|eme|e)" ]- , prod = \tokens -> case tokens of- (Token RegexMatch (GroupMatch (match:_)):_) -> do- n <- parseInt match- Just $ ordinal n+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) -> ordinal <$> parseInt match _ -> Nothing }
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-} {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-} {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}@@ -17,20 +16,20 @@ import Duckling.Dimensions.Types import Duckling.Ordinal.Types (OrdinalData (..))-import qualified Duckling.Ordinal.Types as TOrdinal import Duckling.Types+import qualified Duckling.Ordinal.Types as TOrdinal -- ----------------------------------------------------------------- -- Patterns --- -------------------------------------------------------------------- Production--ordinal :: Int -> Token-ordinal x = Token Ordinal OrdinalData {TOrdinal.value = x}- oneOf :: [Int] -> PatternItem oneOf vs = Predicate $ \x -> case x of (Token Ordinal OrdinalData {TOrdinal.value = v}) -> elem v vs _ -> False++-- -----------------------------------------------------------------+-- Production++ordinal :: Int -> Token+ordinal x = Token Ordinal OrdinalData {TOrdinal.value = x}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE OverloadedStrings #-}
@@ -2,8 +2,7 @@ -- All rights reserved. -- -- This source code is licensed under the BSD-style license found in the--- LICENSE file in the root directory of this source tree. An additional grant--- of patent rights can be found in the PATENTS file in the same directory.+-- LICENSE file in the root directory of this source tree. {-# LANGUAGE GADTs #-}
@@ -0,0 +1,69 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}++module Duckling.Ordinal.KA.Corpus+ ( corpus+ ) where++import Data.String+import Prelude++import Duckling.Ordinal.Types+import Duckling.Testing.Types++import Duckling.Locale+import Duckling.Resolve++corpus :: Corpus+corpus = (testContext {locale = makeLocale KA Nothing}, testOptions, allExamples)+++allExamples :: [Example]+allExamples = concat+ [ examples (OrdinalData 1)+ [ "პირველი"+ , "1-ლი"+ ]+ , examples (OrdinalData 2)+ [ "მეორე"+ , "მე-2"+ ]+ , examples (OrdinalData 3)+ [ "მესამე"+ , "მე-3"+ ]+ , examples (OrdinalData 4)+ [ "მეოთხე"+ , "მე-4"+ ]+ , examples (OrdinalData 8)+ [ "მერვე"+ , "მე-8"+ ]+ , examples (OrdinalData 25)+ [ "ოცდამეხუთე"+ , "25-ე"+ ]+ , examples (OrdinalData 31)+ [ "ოცდამეთერთმეტე"+ , "31-ე"+ ]+ , examples (OrdinalData 42)+ [ "ორმოცდამეორე"+ , "42-ე"+ ]+ , examples (OrdinalData 73)+ [ "სამოცდამეცამეტე"+ , "73-ე"+ ]+ , examples (OrdinalData 90)+ [ "ოთხმოცდამეათე"+ , "90-ე"+ ]+ ]
@@ -0,0 +1,145 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE NoRebindableSyntax #-}++module Duckling.Ordinal.KA.Rules+ ( rules+ ) where++import Data.HashMap.Strict (HashMap)+import Data.String+import Data.Text (Text)+import Prelude+import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text++import Duckling.Dimensions.Types+import Duckling.Numeral.Helpers (parseInt)+import Duckling.Ordinal.Helpers+import Duckling.Regex.Types+import Duckling.Types++ordinalsMap :: HashMap Text Int+ordinalsMap = HashMap.fromList+ [ ("პირველი", 1)+ , ("პირველ", 1)+ , ("მეერთე", 1)+ , ("მეორე", 2)+ , ("მესამე", 3)+ , ("მეოთხე", 4)+ , ("მეხუთე", 5)+ , ("მეექვსე", 6)+ , ("მეშვიდე", 7)+ , ("მერვე", 8)+ , ("მეცხრე", 9)+ , ("მეათე", 10)+ , ("მეთერთმეტე", 11)+ , ("მეთორმეტე", 12)+ , ("მეცამეტე", 13)+ , ("მეთოთხმეტე", 14)+ , ("მეთხუთმეტე", 15)+ , ("მეთქვსმეტე", 16)+ , ("მეჩვიდმეტე", 17)+ , ("მეთვრამეტე", 18)+ , ("მეცხრამეტე", 19)+ , ("მეოცე", 20)+ , ("ოცდამეათე", 30)+ , ("მეორმოცე", 40)+ , ("ორმოცდამეათე", 50)+ , ("მესამოცე", 60)+ , ("სამოცდამეათე", 70)+ , ("მეოთხმოცე", 80)+ , ("ოთხმოცდამეათე", 90)+ ]++cardinalsMap :: HashMap Text Int+cardinalsMap = HashMap.fromList+ [ ("ოცი", 20)+ , ("ოცდა", 20)+ , ("ოცდაათი", 30)+ , ("ორმოცი", 40)+ , ("ორმოცდა", 40)+ , ("ორმოცდაათი", 50)+ , ("სამოცი", 60)+ , ("სამოცდა", 60)+ , ("სამოცდაათი", 70)+ , ("ოთხმოცი", 80)+ , ("ოთხმოცდა", 80)+ , ("ოთხმოცდაათი", 90)+ ]++ruleOrdinals :: Rule+ruleOrdinals = Rule+ { name = "ordinals (first..twentieth,thirtieth,...)"+ , pattern =+ [ regex "(პირველი?|მეორე|მესამე|მეოთხე|მეხუთე|მეექვსე|მეშვიდე|მერვე|მეცხრე|მეათე|მეთერთმეტე|მეთოთხმეტე|მეცამეტე|მეთოთხმეტე|მეთხუთმეტე|მეთექვსმეტე|მეჩვიდმეტე|მეთვრამეტე|მეცხრამეტე|მეოცე|ოცდამეათე|მეორმოცე|ორმოცდამეათე|მესამოცე|სამოცდამეათე|მეოთხმოცე|ოთხმოცდამეათე)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) ->+ ordinal <$> HashMap.lookup (Text.toLower match) ordinalsMap+ _ -> Nothing+ }++ruleCompositeOrdinals :: Rule+ruleCompositeOrdinals = Rule+ { name = "ordinals (composite, e.g. eighty-seven, forty—seventh, twenty ninth, thirtythird)"+ , pattern =+ [ regex "(ოცდა|ორმოცდა|სამოცდა|ოთხმოცდა)[\\s\\-\\—]?(მეერთე|მეორე|მესამე|მეოთხე|მეხუთე|მეექვსე|მეშვიდე|მერვე|მეცხრე|მეათე|მეთერთმეტე|მეთოთხმეტე|მეცამეტე|მეთოთხმეტე|მეთხუთმეტე|მეთექვსმეტე|მეჩვიდმეტე|მეთვრამეტე|მეცხრამეტე)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (tens:units:_)):_) -> do+ tt <- HashMap.lookup (Text.toLower tens) cardinalsMap+ uu <- HashMap.lookup (Text.toLower units) ordinalsMap+ Just (ordinal (tt + uu))+ _ -> Nothing+ }++ruleOrdinalDigits :: Rule+ruleOrdinalDigits = Rule+ { name = "ordinal (digits)"+ , pattern =+ [ regex "0*(\\d+) ?(-ლი|-ე)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) -> ordinal <$> parseInt match+ _ -> Nothing+ }++ruleOrdinalDigits1 :: Rule+ruleOrdinalDigits1 = Rule+ { name = "ordinal (digits)"+ , pattern =+ [ regex "მე-? ?0*(\\d+)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) -> ordinal <$> parseInt match+ _ -> Nothing+ }++ruleOrdinalDigits2 :: Rule+ruleOrdinalDigits2 = Rule+ { name = "ordinal (digits)"+ , pattern =+ [ regex "მე-? ?0*(\\d+) ?(-ლი|-ე)"+ ]+ , prod = \case+ (Token RegexMatch (GroupMatch (match:_)):_) -> ordinal <$> parseInt match+ _ -> Nothing+ }++rules :: [Rule]+rules =+ [ ruleOrdinals+ , ruleCompositeOrdinals+ , ruleOrdinalDigits+ , ruleOrdinalDigits1+ , ruleOrdinalDigits2+ ]
@@ -0,0 +1,37 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in the+-- LICENSE file in the root directory of this source tree.+++{-# LANGUAGE OverloadedStrings #-}++module Duckling.Ordinal.KM.Corpus+ ( corpus+ ) where++import Data.String+import Prelude++import Duckling.Locale+import Duckling.Ordinal.Types+import Duckling.Resolve+import Duckling.Testing.Types++context :: Context+context = testContext{locale = makeLocale KM Nothing}++corpus :: Corpus+corpus = (context, testOptions, allExamples)++allExamples :: [Example]+allExamples = concat+ [ examples (OrdinalData 1)+ [ "ទីមួយ"+ , "ទី១"+ ]+ , examples (OrdinalData 400)+ [ "ទីបួនរយ"+ ]+ ]
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff
file too large to diff