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
27 changes: 27 additions & 0 deletions benchmarks/src/Benchmarks.elm
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import Array.Extra.Unzip
import Benchmark exposing (Benchmark, describe)
import Benchmark.Alternative exposing (rank)
import Benchmark.Runner.Alternative as BenchmarkRunner
import List.Extra
import List.Extra.GroupsOf
import List.Extra.Lift
import List.Extra.NotMember
Expand All @@ -28,6 +29,7 @@ import Set exposing (Set)
import Set.Extra.AreDisjoint
import Set.Extra.SymmetricDifference
import String.Extra.IsBlank
import String.Extra.RightOfLeftOf


main : BenchmarkRunner.Program
Expand Down Expand Up @@ -269,7 +271,32 @@ stringExtra : Benchmark
stringExtra =
describe "String.Extra"
[ stringExtraIsBlank
, describe "String.Extra.{rightOf,leftOf}"
[ describe "1 match" (rightLeft 1)
, describe "10 matches" (rightLeft 10)
, describe "100 matches" (rightLeft 100)
, describe "1000 matches" (rightLeft 1000)
]
]


rightLeft matches =
let
a =
List.Extra.initialize matches String.fromInt
|> String.join "___"
in
[ rank "rightOf"
(\rightOf -> rightOf "___" a)
[ ( "regex", String.Extra.RightOfLeftOf.rightOfRegex )
, ( "String.indexes", String.Extra.RightOfLeftOf.rightOfIndexes )
]
, rank "leftOf"
(\leftOf -> leftOf "___" a)
[ ( "regex", String.Extra.RightOfLeftOf.leftOfRegex )
, ( "String.indexes", String.Extra.RightOfLeftOf.leftOfIndexes )
]
]


maybeExtra : Benchmark
Expand Down
77 changes: 77 additions & 0 deletions benchmarks/src/String/Extra/RightOfLeftOf.elm
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
module String.Extra.RightOfLeftOf exposing (leftOfIndexes, leftOfRegex, rightOfIndexes, rightOfRegex)

import Regex exposing (Regex)


regexFromString : String -> Regex
regexFromString =
Regex.fromString >> Maybe.withDefault Regex.never


regexBased : String -> Bool
regexBased string =
Regex.contains (regexFromString "^\\s*$") string


firstResult : List (Maybe String) -> String
firstResult list =
firstResultHelp "" list


firstResultHelp : String -> List (Maybe String) -> String
firstResultHelp default list =
case list of
[] ->
default

(Just a) :: _ ->
a

Nothing :: rest ->
firstResultHelp default rest


rightOfRegex : String -> String -> String
rightOfRegex pattern string =
string
|> Regex.findAtMost 1 (regexFromString <| regexEscape pattern ++ "((?:.|\\s)*)$")
|> List.map (.submatches >> firstResult)
|> String.concat


rightOfIndexes : String -> String -> String
rightOfIndexes pattern string =
case String.indexes pattern string of
[] ->
""

firstIndex :: rest ->
String.slice (String.length pattern + firstIndex) (String.length string) string


leftOfRegex : String -> String -> String
leftOfRegex pattern string =
string
|> Regex.findAtMost 1 (regexFromString <| "^((?:.|\\s)*?)" ++ regexEscape pattern)
|> List.map (.submatches >> firstResult)
|> String.concat


leftOfIndexes : String -> String -> String
leftOfIndexes pattern string =
case String.indexes pattern string of
[] ->
""

firstIndex :: rest ->
String.slice 0 firstIndex string


regexEscape : String -> String
regexEscape =
Regex.replace regexEscapeRegex (\{ match } -> "\\" ++ match)


regexEscapeRegex : Regex
regexEscapeRegex =
regexFromString "[-/\\^$*+?.()|[\\]{}]"
2 changes: 1 addition & 1 deletion docs.json

Large diffs are not rendered by default.

44 changes: 10 additions & 34 deletions src/String/Extra.elm
Original file line number Diff line number Diff line change
Expand Up @@ -760,10 +760,12 @@ consisting of the characters in the string that are to the right of the pattern.
-}
rightOf : String -> String -> String
rightOf pattern string =
string
|> Regex.findAtMost 1 (regexFromString <| regexEscape pattern ++ "(.*)$")
|> List.map (.submatches >> firstResult)
|> String.concat
case String.indexes pattern string of
[] ->
""

firstIndex :: _ ->
String.slice (String.length pattern + firstIndex) (String.length string) string


{-| Search a string from left to right for a pattern and return a substring
Expand All @@ -774,28 +776,12 @@ consisting of the characters in the string that are to the left of the pattern.
-}
leftOf : String -> String -> String
leftOf pattern string =
string
|> Regex.findAtMost 1 (regexFromString <| "^(.*?)" ++ regexEscape pattern)
|> List.map (.submatches >> firstResult)
|> String.concat


firstResult : List (Maybe String) -> String
firstResult list =
firstResultHelp "" list


firstResultHelp : String -> List (Maybe String) -> String
firstResultHelp default list =
case list of
case String.indexes pattern string of
[] ->
default

(Just a) :: _ ->
a
""

Nothing :: rest ->
firstResultHelp default rest
firstIndex :: _ ->
String.slice 0 firstIndex string


{-| Search a string from right to left for a pattern and return a substring
Expand Down Expand Up @@ -963,16 +949,6 @@ removeDiacritics str =
String.foldl replace "" str


regexEscape : String -> String
regexEscape =
Regex.replace regexEscapeRegex (\{ match } -> "\\" ++ match)


regexEscapeRegex : Regex
regexEscapeRegex =
regexFromString "[-/\\^$*+?.()|[\\]{}]"


regexFromString : String -> Regex
regexFromString str =
Regex.fromString str
Expand Down
56 changes: 51 additions & 5 deletions tests/String/Tests.elm
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module String.Tests exposing (breakTest, cleanTest, countOccurrencesTest, dasherizeTest, decapitalizeTest, ellipsisTest, insertAtTest, isBlankTest, leftOfBackTest, nonBlankTest, pluralizeTest, rightOfBackTest, softBreakTest, stripTagsTest, surroundTest, toSentenceCaseTest, toTitleCaseTest, underscoredTest, unquoteTest, wrapTest)
module String.Tests exposing (breakTest, cleanTest, countOccurrencesTest, dasherizeTest, decapitalizeTest, ellipsisTest, insertAtTest, isBlankTest, leftOfBackTest, leftOfTest, nonBlankTest, pluralizeTest, rightOfBackTest, rightOfTest, softBreakTest, stripTagsTest, surroundTest, toSentenceCaseTest, toTitleCaseTest, underscoredTest, unquoteTest, wrapTest)

import Char.Extra
import Expect
Expand Down Expand Up @@ -428,12 +428,58 @@ leftOfBackTest =
|> Expect.equal "This_is_a_test"


leftOfTest : Test
leftOfTest =
describe "leftOf"
[ test "basic contains multiple" <|
\() ->
String.Extra.leftOf "___" "This___is_a___test___string"
|> Expect.equal "This"
, test "not contains" <|
\() ->
String.Extra.leftOf "-" "This_is_a_test_string"
|> Expect.equal ""
, test "newlines" <|
\() ->
String.Extra.leftOf "_" "This\ntest_string_foo"
|> Expect.equal "This\ntest"
]


rightOfBackTest : Test
rightOfBackTest =
test "rightOfBack" <|
\() ->
String.Extra.rightOfBack "_" "This_is_a_test_string"
|> Expect.equal "string"
describe "rightOfBack"
[ test "basic contains multiple" <|
\() ->
String.Extra.rightOfBack "___" "This___is_a___test___string"
|> Expect.equal "string"
, test "not contains" <|
\() ->
String.Extra.rightOfBack "-" "This_is_a_test_string"
|> Expect.equal ""
, test "newlines" <|
\() ->
String.Extra.rightOfBack "_" "This_is_a\ntest_string"
|> Expect.equal "string"
]


rightOfTest : Test
rightOfTest =
describe "rightOf"
[ test "basic contains multiple" <|
\() ->
String.Extra.rightOf "___" "This___is_a___test___string"
|> Expect.equal "is_a___test___string"
, test "not contains" <|
\() ->
String.Extra.rightOf "-" "This_is_a_test_string"
|> Expect.equal ""
, test "newlines" <|
\() ->
String.Extra.rightOf "_" "This_is_a\ntest_string"
|> Expect.equal "is_a\ntest_string"
]


underscoredTest : Test
Expand Down