diff --git a/include/boost/regex/v4/basic_regex_parser.hpp b/include/boost/regex/v4/basic_regex_parser.hpp index d980d12b..4b103f22 100644 --- a/include/boost/regex/v4/basic_regex_parser.hpp +++ b/include/boost/regex/v4/basic_regex_parser.hpp @@ -1070,26 +1070,46 @@ bool basic_regex_parser::parse_repeat_range(bool isbasic) // skip whitespace: while((m_position != m_end) && this->m_traits.isctype(*m_position, this->m_mask_space)) ++m_position; - // fail if at end: if(this->m_position == this->m_end) { - fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message); - return false; + if(this->flags() & (regbase::main_option_type | regbase::no_perl_ex)) + { + fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message); + return false; + } + // Treat the opening '{' as a literal character, rewind to start of error: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_brace) --m_position; + return parse_literal(); } // get min: v = this->m_traits.toi(m_position, m_end, 10); // skip whitespace: - while((m_position != m_end) && this->m_traits.isctype(*m_position, this->m_mask_space)) - ++m_position; if(v < 0) { - fail(regex_constants::error_badbrace, this->m_position - this->m_base); - return false; + if(this->flags() & (regbase::main_option_type | regbase::no_perl_ex)) + { + fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message); + return false; + } + // Treat the opening '{' as a literal character, rewind to start of error: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_brace) --m_position; + return parse_literal(); } - else if(this->m_position == this->m_end) + while((m_position != m_end) && this->m_traits.isctype(*m_position, this->m_mask_space)) + ++m_position; + if(this->m_position == this->m_end) { - fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message); - return false; + if(this->flags() & (regbase::main_option_type | regbase::no_perl_ex)) + { + fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message); + return false; + } + // Treat the opening '{' as a literal character, rewind to start of error: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_brace) --m_position; + return parse_literal(); } min = v; // see if we have a comma: @@ -1102,8 +1122,15 @@ bool basic_regex_parser::parse_repeat_range(bool isbasic) ++m_position; if(this->m_position == this->m_end) { - fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message); - return false; + if(this->flags() & (regbase::main_option_type | regbase::no_perl_ex)) + { + fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message); + return false; + } + // Treat the opening '{' as a literal character, rewind to start of error: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_brace) --m_position; + return parse_literal(); } // get the value if any: v = this->m_traits.toi(m_position, m_end, 10); @@ -1120,8 +1147,15 @@ bool basic_regex_parser::parse_repeat_range(bool isbasic) // OK now check trailing }: if(this->m_position == this->m_end) { - fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message); - return false; + if(this->flags() & (regbase::main_option_type | regbase::no_perl_ex)) + { + fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message); + return false; + } + // Treat the opening '{' as a literal character, rewind to start of error: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_brace) --m_position; + return parse_literal(); } if(isbasic) { @@ -1144,8 +1178,10 @@ bool basic_regex_parser::parse_repeat_range(bool isbasic) ++m_position; else { - fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message); - return false; + // Treat the opening '{' as a literal character, rewind to start of error: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_brace) --m_position; + return parse_literal(); } // // finally go and add the repeat, unless error: diff --git a/test/regress/test_simple_repeats.cpp b/test/regress/test_simple_repeats.cpp index 044ca2fd..d0e3a299 100644 --- a/test/regress/test_simple_repeats.cpp +++ b/test/regress/test_simple_repeats.cpp @@ -179,21 +179,20 @@ void test_simple_repeats2() { using namespace boost::regex_constants; - TEST_INVALID_REGEX("a{}", perl); - TEST_INVALID_REGEX("a{", perl); - TEST_INVALID_REGEX("a{1", perl); - TEST_INVALID_REGEX("a{1,", perl); - TEST_INVALID_REGEX("a{1,2", perl); - TEST_INVALID_REGEX("a{ 1 , 2 ", perl); - TEST_INVALID_REGEX("a{ }", perl); - TEST_INVALID_REGEX("a}", perl); + TEST_REGEX_SEARCH("a{}", basic, "a{}", match_default, make_array(0, 3, -2, -2)); + TEST_REGEX_SEARCH("a{", basic, "a{", match_default, make_array(0, 2, -2, -2)); + TEST_REGEX_SEARCH("a{1", basic, "a{1", match_default, make_array(0, 3, -2, -2)); + TEST_REGEX_SEARCH("a{1,", basic, "a{1,", match_default, make_array(0, 4, -2, -2)); + TEST_REGEX_SEARCH("a{1,2", basic, "a{1,2", match_default, make_array(0, 5, -2, -2)); + TEST_REGEX_SEARCH("a{ 1 , 2", basic, "a{ 1 , 2", match_default, make_array(0, 8, -2, -2)); + TEST_REGEX_SEARCH("a{ }", basic, "a{ }", match_default, make_array(0, 4, -2, -2)); + TEST_REGEX_SEARCH("a}", basic, "a}", match_default, make_array(0, 2, -2, -2)); TEST_INVALID_REGEX("{1}", perl); - TEST_INVALID_REGEX("a{b}", perl); - TEST_INVALID_REGEX("a{1b}", perl); - TEST_INVALID_REGEX("a{1,b}", perl); - TEST_INVALID_REGEX("a{1,2v}", perl); + TEST_REGEX_SEARCH("a{b}", basic, "a{b}", match_default, make_array(0, 4, -2, -2)); + TEST_REGEX_SEARCH("a{1b", basic, "a{1b", match_default, make_array(0, 4, -2, -2)); + TEST_REGEX_SEARCH("a{1,b}", basic, "a{1,b}", match_default, make_array(0, 6, -2, -2)); + TEST_REGEX_SEARCH("a{1,2v}", basic, "a{1,2v}", match_default, make_array(0, 7, -2, -2)); TEST_INVALID_REGEX("a{2,1}", perl); - // now try operator \\{\\} for POSIX basic regexes TEST_REGEX_SEARCH("a\\{2\\}", basic, "a", match_default, make_array(-2, -2)); TEST_REGEX_SEARCH("a\\{2\\}", basic|no_intervals, "a{2}", match_default, make_array(0, 4, -2, -2));