#1. Contrary to the authors' claim, this one is pretty simple -- if you define a helper function. Here, the function prepend either prepends a string to a Right value, or propagates unchanged a Left value. We then use it to update all equations defining globToRegex' and charClass. The main function, globToRegex, is also updated to handle either case.
(Note: the update is applied to the original version of globToRegex, not to the modified versions created in previous exercises.)
module GlobRegex (globToRegex, matchesGlob) where
import Text.Regex.Posix ((=~))
type GlobError = String
globToRegex :: String -> Either GlobError String
globToRegex cs = case internal of
Left error -> Left error
Right val -> Right ('^' : val ++ "$")
where internal = globToRegex' cs
globToRegex' :: String -> Either GlobError String
globToRegex' "" = Right ""
globToRegex' ('*':cs) = prepend ".*" (globToRegex' cs)
globToRegex' ('?':cs) = prepend "." (globToRegex' cs)
globToRegex' ('[':'!':c:cs) = prepend ("[^" ++ [c]) (charClass cs)
globToRegex' ('[':c:cs) = prepend ['[', c] (charClass cs)
globToRegex' ('[':_) = Left "unterminated character class"
globToRegex' (c:cs) = prepend (escape c) (globToRegex' cs)
escape :: Char -> String
escape c | c `elem` regexChars = '\\' : [c]
| otherwise = [c]
where regexChars = "\\+()^$.{}]"
charClass :: String -> Either GlobError String
charClass (']':cs) = prepend "]" (globToRegex' cs)
charClass (c:cs) = prepend [c] (charClass cs)
charClass _ = Left "unterminated character class"
prepend :: String -> Either GlobError String -> Either GlobError String
prepend prefix (Left error) = Left error
prepend prefix (Right str) = Right (prefix ++ str)
#2. namesMatching never uses globToRegex directly; it uses matchesGlob, which we update thus:
matchesGlob :: FilePath -> String -> Bool
f `matchesGlob` g = case (globToRegex g) of
Right regex -> f =~ regex
Left err -> False
In other words, a bad glob expression simply matches nothing.
0 comments:
Post a Comment