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
17 changes: 17 additions & 0 deletions mrbgems/mruby-regexp/src/re_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -1140,13 +1140,30 @@ strip_extended(mrb_state *mrb, const char *src, mrb_int len, mrb_int *out_len)
continue;
}
if (in_class) {
/* compile_charclass() consumes a POSIX bracket as a unit, so the ']'
of [:name:] does not end the class. Copy it whole and keep the
class open; a malformed bracket falls through and the '[' is
copied as an ordinary member, which is what the parser does too. */
if (ch == '[' && src + 1 < end && src[1] == ':') {
const char *q = src + 2;
while (q < end && *q != ':' && *q != ']') q++;
if (q + 1 < end && *q == ':' && q[1] == ']') {
q += 2;
while (src < q) buf[o++] = *src++;
continue;
}
}
if (ch == ']') in_class = FALSE;
buf[o++] = *src++;
continue;
}
if (ch == '[') {
in_class = TRUE;
buf[o++] = *src++;
/* A ']' written first is a literal member, optionally after '^',
mirroring the `first` flag in compile_charclass(). */
if (src < end && *src == '^') buf[o++] = *src++;
if (src < end && *src == ']') buf[o++] = *src++;
continue;
}
if (ch == '#') {
Expand Down
21 changes: 21 additions & 0 deletions mrbgems/mruby-regexp/test/regexp.rb
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,27 @@
re = Regexp.new('[ ]', Regexp::EXTENDED)
assert_true re.match?(" ")

# a POSIX bracket does not end the class, so what follows it is still
# class content
re = Regexp.new('[[:alpha:] ]', Regexp::EXTENDED)
assert_true re.match?(" ")
assert_true re.match?("a")

re = Regexp.new('[[:alpha:]#x]', Regexp::EXTENDED)
assert_true re.match?("#")

assert_equal " 1 ", Regexp.new('[[:digit:] ]+', Regexp::EXTENDED).match(" 1 ")[0]

# a ']' written first in a class is a literal member, so the class is
# still open after it
re = Regexp.new('[] ]', Regexp::EXTENDED)
assert_true re.match?(" ")
assert_true re.match?("]")

re = Regexp.new('[^] ]', Regexp::EXTENDED)
assert_false re.match?(" ")
assert_true re.match?("a")

# escaped whitespace is preserved
re = Regexp.new('a\\ b', Regexp::EXTENDED)
assert_true re.match?("a b")
Expand Down
Loading