Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 3 additions & 9 deletions src/Data/String.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,15 +153,9 @@ exports.split = function (sep) {
};
};

exports._splitAt = function (just) {
return function (nothing) {
return function (i) {
return function (s) {
return i >= 0 && i < s.length ?
just({ before: s.substring(0, i), after: s.substring(i) }) :
nothing;
};
};
exports.splitAt = function (i) {
return function (s) {
return { before: s.substring(0, i), after: s.substring(i) };
};
};

Expand Down
27 changes: 16 additions & 11 deletions src/Data/String.purs
Original file line number Diff line number Diff line change
Expand Up @@ -421,21 +421,26 @@ foreign import count :: (Char -> Boolean) -> String -> Int
-- |
foreign import split :: Pattern -> String -> Array String

-- | Returns the substrings of a split at the given index, if the index is within bounds.
-- | Splits a string into two substrings, where `before` contains the
-- | characters up to (but not including) the given index, and `after` contains
-- | the rest of the string, from that index on.
-- |
-- | ```purescript
-- | splitAt 2 "Hello World" == Just { before: "He", after: "llo World"}
-- | splitAt 10 "Hi" == Nothing
-- | splitAt 2 "Hello World" == { before: "He", after: "llo World"}
-- | splitAt 10 "Hi" == { before: "Hi", after: ""}
-- | ```
-- |
splitAt :: Int -> String -> Maybe { before :: String, after :: String }
splitAt = _splitAt Just Nothing

foreign import _splitAt :: (forall a. a -> Maybe a)
-> (forall a. Maybe a)
-> Int
-> String
-> Maybe { before :: String, after :: String }
-- | Thus the length of `(splitAt i s).before` will equal either `i` or
-- | `length s`, if that is shorter. (Or if `i` is negative the length will be
-- | 0.)
-- |
-- | In code:
-- | ```purescript
-- | length (splitAt i s).before == min (max i 0) (length s)
-- | (splitAt i s).before <> (splitAt i s).after == s
-- | splitAt i s == {before: take i s, after: drop i s}
-- | ```
foreign import splitAt :: Int -> String -> { before :: String, after :: String }

-- | Converts the string into an array of characters.
-- |
Expand Down
31 changes: 19 additions & 12 deletions src/Data/String/CodePoints.purs
Original file line number Diff line number Diff line change
Expand Up @@ -340,25 +340,32 @@ singletonFallback (CodePoint cp) =
fromCharCode lead <> fromCharCode trail


-- | Returns a record with strings created from the code points on either side
-- | of the given index. If the index is not within the string, Nothing is
-- | returned.
-- | Splits a string into two substrings, where `before` contains the code
-- | points up to (but not including) the given index, and `after` contains the
-- | rest of the string, from that index on.
-- |
-- | ```purescript
-- | >>> splitAt 3 "b 𝐀𝐀 c 𝐀"
-- | Just { before: "b 𝐀", after: "𝐀 c 𝐀" }
-- | ```
-- |
splitAt :: Int -> String -> Maybe { before :: String, after :: String }
-- | Thus the length of `(splitAt i s).before` will equal either `i` or
-- | `length s`, if that is shorter. (Or if `i` is negative the length will be
-- | 0.)
-- |
-- | In code:
-- | ```purescript
-- | length (splitAt i s).before == min (max i 0) (length s)
-- | (splitAt i s).before <> (splitAt i s).after == s
-- | splitAt i s == {before: take i s, after: drop i s}
-- | ```
splitAt :: Int -> String -> { before :: String, after :: String }
splitAt i s =
let cps = toCodePointArray s in
if i < 0 || Array.length cps < i
then Nothing
else Just {
before: fromCodePointArray (Array.take i cps),
after: fromCodePointArray (Array.drop i cps)
}

let before = take i s in
{ before
-- inline drop i s to reuse the result of take i s
, after: String.drop (String.length before) s
}

-- | Returns a string containing the given number of code points from the
-- | beginning of the given string. If the string does not have that many code
Expand Down
10 changes: 4 additions & 6 deletions src/Data/String/NonEmpty.purs
Original file line number Diff line number Diff line change
Expand Up @@ -412,12 +412,10 @@ count = liftS <<< String.count
splitAt
:: Int
-> NonEmptyString
-> Maybe { before :: Maybe NonEmptyString, after :: Maybe NonEmptyString }
splitAt i (NonEmptyString s) = case String.splitAt i s of
Just { before, after } ->
Just { before: fromString before, after: fromString after }
Nothing ->
Nothing
-> { before :: Maybe NonEmptyString, after :: Maybe NonEmptyString }
splitAt i (NonEmptyString s) =
case String.splitAt i s of
{ before, after } -> { before: fromString before, after: fromString after }

-- | Returns the argument converted to lowercase.
-- |
Expand Down
2 changes: 1 addition & 1 deletion src/Data/String/Regex.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ exports._match = function (just) {
return function (r) {
return function (s) {
var m = s.match(r);
if (m == null) {
if (m == null || m.length === 0) {
return nothing;
} else {
for (var i = 0; i < m.length; i++) {
Expand Down
5 changes: 3 additions & 2 deletions src/Data/String/Regex.purs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ module Data.String.Regex

import Prelude

import Data.Array.NonEmpty (NonEmptyArray)
import Data.Either (Either(..))
import Data.Maybe (Maybe(..))
import Data.String (Pattern(..), contains)
Expand Down Expand Up @@ -82,13 +83,13 @@ foreign import _match
-> (forall r. Maybe r)
-> Regex
-> String
-> Maybe (Array (Maybe String))
-> Maybe (NonEmptyArray (Maybe String))

-- | Matches the string against the `Regex` and returns an array of matches
-- | if there were any. Each match has type `Maybe String`, where `Nothing`
-- | represents an unmatched optional capturing group.
-- | See [reference](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match).
match :: Regex -> String -> Maybe (Array (Maybe String))
match :: Regex -> String -> Maybe (NonEmptyArray (Maybe String))
match = _match Just Nothing

-- | Replaces occurences of the `Regex` with the first string. The replacement
Expand Down
25 changes: 12 additions & 13 deletions test/Test/Data/String.purs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Prelude (Unit, Ordering(..), (==), ($), discard, negate, not, (/=), (&&))
import Effect (Effect)
import Effect.Console (log)

import Data.Maybe (Maybe(..), isNothing, maybe)
import Data.Maybe (Maybe(..), isNothing)
import Data.String

import Test.Assert (assert)
Expand Down Expand Up @@ -174,19 +174,18 @@ testString = do
assert $ split (Pattern "d") "abc" == ["abc"]

log "splitAt"
let testSplitAt i str res =
let testSplitAt i str r =
assert $ case splitAt i str of
Nothing ->
isNothing res
Just { before, after } ->
maybe false (\r ->
r.before == before && r.after == after) res

testSplitAt 1 "" Nothing
testSplitAt 0 "a" $ Just {before: "", after: "a"}
testSplitAt 1 "ab" $ Just {before: "a", after: "b"}
testSplitAt 3 "aabcc" $ Just {before: "aab", after: "cc"}
testSplitAt (-1) "abc" $ Nothing
{ before, after } ->
r.before == before && r.after == after

testSplitAt 1 "" {before: "", after: ""}
testSplitAt 0 "a" {before: "", after: "a"}
testSplitAt 1 "a" {before: "a", after: ""}
testSplitAt 1 "ab" {before: "a", after: "b"}
testSplitAt 3 "aabcc" {before: "aab", after: "cc"}
testSplitAt (-1) "abc" {before: "", after: "abc"}
testSplitAt 10 "Hi" {before: "Hi", after: ""}

log "toCharArray"
assert $ toCharArray "" == []
Expand Down
41 changes: 19 additions & 22 deletions test/Test/Data/String/CodePoints.purs
Original file line number Diff line number Diff line change
Expand Up @@ -152,29 +152,26 @@ testStringCodePoints = do
assert $ (singleton <$> codePointFromInt 0x16805) == Just "\x16805"

log "splitAt"
let testSplitAt i s res =
let testSplitAt i s r =
assert $ case splitAt i s of
Nothing ->
isNothing res
Just { before, after } ->
maybe false (\r ->
r.before == before && r.after == after) res

testSplitAt 0 "" $ Just {before: "", after: ""}
testSplitAt 1 "" Nothing
testSplitAt 0 "a" $ Just {before: "", after: "a"}
testSplitAt 1 "ab" $ Just {before: "a", after: "b"}
testSplitAt 3 "aabcc" $ Just {before: "aab", after: "cc"}
testSplitAt (-1) "abc" $ Nothing
testSplitAt 0 str $ Just {before: "", after: str}
testSplitAt 1 str $ Just {before: "a", after: "\xDC00\xD800\xD800\x16805\x16A06\&z"}
testSplitAt 2 str $ Just {before: "a\xDC00", after: "\xD800\xD800\x16805\x16A06\&z"}
testSplitAt 3 str $ Just {before: "a\xDC00\xD800", after: "\xD800\x16805\x16A06\&z"}
testSplitAt 4 str $ Just {before: "a\xDC00\xD800\xD800", after: "\x16805\x16A06\&z"}
testSplitAt 5 str $ Just {before: "a\xDC00\xD800\xD800\x16805", after: "\x16A06\&z"}
testSplitAt 6 str $ Just {before: "a\xDC00\xD800\xD800\x16805\x16A06", after: "z"}
testSplitAt 7 str $ Just {before: str, after: ""}
testSplitAt 8 str $ Nothing
{ before, after } ->
r.before == before && r.after == after

testSplitAt 0 "" {before: "", after: "" }
testSplitAt 1 "" {before: "", after: "" }
testSplitAt 0 "a" {before: "", after: "a"}
testSplitAt 1 "ab" {before: "a", after: "b"}
testSplitAt 3 "aabcc" {before: "aab", after: "cc"}
testSplitAt (-1) "abc" {before: "", after: "abc"}
testSplitAt 0 str {before: "", after: str}
testSplitAt 1 str {before: "a", after: "\xDC00\xD800\xD800\x16805\x16A06\&z"}
testSplitAt 2 str {before: "a\xDC00", after: "\xD800\xD800\x16805\x16A06\&z"}
testSplitAt 3 str {before: "a\xDC00\xD800", after: "\xD800\x16805\x16A06\&z"}
testSplitAt 4 str {before: "a\xDC00\xD800\xD800", after: "\x16805\x16A06\&z"}
testSplitAt 5 str {before: "a\xDC00\xD800\xD800\x16805", after: "\x16A06\&z"}
testSplitAt 6 str {before: "a\xDC00\xD800\xD800\x16805\x16A06", after: "z"}
testSplitAt 7 str {before: str, after: ""}
testSplitAt 8 str {before: str, after: ""}

log "take"
assert $ take (-1) str == ""
Expand Down
14 changes: 5 additions & 9 deletions test/Test/Data/String/NonEmpty.purs
Original file line number Diff line number Diff line change
Expand Up @@ -203,15 +203,11 @@ testNonEmptyString = do
let
testSplitAt i str res =
assert $ case splitAt i str of
Nothing ->
isNothing res
Just { before, after } ->
maybe false (\r ->
r.before == before && r.after == after) res
testSplitAt 0 (nes "a") (Just { before: Nothing, after: Just (nes "a") })
testSplitAt 1 (nes "ab") (Just { before: Just (nes "a"), after: Just (nes "b") })
testSplitAt 3 (nes "aabcc") (Just { before: Just (nes "aab"), after: Just (nes "cc") })
testSplitAt (-1) (nes "abc") Nothing
{ before, after } -> res.before == before && res.after == after
testSplitAt 0 (nes "a") { before: Nothing, after: Just (nes "a") }
testSplitAt 1 (nes "ab") { before: Just (nes "a"), after: Just (nes "b") }
testSplitAt 3 (nes "aabcc") { before: Just (nes "aab"), after: Just (nes "cc") }
testSplitAt (-1) (nes "abc") { before: Nothing, after: Just (nes "abc") }

log "toLower"
assert $ toLower (nes "bAtMaN") == nes "batman"
Expand Down
20 changes: 12 additions & 8 deletions test/Test/Data/String/Regex.purs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
module Test.Data.String.Regex (testStringRegex) where

import Prelude (Unit, ($), (<>), discard, (==), not)

import Effect (Effect)
import Effect.Console (log)
import Data.String.Regex

import Data.Array.NonEmpty (NonEmptyArray, fromArray)
import Data.Either (isLeft)
import Data.Maybe (Maybe(..))
import Data.String.Regex
import Data.Maybe (Maybe(..), fromJust)
import Data.String.Regex.Flags (global, ignoreCase, noFlags)
import Data.String.Regex.Unsafe (unsafeRegex)

import Effect (Effect)
import Effect.Console (log)
import Partial.Unsafe (unsafePartial)
import Prelude (type (~>), Unit, discard, not, ($), (<<<), (<>), (==))
import Test.Assert (assert)

testStringRegex :: Effect Unit
Expand All @@ -26,7 +26,8 @@ testStringRegex = do
assert $ "quxbarquxbaz" == replace (unsafeRegex "foo" (global <> ignoreCase)) "qux" "foobarFOObaz"

log "match"
assert $ match (unsafeRegex "^abc$" noFlags) "abc" == Just [Just "abc"]
assert $ match (unsafeRegex "^abc$" noFlags) "abc" == Just (nea [Just "abc"])
assert $ match (unsafeRegex "^abc$" noFlags) "xyz" == Nothing

log "replace"
assert $ replace (unsafeRegex "-" noFlags) "!" "a-b-c" == "a!b-c"
Expand All @@ -50,3 +51,6 @@ testStringRegex = do
let pattern = unsafeRegex "a" (parseFlags "g")
assert $ test pattern "a"
assert $ test pattern "a"

nea :: Array ~> NonEmptyArray
nea = unsafePartial fromJust <<< fromArray