From b6654d49e2300416b25c05a00a0e6065c29fcf07 Mon Sep 17 00:00:00 2001 From: Nicholas Wolverson Date: Thu, 26 Dec 2024 12:18:56 +0000 Subject: [PATCH 1/3] Update take docstring to match the behaviour (#172) --- src/Data/String/CodePoints.purs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Data/String/CodePoints.purs b/src/Data/String/CodePoints.purs index 65e0b55..610e497 100644 --- a/src/Data/String/CodePoints.purs +++ b/src/Data/String/CodePoints.purs @@ -314,7 +314,7 @@ lastIndexOf' p i 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 --- | points, returns the empty string. Operates in constant space and in time +-- | points, returns the entire string. Operates in constant space and in time -- | linear to the given number. -- | -- | ```purescript From 03b03a7b5df720a97f9024ae612eb94bd4155399 Mon Sep 17 00:00:00 2001 From: Eryk Ciepiela Date: Fri, 5 Sep 2025 15:21:12 +0200 Subject: [PATCH 2/3] CodeUnits length function doc references itself and is wrong (#177) * CodeUnits length function doc references itself and is wrong * reference do Data.String.CodeUnits.length * referencing Data.String.CodePoints.kength from Data.String.CodeUnits.length --- src/Data/String/CodePoints.purs | 2 +- src/Data/String/CodeUnits.purs | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Data/String/CodePoints.purs b/src/Data/String/CodePoints.purs index 610e497..b695364 100644 --- a/src/Data/String/CodePoints.purs +++ b/src/Data/String/CodePoints.purs @@ -207,7 +207,7 @@ uncons s = case CU.length s of -- | ```purescript -- | >>> length "b 𝐀𝐀 c 𝐀" -- | 8 --- | -- compare to Data.String: +-- | -- compare to Data.String.CodeUnits: -- | >>> length "b 𝐀𝐀 c 𝐀" -- | 11 -- | ``` diff --git a/src/Data/String/CodeUnits.purs b/src/Data/String/CodeUnits.purs index 5fed21f..ac78266 100644 --- a/src/Data/String/CodeUnits.purs +++ b/src/Data/String/CodeUnits.purs @@ -145,6 +145,10 @@ uncons s = Just { head: U.charAt zero s, tail: drop one s } -- | -- | ```purescript -- | length "Hello World" == 11 +-- | +-- | length "𝐀A" == 3 +-- | -- compare to Data.String.CodePoints: +-- | length "𝐀A" == 2 -- | ``` -- | foreign import length :: String -> Int From 1c9cde35c87d9b1626cf6d4b3c38c548fa45e91d Mon Sep 17 00:00:00 2001 From: triallax <6daf084a-8eaf-40fb-86c7-8500077c3b69@anonaddy.me> Date: Fri, 10 Apr 2026 22:16:25 +0000 Subject: [PATCH 3/3] Add startsWith and endsWith (#147) --- CHANGELOG.md | 1 + src/Data/String/CodePoints.purs | 2 +- src/Data/String/CodeUnits.purs | 33 +++++++++++++++++++++++--- src/Data/String/NonEmpty.purs | 2 +- src/Data/String/NonEmpty/Internal.purs | 25 +++++++++++++++++++ test/Test/Data/String/CodeUnits.purs | 14 +++++++++++ test/Test/Data/String/NonEmpty.purs | 13 ++++++++++ 7 files changed, 85 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 878d55d..f0f30c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ Notable changes to this project are documented in this file. The format is based Breaking changes: New features: +- Added `startsWith` and `endsWith` (#147) Bugfixes: diff --git a/src/Data/String/CodePoints.purs b/src/Data/String/CodePoints.purs index b695364..f5b5fd2 100644 --- a/src/Data/String/CodePoints.purs +++ b/src/Data/String/CodePoints.purs @@ -34,7 +34,7 @@ import Data.Array as Array import Data.Enum (class BoundedEnum, class Enum, Cardinality(..), defaultPred, defaultSucc, fromEnum, toEnum, toEnumWithDefaults) import Data.Int (hexadecimal, toStringAs) import Data.Maybe (Maybe(..)) -import Data.String.CodeUnits (contains, stripPrefix, stripSuffix) as Exports +import Data.String.CodeUnits (contains, stripPrefix, stripSuffix, startsWith, endsWith) as Exports import Data.String.CodeUnits as CU import Data.String.Common (toUpper) import Data.String.Pattern (Pattern) diff --git a/src/Data/String/CodeUnits.purs b/src/Data/String/CodeUnits.purs index ac78266..ec4d4cd 100644 --- a/src/Data/String/CodeUnits.purs +++ b/src/Data/String/CodeUnits.purs @@ -22,6 +22,8 @@ module Data.String.CodeUnits , dropWhile , slice , splitAt + , startsWith + , endsWith ) where import Prelude @@ -31,9 +33,10 @@ import Data.String.Pattern (Pattern(..)) import Data.String.Unsafe as U ------------------------------------------------------------------------------- --- `stripPrefix`, `stripSuffix`, and `contains` are CodeUnit/CodePoint agnostic --- as they are based on patterns rather than lengths/indices, but they need to --- be defined in here to avoid a circular module dependency +-- `stripPrefix`, `stripSuffix`, `startsWith`, `endsWith`, and `contains` are +-- CodeUnit/CodePoint agnostic as they are based on patterns rather than +-- lengths/indices, but they need to be defined in here to avoid a circular +-- module dependency ------------------------------------------------------------------------------- -- | If the string starts with the given prefix, return the portion of the @@ -61,6 +64,30 @@ stripSuffix (Pattern suffix) str = let { before, after } = splitAt (length str - length suffix) str in if after == suffix then Just before else Nothing +-- | Checks whether the given string starts with the pattern. +-- | +-- | **NOTE**: if you also want to get the string stripped of the pattern, see +-- | `stripPrefix`. +-- | +-- | ```purescript +-- | startsWith (Pattern "foo") "foobar" == true +-- | startsWith (Pattern "bar") "foobar" == false +-- | ``` +startsWith :: Pattern -> String -> Boolean +startsWith pat = isJust <<< stripPrefix pat + +-- | Checks whether the given string ends with the pattern. +-- | +-- | **NOTE**: if you also want to get the string stripped of the pattern, see +-- | `stripSuffix`. +-- | +-- | ```purescript +-- | endsWith (Pattern "bar") "foobar" == true +-- | endsWith (Pattern "foo") "foobar" == false +-- | ``` +endsWith :: Pattern -> String -> Boolean +endsWith pat = isJust <<< stripSuffix pat + -- | Checks whether the pattern appears in the given string. -- | -- | ```purescript diff --git a/src/Data/String/NonEmpty.purs b/src/Data/String/NonEmpty.purs index 6b6210c..72e10b3 100644 --- a/src/Data/String/NonEmpty.purs +++ b/src/Data/String/NonEmpty.purs @@ -4,6 +4,6 @@ module Data.String.NonEmpty , module Data.String.NonEmpty.CodePoints ) where -import Data.String.NonEmpty.Internal (NonEmptyString, class MakeNonEmpty, NonEmptyReplacement(..), appendString, contains, fromString, join1With, joinWith, joinWith1, localeCompare, nes, prependString, replace, replaceAll, stripPrefix, stripSuffix, toLower, toString, toUpper, trim, unsafeFromString) +import Data.String.NonEmpty.Internal (NonEmptyString, class MakeNonEmpty, NonEmptyReplacement(..), appendString, contains, fromString, join1With, joinWith, joinWith1, localeCompare, nes, prependString, replace, replaceAll, stripPrefix, stripSuffix, startsWith, endsWith, toLower, toString, toUpper, trim, unsafeFromString) import Data.String.Pattern (Pattern(..)) import Data.String.NonEmpty.CodePoints diff --git a/src/Data/String/NonEmpty/Internal.purs b/src/Data/String/NonEmpty/Internal.purs index 8722654..0b12623 100644 --- a/src/Data/String/NonEmpty/Internal.purs +++ b/src/Data/String/NonEmpty/Internal.purs @@ -124,6 +124,31 @@ stripPrefix pat = fromString <=< liftS (String.stripPrefix pat) stripSuffix :: Pattern -> NonEmptyString -> Maybe NonEmptyString stripSuffix pat = fromString <=< liftS (String.stripSuffix pat) + +-- | Checks whether the given string starts with the pattern. +-- | +-- | **NOTE**: if you also want to get the string stripped of the pattern, see +-- | `stripPrefix`. +-- | +-- | ```purescript +-- | startsWith (Pattern "foo") (NonEmptyString "foobar") == true +-- | startsWith (Pattern "bar") (NonEmptyString "foobar") == false +-- | ``` +startsWith :: Pattern -> NonEmptyString -> Boolean +startsWith = liftS <<< String.startsWith + +-- | Checks whether the given string ends with the pattern. +-- | +-- | **NOTE**: if you also want to get the string stripped of the pattern, see +-- | `stripSuffix`. +-- | +-- | ```purescript +-- | endsWith (Pattern "bar") (NonEmptyString "foobar") == true +-- | endsWith (Pattern "foo") (NonEmptyString "foobar") == false +-- | ``` +endsWith :: Pattern -> NonEmptyString -> Boolean +endsWith = liftS <<< String.endsWith + -- | Checks whether the pattern appears in the given string. -- | -- | ```purescript diff --git a/test/Test/Data/String/CodeUnits.purs b/test/Test/Data/String/CodeUnits.purs index ddd512b..30bf100 100644 --- a/test/Test/Data/String/CodeUnits.purs +++ b/test/Test/Data/String/CodeUnits.purs @@ -64,6 +64,20 @@ testStringCodeUnits = do , expected: Just "" } + log "startsWith" + assert $ SCU.startsWith (Pattern "foo") "foobar" + assert $ SCU.startsWith (Pattern "foo") "foo" + assert $ SCU.startsWith (Pattern "") "" + assert $ SCU.startsWith (Pattern "") "foo" + assert $ not $ SCU.startsWith (Pattern "foo") "" + + log "endsWith" + assert $ SCU.endsWith (Pattern "bar") "foobar" + assert $ SCU.endsWith (Pattern "bar") "bar" + assert $ SCU.endsWith (Pattern "") "" + assert $ SCU.endsWith (Pattern "") "bar" + assert $ not $ SCU.endsWith (Pattern "bar") "" + log "charAt" assertEqual { actual: SCU.charAt 0 "" diff --git a/test/Test/Data/String/NonEmpty.purs b/test/Test/Data/String/NonEmpty.purs index a4103ec..46f2cd0 100644 --- a/test/Test/Data/String/NonEmpty.purs +++ b/test/Test/Data/String/NonEmpty.purs @@ -144,6 +144,19 @@ testNonEmptyString = do , expected: Nothing } + log "startsWith" + assert $ NES.startsWith (Pattern "foo") (nes (Proxy :: Proxy "foobar")) + assert $ NES.startsWith (Pattern "foo") (nes (Proxy :: Proxy "foo")) + assert $ NES.startsWith (Pattern "") (nes (Proxy :: Proxy "foo")) + assert $ not $ NES.startsWith (Pattern "foo") (nes (Proxy :: Proxy "f")) + + log "endsWith" + assert $ NES.endsWith (Pattern "bar") (nes (Proxy :: Proxy "foobar")) + assert $ NES.endsWith (Pattern "bar") (nes (Proxy :: Proxy "bar")) + assert $ NES.endsWith (Pattern "") (nes (Proxy :: Proxy "f")) + assert $ NES.endsWith (Pattern "") (nes (Proxy :: Proxy "bar")) + assert $ not $ NES.endsWith (Pattern "bar") (nes (Proxy :: Proxy "b")) + log "toLower" assertEqual { actual: NES.toLower (nes (Proxy :: Proxy "bAtMaN"))