4
4
module Data.String.Regex
5
5
( Regex (..)
6
6
, RegexFlags (..)
7
+ , RegexFlagsRec
7
8
, regex
8
9
, source
9
10
, flags
@@ -16,13 +17,15 @@ module Data.String.Regex
16
17
, search
17
18
, split
18
19
, noFlags
20
+ , g , i , m , s , u
19
21
) where
20
22
21
23
import Prelude
22
24
23
25
import Data.Either (Either (..))
24
26
import Data.Maybe (Maybe (..))
25
27
import Data.String (contains )
28
+ import Data.Monoid (class Monoid )
26
29
27
30
-- | Wraps Javascript `RegExp` objects.
28
31
foreign import data Regex :: *
@@ -32,22 +35,89 @@ foreign import showRegex' :: Regex -> String
32
35
instance showRegex :: Show Regex where
33
36
show = showRegex'
34
37
35
- -- | Flags that control matching.
36
- type RegexFlags =
37
- { global :: Boolean
38
+ type RegexFlagsRec =
39
+ { global :: Boolean
38
40
, ignoreCase :: Boolean
39
- , multiline :: Boolean
40
- , sticky :: Boolean
41
- , unicode :: Boolean
41
+ , multiline :: Boolean
42
+ , sticky :: Boolean
43
+ , unicode :: Boolean
42
44
}
43
45
46
+ -- | Flags that control matching.
47
+ data RegexFlags = RegexFlags RegexFlagsRec
48
+
44
49
-- | All flags set to false.
45
50
noFlags :: RegexFlags
46
- noFlags = { global : false
47
- , ignoreCase : false
48
- , multiline : false
49
- , sticky : false
50
- , unicode : false }
51
+ noFlags = RegexFlags
52
+ { global : false
53
+ , ignoreCase : false
54
+ , multiline : false
55
+ , sticky : false
56
+ , unicode : false
57
+ }
58
+
59
+ -- | Only global flag set to true
60
+ g :: RegexFlags
61
+ g = RegexFlags
62
+ { global : true
63
+ , ignoreCase : false
64
+ , multiline : false
65
+ , sticky : false
66
+ , unicode : false
67
+ }
68
+
69
+ -- | Only ignoreCase flag set to true
70
+ i :: RegexFlags
71
+ i = RegexFlags
72
+ { global : false
73
+ , ignoreCase : true
74
+ , multiline : false
75
+ , sticky : false
76
+ , unicode : false
77
+ }
78
+
79
+ -- | Only multiline flag set to true
80
+ m :: RegexFlags
81
+ m = RegexFlags
82
+ { global : false
83
+ , ignoreCase : false
84
+ , multiline : true
85
+ , sticky : false
86
+ , unicode : false
87
+ }
88
+
89
+ -- | Only sticky flag set to true
90
+ s :: RegexFlags
91
+ s = RegexFlags
92
+ { global : false
93
+ , ignoreCase : false
94
+ , multiline : false
95
+ , sticky : true
96
+ , unicode : false
97
+ }
98
+
99
+ -- | Only unicode flag set to true
100
+ u :: RegexFlags
101
+ u = RegexFlags
102
+ { global : false
103
+ , ignoreCase : false
104
+ , multiline : false
105
+ , sticky : false
106
+ , unicode : true
107
+ }
108
+
109
+ instance semigroupRegexFlags :: Semigroup RegexFlags where
110
+ append (RegexFlags x) (RegexFlags y) = RegexFlags
111
+ { global : x.global || y.global
112
+ , ignoreCase : x.ignoreCase || y.ignoreCase
113
+ , multiline : x.multiline || y.multiline
114
+ , sticky : x.sticky || y.sticky
115
+ , unicode : x.unicode || y.unicode
116
+ }
117
+
118
+ instance monoidRegexFlags :: Monoid RegexFlags where
119
+ mempty = noFlags
120
+
51
121
52
122
foreign import regex' :: (String -> Either String Regex )
53
123
-> (Regex -> Either String Regex )
@@ -58,31 +128,37 @@ foreign import regex' :: (String -> Either String Regex)
58
128
-- | Constructs a `Regex` from a pattern string and flags. Fails with
59
129
-- | `Left error` if the pattern contains a syntax error.
60
130
regex :: String -> RegexFlags -> Either String Regex
61
- regex s f = regex' Left Right s $ renderFlags f
131
+ regex str f = regex' Left Right str $ renderFlags f
62
132
63
133
-- | Returns the pattern string used to construct the given `Regex`.
64
134
foreign import source :: Regex -> String
65
135
66
136
-- | Returns the `RegexFlags` used to construct the given `Regex`.
67
- foreign import flags :: Regex -> RegexFlags
137
+ flags :: Regex -> RegexFlags
138
+ flags = RegexFlags <<< flags'
139
+
140
+ -- | Returns the `RegexFlags` inner record used to construct the given `Regex`.
141
+ foreign import flags' :: Regex -> RegexFlagsRec
142
+
143
+
68
144
69
145
-- | Returns the string representation of the given `RegexFlags`.
70
146
renderFlags :: RegexFlags -> String
71
- renderFlags f =
72
- (if f.global then " g" else " " ) <>
147
+ renderFlags ( RegexFlags f) =
148
+ (if f.global then " g" else " " ) <>
73
149
(if f.ignoreCase then " i" else " " ) <>
74
- (if f.multiline then " m" else " " ) <>
75
- (if f.sticky then " y" else " " ) <>
76
- (if f.unicode then " u" else " " )
150
+ (if f.multiline then " m" else " " ) <>
151
+ (if f.sticky then " y" else " " ) <>
152
+ (if f.unicode then " u" else " " )
77
153
78
154
-- | Parses the string representation of `RegexFlags`.
79
155
parseFlags :: String -> RegexFlags
80
- parseFlags s =
81
- { global: contains " g" s
82
- , ignoreCase: contains " i" s
83
- , multiline: contains " m" s
84
- , sticky: contains " y" s
85
- , unicode: contains " u" s
156
+ parseFlags str = RegexFlags
157
+ { global : contains " g" str
158
+ , ignoreCase : contains " i" str
159
+ , multiline : contains " m" str
160
+ , sticky : contains " y" str
161
+ , unicode : contains " u" str
86
162
}
87
163
88
164
-- | Returns `true` if the `Regex` matches the string. In contrast to
0 commit comments