Commit 769185d6 authored by Milo Yip's avatar Milo Yip

Refactor regex

Remove mutable which causes reentrant issue
parent 328ead0e
...@@ -43,12 +43,40 @@ RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated ...@@ -43,12 +43,40 @@ RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {
///////////////////////////////////////////////////////////////////////////////
// DecodedStream
template <typename SourceStream, typename Encoding>
class DecodedStream {
public:
DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); }
unsigned Peek() { return codepoint_; }
unsigned Take() {
unsigned c = codepoint_;
if (c) // No further decoding when '\0'
Decode();
return c;
}
private:
void Decode() {
if (!Encoding::Decode(ss_, &codepoint_))
codepoint_ = 0;
}
SourceStream& ss_;
unsigned codepoint_;
};
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// GenericRegex // GenericRegex
static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1 static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1
static const SizeType kRegexInvalidRange = ~SizeType(0); static const SizeType kRegexInvalidRange = ~SizeType(0);
template <typename Encoding, typename Allocator>
class GenericRegexSearch;
//! Regular expression engine with subset of ECMAscript grammar. //! Regular expression engine with subset of ECMAscript grammar.
/*! /*!
Supported regular expression syntax: Supported regular expression syntax:
...@@ -84,45 +112,25 @@ static const SizeType kRegexInvalidRange = ~SizeType(0); ...@@ -84,45 +112,25 @@ static const SizeType kRegexInvalidRange = ~SizeType(0);
template <typename Encoding, typename Allocator = CrtAllocator> template <typename Encoding, typename Allocator = CrtAllocator>
class GenericRegex { class GenericRegex {
public: public:
typedef Encoding EncodingType;
typedef typename Encoding::Ch Ch; typedef typename Encoding::Ch Ch;
template <typename, typename> friend class GenericRegexSearch;
GenericRegex(const Ch* source, Allocator* allocator = 0) : GenericRegex(const Ch* source, Allocator* allocator = 0) :
states_(allocator, 256), ranges_(allocator, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(), states_(allocator, 256), ranges_(allocator, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(),
stateSet_(), state0_(allocator, 0), state1_(allocator, 0), anchorBegin_(), anchorEnd_() anchorBegin_(), anchorEnd_()
{ {
GenericStringStream<Encoding> ss(source); GenericStringStream<Encoding> ss(source);
DecodedStream<GenericStringStream<Encoding> > ds(ss); DecodedStream<GenericStringStream<Encoding>, Encoding> ds(ss);
Parse(ds); Parse(ds);
} }
~GenericRegex() { ~GenericRegex() {}
Allocator::Free(stateSet_);
}
bool IsValid() const { bool IsValid() const {
return root_ != kRegexInvalidState; return root_ != kRegexInvalidState;
} }
template <typename InputStream>
bool Match(InputStream& is) const {
return SearchWithAnchoring(is, true, true);
}
bool Match(const Ch* s) const {
GenericStringStream<Encoding> is(s);
return Match(is);
}
template <typename InputStream>
bool Search(InputStream& is) const {
return SearchWithAnchoring(is, anchorBegin_, anchorEnd_);
}
bool Search(const Ch* s) const {
GenericStringStream<Encoding> is(s);
return Search(is);
}
private: private:
enum Operator { enum Operator {
kZeroOrOne, kZeroOrOne,
...@@ -157,28 +165,6 @@ private: ...@@ -157,28 +165,6 @@ private:
SizeType minIndex; SizeType minIndex;
}; };
template <typename SourceStream>
class DecodedStream {
public:
DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); }
unsigned Peek() { return codepoint_; }
unsigned Take() {
unsigned c = codepoint_;
if (c) // No further decoding when '\0'
Decode();
return c;
}
private:
void Decode() {
if (!Encoding::Decode(ss_, &codepoint_))
codepoint_ = 0;
}
SourceStream& ss_;
unsigned codepoint_;
};
State& GetState(SizeType index) { State& GetState(SizeType index) {
RAPIDJSON_ASSERT(index < stateCount_); RAPIDJSON_ASSERT(index < stateCount_);
return states_.template Bottom<State>()[index]; return states_.template Bottom<State>()[index];
...@@ -200,7 +186,7 @@ private: ...@@ -200,7 +186,7 @@ private:
} }
template <typename InputStream> template <typename InputStream>
void Parse(DecodedStream<InputStream>& ds) { void Parse(DecodedStream<InputStream, Encoding>& ds) {
Allocator allocator; Allocator allocator;
Stack<Allocator> operandStack(&allocator, 256); // Frag Stack<Allocator> operandStack(&allocator, 256); // Frag
Stack<Allocator> operatorStack(&allocator, 256); // Operator Stack<Allocator> operatorStack(&allocator, 256); // Operator
...@@ -327,14 +313,6 @@ private: ...@@ -327,14 +313,6 @@ private:
printf("\n"); printf("\n");
#endif #endif
} }
// Preallocate buffer for SearchWithAnchoring()
RAPIDJSON_ASSERT(stateSet_ == 0);
if (stateCount_ > 0) {
stateSet_ = static_cast<unsigned*>(states_.GetAllocator().Malloc(GetStateSetSize()));
state0_.template Reserve<SizeType>(stateCount_);
state1_.template Reserve<SizeType>(stateCount_);
}
} }
SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) { SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) {
...@@ -483,7 +461,7 @@ private: ...@@ -483,7 +461,7 @@ private:
} }
template <typename InputStream> template <typename InputStream>
bool ParseUnsigned(DecodedStream<InputStream>& ds, unsigned* u) { bool ParseUnsigned(DecodedStream<InputStream, Encoding>& ds, unsigned* u) {
unsigned r = 0; unsigned r = 0;
if (ds.Peek() < '0' || ds.Peek() > '9') if (ds.Peek() < '0' || ds.Peek() > '9')
return false; return false;
...@@ -497,7 +475,7 @@ private: ...@@ -497,7 +475,7 @@ private:
} }
template <typename InputStream> template <typename InputStream>
bool ParseRange(DecodedStream<InputStream>& ds, SizeType* range) { bool ParseRange(DecodedStream<InputStream, Encoding>& ds, SizeType* range) {
bool isBegin = true; bool isBegin = true;
bool negate = false; bool negate = false;
int step = 0; int step = 0;
...@@ -575,7 +553,7 @@ private: ...@@ -575,7 +553,7 @@ private:
} }
template <typename InputStream> template <typename InputStream>
bool CharacterEscape(DecodedStream<InputStream>& ds, unsigned* escapedCodepoint) { bool CharacterEscape(DecodedStream<InputStream, Encoding>& ds, unsigned* escapedCodepoint) {
unsigned codepoint; unsigned codepoint;
switch (codepoint = ds.Take()) { switch (codepoint = ds.Take()) {
case '^': case '^':
...@@ -603,34 +581,93 @@ private: ...@@ -603,34 +581,93 @@ private:
} }
} }
Stack<Allocator> states_;
Stack<Allocator> ranges_;
SizeType root_;
SizeType stateCount_;
SizeType rangeCount_;
static const unsigned kInfinityQuantifier = ~0u;
// For SearchWithAnchoring()
bool anchorBegin_;
bool anchorEnd_;
};
template <typename RegexType, typename Allocator = CrtAllocator>
class GenericRegexSearch {
public:
typedef typename RegexType::EncodingType Encoding;
typedef typename Encoding::Ch Ch;
GenericRegexSearch(const RegexType& regex, Allocator* allocator = 0) :
regex_(regex), allocator_(allocator), ownAllocator_(0),
state0_(allocator, 0), state1_(allocator, 0), stateSet_()
{
RAPIDJSON_ASSERT(regex_.IsValid());
if (!allocator_)
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
stateSet_ = static_cast<unsigned*>(allocator_->Malloc(GetStateSetSize()));
state0_.template Reserve<SizeType>(regex_.stateCount_);
state1_.template Reserve<SizeType>(regex_.stateCount_);
}
~GenericRegexSearch() {
Allocator::Free(stateSet_);
RAPIDJSON_DELETE(ownAllocator_);
}
template <typename InputStream> template <typename InputStream>
bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) const { bool Match(InputStream& is) {
RAPIDJSON_ASSERT(IsValid()); return SearchWithAnchoring(is, true, true);
DecodedStream<InputStream> ds(is); }
bool Match(const Ch* s) {
GenericStringStream<Encoding> is(s);
return Match(is);
}
template <typename InputStream>
bool Search(InputStream& is) {
return SearchWithAnchoring(is, regex_.anchorBegin_, regex_.anchorEnd_);
}
bool Search(const Ch* s) {
GenericStringStream<Encoding> is(s);
return Search(is);
}
private:
typedef typename RegexType::State State;
typedef typename RegexType::Range Range;
template <typename InputStream>
bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) {
DecodedStream<InputStream, Encoding> ds(is);
state0_.Clear(); state0_.Clear();
Stack<Allocator> *current = &state0_, *next = &state1_; Stack<Allocator> *current = &state0_, *next = &state1_;
const size_t stateSetSize = GetStateSetSize(); const size_t stateSetSize = GetStateSetSize();
std::memset(stateSet_, 0, stateSetSize); std::memset(stateSet_, 0, stateSetSize);
bool matched = AddState(*current, root_); bool matched = AddState(*current, regex_.root_);
unsigned codepoint; unsigned codepoint;
while (!current->Empty() && (codepoint = ds.Take()) != 0) { while (!current->Empty() && (codepoint = ds.Take()) != 0) {
std::memset(stateSet_, 0, stateSetSize); std::memset(stateSet_, 0, stateSetSize);
next->Clear(); next->Clear();
matched = false; matched = false;
for (const SizeType* s = current->template Bottom<SizeType>(); s != current->template End<SizeType>(); ++s) { for (const SizeType* s = current->template Bottom<SizeType>(); s != current->template End<SizeType>(); ++s) {
const State& sr = GetState(*s); const State& sr = regex_.GetState(*s);
if (sr.codepoint == codepoint || if (sr.codepoint == codepoint ||
sr.codepoint == kAnyCharacterClass || sr.codepoint == RegexType::kAnyCharacterClass ||
(sr.codepoint == kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint))) (sr.codepoint == RegexType::kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint)))
{ {
matched = AddState(*next, sr.out) || matched; matched = AddState(*next, sr.out) || matched;
if (!anchorEnd && matched) if (!anchorEnd && matched)
return true; return true;
} }
if (!anchorBegin) if (!anchorBegin)
AddState(*next, root_); AddState(*next, regex_.root_);
} }
internal::Swap(current, next); internal::Swap(current, next);
} }
...@@ -639,14 +676,14 @@ private: ...@@ -639,14 +676,14 @@ private:
} }
size_t GetStateSetSize() const { size_t GetStateSetSize() const {
return (stateCount_ + 31) / 32 * 4; return (regex_.stateCount_ + 31) / 32 * 4;
} }
// Return whether the added states is a match state // Return whether the added states is a match state
bool AddState(Stack<Allocator>& l, SizeType index) const { bool AddState(Stack<Allocator>& l, SizeType index) {
RAPIDJSON_ASSERT(index != kRegexInvalidState); RAPIDJSON_ASSERT(index != kRegexInvalidState);
const State& s = GetState(index); const State& s = regex_.GetState(index);
if (s.out1 != kRegexInvalidState) { // Split if (s.out1 != kRegexInvalidState) { // Split
bool matched = AddState(l, s.out); bool matched = AddState(l, s.out);
return AddState(l, s.out1) || matched; return AddState(l, s.out1) || matched;
...@@ -659,33 +696,26 @@ private: ...@@ -659,33 +696,26 @@ private:
} }
bool MatchRange(SizeType rangeIndex, unsigned codepoint) const { bool MatchRange(SizeType rangeIndex, unsigned codepoint) const {
bool yes = (GetRange(rangeIndex).start & kRangeNegationFlag) == 0; bool yes = (regex_.GetRange(rangeIndex).start & RegexType::kRangeNegationFlag) == 0;
while (rangeIndex != kRegexInvalidRange) { while (rangeIndex != kRegexInvalidRange) {
const Range& r = GetRange(rangeIndex); const Range& r = regex_.GetRange(rangeIndex);
if (codepoint >= (r.start & ~kRangeNegationFlag) && codepoint <= r.end) if (codepoint >= (r.start & ~RegexType::kRangeNegationFlag) && codepoint <= r.end)
return yes; return yes;
rangeIndex = r.next; rangeIndex = r.next;
} }
return !yes; return !yes;
} }
Stack<Allocator> states_; const RegexType& regex_;
Stack<Allocator> ranges_; Allocator* allocator_;
SizeType root_; Allocator* ownAllocator_;
SizeType stateCount_; Stack<Allocator> state0_;
SizeType rangeCount_; Stack<Allocator> state1_;
uint32_t* stateSet_;
static const unsigned kInfinityQuantifier = ~0u;
// For SearchWithAnchoring()
uint32_t* stateSet_; // allocated by states_.GetAllocator()
mutable Stack<Allocator> state0_;
mutable Stack<Allocator> state1_;
bool anchorBegin_;
bool anchorEnd_;
}; };
typedef GenericRegex<UTF8<> > Regex; typedef GenericRegex<UTF8<> > Regex;
typedef GenericRegexSearch<Regex> RegexSearch;
} // namespace internal } // namespace internal
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END
......
...@@ -1011,7 +1011,8 @@ private: ...@@ -1011,7 +1011,8 @@ private:
} }
static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) { static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) {
return pattern->Search(str); GenericRegexSearch<RegexType> rs(*pattern);
return rs.Search(str);
} }
#elif RAPIDJSON_SCHEMA_USE_STDREGEX #elif RAPIDJSON_SCHEMA_USE_STDREGEX
template <typename ValueType> template <typename ValueType>
......
...@@ -20,523 +20,569 @@ using namespace rapidjson::internal; ...@@ -20,523 +20,569 @@ using namespace rapidjson::internal;
TEST(Regex, Single) { TEST(Regex, Single) {
Regex re("a"); Regex re("a");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("a")); RegexSearch rs(re);
EXPECT_FALSE(re.Match("")); EXPECT_TRUE(rs.Match("a"));
EXPECT_FALSE(re.Match("b")); EXPECT_FALSE(rs.Match(""));
EXPECT_FALSE(rs.Match("b"));
} }
TEST(Regex, Concatenation) { TEST(Regex, Concatenation) {
Regex re("abc"); Regex re("abc");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("abc")); RegexSearch rs(re);
EXPECT_FALSE(re.Match("")); EXPECT_TRUE(rs.Match("abc"));
EXPECT_FALSE(re.Match("a")); EXPECT_FALSE(rs.Match(""));
EXPECT_FALSE(re.Match("b")); EXPECT_FALSE(rs.Match("a"));
EXPECT_FALSE(re.Match("ab")); EXPECT_FALSE(rs.Match("b"));
EXPECT_FALSE(re.Match("abcd")); EXPECT_FALSE(rs.Match("ab"));
EXPECT_FALSE(rs.Match("abcd"));
} }
TEST(Regex, Alternation1) { TEST(Regex, Alternation1) {
Regex re("abab|abbb"); Regex re("abab|abbb");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("abab")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("abbb")); EXPECT_TRUE(rs.Match("abab"));
EXPECT_FALSE(re.Match("")); EXPECT_TRUE(rs.Match("abbb"));
EXPECT_FALSE(re.Match("ab")); EXPECT_FALSE(rs.Match(""));
EXPECT_FALSE(re.Match("ababa")); EXPECT_FALSE(rs.Match("ab"));
EXPECT_FALSE(re.Match("abb")); EXPECT_FALSE(rs.Match("ababa"));
EXPECT_FALSE(re.Match("abbbb")); EXPECT_FALSE(rs.Match("abb"));
EXPECT_FALSE(rs.Match("abbbb"));
} }
TEST(Regex, Alternation2) { TEST(Regex, Alternation2) {
Regex re("a|b|c"); Regex re("a|b|c");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("a")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("b")); EXPECT_TRUE(rs.Match("a"));
EXPECT_TRUE(re.Match("c")); EXPECT_TRUE(rs.Match("b"));
EXPECT_FALSE(re.Match("")); EXPECT_TRUE(rs.Match("c"));
EXPECT_FALSE(re.Match("aa")); EXPECT_FALSE(rs.Match(""));
EXPECT_FALSE(re.Match("ab")); EXPECT_FALSE(rs.Match("aa"));
EXPECT_FALSE(rs.Match("ab"));
} }
TEST(Regex, Parenthesis1) { TEST(Regex, Parenthesis1) {
Regex re("(ab)c"); Regex re("(ab)c");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("abc")); RegexSearch rs(re);
EXPECT_FALSE(re.Match("")); EXPECT_TRUE(rs.Match("abc"));
EXPECT_FALSE(re.Match("a")); EXPECT_FALSE(rs.Match(""));
EXPECT_FALSE(re.Match("b")); EXPECT_FALSE(rs.Match("a"));
EXPECT_FALSE(re.Match("ab")); EXPECT_FALSE(rs.Match("b"));
EXPECT_FALSE(re.Match("abcd")); EXPECT_FALSE(rs.Match("ab"));
EXPECT_FALSE(rs.Match("abcd"));
} }
TEST(Regex, Parenthesis2) { TEST(Regex, Parenthesis2) {
Regex re("a(bc)"); Regex re("a(bc)");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("abc")); RegexSearch rs(re);
EXPECT_FALSE(re.Match("")); EXPECT_TRUE(rs.Match("abc"));
EXPECT_FALSE(re.Match("a")); EXPECT_FALSE(rs.Match(""));
EXPECT_FALSE(re.Match("b")); EXPECT_FALSE(rs.Match("a"));
EXPECT_FALSE(re.Match("ab")); EXPECT_FALSE(rs.Match("b"));
EXPECT_FALSE(re.Match("abcd")); EXPECT_FALSE(rs.Match("ab"));
EXPECT_FALSE(rs.Match("abcd"));
} }
TEST(Regex, Parenthesis3) { TEST(Regex, Parenthesis3) {
Regex re("(a|b)(c|d)"); Regex re("(a|b)(c|d)");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("ac")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("ad")); EXPECT_TRUE(rs.Match("ac"));
EXPECT_TRUE(re.Match("bc")); EXPECT_TRUE(rs.Match("ad"));
EXPECT_TRUE(re.Match("bd")); EXPECT_TRUE(rs.Match("bc"));
EXPECT_FALSE(re.Match("")); EXPECT_TRUE(rs.Match("bd"));
EXPECT_FALSE(re.Match("ab")); EXPECT_FALSE(rs.Match(""));
EXPECT_FALSE(re.Match("cd")); EXPECT_FALSE(rs.Match("ab"));
EXPECT_FALSE(rs.Match("cd"));
} }
TEST(Regex, ZeroOrOne1) { TEST(Regex, ZeroOrOne1) {
Regex re("a?"); Regex re("a?");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("a")); EXPECT_TRUE(rs.Match(""));
EXPECT_FALSE(re.Match("aa")); EXPECT_TRUE(rs.Match("a"));
EXPECT_FALSE(rs.Match("aa"));
} }
TEST(Regex, ZeroOrOne2) { TEST(Regex, ZeroOrOne2) {
Regex re("a?b"); Regex re("a?b");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("b")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("ab")); EXPECT_TRUE(rs.Match("b"));
EXPECT_FALSE(re.Match("a")); EXPECT_TRUE(rs.Match("ab"));
EXPECT_FALSE(re.Match("aa")); EXPECT_FALSE(rs.Match("a"));
EXPECT_FALSE(re.Match("bb")); EXPECT_FALSE(rs.Match("aa"));
EXPECT_FALSE(re.Match("ba")); EXPECT_FALSE(rs.Match("bb"));
EXPECT_FALSE(rs.Match("ba"));
} }
TEST(Regex, ZeroOrOne3) { TEST(Regex, ZeroOrOne3) {
Regex re("ab?"); Regex re("ab?");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("a")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("ab")); EXPECT_TRUE(rs.Match("a"));
EXPECT_FALSE(re.Match("b")); EXPECT_TRUE(rs.Match("ab"));
EXPECT_FALSE(re.Match("aa")); EXPECT_FALSE(rs.Match("b"));
EXPECT_FALSE(re.Match("bb")); EXPECT_FALSE(rs.Match("aa"));
EXPECT_FALSE(re.Match("ba")); EXPECT_FALSE(rs.Match("bb"));
EXPECT_FALSE(rs.Match("ba"));
} }
TEST(Regex, ZeroOrOne4) { TEST(Regex, ZeroOrOne4) {
Regex re("a?b?"); Regex re("a?b?");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("a")); EXPECT_TRUE(rs.Match(""));
EXPECT_TRUE(re.Match("b")); EXPECT_TRUE(rs.Match("a"));
EXPECT_TRUE(re.Match("ab")); EXPECT_TRUE(rs.Match("b"));
EXPECT_FALSE(re.Match("aa")); EXPECT_TRUE(rs.Match("ab"));
EXPECT_FALSE(re.Match("bb")); EXPECT_FALSE(rs.Match("aa"));
EXPECT_FALSE(re.Match("ba")); EXPECT_FALSE(rs.Match("bb"));
EXPECT_FALSE(re.Match("abc")); EXPECT_FALSE(rs.Match("ba"));
EXPECT_FALSE(rs.Match("abc"));
} }
TEST(Regex, ZeroOrOne5) { TEST(Regex, ZeroOrOne5) {
Regex re("a(ab)?b"); Regex re("a(ab)?b");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("ab")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("aabb")); EXPECT_TRUE(rs.Match("ab"));
EXPECT_FALSE(re.Match("aab")); EXPECT_TRUE(rs.Match("aabb"));
EXPECT_FALSE(re.Match("abb")); EXPECT_FALSE(rs.Match("aab"));
EXPECT_FALSE(rs.Match("abb"));
} }
TEST(Regex, ZeroOrMore1) { TEST(Regex, ZeroOrMore1) {
Regex re("a*"); Regex re("a*");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("a")); EXPECT_TRUE(rs.Match(""));
EXPECT_TRUE(re.Match("aa")); EXPECT_TRUE(rs.Match("a"));
EXPECT_FALSE(re.Match("b")); EXPECT_TRUE(rs.Match("aa"));
EXPECT_FALSE(re.Match("ab")); EXPECT_FALSE(rs.Match("b"));
EXPECT_FALSE(rs.Match("ab"));
} }
TEST(Regex, ZeroOrMore2) { TEST(Regex, ZeroOrMore2) {
Regex re("a*b"); Regex re("a*b");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("b")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("ab")); EXPECT_TRUE(rs.Match("b"));
EXPECT_TRUE(re.Match("aab")); EXPECT_TRUE(rs.Match("ab"));
EXPECT_FALSE(re.Match("")); EXPECT_TRUE(rs.Match("aab"));
EXPECT_FALSE(re.Match("bb")); EXPECT_FALSE(rs.Match(""));
EXPECT_FALSE(rs.Match("bb"));
} }
TEST(Regex, ZeroOrMore3) { TEST(Regex, ZeroOrMore3) {
Regex re("a*b*"); Regex re("a*b*");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("a")); EXPECT_TRUE(rs.Match(""));
EXPECT_TRUE(re.Match("aa")); EXPECT_TRUE(rs.Match("a"));
EXPECT_TRUE(re.Match("b")); EXPECT_TRUE(rs.Match("aa"));
EXPECT_TRUE(re.Match("bb")); EXPECT_TRUE(rs.Match("b"));
EXPECT_TRUE(re.Match("ab")); EXPECT_TRUE(rs.Match("bb"));
EXPECT_TRUE(re.Match("aabb")); EXPECT_TRUE(rs.Match("ab"));
EXPECT_FALSE(re.Match("ba")); EXPECT_TRUE(rs.Match("aabb"));
EXPECT_FALSE(rs.Match("ba"));
} }
TEST(Regex, ZeroOrMore4) { TEST(Regex, ZeroOrMore4) {
Regex re("a(ab)*b"); Regex re("a(ab)*b");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("ab")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("aabb")); EXPECT_TRUE(rs.Match("ab"));
EXPECT_TRUE(re.Match("aababb")); EXPECT_TRUE(rs.Match("aabb"));
EXPECT_FALSE(re.Match("")); EXPECT_TRUE(rs.Match("aababb"));
EXPECT_FALSE(re.Match("aa")); EXPECT_FALSE(rs.Match(""));
EXPECT_FALSE(rs.Match("aa"));
} }
TEST(Regex, OneOrMore1) { TEST(Regex, OneOrMore1) {
Regex re("a+"); Regex re("a+");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("a")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("aa")); EXPECT_TRUE(rs.Match("a"));
EXPECT_FALSE(re.Match("")); EXPECT_TRUE(rs.Match("aa"));
EXPECT_FALSE(re.Match("b")); EXPECT_FALSE(rs.Match(""));
EXPECT_FALSE(re.Match("ab")); EXPECT_FALSE(rs.Match("b"));
EXPECT_FALSE(rs.Match("ab"));
} }
TEST(Regex, OneOrMore2) { TEST(Regex, OneOrMore2) {
Regex re("a+b"); Regex re("a+b");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("ab")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("aab")); EXPECT_TRUE(rs.Match("ab"));
EXPECT_FALSE(re.Match("")); EXPECT_TRUE(rs.Match("aab"));
EXPECT_FALSE(re.Match("b")); EXPECT_FALSE(rs.Match(""));
EXPECT_FALSE(rs.Match("b"));
} }
TEST(Regex, OneOrMore3) { TEST(Regex, OneOrMore3) {
Regex re("a+b+"); Regex re("a+b+");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("ab")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("aab")); EXPECT_TRUE(rs.Match("ab"));
EXPECT_TRUE(re.Match("abb")); EXPECT_TRUE(rs.Match("aab"));
EXPECT_TRUE(re.Match("aabb")); EXPECT_TRUE(rs.Match("abb"));
EXPECT_FALSE(re.Match("")); EXPECT_TRUE(rs.Match("aabb"));
EXPECT_FALSE(re.Match("b")); EXPECT_FALSE(rs.Match(""));
EXPECT_FALSE(re.Match("ba")); EXPECT_FALSE(rs.Match("b"));
EXPECT_FALSE(rs.Match("ba"));
} }
TEST(Regex, OneOrMore4) { TEST(Regex, OneOrMore4) {
Regex re("a(ab)+b"); Regex re("a(ab)+b");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("aabb")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("aababb")); EXPECT_TRUE(rs.Match("aabb"));
EXPECT_FALSE(re.Match("")); EXPECT_TRUE(rs.Match("aababb"));
EXPECT_FALSE(re.Match("ab")); EXPECT_FALSE(rs.Match(""));
EXPECT_FALSE(rs.Match("ab"));
} }
TEST(Regex, QuantifierExact1) { TEST(Regex, QuantifierExact1) {
Regex re("ab{3}c"); Regex re("ab{3}c");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("abbbc")); RegexSearch rs(re);
EXPECT_FALSE(re.Match("ac")); EXPECT_TRUE(rs.Match("abbbc"));
EXPECT_FALSE(re.Match("abc")); EXPECT_FALSE(rs.Match("ac"));
EXPECT_FALSE(re.Match("abbc")); EXPECT_FALSE(rs.Match("abc"));
EXPECT_FALSE(re.Match("abbbbc")); EXPECT_FALSE(rs.Match("abbc"));
EXPECT_FALSE(rs.Match("abbbbc"));
} }
TEST(Regex, QuantifierExact2) { TEST(Regex, QuantifierExact2) {
Regex re("a(bc){3}d"); Regex re("a(bc){3}d");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("abcbcbcd")); RegexSearch rs(re);
EXPECT_FALSE(re.Match("ad")); EXPECT_TRUE(rs.Match("abcbcbcd"));
EXPECT_FALSE(re.Match("abcd")); EXPECT_FALSE(rs.Match("ad"));
EXPECT_FALSE(re.Match("abcbcd")); EXPECT_FALSE(rs.Match("abcd"));
EXPECT_FALSE(re.Match("abcbcbcbcd")); EXPECT_FALSE(rs.Match("abcbcd"));
EXPECT_FALSE(rs.Match("abcbcbcbcd"));
} }
TEST(Regex, QuantifierExact3) { TEST(Regex, QuantifierExact3) {
Regex re("a(b|c){3}d"); Regex re("a(b|c){3}d");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("abbbd")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("acccd")); EXPECT_TRUE(rs.Match("abbbd"));
EXPECT_TRUE(re.Match("abcbd")); EXPECT_TRUE(rs.Match("acccd"));
EXPECT_FALSE(re.Match("ad")); EXPECT_TRUE(rs.Match("abcbd"));
EXPECT_FALSE(re.Match("abbd")); EXPECT_FALSE(rs.Match("ad"));
EXPECT_FALSE(re.Match("accccd")); EXPECT_FALSE(rs.Match("abbd"));
EXPECT_FALSE(re.Match("abbbbd")); EXPECT_FALSE(rs.Match("accccd"));
EXPECT_FALSE(rs.Match("abbbbd"));
} }
TEST(Regex, QuantifierMin1) { TEST(Regex, QuantifierMin1) {
Regex re("ab{3,}c"); Regex re("ab{3,}c");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("abbbc")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("abbbbc")); EXPECT_TRUE(rs.Match("abbbc"));
EXPECT_TRUE(re.Match("abbbbbc")); EXPECT_TRUE(rs.Match("abbbbc"));
EXPECT_FALSE(re.Match("ac")); EXPECT_TRUE(rs.Match("abbbbbc"));
EXPECT_FALSE(re.Match("abc")); EXPECT_FALSE(rs.Match("ac"));
EXPECT_FALSE(re.Match("abbc")); EXPECT_FALSE(rs.Match("abc"));
EXPECT_FALSE(rs.Match("abbc"));
} }
TEST(Regex, QuantifierMin2) { TEST(Regex, QuantifierMin2) {
Regex re("a(bc){3,}d"); Regex re("a(bc){3,}d");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("abcbcbcd")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("abcbcbcbcd")); EXPECT_TRUE(rs.Match("abcbcbcd"));
EXPECT_FALSE(re.Match("ad")); EXPECT_TRUE(rs.Match("abcbcbcbcd"));
EXPECT_FALSE(re.Match("abcd")); EXPECT_FALSE(rs.Match("ad"));
EXPECT_FALSE(re.Match("abcbcd")); EXPECT_FALSE(rs.Match("abcd"));
EXPECT_FALSE(rs.Match("abcbcd"));
} }
TEST(Regex, QuantifierMin3) { TEST(Regex, QuantifierMin3) {
Regex re("a(b|c){3,}d"); Regex re("a(b|c){3,}d");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("abbbd")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("acccd")); EXPECT_TRUE(rs.Match("abbbd"));
EXPECT_TRUE(re.Match("abcbd")); EXPECT_TRUE(rs.Match("acccd"));
EXPECT_TRUE(re.Match("accccd")); EXPECT_TRUE(rs.Match("abcbd"));
EXPECT_TRUE(re.Match("abbbbd")); EXPECT_TRUE(rs.Match("accccd"));
EXPECT_FALSE(re.Match("ad")); EXPECT_TRUE(rs.Match("abbbbd"));
EXPECT_FALSE(re.Match("abbd")); EXPECT_FALSE(rs.Match("ad"));
EXPECT_FALSE(rs.Match("abbd"));
} }
TEST(Regex, QuantifierMinMax1) { TEST(Regex, QuantifierMinMax1) {
Regex re("ab{3,5}c"); Regex re("ab{3,5}c");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("abbbc")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("abbbbc")); EXPECT_TRUE(rs.Match("abbbc"));
EXPECT_TRUE(re.Match("abbbbbc")); EXPECT_TRUE(rs.Match("abbbbc"));
EXPECT_FALSE(re.Match("ac")); EXPECT_TRUE(rs.Match("abbbbbc"));
EXPECT_FALSE(re.Match("abc")); EXPECT_FALSE(rs.Match("ac"));
EXPECT_FALSE(re.Match("abbc")); EXPECT_FALSE(rs.Match("abc"));
EXPECT_FALSE(re.Match("abbbbbbc")); EXPECT_FALSE(rs.Match("abbc"));
EXPECT_FALSE(rs.Match("abbbbbbc"));
} }
TEST(Regex, QuantifierMinMax2) { TEST(Regex, QuantifierMinMax2) {
Regex re("a(bc){3,5}d"); Regex re("a(bc){3,5}d");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("abcbcbcd")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("abcbcbcbcd")); EXPECT_TRUE(rs.Match("abcbcbcd"));
EXPECT_TRUE(re.Match("abcbcbcbcbcd")); EXPECT_TRUE(rs.Match("abcbcbcbcd"));
EXPECT_FALSE(re.Match("ad")); EXPECT_TRUE(rs.Match("abcbcbcbcbcd"));
EXPECT_FALSE(re.Match("abcd")); EXPECT_FALSE(rs.Match("ad"));
EXPECT_FALSE(re.Match("abcbcd")); EXPECT_FALSE(rs.Match("abcd"));
EXPECT_FALSE(re.Match("abcbcbcbcbcbcd")); EXPECT_FALSE(rs.Match("abcbcd"));
EXPECT_FALSE(rs.Match("abcbcbcbcbcbcd"));
} }
TEST(Regex, QuantifierMinMax3) { TEST(Regex, QuantifierMinMax3) {
Regex re("a(b|c){3,5}d"); Regex re("a(b|c){3,5}d");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("abbbd")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("acccd")); EXPECT_TRUE(rs.Match("abbbd"));
EXPECT_TRUE(re.Match("abcbd")); EXPECT_TRUE(rs.Match("acccd"));
EXPECT_TRUE(re.Match("accccd")); EXPECT_TRUE(rs.Match("abcbd"));
EXPECT_TRUE(re.Match("abbbbd")); EXPECT_TRUE(rs.Match("accccd"));
EXPECT_TRUE(re.Match("acccccd")); EXPECT_TRUE(rs.Match("abbbbd"));
EXPECT_TRUE(re.Match("abbbbbd")); EXPECT_TRUE(rs.Match("acccccd"));
EXPECT_FALSE(re.Match("ad")); EXPECT_TRUE(rs.Match("abbbbbd"));
EXPECT_FALSE(re.Match("abbd")); EXPECT_FALSE(rs.Match("ad"));
EXPECT_FALSE(re.Match("accccccd")); EXPECT_FALSE(rs.Match("abbd"));
EXPECT_FALSE(re.Match("abbbbbbd")); EXPECT_FALSE(rs.Match("accccccd"));
EXPECT_FALSE(rs.Match("abbbbbbd"));
} }
// Issue538 // Issue538
TEST(Regex, QuantifierMinMax4) { TEST(Regex, QuantifierMinMax4) {
Regex re("a(b|c){0,3}d"); Regex re("a(b|c){0,3}d");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("ad")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("abd")); EXPECT_TRUE(rs.Match("ad"));
EXPECT_TRUE(re.Match("acd")); EXPECT_TRUE(rs.Match("abd"));
EXPECT_TRUE(re.Match("abbd")); EXPECT_TRUE(rs.Match("acd"));
EXPECT_TRUE(re.Match("accd")); EXPECT_TRUE(rs.Match("abbd"));
EXPECT_TRUE(re.Match("abcd")); EXPECT_TRUE(rs.Match("accd"));
EXPECT_TRUE(re.Match("abbbd")); EXPECT_TRUE(rs.Match("abcd"));
EXPECT_TRUE(re.Match("acccd")); EXPECT_TRUE(rs.Match("abbbd"));
EXPECT_FALSE(re.Match("abbbbd")); EXPECT_TRUE(rs.Match("acccd"));
EXPECT_FALSE(re.Match("add")); EXPECT_FALSE(rs.Match("abbbbd"));
EXPECT_FALSE(re.Match("accccd")); EXPECT_FALSE(rs.Match("add"));
EXPECT_FALSE(re.Match("abcbcd")); EXPECT_FALSE(rs.Match("accccd"));
EXPECT_FALSE(rs.Match("abcbcd"));
} }
// Issue538 // Issue538
TEST(Regex, QuantifierMinMax5) { TEST(Regex, QuantifierMinMax5) {
Regex re("a(b|c){0,}d"); Regex re("a(b|c){0,}d");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("ad")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("abd")); EXPECT_TRUE(rs.Match("ad"));
EXPECT_TRUE(re.Match("acd")); EXPECT_TRUE(rs.Match("abd"));
EXPECT_TRUE(re.Match("abbd")); EXPECT_TRUE(rs.Match("acd"));
EXPECT_TRUE(re.Match("accd")); EXPECT_TRUE(rs.Match("abbd"));
EXPECT_TRUE(re.Match("abcd")); EXPECT_TRUE(rs.Match("accd"));
EXPECT_TRUE(re.Match("abbbd")); EXPECT_TRUE(rs.Match("abcd"));
EXPECT_TRUE(re.Match("acccd")); EXPECT_TRUE(rs.Match("abbbd"));
EXPECT_TRUE(re.Match("abbbbd")); EXPECT_TRUE(rs.Match("acccd"));
EXPECT_TRUE(re.Match("accccd")); EXPECT_TRUE(rs.Match("abbbbd"));
EXPECT_TRUE(re.Match("abcbcd")); EXPECT_TRUE(rs.Match("accccd"));
EXPECT_FALSE(re.Match("add")); EXPECT_TRUE(rs.Match("abcbcd"));
EXPECT_FALSE(re.Match("aad")); EXPECT_FALSE(rs.Match("add"));
EXPECT_FALSE(rs.Match("aad"));
} }
#define EURO "\xE2\x82\xAC" // "\xE2\x82\xAC" is UTF-8 sequence of Euro sign U+20AC #define EURO "\xE2\x82\xAC" // "\xE2\x82\xAC" is UTF-8 rsquence of Euro sign U+20AC
TEST(Regex, Unicode) { TEST(Regex, Unicode) {
Regex re("a" EURO "+b"); Regex re("a" EURO "+b");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("a" EURO "b")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("a" EURO EURO "b")); EXPECT_TRUE(rs.Match("a" EURO "b"));
EXPECT_FALSE(re.Match("a?b")); EXPECT_TRUE(rs.Match("a" EURO EURO "b"));
EXPECT_FALSE(re.Match("a" EURO "\xAC" "b")); // unaware of UTF-8 will match EXPECT_FALSE(rs.Match("a?b"));
EXPECT_FALSE(rs.Match("a" EURO "\xAC" "b")); // unaware of UTF-8 will match
} }
TEST(Regex, AnyCharacter) { TEST(Regex, AnyCharacter) {
Regex re("."); Regex re(".");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("a")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("b")); EXPECT_TRUE(rs.Match("a"));
EXPECT_TRUE(re.Match(EURO)); EXPECT_TRUE(rs.Match("b"));
EXPECT_FALSE(re.Match("")); EXPECT_TRUE(rs.Match(EURO));
EXPECT_FALSE(re.Match("aa")); EXPECT_FALSE(rs.Match(""));
EXPECT_FALSE(rs.Match("aa"));
} }
TEST(Regex, CharacterRange1) { TEST(Regex, CharacterRange1) {
Regex re("[abc]"); Regex re("[abc]");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("a")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("b")); EXPECT_TRUE(rs.Match("a"));
EXPECT_TRUE(re.Match("c")); EXPECT_TRUE(rs.Match("b"));
EXPECT_FALSE(re.Match("")); EXPECT_TRUE(rs.Match("c"));
EXPECT_FALSE(re.Match("`")); EXPECT_FALSE(rs.Match(""));
EXPECT_FALSE(re.Match("d")); EXPECT_FALSE(rs.Match("`"));
EXPECT_FALSE(re.Match("aa")); EXPECT_FALSE(rs.Match("d"));
EXPECT_FALSE(rs.Match("aa"));
} }
TEST(Regex, CharacterRange2) { TEST(Regex, CharacterRange2) {
Regex re("[^abc]"); Regex re("[^abc]");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("`")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("d")); EXPECT_TRUE(rs.Match("`"));
EXPECT_FALSE(re.Match("a")); EXPECT_TRUE(rs.Match("d"));
EXPECT_FALSE(re.Match("b")); EXPECT_FALSE(rs.Match("a"));
EXPECT_FALSE(re.Match("c")); EXPECT_FALSE(rs.Match("b"));
EXPECT_FALSE(re.Match("")); EXPECT_FALSE(rs.Match("c"));
EXPECT_FALSE(re.Match("aa")); EXPECT_FALSE(rs.Match(""));
EXPECT_FALSE(rs.Match("aa"));
} }
TEST(Regex, CharacterRange3) { TEST(Regex, CharacterRange3) {
Regex re("[a-c]"); Regex re("[a-c]");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("a")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("b")); EXPECT_TRUE(rs.Match("a"));
EXPECT_TRUE(re.Match("c")); EXPECT_TRUE(rs.Match("b"));
EXPECT_FALSE(re.Match("")); EXPECT_TRUE(rs.Match("c"));
EXPECT_FALSE(re.Match("`")); EXPECT_FALSE(rs.Match(""));
EXPECT_FALSE(re.Match("d")); EXPECT_FALSE(rs.Match("`"));
EXPECT_FALSE(re.Match("aa")); EXPECT_FALSE(rs.Match("d"));
EXPECT_FALSE(rs.Match("aa"));
} }
TEST(Regex, CharacterRange4) { TEST(Regex, CharacterRange4) {
Regex re("[^a-c]"); Regex re("[^a-c]");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("`")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("d")); EXPECT_TRUE(rs.Match("`"));
EXPECT_FALSE(re.Match("a")); EXPECT_TRUE(rs.Match("d"));
EXPECT_FALSE(re.Match("b")); EXPECT_FALSE(rs.Match("a"));
EXPECT_FALSE(re.Match("c")); EXPECT_FALSE(rs.Match("b"));
EXPECT_FALSE(re.Match("")); EXPECT_FALSE(rs.Match("c"));
EXPECT_FALSE(re.Match("aa")); EXPECT_FALSE(rs.Match(""));
EXPECT_FALSE(rs.Match("aa"));
} }
TEST(Regex, CharacterRange5) { TEST(Regex, CharacterRange5) {
Regex re("[-]"); Regex re("[-]");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("-")); RegexSearch rs(re);
EXPECT_FALSE(re.Match("")); EXPECT_TRUE(rs.Match("-"));
EXPECT_FALSE(re.Match("a")); EXPECT_FALSE(rs.Match(""));
EXPECT_FALSE(rs.Match("a"));
} }
TEST(Regex, CharacterRange6) { TEST(Regex, CharacterRange6) {
Regex re("[a-]"); Regex re("[a-]");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("a")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("-")); EXPECT_TRUE(rs.Match("a"));
EXPECT_FALSE(re.Match("")); EXPECT_TRUE(rs.Match("-"));
EXPECT_FALSE(re.Match("`")); EXPECT_FALSE(rs.Match(""));
EXPECT_FALSE(re.Match("b")); EXPECT_FALSE(rs.Match("`"));
EXPECT_FALSE(rs.Match("b"));
} }
TEST(Regex, CharacterRange7) { TEST(Regex, CharacterRange7) {
Regex re("[-a]"); Regex re("[-a]");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("a")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("-")); EXPECT_TRUE(rs.Match("a"));
EXPECT_FALSE(re.Match("")); EXPECT_TRUE(rs.Match("-"));
EXPECT_FALSE(re.Match("`")); EXPECT_FALSE(rs.Match(""));
EXPECT_FALSE(re.Match("b")); EXPECT_FALSE(rs.Match("`"));
EXPECT_FALSE(rs.Match("b"));
} }
TEST(Regex, CharacterRange8) { TEST(Regex, CharacterRange8) {
Regex re("[a-zA-Z0-9]*"); Regex re("[a-zA-Z0-9]*");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("Milo")); RegexSearch rs(re);
EXPECT_TRUE(re.Match("MT19937")); EXPECT_TRUE(rs.Match("Milo"));
EXPECT_TRUE(re.Match("43")); EXPECT_TRUE(rs.Match("MT19937"));
EXPECT_FALSE(re.Match("a_b")); EXPECT_TRUE(rs.Match("43"));
EXPECT_FALSE(re.Match("!")); EXPECT_FALSE(rs.Match("a_b"));
EXPECT_FALSE(rs.Match("!"));
} }
TEST(Regex, Search) { TEST(Regex, Search) {
Regex re("abc"); Regex re("abc");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Search("abc")); RegexSearch rs(re);
EXPECT_TRUE(re.Search("_abc")); EXPECT_TRUE(rs.Search("abc"));
EXPECT_TRUE(re.Search("abc_")); EXPECT_TRUE(rs.Search("_abc"));
EXPECT_TRUE(re.Search("_abc_")); EXPECT_TRUE(rs.Search("abc_"));
EXPECT_TRUE(re.Search("__abc__")); EXPECT_TRUE(rs.Search("_abc_"));
EXPECT_TRUE(re.Search("abcabc")); EXPECT_TRUE(rs.Search("__abc__"));
EXPECT_FALSE(re.Search("a")); EXPECT_TRUE(rs.Search("abcabc"));
EXPECT_FALSE(re.Search("ab")); EXPECT_FALSE(rs.Search("a"));
EXPECT_FALSE(re.Search("bc")); EXPECT_FALSE(rs.Search("ab"));
EXPECT_FALSE(re.Search("cba")); EXPECT_FALSE(rs.Search("bc"));
EXPECT_FALSE(rs.Search("cba"));
} }
TEST(Regex, Search_BeginAnchor) { TEST(Regex, Search_BeginAnchor) {
Regex re("^abc"); Regex re("^abc");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Search("abc")); RegexSearch rs(re);
EXPECT_TRUE(re.Search("abc_")); EXPECT_TRUE(rs.Search("abc"));
EXPECT_TRUE(re.Search("abcabc")); EXPECT_TRUE(rs.Search("abc_"));
EXPECT_FALSE(re.Search("_abc")); EXPECT_TRUE(rs.Search("abcabc"));
EXPECT_FALSE(re.Search("_abc_")); EXPECT_FALSE(rs.Search("_abc"));
EXPECT_FALSE(re.Search("a")); EXPECT_FALSE(rs.Search("_abc_"));
EXPECT_FALSE(re.Search("ab")); EXPECT_FALSE(rs.Search("a"));
EXPECT_FALSE(re.Search("bc")); EXPECT_FALSE(rs.Search("ab"));
EXPECT_FALSE(re.Search("cba")); EXPECT_FALSE(rs.Search("bc"));
EXPECT_FALSE(rs.Search("cba"));
} }
TEST(Regex, Search_EndAnchor) { TEST(Regex, Search_EndAnchor) {
Regex re("abc$"); Regex re("abc$");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Search("abc")); RegexSearch rs(re);
EXPECT_TRUE(re.Search("_abc")); EXPECT_TRUE(rs.Search("abc"));
EXPECT_TRUE(re.Search("abcabc")); EXPECT_TRUE(rs.Search("_abc"));
EXPECT_FALSE(re.Search("abc_")); EXPECT_TRUE(rs.Search("abcabc"));
EXPECT_FALSE(re.Search("_abc_")); EXPECT_FALSE(rs.Search("abc_"));
EXPECT_FALSE(re.Search("a")); EXPECT_FALSE(rs.Search("_abc_"));
EXPECT_FALSE(re.Search("ab")); EXPECT_FALSE(rs.Search("a"));
EXPECT_FALSE(re.Search("bc")); EXPECT_FALSE(rs.Search("ab"));
EXPECT_FALSE(re.Search("cba")); EXPECT_FALSE(rs.Search("bc"));
EXPECT_FALSE(rs.Search("cba"));
} }
TEST(Regex, Search_BothAnchor) { TEST(Regex, Search_BothAnchor) {
Regex re("^abc$"); Regex re("^abc$");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Search("abc")); RegexSearch rs(re);
EXPECT_FALSE(re.Search("")); EXPECT_TRUE(rs.Search("abc"));
EXPECT_FALSE(re.Search("a")); EXPECT_FALSE(rs.Search(""));
EXPECT_FALSE(re.Search("b")); EXPECT_FALSE(rs.Search("a"));
EXPECT_FALSE(re.Search("ab")); EXPECT_FALSE(rs.Search("b"));
EXPECT_FALSE(re.Search("abcd")); EXPECT_FALSE(rs.Search("ab"));
EXPECT_FALSE(rs.Search("abcd"));
} }
TEST(Regex, Escape) { TEST(Regex, Escape) {
const char* s = "\\^\\$\\|\\(\\)\\?\\*\\+\\.\\[\\]\\{\\}\\\\\\f\\n\\r\\t\\v[\\b][\\[][\\]]"; const char* s = "\\^\\$\\|\\(\\)\\?\\*\\+\\.\\[\\]\\{\\}\\\\\\f\\n\\r\\t\\v[\\b][\\[][\\]]";
Regex re(s); Regex re(s);
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("^$|()?*+.[]{}\\\x0C\n\r\t\x0B\b[]")); RegexSearch rs(re);
EXPECT_FALSE(re.Match(s)); // Not escaping EXPECT_TRUE(rs.Match("^$|()?*+.[]{}\\\x0C\n\r\t\x0B\b[]"));
EXPECT_FALSE(rs.Match(s)); // Not escaping
} }
TEST(Regex, Invalid) { TEST(Regex, Invalid) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment