2
\$\begingroup\$

We all know that std::regex class doesn't allow access to the original string which was used as the source expression. (In fact, GCC even keeps the original string as _M_original_str, but won't allow external access. Still, I have not used this member because it is implementation detail.)

So I derived a lightweight class to so that the std::regex will seem to behave like the string it was created from, well... not exactly, but kind of close. It lets the std::regex do its thing, but also keeps a record of the current string associated with the regex expression as its own member. And uses this member to allow new behaviors.

It allows direct retrieval of the original string. It also allows direct comparison with a std::string to check for equality, which in turn allows two regex's to be checked for equality.

But there's a catch. To check for equality, it uses the tracked string inside both objects to check for equality, which is a little flawed because two distinct strings can lead to same regex. So in that case it fails.

Also, since a constructor called with no arguments must create a regex object which matches nothing, I've accounted for that by keeping track of it in the derived class by maintaining a bool.

I want to know if it is good enough?
Have I tied up all loose ends while deriving from std::regex?
Can using it carelessly create unexpected errors?

So here it is:

#include <iostream>
#include <regex>
#include <string>

using namespace std;

class Regex: public regex
{
public:
    Regex ();
    Regex ( const string& str, flag_type flag = regex::ECMAScript );
    Regex ( const Regex& rhs );

    Regex& Assign ( const string& str, flag_type flag = regex::ECMAScript );
    Regex& Assign ( const Regex& rhs );

    string GetSourceStr () const { return m_str; }

    Regex& operator= ( const string& str ) { return this->Assign( str, flags() ); }
    Regex& operator= ( const Regex& rhs ) { return this->Assign( rhs ); }

    bool operator== ( const Regex& rhs ) const
      { return  m_str == rhs.m_str && m_match_nothing == rhs.m_match_nothing; }

    bool operator== ( const string& rhs_str ) const
      { return  m_str == rhs_str && !m_match_nothing; }

private:
    string m_str;
    bool m_match_nothing;
};

Regex::Regex ()
: regex(), m_str( "" ), m_match_nothing( true )
{}

Regex::Regex ( const string& str, flag_type flag )
: regex( str, flag ), m_str( str ), m_match_nothing( false )
{}

Regex::Regex ( const Regex& rhs )
: regex( rhs ), m_str( rhs.m_str ), m_match_nothing( rhs.m_match_nothing )
{}

Regex& Regex::Assign( const string& str, flag_type flag )
{
    m_str = str;
    m_match_nothing = false;
    regex::assign( str, flag );

    return *this;
}

Regex& Regex::Assign( const Regex& rhs )
{
    if ( this == &rhs ) return *this;

    m_str = rhs.m_str;
    m_match_nothing = rhs.m_match_nothing;
    regex::assign( rhs );

    return *this;
}

int main()
{
    string text;
    string blank_str;

    Regex pattern; // default regex object: matches nothing
    Regex pattern2(""); // a regex object which only matches a blank string

    cout << (regex_match(blank_str, pattern) ? "1 match" : "1 no_match") << "\n"
         << (regex_match(blank_str, pattern2) ? "2 match" : "2 no_match") << "\n"
         << (pattern==pattern2 ? "1==2" : "1!=2") << "\n\n";

    pattern = "a*c+";
    cout << (pattern=="a*c+" ? "yeah" : "nah") << "\n"
         << (pattern=="abc+" ? "yeah" : "nah") << "\n";

    return 0;
}

\$\endgroup\$
1
2
\$\begingroup\$

This looks like a bug:

Regex& Regex::Assign( const Regex& rhs )
{
    if ( this != &rhs ) return *this;  // <- ?

    m_str = rhs.m_str;
    m_match_nothing = rhs.m_match_nothing;
    regex::assign( rhs );

    return *this;
}

Presumably you want to abort the assignment early if:

if ( this == &rhs ) return *this;

At the moment, you only update the variables if the rhs is the same as the object receiving the call... which already has those variable values.

\$\endgroup\$
1
  • \$\begingroup\$ Arrghhh, I had it like {if (this != &rhs) {assigment();} return *this;}, later I changed it to show early exit more directly, but left the !=. \$\endgroup\$ Jul 7 '16 at 6:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.