>
> module CityEntry
>   (makeCityTuple,
>    displayCityTuple,
>    normalizeCityStateEntry)
>   where
>   import SequenceUtilities(pam)
>   import IOutilities(trim, capitalizeWord)
>   import DataEntryUtilities(spaceAfterComma, capitalizeWords)
>   import UnitedStatesTable(stateTable)

function: normalizeCityStateEntry
convert string containing city/state/zipcode entry to standard form

>   normalizeCityStateEntry :: String -> String
>   normalizeCityStateEntry = displayCityTuple . makeCityTuple


function: displayCityTuple
form display string from city-tuple

>   displayCityTuple :: (String, String, String) -> String
>   displayCityTuple(city, state, zipcode) =
>     city ++ ", " ++ state ++ " " ++ zipcode


function: makeCityTuple
convert string containing city/state/optional-zipcode
to standard city-tuple

>   makeCityTuple :: String -> (String, String, String)
>   makeCityTuple entry = (capitalizeWords city, state, zipcode)
>     where
>     (city, state, zipcode)
>       | commaPresentAfterCity   = parseWithComma cityPart statePart
>       | otherwise               = parseSansComma entryWordsReversed
>     cityPart  = (trim . keepContent) beforeComma
>     statePart = (trim . keepContent) (drop 1 commaAndBeyond)
>     (beforeComma, commaAndBeyond) = break(== ',') entryInCaps
>     commaPresentAfterCity = (not . null) statePart   &&
>                             (not . isDigit . head) statePart
>     entryWordsReversed = (reverse . words . keepContent) entryInCaps
>     entryInCaps = (spaceAfterComma . map toUpper) entry


function: parseWithComma
form city, state, and zipcode from an entry string that has a comma
separating the city from the state

>   parseWithComma :: String -> String -> (String, String, String)
>   parseWithComma cityPart statePart = (cityPart, state, zipcode)
>     where
>     (zipcode, stateWordsReversed) =
>       (parseZipcode . reverse . words) statePart
>     stateString = (unwords . reverse) stateWordsReversed
>     state =  maybe stateString id (lookup stateString stateTable)


function: parseSansComma
form city, state, and zipcode from an entry string without a comma
separating the city from the state

>   parseSansComma :: [String] -> (String, String, String)
>   parseSansComma entryWordsReversed = (city, state, zipcode)
>     where
>     (zipcode, stateCity) = parseZipcode entryWordsReversed
>     (city1, oneWordState) = parseState 1 (head stateCity) stateCity
>     (city2, twoWordState) = parseState 2 notState stateCity
>     (city, state)
>       | twoWordState == notState  = (city1, oneWordState)
>       | otherwise                 = (city2, twoWordState)
>     notState = ""


function: parseZipcode
separate zipcode, if present, from other words in entry;
if zipcode not present, use empty string for zipcode

>   parseZipcode :: [String] -> (String, [String])
>   parseZipcode wordsReversed = (zipcode, otherWordsReversed)
>     where
>     shouldBeZipcode = head wordsReversed
>     wordsWithZipcodePatch = emptyZipcodeIfMissing ++ wordsReversed
>     emptyZipcodeIfMissing
>       | (isDigit . head) shouldBeZipcode    = [  ]
>       | otherwise                           = [""]
>     ([zipcode], otherWordsReversed) = splitAt 1 wordsWithZipcodePatch


function: parseState
deliver city and code for state with name containing numWordsInState
words, if such a state is present in second argument;
if not, deliver entered state

>   parseState :: Int -> String -> [String] -> (String, String)
>   parseState numWordsInState enteredState stateCityWords =
>     (city, maybe enteredState id (lookup state stateTable))
>     where
>     (stateWords, cityWords) = splitAt numWordsInState stateCityWords
>     state = (unwords . reverse) stateWords
>     city  = (unwords . reverse) cityWords


function: keepContent
eliminate chararacters carrying no information about entry

>   keepContent :: String -> String
>   keepContent = filter(or . pam[isAlpha, isDigit, (== ' ')])
Last Modified: