Skip to content

Commit b96a714

Browse files
committed
Fix edge cases for starts_with?, ends_with? and contains?
1 parent 6004a36 commit b96a714

File tree

2 files changed

+45
-14
lines changed

2 files changed

+45
-14
lines changed

lib/elixir/lib/string.ex

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -811,12 +811,16 @@ defmodule String do
811811
"""
812812
@spec starts_with?(t, t | [t]) :: boolean
813813

814-
def starts_with?(string, prefixes) do
815-
case :binary.match(string, prefixes) do
816-
:nomatch -> false
817-
{0, _} -> true
818-
_ -> false
819-
end
814+
def starts_with?(_, "") do
815+
true
816+
end
817+
818+
def starts_with?(string, prefix) when is_binary(prefix) do
819+
match?({0,_}, :binary.match(string, prefix))
820+
end
821+
822+
def starts_with?(string, prefixes) when is_list(prefixes) do
823+
Enum.any?(prefixes, starts_with?(string, &1))
820824
end
821825

822826
@doc """
@@ -847,7 +851,7 @@ defmodule String do
847851

848852
@doc """
849853
Returns true if `string` contains match, otherwise false.
850-
`matches` can be either a single match of a list of matches.
854+
`matches` can be either a single string or a list of strings.
851855
852856
## Examples
853857
@@ -859,13 +863,13 @@ defmodule String do
859863
false
860864
861865
"""
862-
def contains?(string, matches) when is_list(matches) do
863-
case :binary.match(string, matches) do
864-
:nomatch -> false
865-
_ -> true
866-
end
867-
end
866+
@spec contains?(t, t | [t]) :: boolean
868867

869-
def contains?(string, match), do: contains?(string, [ match ])
868+
def contains?(_, "") do
869+
true
870+
end
870871

872+
def contains?(string, matches) do
873+
:nomatch != :binary.match(string, matches)
874+
end
871875
end

lib/elixir/test/elixir/string_test.exs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,16 @@ defmodule StringTest do
281281
end
282282

283283
test :starts_with? do
284+
assert String.starts_with? "", ""
285+
assert String.starts_with? "", ["", "a"]
286+
assert String.starts_with? "b", ["", "a"]
287+
288+
assert String.starts_with? "abc", ""
289+
assert String.starts_with? "abc", [""]
290+
291+
refute String.starts_with? "", "abc"
292+
refute String.starts_with? "", [" "]
293+
284294
assert String.starts_with? "hello", "he"
285295
assert String.starts_with? "hello", "hello"
286296
assert String.starts_with? "hello", ["hellö", "hell"]
@@ -292,6 +302,16 @@ defmodule StringTest do
292302
end
293303

294304
test :ends_with? do
305+
assert String.ends_with? "", ""
306+
assert String.ends_with? "", ["", "a"]
307+
refute String.ends_with? "", ["a", "b"]
308+
309+
assert String.ends_with? "abc", ""
310+
assert String.ends_with? "abc", ["", "x"]
311+
312+
refute String.ends_with? "", "abc"
313+
refute String.ends_with? "", [" "]
314+
295315
assert String.ends_with? "hello", "lo"
296316
assert String.ends_with? "hello", "hello"
297317
assert String.ends_with? "hello", ["hell", "lo", "xx"]
@@ -304,6 +324,13 @@ defmodule StringTest do
304324
end
305325

306326
test :contains? do
327+
assert String.contains? "", ""
328+
assert String.contains? "abc", ""
329+
assert String.contains? "abc", ["", "x"]
330+
331+
refute String.contains? "", " "
332+
refute String.contains? "", "a"
333+
307334
assert String.contains? "elixir of life", "of"
308335
assert String.contains? "エリクシア", "シ"
309336
assert String.contains? "elixir of life", ["mercury", "life"]

0 commit comments

Comments
 (0)