>
> module DateEntry
>   (makeDateTuple,
>    displayDateTuple,
>    normalizeDateEntry)
>   where
>   import SequenceUtilities(pam, rightJustifyWith)
>   import IOutilities(integralFromString, capitalizeWord)
>   import DataEntryUtilities(blank, comma, hyphen, period, slash)

function: normalizeDateEntry
convert string containing date entry to standard form

>   normalizeDateEntry :: String -> String
>   normalizeDateEntry = displayDateTuple . makeDateTuple


function: displayDateTuple
form display string from date tuple

>   displayDateTuple :: (Int, Int, Int) -> String
>   displayDateTuple(year, month, day) =
>     monthString ++ [blank] ++ show day ++ [comma, blank] ++ show year
>     where
>     monthString = (capitalizeWord . head . drop(month - 1)) monthNames


function: makeDateTuple
convert string containing an date entry to a date tuple

>   makeDateTuple :: String -> (Int, Int, Int)
>   makeDateTuple entry = (year, month, day)
>     where
>     [year, month, day]
>       | numericForm
>          = map integralFromString
>                ["19" ++ rightJustifyWith '0' 2 yearStringNumericForm,
>                 monthStringNumericForm,
>                 dayStringNumericForm]
>       | otherwise
>          = [integralFromString yearString,
>             maybe violation id (lookup monthString monthTable),
>             integralFromString dayString]
>     [yearString, monthString, dayString]
>       = pam [getYearString, getMonthString, getDayString] entryWords
>     ([monthStringNumericForm,
>          dayStringNumericForm],
>      [yearStringNumericForm]   ) = splitAt 2 entryWords
>     numericForm = (null . dropWhile(not . isMonth)) entryWords
>     entryWords = (words . map(substitute spaceForDelimiter) .
>                                                   map toLower) entry
>     violation = error("misspelled month: " ++ monthString ++
>                       "; in date entry: " ++ entry)


function: getYearString, getMonthString, getDayString
extract appropriate string from words in (non-numeric) date entry

>   getYearString, getMonthString, getDayString :: [String] -> String
>   getYearString  = getComponent isYear
>   getMonthString = getComponent isMonth
>   getDayString   = getComponent isDay

function: getComponent
get component satisfying given criterion from sequence

>   getComponent :: (a -> Bool) -> [a] -> a
>   getComponent isComponent = head . filter isComponent


functions: isYear, isMonth, isDay
True iff argument is the component indicated

>   isYear, isMonth, isDay :: String -> Bool
>   isYear  = and . pam[isDigit . head, not . null . drop 2]
>   isMonth = isAlpha . head
>   isDay   = and . pam[isDigit . head, null . drop 2]


function: substitute
translate key if found in table

>   substitute :: Eq a => [(a, a)] -> a -> a
>   substitute table key =
>     maybe key id (lookup key table)


variable: spaceForDelimiter
table to change comma, hyphen, slash, or period to space

>   spaceForDelimiter :: [(Char, Char)]
>   spaceForDelimiter = [(comma,  blank),
>                        (hyphen, blank),
>                        (period, blank),
>                        (slash,  blank) ]


variable: monthTable
table to convert months to numbers

>   monthTable :: [(String, Int)]
>   monthTable = zip monthNames [1 .. 12]                 ++
>                zip (map (take 3) monthNames) [1 .. 12]  ++
>                [("sept", 9)]

variable: monthNames

>   monthNames :: [String]
>   monthNames = words("january february march april may june july " ++
>                       "august september october november december")


---------------- unit tests -------------

>   tst1 = makeDateTuple "December 17, 1996"
>   tst2 = makeDateTuple "Dec. 17, 1996"
>   tst3 = makeDateTuple "17 Sep 1996"
>   tst4 = makeDateTuple "1996 Sept 1"
>   tst5 = makeDateTuple "8/12/96"
>   tst6 = makeDateTuple "6/1/01"

>   n1 = normalizeDateEntry "December 19, 1996"
>   n2 = normalizeDateEntry "Dec. 19, 1996"
>   n3 = normalizeDateEntry "19 Dec. 1996"
>   n4 = normalizeDateEntry "1996 March 19"

Last Modified: