-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathGlobber.hs
61 lines (51 loc) · 2.07 KB
/
Globber.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
module Globber (matchGlob) where
import Data.HashSet
import Data.List
type GlobPattern = String
data Pattern = Literal Char
| Any
| AnyMore
| Set { set :: HashSet[Int] }
| End
data PatternSeg = PatternSeg { pattern :: Pattern, nextPattern :: GlobPattern }
data StringSeg = StringSeg { ch :: Char, nextString :: String }
isMatch :: Pattern -> Char -> Bool
isMatch Any c = True
isMatch AnyMore c = True
isMatch (Literal ch) c
| ch == c = True
| otherwise = False
extractSet :: GlobPattern -> Maybe PatternSeg
extractSet pattern = case elemIndex ']' pattern of
Just index -> Nothing
Nothing -> Nothing
readString :: String -> Maybe StringSeg
readString string
| length string == 0 = Nothing
| otherwise = Just StringSeg { ch = head string, nextString = drop 1 string }
readPattern :: GlobPattern -> Maybe PatternSeg
readPattern pattern
| length pattern == 0 = Just PatternSeg { pattern = End, nextPattern = "" }
| p == '\\' = Just PatternSeg { pattern = Literal (head remain), nextPattern = drop 1 remain }
| p == '?' = Just PatternSeg { pattern = Any, nextPattern = remain }
| p == '*' = Just PatternSeg { pattern = AnyMore, nextPattern = remain }
| p == '[' = extractSet remain
| otherwise = Just PatternSeg { pattern = Literal p, nextPattern = remain }
where p = head pattern
remain = drop 1 pattern
matchGlob :: GlobPattern -> String -> Bool
matchGlob pattern string = loop pattern string
where loop p s = case stringSeg of
Just (StringSeg ch nextString) -> case patternSeg' of
Just (PatternSeg pattern nextPattern) -> case pattern of
End -> False
_ -> if isMatch pattern ch then loop nextPattern nextString else False
Nothing -> False
Nothing -> case patternSeg' of
Just (PatternSeg pattern nextPattern) -> case pattern of
End -> True
AnyMore -> True
_ -> False
Nothing -> False
where stringSeg = readString string
patternSeg' = readPattern pattern