Skip to content

Commit c62a7e1

Browse files
committed
Reimplement =~ to use Regex.match? or String.contains?
1 parent 2b8854c commit c62a7e1

File tree

3 files changed

+55
-9
lines changed

3 files changed

+55
-9
lines changed

lib/elixir/lib/kernel.ex

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2814,21 +2814,51 @@ defmodule Kernel do
28142814
defmacro left in right
28152815

28162816
@doc """
2817-
Matches the term on the left against the regular expression
2818-
on the right. It returns nil if not match happened or the
2819-
first match otherwise.
2817+
Matches the term on the left against the regular expression or string on the
2818+
right. Returns true if `left` matches `right` (if it's a regular expression)
2819+
or contains `right` (if it's a string).
28202820
28212821
## Examples
28222822
28232823
iex> "abcd" =~ %r/c(d)/
2824-
2
2824+
true
2825+
28252826
iex> "abcd" =~ %r/e/
2826-
nil
2827+
false
2828+
2829+
iex> "abcd" =~ "bc"
2830+
true
2831+
2832+
iex> "abcd" =~ "ad"
2833+
false
28272834
28282835
"""
2836+
# fast path for literal binaries
2837+
defmacro left =~ right when is_binary(right) do
2838+
quote do
2839+
String.contains?(unquote(left), unquote(right))
2840+
end
2841+
end
2842+
2843+
# fast path for literal binaries
2844+
defmacro left =~ ({:<<>>, _, [_bin]} = right) do
2845+
quote do
2846+
String.contains?(unquote(left), unquote(right))
2847+
end
2848+
end
2849+
2850+
# slow path for everything else
28292851
defmacro left =~ right do
28302852
quote do
2831-
Regex.index(unquote(right), unquote(left))
2853+
str = unquote(left)
2854+
case unquote(right) do
2855+
bin when is_binary(bin) ->
2856+
String.contains?(str, bin)
2857+
re when is_regex(re) ->
2858+
Regex.match?(re, str)
2859+
other ->
2860+
raise ArgumentError, message: "bad argument on the right side of =~: #{inspect other}"
2861+
end
28322862
end
28332863
end
28342864

lib/elixir/test/elixir/kernel_test.exs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,24 @@ defmodule KernelTest do
44
use ExUnit.Case, async: true
55

66
test :match do
7-
assert "abcd" =~ %r/c(d)/
8-
refute "abcd" =~ %r/e/
7+
assert ("abcd" =~ %r/c(d)/) == true
8+
assert ("abcd" =~ %r/e/) == false
9+
10+
string = "^ab+cd*$"
11+
assert (string =~ "ab+") == true
12+
assert (string =~ "bb") == false
13+
14+
assert_raise ArgumentError, "bad argument on the right side of =~: [\"^a\",\"*$\"]", fn ->
15+
string =~ ["^a", "*$"]
16+
end
17+
18+
assert_raise ArgumentError, "argument error", fn ->
19+
1234 =~ "hello"
20+
end
21+
22+
assert_raise ArgumentError, "argument error", fn ->
23+
1234 =~ %r"hello"
24+
end
925
end
1026

1127
test :nil? do

lib/elixir/test/elixir/regex_test.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ defmodule Regex.BinaryTest do
4040
end
4141

4242
test :unicode do
43-
assert ("josé" =~ %r"\p{Latin}$"u) == 3
43+
assert ("josé" =~ %r"\p{Latin}$"u)
4444
end
4545

4646
test :groups do

0 commit comments

Comments
 (0)