mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-08-18 06:55:48 +03:00
Add RegEx class. Refactor PatternMatcher.
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
#include <cstring>
|
||||
#include <eepp/core/core.hpp>
|
||||
#include <eepp/system/lua-str.hpp>
|
||||
#include <eepp/system/luapattern.hpp>
|
||||
|
||||
@@ -10,6 +9,24 @@ namespace EE { namespace System {
|
||||
const int MAX_DEFAULT_MATCHES = 12;
|
||||
static bool sFailHandlerInitialized = false;
|
||||
|
||||
static void failHandler( const char* msg ) {
|
||||
throw std::string( msg );
|
||||
}
|
||||
|
||||
LuaPatternStorage::LuaPatternStorage( const std::string& pattern ) :
|
||||
LuaPattern( "" ), mPatternStorage( pattern ) {
|
||||
mPattern = std::string_view{ mPatternStorage };
|
||||
}
|
||||
|
||||
LuaPatternStorage::LuaPatternStorage( std::string&& pattern ) :
|
||||
LuaPattern( "" ), mPatternStorage( std::move( pattern ) ) {
|
||||
mPattern = std::string_view{ mPatternStorage };
|
||||
}
|
||||
|
||||
const size_t& LuaPattern::getNumMatches() const {
|
||||
return mMatchNum;
|
||||
}
|
||||
|
||||
std::string_view LuaPattern::getURLPattern() {
|
||||
return "https?://[%w_.~!*:@&+$/?%%#-]-%w[-.%w]*%.%w%w%w?%w?:?%d*/?[%w_.~!*:@&+$/?%%#=-]*"sv;
|
||||
}
|
||||
@@ -18,10 +35,6 @@ std::string_view LuaPattern::getURIPattern() {
|
||||
return "%w+://[%w_.~!*:@&+$/?%%#-]-%w[-.%w]*%.%w%w%w?%w?:?%d*/?[%w_.~!*:@&+$/?%%#=-]*"sv;
|
||||
}
|
||||
|
||||
static void failHandler( const char* msg ) {
|
||||
throw std::string( msg );
|
||||
}
|
||||
|
||||
std::string LuaPattern::match( const std::string& string, const std::string_view& pattern ) {
|
||||
LuaPattern matcher( pattern );
|
||||
int start = 0, end = 0;
|
||||
@@ -42,7 +55,8 @@ std::string LuaPattern::matchesAny( const std::vector<std::string>& stringvec,
|
||||
return "";
|
||||
}
|
||||
|
||||
LuaPattern::Range LuaPattern::find( const std::string& string, const std::string_view& pattern ) {
|
||||
PatternMatcher::Range LuaPattern::firstMatch( const std::string& string,
|
||||
const std::string_view& pattern ) {
|
||||
LuaPattern matcher( pattern );
|
||||
int start = 0, end = 0;
|
||||
if ( matcher.find( string, start, end ) )
|
||||
@@ -50,11 +64,12 @@ LuaPattern::Range LuaPattern::find( const std::string& string, const std::string
|
||||
return { -1, -1 };
|
||||
}
|
||||
|
||||
bool LuaPattern::matches( const std::string& string, const std::string_view& pattern ) {
|
||||
return find( string, pattern ).isValid();
|
||||
bool LuaPattern::hasMatches( const std::string& string, const std::string_view& pattern ) {
|
||||
return LuaPattern::firstMatch( string, pattern ).isValid();
|
||||
}
|
||||
|
||||
LuaPattern::LuaPattern( const std::string_view& pattern ) : mPattern( pattern ), mMatchNum( 0 ) {
|
||||
LuaPattern::LuaPattern( const std::string_view& pattern ) :
|
||||
PatternMatcher( PatternType::LuaPattern ), mPattern( pattern ), mMatchNum( 0 ) {
|
||||
if ( !sFailHandlerInitialized ) {
|
||||
sFailHandlerInitialized = true;
|
||||
lua_str_fail_func( failHandler );
|
||||
@@ -62,12 +77,12 @@ LuaPattern::LuaPattern( const std::string_view& pattern ) : mPattern( pattern ),
|
||||
}
|
||||
|
||||
bool LuaPattern::matches( const char* stringSearch, int stringStartOffset,
|
||||
LuaPattern::Range* matchList, size_t stringLength ) const {
|
||||
PatternMatcher::Range* matchList, size_t stringLength ) const {
|
||||
if ( stringLength == 0 )
|
||||
stringLength = strlen( stringSearch );
|
||||
|
||||
if ( matchList == nullptr ) {
|
||||
LuaPattern::Range matchesBuffer[MAX_DEFAULT_MATCHES];
|
||||
PatternMatcher::Range matchesBuffer[MAX_DEFAULT_MATCHES];
|
||||
try {
|
||||
mMatchNum = lua_str_match( stringSearch, stringStartOffset, stringLength,
|
||||
mPattern.data(), (LuaMatch*)matchesBuffer );
|
||||
@@ -85,185 +100,9 @@ bool LuaPattern::matches( const char* stringSearch, int stringStartOffset,
|
||||
return mMatchNum == 0 ? false : true;
|
||||
}
|
||||
|
||||
bool LuaPattern::matches( const std::string& str, LuaPattern::Range* matchList,
|
||||
bool LuaPattern::matches( const std::string& str, PatternMatcher::Range* matchList,
|
||||
int stringStartOffset ) const {
|
||||
return matches( str.c_str(), stringStartOffset, matchList, str.size() );
|
||||
}
|
||||
|
||||
bool LuaPattern::find( const char* stringSearch, int& startMatch, int& endMatch,
|
||||
int stringStartOffset, int stringLength, int returnMatchIndex ) const {
|
||||
LuaPattern::Range matchesBuffer[MAX_DEFAULT_MATCHES];
|
||||
if ( matches( stringSearch, stringStartOffset, matchesBuffer, stringLength ) ) {
|
||||
range( returnMatchIndex, startMatch, endMatch, matchesBuffer );
|
||||
return true;
|
||||
} else {
|
||||
startMatch = -1;
|
||||
endMatch = -1;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool LuaPattern::find( const std::string& s, int& startMatch, int& endMatch, int offset,
|
||||
int returnedMatchIndex ) const {
|
||||
return find( s.c_str(), startMatch, endMatch, offset, s.size(), returnedMatchIndex );
|
||||
}
|
||||
|
||||
bool LuaPattern::range( int indexGet, int& startMatch, int& endMatch,
|
||||
LuaPattern::Range* returnedMatched ) const {
|
||||
if ( indexGet == -1 )
|
||||
indexGet = getNumMatches() > 1 ? 1 : 0;
|
||||
if ( indexGet >= 0 && indexGet < (int)getNumMatches() ) {
|
||||
startMatch = returnedMatched[indexGet].start;
|
||||
endMatch = returnedMatched[indexGet].end;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t& LuaPattern::getNumMatches() const {
|
||||
return mMatchNum;
|
||||
}
|
||||
|
||||
bool LuaPattern::LuaPattern::State::range( int index, int& start, int& end ) {
|
||||
return mPattern->range( index, start, end, mRanges );
|
||||
}
|
||||
|
||||
bool LuaPattern::LuaPattern::State::matches( const char* string, size_t length ) {
|
||||
return mPattern->matches( string, 0, mRanges, length );
|
||||
}
|
||||
|
||||
LuaPattern::State::State( LuaPattern* pattern, bool ownPattern ) :
|
||||
mRefCount( 1 ), mOwnPattern( ownPattern ) {
|
||||
mRanges = new Range[10];
|
||||
mPattern = ownPattern ? new LuaPattern( pattern->getPatern() ) : pattern;
|
||||
}
|
||||
|
||||
LuaPattern::State::~State() {
|
||||
delete[] mRanges;
|
||||
if ( mOwnPattern )
|
||||
delete mPattern;
|
||||
}
|
||||
|
||||
LuaPattern::Match::Match( LuaPattern& r, const char* string, bool ownPattern ) : mString( string ) {
|
||||
mLength = strlen( string );
|
||||
mState = new LuaPattern::LuaPattern::State( &r, ownPattern );
|
||||
}
|
||||
|
||||
LuaPattern::Match::Match( LuaPattern& r, const std::string& string, bool ownPattern ) {
|
||||
mState = new LuaPattern::LuaPattern::State( &r, ownPattern );
|
||||
mString = string.c_str();
|
||||
mLength = string.size();
|
||||
}
|
||||
|
||||
LuaPattern::Match::~Match() {
|
||||
--mState->mRefCount;
|
||||
if ( mState->mRefCount == 0 )
|
||||
delete mState;
|
||||
}
|
||||
|
||||
LuaPattern::Match::Match( const LuaPattern::Match& other ) :
|
||||
mState( other.mState ), mString( other.mString ), mLength( other.mLength ) {
|
||||
++mState->mRefCount;
|
||||
}
|
||||
|
||||
LuaPattern::Match& LuaPattern::Match::operator=( const Match& ) {
|
||||
++mState->mRefCount;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void LuaPattern::Match::next() {
|
||||
int m1 = 0, m2 = 0;
|
||||
mState->range( 0, m1, m2 );
|
||||
mString += m2;
|
||||
mLength -= m2;
|
||||
}
|
||||
|
||||
std::string LuaPattern::Match::group( int idx ) const {
|
||||
int m1, m2;
|
||||
if ( mState->range( idx, m1, m2 ) )
|
||||
return std::string( mString + m1, m2 - m1 );
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string_view LuaPattern::Match::groupView( int idx ) const {
|
||||
static constexpr auto EMPTY = ""sv;
|
||||
int m1, m2;
|
||||
if ( mState->range( idx, m1, m2 ) )
|
||||
return std::string_view( mString + m1, m2 - m1 );
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
bool LuaPattern::Match::range( int idx, int& start, int& end ) const {
|
||||
return mState->range( idx, start, end );
|
||||
}
|
||||
|
||||
std::string LuaPattern::Match::operator[]( int index ) const {
|
||||
return group( index );
|
||||
}
|
||||
|
||||
bool LuaPattern::Match::matches() {
|
||||
return mState->matches( mString, mLength );
|
||||
}
|
||||
|
||||
bool LuaPattern::Match::subst( std::string& res ) {
|
||||
if ( !matches() ) {
|
||||
res.append( mString );
|
||||
return false;
|
||||
}
|
||||
int start = 0, end = 0;
|
||||
mState->range( 0, start, end );
|
||||
if ( start == 0 )
|
||||
return true;
|
||||
res.append( mString, start );
|
||||
return true;
|
||||
}
|
||||
|
||||
LuaPattern::Match LuaPattern::gmatch( const char* s ) & {
|
||||
return LuaPattern::Match( *this, s, false );
|
||||
}
|
||||
|
||||
LuaPattern::Match LuaPattern::gmatch( const std::string& s ) & {
|
||||
return LuaPattern::Match( *this, s, false );
|
||||
}
|
||||
|
||||
LuaPattern::Match LuaPattern::gmatch( const char* s ) && {
|
||||
return LuaPattern::Match( *this, s, true );
|
||||
}
|
||||
|
||||
LuaPattern::Match LuaPattern::gmatch( const std::string& string ) && {
|
||||
return LuaPattern::Match( *this, string, true );
|
||||
}
|
||||
|
||||
std::string LuaPattern::gsub( const char* text, const char* replace ) {
|
||||
LuaPattern::Match ms( *this, text );
|
||||
std::string res;
|
||||
while ( ms.subst( res ) ) {
|
||||
for ( const char* ptr = replace; *ptr; ++ptr ) {
|
||||
if ( *ptr == '%' ) {
|
||||
++ptr;
|
||||
int ngroup = (int)*ptr - (int)'0';
|
||||
res += ms.group( ngroup );
|
||||
} else {
|
||||
res += *ptr;
|
||||
}
|
||||
}
|
||||
ms.next();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string LuaPattern::gsub( const std::string& text, const std::string& replace ) {
|
||||
return gsub( text.c_str(), replace.c_str() );
|
||||
}
|
||||
|
||||
LuaPatternStorage::LuaPatternStorage( const std::string& pattern ) :
|
||||
LuaPattern( "" ), mPatternStorage( pattern ) {
|
||||
mPattern = std::string_view{ mPatternStorage };
|
||||
}
|
||||
|
||||
LuaPatternStorage::LuaPatternStorage( std::string&& pattern ) :
|
||||
LuaPattern( "" ), mPatternStorage( std::move( pattern ) ) {
|
||||
mPattern = std::string_view{ mPatternStorage };
|
||||
}
|
||||
|
||||
}} // namespace EE::System
|
||||
|
||||
186
src/eepp/system/patternmatcher.cpp
Normal file
186
src/eepp/system/patternmatcher.cpp
Normal file
@@ -0,0 +1,186 @@
|
||||
#include <cstring>
|
||||
#include <eepp/system/luapattern.hpp>
|
||||
#include <eepp/system/patternmatcher.hpp>
|
||||
#include <eepp/system/regex.hpp>
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
namespace EE { namespace System {
|
||||
|
||||
#define MAX_DEFAULT_MATCHES 12
|
||||
|
||||
bool PatternMatcher::find( const char* stringSearch, int& startMatch, int& endMatch,
|
||||
int stringStartOffset, int stringLength, int returnMatchIndex ) const {
|
||||
PatternMatcher::Range matchesBuffer[MAX_DEFAULT_MATCHES];
|
||||
if ( matches( stringSearch, stringStartOffset, matchesBuffer, stringLength ) ) {
|
||||
range( returnMatchIndex, startMatch, endMatch, matchesBuffer );
|
||||
return true;
|
||||
} else {
|
||||
startMatch = -1;
|
||||
endMatch = -1;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool PatternMatcher::find( const std::string& s, int& startMatch, int& endMatch, int offset,
|
||||
int returnedMatchIndex ) const {
|
||||
return find( s.c_str(), startMatch, endMatch, offset, s.size(), returnedMatchIndex );
|
||||
}
|
||||
|
||||
bool PatternMatcher::range( int indexGet, int& startMatch, int& endMatch,
|
||||
PatternMatcher::Range* returnedMatched ) const {
|
||||
if ( indexGet == -1 )
|
||||
indexGet = getNumMatches() > 1 ? 1 : 0;
|
||||
if ( indexGet >= 0 && indexGet < (int)getNumMatches() ) {
|
||||
startMatch = returnedMatched[indexGet].start;
|
||||
endMatch = returnedMatched[indexGet].end;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PatternMatcher::State::range( int index, int& start, int& end ) {
|
||||
return mPattern->range( index, start, end, mRanges );
|
||||
}
|
||||
|
||||
bool PatternMatcher::State::matches( const char* string, size_t length ) {
|
||||
return mPattern->matches( string, 0, mRanges, length );
|
||||
}
|
||||
|
||||
PatternMatcher::State::State( PatternMatcher* pattern, bool ownPattern ) :
|
||||
mRefCount( 1 ), mOwnPattern( ownPattern ) {
|
||||
mRanges = new Range[10];
|
||||
if ( ownPattern ) {
|
||||
switch ( pattern->getType() ) {
|
||||
case PatternType::LuaPattern:
|
||||
mPattern = new LuaPattern( pattern->getPattern() );
|
||||
break;
|
||||
case PatternType::PCRE:
|
||||
mPattern = new RegEx( pattern->getPattern() );
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
mPattern = pattern;
|
||||
}
|
||||
}
|
||||
|
||||
PatternMatcher::State::~State() {
|
||||
delete[] mRanges;
|
||||
if ( mOwnPattern )
|
||||
delete mPattern;
|
||||
}
|
||||
|
||||
PatternMatcher::Match::Match( PatternMatcher& r, const char* string, bool ownPattern ) :
|
||||
mString( string ) {
|
||||
mLength = strlen( string );
|
||||
mState = new PatternMatcher::State( &r, ownPattern );
|
||||
}
|
||||
|
||||
PatternMatcher::Match::Match( PatternMatcher& r, const std::string& string, bool ownPattern ) {
|
||||
mState = new PatternMatcher::State( &r, ownPattern );
|
||||
mString = string.c_str();
|
||||
mLength = string.size();
|
||||
}
|
||||
|
||||
PatternMatcher::Match::~Match() {
|
||||
--mState->mRefCount;
|
||||
if ( mState->mRefCount == 0 )
|
||||
delete mState;
|
||||
}
|
||||
|
||||
PatternMatcher::Match::Match( const PatternMatcher::Match& other ) :
|
||||
mState( other.mState ), mString( other.mString ), mLength( other.mLength ) {
|
||||
++mState->mRefCount;
|
||||
}
|
||||
|
||||
PatternMatcher::Match& PatternMatcher::Match::operator=( const Match& ) {
|
||||
++mState->mRefCount;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void PatternMatcher::Match::next() {
|
||||
int m1 = 0, m2 = 0;
|
||||
mState->range( 0, m1, m2 );
|
||||
mString += m2;
|
||||
mLength -= m2;
|
||||
}
|
||||
|
||||
std::string PatternMatcher::Match::group( int idx ) const {
|
||||
int m1, m2;
|
||||
if ( mState->range( idx, m1, m2 ) )
|
||||
return std::string( mString + m1, m2 - m1 );
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string_view PatternMatcher::Match::groupView( int idx ) const {
|
||||
static constexpr auto EMPTY = ""sv;
|
||||
int m1, m2;
|
||||
if ( mState->range( idx, m1, m2 ) )
|
||||
return std::string_view( mString + m1, m2 - m1 );
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
bool PatternMatcher::Match::range( int idx, int& start, int& end ) const {
|
||||
return mState->range( idx, start, end );
|
||||
}
|
||||
|
||||
std::string PatternMatcher::Match::operator[]( int index ) const {
|
||||
return group( index );
|
||||
}
|
||||
|
||||
bool PatternMatcher::Match::matches() {
|
||||
return mState->matches( mString, mLength );
|
||||
}
|
||||
|
||||
bool PatternMatcher::Match::subst( std::string& res ) {
|
||||
if ( !matches() ) {
|
||||
res.append( mString );
|
||||
return false;
|
||||
}
|
||||
int start = 0, end = 0;
|
||||
mState->range( 0, start, end );
|
||||
if ( start == 0 )
|
||||
return true;
|
||||
res.append( mString, start );
|
||||
return true;
|
||||
}
|
||||
|
||||
PatternMatcher::Match PatternMatcher::gmatch( const char* s ) & {
|
||||
return PatternMatcher::Match( *this, s, false );
|
||||
}
|
||||
|
||||
PatternMatcher::Match PatternMatcher::gmatch( const std::string& s ) & {
|
||||
return PatternMatcher::Match( *this, s, false );
|
||||
}
|
||||
|
||||
PatternMatcher::Match PatternMatcher::gmatch( const char* s ) && {
|
||||
return PatternMatcher::Match( *this, s, true );
|
||||
}
|
||||
|
||||
PatternMatcher::Match PatternMatcher::gmatch( const std::string& string ) && {
|
||||
return PatternMatcher::Match( *this, string, true );
|
||||
}
|
||||
|
||||
std::string PatternMatcher::gsub( const char* text, const char* replace ) {
|
||||
PatternMatcher::Match ms( *this, text );
|
||||
std::string res;
|
||||
while ( ms.subst( res ) ) {
|
||||
for ( const char* ptr = replace; *ptr; ++ptr ) {
|
||||
if ( *ptr == '%' ) {
|
||||
++ptr;
|
||||
int ngroup = (int)*ptr - (int)'0';
|
||||
res += ms.group( ngroup );
|
||||
} else {
|
||||
res += *ptr;
|
||||
}
|
||||
}
|
||||
ms.next();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string PatternMatcher::gsub( const std::string& text, const std::string& replace ) {
|
||||
return gsub( text.c_str(), replace.c_str() );
|
||||
}
|
||||
|
||||
}} // namespace EE::System
|
||||
106
src/eepp/system/regex.cpp
Normal file
106
src/eepp/system/regex.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
#include <eepp/system/regex.hpp>
|
||||
#include <pcre2.h>
|
||||
|
||||
namespace EE { namespace System {
|
||||
|
||||
RegEx::RegEx( const std::string_view& pattern ) :
|
||||
PatternMatcher( PatternType::PCRE ),
|
||||
mPattern( pattern ),
|
||||
mMatchNum( 0 ),
|
||||
mCompiledPattern( nullptr ),
|
||||
mCaptureCount( 0 ),
|
||||
mValid( true ) {
|
||||
int errornumber;
|
||||
PCRE2_SIZE erroroffset;
|
||||
PCRE2_SPTR pattern_sptr = reinterpret_cast<PCRE2_SPTR>( pattern.data() );
|
||||
|
||||
mCompiledPattern = pcre2_compile( pattern_sptr, // the pattern
|
||||
pattern.size(), // the length of the pattern
|
||||
0, // default options
|
||||
&errornumber, // for error number
|
||||
&erroroffset, // for error offset
|
||||
NULL // use default compile context
|
||||
);
|
||||
|
||||
if ( mCompiledPattern == NULL ) {
|
||||
PCRE2_UCHAR buffer[256];
|
||||
pcre2_get_error_message( errornumber, buffer, sizeof( buffer ) );
|
||||
mValid = false;
|
||||
// throw std::runtime_error( "PCRE2 compilation failed at offset " +
|
||||
// std::to_string( erroroffset ) + ": " +
|
||||
// reinterpret_cast<const char*>( buffer ) );
|
||||
}
|
||||
|
||||
int rc = pcre2_pattern_info( reinterpret_cast<pcre2_code*>( mCompiledPattern ),
|
||||
PCRE2_INFO_CAPTURECOUNT, &mCaptureCount );
|
||||
if ( rc != 0 ) {
|
||||
// throw std::runtime_error( "PCRE2 pattern info failed with error code " +
|
||||
// std::to_string( rc ) );
|
||||
mValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
RegEx::~RegEx() {
|
||||
if ( mCompiledPattern != nullptr ) {
|
||||
pcre2_code_free( reinterpret_cast<pcre2_code*>( mCompiledPattern ) );
|
||||
}
|
||||
}
|
||||
|
||||
bool RegEx::matches( const char* stringSearch, int stringStartOffset,
|
||||
PatternMatcher::Range* matchList, size_t stringLength ) const {
|
||||
auto* compiledPattern = reinterpret_cast<pcre2_code*>( mCompiledPattern );
|
||||
pcre2_match_data* match_data = pcre2_match_data_create_from_pattern( compiledPattern, NULL );
|
||||
|
||||
PCRE2_SPTR subject = reinterpret_cast<PCRE2_SPTR>( stringSearch );
|
||||
|
||||
int rc = pcre2_match( compiledPattern, // the compiled pattern
|
||||
subject, // the subject string
|
||||
stringLength, // the length of the subject
|
||||
stringStartOffset, // start at offset in the subject
|
||||
0, // default options
|
||||
match_data, // match data
|
||||
NULL // match context
|
||||
);
|
||||
|
||||
if ( rc < 0 ) {
|
||||
pcre2_match_data_free( match_data );
|
||||
mMatchNum = 0;
|
||||
// if ( rc == PCRE2_ERROR_NOMATCH )
|
||||
return false;
|
||||
// else
|
||||
// throw std::runtime_error( "PCRE2 matching error " + std::to_string( rc ) );
|
||||
}
|
||||
|
||||
mMatchNum = rc;
|
||||
|
||||
if ( matchList != nullptr ) {
|
||||
PCRE2_SIZE* ovector = pcre2_get_ovector_pointer( match_data );
|
||||
for ( size_t i = 0; i < static_cast<size_t>( rc ); ++i ) {
|
||||
matchList[i].start = static_cast<int>( ovector[2 * i] );
|
||||
matchList[i].end = static_cast<int>( ovector[2 * i + 1] );
|
||||
}
|
||||
}
|
||||
|
||||
pcre2_match_data_free( match_data );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RegEx::matches( const std::string& str, PatternMatcher::Range* matchList,
|
||||
int stringStartOffset ) const {
|
||||
return matches( str.c_str(), stringStartOffset, matchList, str.size() );
|
||||
}
|
||||
|
||||
const size_t& RegEx::getNumMatches() const {
|
||||
return mMatchNum;
|
||||
}
|
||||
|
||||
RegExStorage::RegExStorage( const std::string& pattern ) : RegEx( "" ), mPatternStorage( pattern ) {
|
||||
mPattern = std::string_view{ mPatternStorage };
|
||||
}
|
||||
|
||||
RegExStorage::RegExStorage( std::string&& pattern ) :
|
||||
RegEx( "" ), mPatternStorage( std::move( pattern ) ) {
|
||||
mPattern = std::string_view{ mPatternStorage };
|
||||
}
|
||||
|
||||
}} // namespace EE::System
|
||||
@@ -59,12 +59,12 @@ Time Time::fromString( const std::string& str ) {
|
||||
}
|
||||
|
||||
std::string Time::toString() const {
|
||||
Uint64 totalSeconds = asSeconds();
|
||||
double totalSeconds = asSeconds();
|
||||
|
||||
if ( asSeconds() < 1 ) {
|
||||
if ( totalSeconds < 1 ) {
|
||||
return String::fromFloat( asMilliseconds(), "ms" );
|
||||
} else if ( totalSeconds < 60 ) {
|
||||
return String::format( "%lus", static_cast<unsigned long>( totalSeconds ) );
|
||||
return String::fromFloat( totalSeconds, "s" );
|
||||
}
|
||||
|
||||
long minutesLeft = totalSeconds / 60;
|
||||
|
||||
@@ -396,7 +396,7 @@ bool Engine::openURI( const std::string& url ) {
|
||||
if ( nullptr == getPlatformHelper() )
|
||||
return false;
|
||||
|
||||
if ( !LuaPattern::matches( url, "^%w+://" ) )
|
||||
if ( !LuaPattern::hasMatches( url, "^%w+://" ) )
|
||||
return openURI( "file://" + url );
|
||||
|
||||
if ( String::startsWith( url, "file://" ) ) {
|
||||
|
||||
@@ -535,7 +535,7 @@ void UITerminal::createDefaultContextMenuOptions( UIPopUpMenu* menu ) {
|
||||
if ( mTerm->getTerminal()->hasSelection() ) {
|
||||
auto sel( mTerm->getTerminal()->getSelection() );
|
||||
|
||||
if ( LuaPattern::matches( sel, LuaPattern::getURIPattern() ) ) {
|
||||
if ( LuaPattern::hasMatches( sel, LuaPattern::getURIPattern() ) ) {
|
||||
menuAdd( menu, i18n( "uiterminal_open_link", "Open Link" ), "earth",
|
||||
"terminal-open-link" );
|
||||
}
|
||||
|
||||
34
src/tests/unit_tests/regex.cpp
Normal file
34
src/tests/unit_tests/regex.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#include "utest.h"
|
||||
#include <eepp/system/luapattern.hpp>
|
||||
#include <eepp/system/regex.hpp>
|
||||
|
||||
using namespace EE::System;
|
||||
|
||||
UTEST( RegEx, basicTest ) {
|
||||
RegEx regex( "\\d+" );
|
||||
std::string testStr = "The number is 42.";
|
||||
PatternMatcher::Range matches[10];
|
||||
regex.matches( testStr, matches );
|
||||
EXPECT_EQ( regex.isValid(), true );
|
||||
EXPECT_EQ( regex.getNumMatches(), 1ul );
|
||||
for ( size_t i = 0; i < regex.getNumMatches(); ++i ) {
|
||||
int start = matches[i].start;
|
||||
int end = matches[i].end;
|
||||
EXPECT_EQ( start, 14 );
|
||||
EXPECT_EQ( end, 16 );
|
||||
}
|
||||
}
|
||||
|
||||
UTEST( LuaPattern, basicTest ) {
|
||||
LuaPattern regex( "%d+" );
|
||||
std::string testStr = "The number is 42.";
|
||||
PatternMatcher::Range matches[10];
|
||||
regex.matches( testStr, matches );
|
||||
EXPECT_EQ( regex.getNumMatches(), 1ul );
|
||||
for ( size_t i = 0; i < regex.getNumMatches(); ++i ) {
|
||||
int start = matches[i].start;
|
||||
int end = matches[i].end;
|
||||
EXPECT_EQ( start, 14 );
|
||||
EXPECT_EQ( end, 16 );
|
||||
}
|
||||
}
|
||||
@@ -85,7 +85,7 @@ UTEST( TextFormat, autodetectProject ) {
|
||||
if ( "a" == extension || "zip" == extension || "dll" == extension ||
|
||||
"dat" == extension || "cur" == extension || "icns" == extension ||
|
||||
"wav" == extension || Image::isImageExtension( file.getFilepath() ) ||
|
||||
LuaPattern::matches( file.getFilepath(), "SDL2%-%d+%.%d+%.%d+" ) )
|
||||
LuaPattern::hasMatches( file.getFilepath(), "SDL2%-%d+%.%d+%.%d+" ) )
|
||||
continue;
|
||||
IOStreamFile stream( file.getFilepath() );
|
||||
auto expectedEncoding = getEncoding( file.getFileName() );
|
||||
|
||||
@@ -392,7 +392,7 @@ void DocSearchController::findAndReplace( SearchState& search, const String& rep
|
||||
if ( doc.hasSelection() &&
|
||||
( doc.getSelectedText() == txt ||
|
||||
( search.type == TextDocument::FindReplaceType::LuaPattern &&
|
||||
LuaPattern::matches( doc.getAllSelectedText().toUtf8(), txt.toUtf8() ) ) ) ) {
|
||||
LuaPattern::hasMatches( doc.getAllSelectedText().toUtf8(), txt.toUtf8() ) ) ) ) {
|
||||
replaceSelection( search, repl );
|
||||
} else {
|
||||
findNextText( search );
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "globalsearchcontroller.hpp"
|
||||
#include "ecode.hpp"
|
||||
#include "globalsearchcontroller.hpp"
|
||||
#include "uitreeviewglobalsearch.hpp"
|
||||
|
||||
namespace ecode {
|
||||
@@ -63,7 +63,7 @@ size_t GlobalSearchController::replaceInFiles( const std::string& replaceText,
|
||||
|
||||
const ProjectSearch::Result& res = model->getResult();
|
||||
bool hasCaptures =
|
||||
model->isResultFromLuaPattern() && LuaPattern::find( replaceText, "$%d+" ).isValid();
|
||||
model->isResultFromLuaPattern() && LuaPattern::hasMatches( replaceText, "$%d+" );
|
||||
|
||||
if ( hasCaptures ) {
|
||||
for ( const auto& fileResult : res ) {
|
||||
|
||||
@@ -672,9 +672,9 @@ void AutoCompletePlugin::tryStartSnippetNav( const Suggestion& suggestion, UICod
|
||||
bool AutoCompletePlugin::hasCompleteSteps( const Suggestion& suggestion ) {
|
||||
if ( suggestion.kind != LSPCompletionItemKind::Snippet )
|
||||
return false;
|
||||
if ( LuaPattern::matches( suggestion.insertText, SNIPPET_PTRN1 ) ||
|
||||
LuaPattern::matches( suggestion.insertText, SNIPPET_PTRN2 ) ||
|
||||
LuaPattern::matches( suggestion.insertText, SNIPPET_PTRN3 ) ) {
|
||||
if ( LuaPattern::hasMatches( suggestion.insertText, SNIPPET_PTRN1 ) ||
|
||||
LuaPattern::hasMatches( suggestion.insertText, SNIPPET_PTRN2 ) ||
|
||||
LuaPattern::hasMatches( suggestion.insertText, SNIPPET_PTRN3 ) ) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -496,7 +496,7 @@ FormatterPlugin::Formatter FormatterPlugin::supportsFormatter( std::shared_ptr<T
|
||||
|
||||
for ( const auto& formatter : mFormatters ) {
|
||||
for ( const auto& ext : formatter.files ) {
|
||||
if ( LuaPattern::matches( fileName, ext ) )
|
||||
if ( LuaPattern::hasMatches( fileName, ext ) )
|
||||
return formatter;
|
||||
auto& files = def.getFiles();
|
||||
if ( std::find( files.begin(), files.end(), ext ) != files.end() )
|
||||
|
||||
@@ -934,7 +934,7 @@ static bool isPath( const std::string& file ) {
|
||||
bool ret = !file.empty() && file[0] == '/';
|
||||
#if EE_PLATFORM == EE_PLATFORM_WIN
|
||||
if ( !ret )
|
||||
ret = LuaPattern::matches( file, "%w:[\\/][\\/]" );
|
||||
ret = LuaPattern::hasMatches( file, "%w:[\\/][\\/]" );
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1335,7 +1335,7 @@ Linter LinterPlugin::supportsLinter( std::shared_ptr<TextDocument> doc ) {
|
||||
|
||||
for ( auto& linter : mLinters ) {
|
||||
for ( auto& ext : linter.files ) {
|
||||
if ( LuaPattern::find( fileName, ext ).isValid() )
|
||||
if ( LuaPattern::hasMatches( fileName, ext ) )
|
||||
return linter;
|
||||
auto& files = def.getFiles();
|
||||
if ( std::find( files.begin(), files.end(), ext ) != files.end() ) {
|
||||
|
||||
@@ -28,7 +28,7 @@ LSPClientServerManager::supportsLSP( const std::shared_ptr<TextDocument>& doc )
|
||||
|
||||
for ( auto& lsp : mLSPs ) {
|
||||
for ( auto& ext : lsp.filePatterns ) {
|
||||
if ( LuaPattern::find( fileName, ext ).isValid() ) {
|
||||
if ( LuaPattern::hasMatches( fileName, ext ) ) {
|
||||
lsps.push_back( lsp );
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -12,9 +12,9 @@ UITerminal* TerminalManager::createTerminalInSplitter( const std::string& workin
|
||||
bool fallback ) {
|
||||
#if EE_PLATFORM == EE_PLATFORM_WIN
|
||||
std::string os = Sys::getOSName( true );
|
||||
if ( !LuaPattern::matches( os, "Windows 1%d"sv ) &&
|
||||
!LuaPattern::matches( os, "Windows Server 201[69]"sv ) &&
|
||||
!LuaPattern::matches( os, "Windows Server 202%d"sv ) )
|
||||
if ( !LuaPattern::hasMatches( os, "Windows 1%d"sv ) &&
|
||||
!LuaPattern::hasMatches( os, "Windows Server 201[69]"sv ) &&
|
||||
!LuaPattern::hasMatches( os, "Windows Server 202%d"sv ) )
|
||||
return nullptr;
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user