Skip to content

Commit

Permalink
Add Regex.needs_escape?
Browse files Browse the repository at this point in the history
  • Loading branch information
Sija committed Apr 19, 2018
1 parent aa596d3 commit 0f7f5c1
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 9 deletions.
11 changes: 11 additions & 0 deletions spec/std/regex_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,17 @@ describe "Regex" do
expect_raises(ArgumentError) { Regex.new("foo)") }
end

it "checks if Char need to be escaped" do
Regex.needs_escape?('*').should be_true
Regex.needs_escape?('|').should be_true
Regex.needs_escape?('@').should be_false
end

it "checks if String need to be escaped" do
Regex.needs_escape?("10$").should be_true
Regex.needs_escape?("foo").should be_false
end

it "escapes" do
Regex.escape(" .\\+*?[^]$(){}=!<>|:-hello").should eq("\\ \\.\\\\\\+\\*\\?\\[\\^\\]\\$\\(\\)\\{\\}\\=\\!\\<\\>\\|\\:\\-hello")
end
Expand Down
41 changes: 32 additions & 9 deletions src/regex.cr
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,15 @@ require "./regex/*"
# `Hash` of `String` => `Int32`, and therefore requires named capture groups to have
# unique names within a single `Regex`.
class Regex
# List of metacharacters that need to be escaped.
#
# See `Regex.needs_escape?` and `Regex.escape`.
SPECIAL_CHARACTERS = {
' ', '.', '\\', '+', '*', '?', '[', '^', ']',
'$', '(', ')', '{', '}', '=', '!', '<', '>',
'|', ':', '-',
}

@[Flags]
enum Options
IGNORE_CASE = 1
Expand Down Expand Up @@ -265,6 +274,27 @@ class Regex
end
end

# Returns `true` if *char* need to be escaped, `false` otherwise.
#
# ```
# Regex.needs_escape?('*') # => true
# Regex.needs_escape?('@') # => false
# ```
def self.needs_escape?(char : Char) : Bool
SPECIAL_CHARACTERS.includes?(char)
end

# Returns `true` if *str* need to be escaped, `false` otherwise.
#
# ```
# Regex.needs_escape?("10$") # => true
# Regex.needs_escape?("foo") # => false
# ```
def self.needs_escape?(str : String) : Bool
str.each_char { |char| return true if SPECIAL_CHARACTERS.includes?(char) }
false
end

# Returns a `String` constructed by escaping any metacharacters in *str*.
#
# ```
Expand All @@ -274,15 +304,8 @@ class Regex
def self.escape(str) : String
String.build do |result|
str.each_byte do |byte|
case byte.unsafe_chr
when ' ', '.', '\\', '+', '*', '?', '[',
'^', ']', '$', '(', ')', '{', '}',
'=', '!', '<', '>', '|', ':', '-'
result << '\\'
result.write_byte byte
else
result.write_byte byte
end
result << '\\' if needs_escape?(byte.unsafe_chr)
result.write_byte byte
end
end
end
Expand Down

0 comments on commit 0f7f5c1

Please sign in to comment.