Skip to content

Commit 88e16f7

Browse files
committed
Added a monoid instance and helper functions to regex flags
1 parent 2e60399 commit 88e16f7

File tree

3 files changed

+107
-26
lines changed

3 files changed

+107
-26
lines changed

src/Data/String/Regex.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ exports.source = function (r) {
2525
return r.source;
2626
};
2727

28-
exports.flags = function (r) {
28+
exports["flags'"] = function (r) {
2929
return {
3030
multiline: r.multiline,
3131
ignoreCase: r.ignoreCase,

src/Data/String/Regex.purs

Lines changed: 100 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
module Data.String.Regex
55
( Regex(..)
66
, RegexFlags(..)
7+
, RegexFlagsRec
78
, regex
89
, source
910
, flags
@@ -16,13 +17,15 @@ module Data.String.Regex
1617
, search
1718
, split
1819
, noFlags
20+
, g, i, m, s, u
1921
) where
2022

2123
import Prelude
2224

2325
import Data.Either (Either(..))
2426
import Data.Maybe (Maybe(..))
2527
import Data.String (contains)
28+
import Data.Monoid (class Monoid)
2629

2730
-- | Wraps Javascript `RegExp` objects.
2831
foreign import data Regex :: *
@@ -32,22 +35,89 @@ foreign import showRegex' :: Regex -> String
3235
instance showRegex :: Show Regex where
3336
show = showRegex'
3437

35-
-- | Flags that control matching.
36-
type RegexFlags =
37-
{ global :: Boolean
38+
type RegexFlagsRec =
39+
{ global :: Boolean
3840
, ignoreCase :: Boolean
39-
, multiline :: Boolean
40-
, sticky :: Boolean
41-
, unicode :: Boolean
41+
, multiline :: Boolean
42+
, sticky :: Boolean
43+
, unicode :: Boolean
4244
}
4345

46+
-- | Flags that control matching.
47+
data RegexFlags = RegexFlags RegexFlagsRec
48+
4449
-- | All flags set to false.
4550
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+
51121

52122
foreign import regex' :: (String -> Either String Regex)
53123
-> (Regex -> Either String Regex)
@@ -58,31 +128,37 @@ foreign import regex' :: (String -> Either String Regex)
58128
-- | Constructs a `Regex` from a pattern string and flags. Fails with
59129
-- | `Left error` if the pattern contains a syntax error.
60130
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
62132

63133
-- | Returns the pattern string used to construct the given `Regex`.
64134
foreign import source :: Regex -> String
65135

66136
-- | 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+
68144

69145
-- | Returns the string representation of the given `RegexFlags`.
70146
renderFlags :: RegexFlags -> String
71-
renderFlags f =
72-
(if f.global then "g" else "") <>
147+
renderFlags (RegexFlags f) =
148+
(if f.global then "g" else "") <>
73149
(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 "")
77153

78154
-- | Parses the string representation of `RegexFlags`.
79155
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
86162
}
87163

88164
-- | Returns `true` if the `Regex` matches the string. In contrast to

test/Test/Data/String/Regex.purs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module Test.Data.String.Regex (testStringRegex) where
22

3-
import Prelude (Unit, ($), bind, (==), not)
3+
import Prelude (Unit, ($), (<>), bind, (==), not)
44

55
import Control.Monad.Eff (Eff)
66
import Control.Monad.Eff.Console (CONSOLE, log)
@@ -24,6 +24,11 @@ testStringRegex = do
2424
assert $ not (test (regex' "^b" noFlags) "abc")
2525
assert $ isLeft (regex "+" noFlags)
2626

27+
log "flags"
28+
assert $ "quxbarfoobaz" == replace (regex' "foo" noFlags) "qux" "foobarfoobaz"
29+
assert $ "quxbarquxbaz" == replace (regex' "foo" g) "qux" "foobarfoobaz"
30+
assert $ "quxbarquxbaz" == replace (regex' "foo" (g <> i)) "qux" "foobarFOObaz"
31+
2732
log "match"
2833
assert $ match (regex' "^abc$" noFlags) "abc" == Just [Just "abc"]
2934

0 commit comments

Comments
 (0)