Merge pull request #44137 from nirvn/core_regexp_more

[qt6] A few more QRegExp aurevoirs in src/core
This commit is contained in:
Mathieu Pellerin 2021-07-14 20:37:02 +07:00 committed by GitHub
commit 94aa4a4f76
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 161 additions and 93 deletions

View File

@ -315,6 +315,17 @@ Convert simple HTML to markdown. Only br, b and link are supported.
:return: String formatted as markdown
.. versionadded:: 3.10
%End
static QString qRegExpEscape( const QString &string );
%Docstring
Returns an escaped string matching the behavior of QRegExp.escape.
:param string: String to escape
:return: Escaped string
.. versionadded:: 3.22
%End
};

View File

@ -499,14 +499,13 @@ QSet<QString> QgsExpression::referencedVariables( const QString &text )
int index = 0;
while ( index < text.size() )
{
QRegExp rx = QRegExp( "\\[%([^\\]]+)%\\]" );
int pos = rx.indexIn( text, index );
if ( pos < 0 )
const thread_local QRegularExpression rx( "\\[%([^\\]]+)%\\]" );
const QRegularExpressionMatch match = rx.match( text );
if ( !match.hasMatch() )
break;
index = pos + rx.matchedLength();
QString to_replace = rx.cap( 1 ).trimmed();
index = match.capturedStart() + match.capturedLength();
QString to_replace = match.captured( 1 ).trimmed();
QgsExpression exp( to_replace );
variables.unite( exp.referencedVariables() );

View File

@ -19,6 +19,7 @@
#include "qgsgeometry.h"
#include "qgsfeaturerequest.h"
#include "qgsstringutils.h"
#include <QRegularExpression>
@ -531,39 +532,39 @@ QVariant QgsExpressionNodeBinaryOperator::evalNode( QgsExpression *parent, const
ENSURE_NO_EVAL_ERROR
QString regexp = QgsExpressionUtils::getStringValue( vR, parent );
ENSURE_NO_EVAL_ERROR
// TODO: cache QRegExp in case that regexp is a literal string (i.e. it will stay constant)
// TODO: cache QRegularExpression in case that regexp is a literal string (i.e. it will stay constant)
bool matches;
if ( mOp == boLike || mOp == boILike || mOp == boNotLike || mOp == boNotILike ) // change from LIKE syntax to regexp
{
QString esc_regexp = QRegExp::escape( regexp );
QString esc_regexp = QgsStringUtils::qRegExpEscape( regexp );
// manage escape % and _
if ( esc_regexp.startsWith( '%' ) )
{
esc_regexp.replace( 0, 1, QStringLiteral( ".*" ) );
}
thread_local QRegExp rx1( QStringLiteral( "[^\\\\](%)" ) );
const thread_local QRegularExpression rx1( QStringLiteral( "[^\\\\](%)" ) );
int pos = 0;
while ( ( pos = rx1.indexIn( esc_regexp, pos ) ) != -1 )
while ( ( pos = esc_regexp.indexOf( rx1, pos ) ) != -1 )
{
esc_regexp.replace( pos + 1, 1, QStringLiteral( ".*" ) );
pos += 1;
}
thread_local QRegExp rx2( QStringLiteral( "\\\\%" ) );
const thread_local QRegularExpression rx2( QStringLiteral( "\\\\%" ) );
esc_regexp.replace( rx2, QStringLiteral( "%" ) );
if ( esc_regexp.startsWith( '_' ) )
{
esc_regexp.replace( 0, 1, QStringLiteral( "." ) );
}
thread_local QRegExp rx3( QStringLiteral( "[^\\\\](_)" ) );
const thread_local QRegularExpression rx3( QStringLiteral( "[^\\\\](_)" ) );
pos = 0;
while ( ( pos = rx3.indexIn( esc_regexp, pos ) ) != -1 )
while ( ( pos = esc_regexp.indexOf( rx3, pos ) ) != -1 )
{
esc_regexp.replace( pos + 1, 1, '.' );
pos += 1;
}
esc_regexp.replace( QLatin1String( "\\\\_" ), QLatin1String( "_" ) );
matches = QRegExp( esc_regexp, mOp == boLike || mOp == boNotLike ? Qt::CaseSensitive : Qt::CaseInsensitive ).exactMatch( str );
matches = QRegularExpression( QRegularExpression::anchoredPattern( esc_regexp ), mOp == boLike || mOp == boNotLike ? QRegularExpression::NoPatternOption : QRegularExpression::CaseInsensitiveOption ).match( str ).hasMatch();
}
else
{
@ -1479,8 +1480,9 @@ bool QgsExpressionNodeColumnRef::prepareNode( QgsExpression *parent, const QgsEx
QString QgsExpressionNodeColumnRef::dump() const
{
const thread_local QRegExp re( QStringLiteral( "^[A-Za-z_\x80-\xff][A-Za-z0-9_\x80-\xff]*$" ) );
return re.exactMatch( mName ) ? mName : QgsExpression::quotedColumnRef( mName );
const thread_local QRegularExpression re( QStringLiteral( "^[A-Za-z_\x80-\xff][A-Za-z0-9_\x80-\xff]*$" ) );
const QRegularExpressionMatch match = re.match( mName );
return match.hasMatch() ? mName : QgsExpression::quotedColumnRef( mName );
}
QSet<QString> QgsExpressionNodeColumnRef::referencedColumns() const

View File

@ -30,10 +30,12 @@
#include "qgsprovidersublayerdetails.h"
#include <QFileInfo>
#include <mutex>
#include <QRegularExpression>
#include <QUrlQuery>
#include <QUrl>
#include <mutex>
// defined in qgsgdalprovider.cpp
void buildSupportedRasterFileFilterAndExtensions( QString &fileFiltersString, QStringList &extensions, QStringList &wildcards );
@ -225,8 +227,8 @@ QgsDataItem *QgsGdalDataItemProvider::createDataItem( const QString &pathIn, Qgs
const auto constSWildcards = sWildcards;
for ( const QString &wildcard : constSWildcards )
{
QRegExp rx( wildcard, Qt::CaseInsensitive, QRegExp::Wildcard );
if ( rx.exactMatch( info.fileName() ) )
const QRegularExpression rx( QRegularExpression::wildcardToRegularExpression( wildcard ), QRegularExpression::CaseInsensitiveOption );
if ( rx.match( info.fileName() ).hasMatch() )
{
matches = true;
break;

View File

@ -2455,7 +2455,7 @@ void buildSupportedRasterFileFilterAndExtensions( QString &fileFiltersString, QS
QString myGdalDriverLongName = GDALGetMetadataItem( myGdalDriver, GDAL_DMD_LONGNAME, "" );
// remove any superfluous (.*) strings at the end as
// they'll confuse QFileDialog::getOpenFileNames()
myGdalDriverLongName.remove( QRegExp( "\\(.*\\)$" ) );
myGdalDriverLongName.remove( QRegularExpression( "\\(.*\\)$" ) );
// if we have both the file name extension and the long name,
// then we've all the information we need for the current

View File

@ -630,8 +630,8 @@ QgsDataItem *QgsOgrDataItemProvider::createDataItem( const QString &pathIn, QgsD
const auto constWildcards = QgsOgrProviderUtils::wildcards();
for ( const QString &wildcard : constWildcards )
{
QRegExp rx( wildcard, Qt::CaseInsensitive, QRegExp::Wildcard );
if ( rx.exactMatch( info.fileName() ) )
const QRegularExpression rx( QRegularExpression::wildcardToRegularExpression( wildcard ), QRegularExpression::CaseInsensitiveOption );
if ( rx.match( info.fileName() ).hasMatch() )
{
matches = true;
break;

View File

@ -18,10 +18,6 @@
#include "qgsproviderregistry.h"
#include <QString>
#include <QDir>
#include <QLibrary>
#include "qgis.h"
#include "qgsdataprovider.h"
#include "qgsdataitemprovider.h"
@ -51,6 +47,11 @@
#include "qgspostgresprovider.h"
#endif
#include <QString>
#include <QDir>
#include <QLibrary>
#include <QRegularExpression>
static QgsProviderRegistry *sInstance = nullptr;
QgsProviderRegistry *QgsProviderRegistry::instance( const QString &pluginPath )
@ -218,7 +219,7 @@ void QgsProviderRegistry::init()
// provider file regex pattern, only files matching the pattern are loaded if the variable is defined
QString filePattern = getenv( "QGIS_PROVIDER_FILE" );
QRegExp fileRegexp;
QRegularExpression fileRegexp;
if ( !filePattern.isEmpty() )
{
fileRegexp.setPattern( filePattern );
@ -229,9 +230,9 @@ void QgsProviderRegistry::init()
const auto constEntryInfoList = mLibraryDirectory.entryInfoList();
for ( const QFileInfo &fi : constEntryInfoList )
{
if ( !fileRegexp.isEmpty() )
if ( !filePattern.isEmpty() )
{
if ( fileRegexp.indexIn( fi.fileName() ) == -1 )
if ( fi.fileName().indexOf( fileRegexp ) == -1 )
{
QgsDebugMsg( "provider " + fi.fileName() + " skipped because doesn't match pattern " + filePattern );
continue;

View File

@ -688,6 +688,39 @@ QString QgsStringUtils::substituteVerticalCharacters( QString string )
return string;
}
QString QgsStringUtils::qRegExpEscape( const QString &string )
{
// code and logic taken from the Qt source code
const QLatin1Char backslash( '\\' );
const int count = string.count();
QString escaped;
escaped.reserve( count * 2 );
for ( int i = 0; i < count; i++ )
{
switch ( string.at( i ).toLatin1() )
{
case '$':
case '(':
case ')':
case '*':
case '+':
case '.':
case '?':
case '[':
case '\\':
case ']':
case '^':
case '{':
case '|':
case '}':
escaped.append( backslash );
}
escaped.append( string.at( i ) );
}
return escaped;
}
QgsStringReplacement::QgsStringReplacement( const QString &match, const QString &replacement, bool caseSensitive, bool wholeWordOnly )
: mMatch( match )
, mReplacement( replacement )

View File

@ -307,6 +307,14 @@ class CORE_EXPORT QgsStringUtils
*/
static QString htmlToMarkdown( const QString &html );
/**
* Returns an escaped string matching the behavior of QRegExp::escape.
* \param string String to escape
* \returns Escaped string
* \since QGIS 3.22
*/
static QString qRegExpEscape( const QString &string );
};
#endif //QGSSTRINGUTILS_H

View File

@ -15,15 +15,6 @@
* *
***************************************************************************/
#include <QApplication>
#include <QDateTime>
#include <QDir>
#include <QFileInfo>
#include <QVector>
#include <QStyle>
#include <QDomDocument>
#include <QDomElement>
#include "qgssettings.h"
#include "qgscptcityarchive.h"
#include "qgis.h"
@ -34,6 +25,16 @@
#include "qgsapplication.h"
#include "qgssymbollayerutils.h"
#include <QApplication>
#include <QDateTime>
#include <QDir>
#include <QFileInfo>
#include <QVector>
#include <QStyle>
#include <QDomDocument>
#include <QDomElement>
#include <QRegularExpression>
typedef QMap< QString, QgsCptCityArchive * > ArchiveRegistry;
typedef QMap< QString, QMap< QString, QString > > CopyingInfoMap;
@ -974,12 +975,12 @@ QMap< QString, QStringList > QgsCptCityDirectoryItem::rampsMap()
}
else
{
QRegExp rxVariant( "^(.*[^\\d])(\\d{1,3})$" );
int pos = rxVariant.indexIn( schemeName );
if ( pos > -1 )
const thread_local QRegularExpression rxVariant( "^(.*[^\\d])(\\d{1,3})$" );
const QRegularExpressionMatch match = rxVariant.match( schemeName );
if ( match.hasMatch() )
{
curName = rxVariant.cap( 1 );
curVariant = rxVariant.cap( 2 );
curName = match.captured( 1 );
curVariant = match.captured( 2 );
}
}

View File

@ -16,6 +16,7 @@
#include "qgsrendererrange.h"
#include "qgsclassificationmethod.h"
#include "qgssymbol.h"
#include <QLocale>
@ -220,7 +221,7 @@ QString QgsRendererRangeLabelFormat::formatNumber( double value ) const
QString valueStr = QLocale().toString( value, 'f', mPrecision );
if ( mTrimTrailingZeroes )
valueStr = valueStr.remove( mReTrailingZeroes );
if ( mReNegativeZero.exactMatch( valueStr ) )
if ( mReNegativeZero.match( valueStr ).hasMatch() )
valueStr = valueStr.mid( 1 );
return valueStr;
}

View File

@ -16,12 +16,12 @@
#ifndef QGSRENDERERRANGE_H
#define QGSRENDERERRANGE_H
#include <QRegExp>
#include "qgis_core.h"
#include "qgis_sip.h"
#include "qgssymbollayerutils.h"
#include <QRegularExpression>
class QDomDocument;
class QDomElement;
@ -141,8 +141,8 @@ class CORE_EXPORT Q_DECL_DEPRECATED QgsRendererRangeLabelFormat SIP_DEPRECATED
// values used to manage number formatting - precision and trailing zeroes
double mNumberScale = 1.0;
QString mNumberSuffix;
QRegExp mReTrailingZeroes;
QRegExp mReNegativeZero;
QRegularExpression mReTrailingZeroes;
QRegularExpression mReNegativeZero;
};

View File

@ -51,7 +51,6 @@
#include <QIcon>
#include <QPainter>
#include <QSettings>
#include <QRegExp>
#include <QPicture>
#include <QUrl>
#include <QUrlQuery>
@ -3258,7 +3257,8 @@ QList<QColor> QgsSymbolLayerUtils::parseColorList( const QString &colorStr )
QList<QColor> colors;
//try splitting string at commas, spaces or newlines
QStringList components = colorStr.simplified().split( QRegExp( "(,|\\s)" ) );
const thread_local QRegularExpression sepCommaSpaceRegExp( "(,|\\s)" );
QStringList components = colorStr.simplified().split( sepCommaSpaceRegExp );
QStringList::iterator it = components.begin();
for ( ; it != components.end(); ++it )
{
@ -3274,7 +3274,8 @@ QList<QColor> QgsSymbolLayerUtils::parseColorList( const QString &colorStr )
}
//try splitting string at commas or newlines
components = colorStr.split( QRegExp( "(,|\n)" ) );
const thread_local QRegularExpression sepCommaRegExp( "(,|\n)" );
components = colorStr.split( sepCommaRegExp );
it = components.begin();
for ( ; it != components.end(); ++it )
{
@ -3594,10 +3595,11 @@ QgsNamedColorList QgsSymbolLayerUtils::importColorsFromGpl( QFile &file, bool &o
}
if ( line.startsWith( QLatin1String( "Name:" ) ) )
{
QRegExp nameRx( "Name:\\s*(\\S.*)$" );
if ( nameRx.indexIn( line ) != -1 )
const thread_local QRegularExpression nameRx( "Name:\\s*(\\S.*)$" );
const QRegularExpressionMatch match = nameRx.match( line );
if ( match.hasMatch() )
{
name = nameRx.cap( 1 );
name = match.captured( 1 );
}
}
@ -3613,17 +3615,18 @@ QgsNamedColorList QgsSymbolLayerUtils::importColorsFromGpl( QFile &file, bool &o
}
//ready to start reading colors
QRegExp rx( "^\\s*(\\d+)\\s+(\\d+)\\s+(\\d+)(\\s.*)?$" );
const thread_local QRegularExpression rx( "^\\s*(\\d+)\\s+(\\d+)\\s+(\\d+)(\\s.*)?$" );
while ( !in.atEnd() )
{
line = in.readLine();
if ( rx.indexIn( line ) == -1 )
const QRegularExpressionMatch match = rx.match( line );
if ( !match.hasMatch() )
{
continue;
}
int red = rx.cap( 1 ).toInt();
int green = rx.cap( 2 ).toInt();
int blue = rx.cap( 3 ).toInt();
int red = match.captured( 1 ).toInt();
int green = match.captured( 2 ).toInt();
int blue = match.captured( 3 ).toInt();
QColor color = QColor( red, green, blue );
if ( !color.isValid() )
{
@ -3634,7 +3637,7 @@ QgsNamedColorList QgsSymbolLayerUtils::importColorsFromGpl( QFile &file, bool &o
QString label;
if ( rx.captureCount() > 3 )
{
label = rx.cap( 4 ).simplified();
label = match.captured( 4 ).simplified();
}
else
{
@ -3659,11 +3662,11 @@ QColor QgsSymbolLayerUtils::parseColorWithAlpha( const QString &colorStr, bool &
{
QColor parsedColor;
QRegExp hexColorAlphaRx( "^\\s*#?([0-9a-fA-F]{6})([0-9a-fA-F]{2})\\s*$" );
int hexColorIndex = hexColorAlphaRx.indexIn( colorStr );
const thread_local QRegularExpression hexColorAlphaRx( "^\\s*#?([0-9a-fA-F]{6})([0-9a-fA-F]{2})\\s*$" );
QRegularExpressionMatch match = hexColorAlphaRx.match( colorStr );
//color in hex format "#aabbcc", but not #aabbccdd
if ( hexColorIndex == -1 && QColor::isValidColor( colorStr ) )
if ( !match.hasMatch() && QColor::isValidColor( colorStr ) )
{
//string is a valid hex color string
parsedColor.setNamedColor( colorStr );
@ -3675,12 +3678,12 @@ QColor QgsSymbolLayerUtils::parseColorWithAlpha( const QString &colorStr, bool &
}
//color in hex format, with alpha
if ( hexColorIndex > -1 )
if ( match.hasMatch() )
{
QString hexColor = hexColorAlphaRx.cap( 1 );
QString hexColor = match.captured( 1 );
parsedColor.setNamedColor( QStringLiteral( "#" ) + hexColor );
bool alphaOk;
int alphaHex = hexColorAlphaRx.cap( 2 ).toInt( &alphaOk, 16 );
int alphaHex = match.captured( 2 ).toInt( &alphaOk, 16 );
if ( parsedColor.isValid() && alphaOk )
{
@ -3693,8 +3696,8 @@ QColor QgsSymbolLayerUtils::parseColorWithAlpha( const QString &colorStr, bool &
if ( !strictEval )
{
//color in hex format, without #
QRegExp hexColorRx2( "^\\s*(?:[0-9a-fA-F]{3}){1,2}\\s*$" );
if ( hexColorRx2.indexIn( colorStr ) != -1 )
const thread_local QRegularExpression hexColorRx2( "^\\s*(?:[0-9a-fA-F]{3}){1,2}\\s*$" );
if ( colorStr.indexOf( hexColorRx2 ) != -1 )
{
//add "#" and parse
parsedColor.setNamedColor( QStringLiteral( "#" ) + colorStr );
@ -3707,12 +3710,13 @@ QColor QgsSymbolLayerUtils::parseColorWithAlpha( const QString &colorStr, bool &
}
//color in (rrr,ggg,bbb) format, brackets and rgb prefix optional
QRegExp rgbFormatRx( "^\\s*(?:rgb)?\\(?\\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\s*,\\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\s*,\\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\s*\\)?\\s*;?\\s*$" );
if ( rgbFormatRx.indexIn( colorStr ) != -1 )
const thread_local QRegularExpression rgbFormatRx( "^\\s*(?:rgb)?\\(?\\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\s*,\\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\s*,\\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\s*\\)?\\s*;?\\s*$" );
match = rgbFormatRx.match( colorStr );
if ( match.hasMatch() )
{
int r = rgbFormatRx.cap( 1 ).toInt();
int g = rgbFormatRx.cap( 2 ).toInt();
int b = rgbFormatRx.cap( 3 ).toInt();
int r = match.captured( 1 ).toInt();
int g = match.captured( 2 ).toInt();
int b = match.captured( 3 ).toInt();
parsedColor.setRgb( r, g, b );
if ( parsedColor.isValid() )
{
@ -3722,8 +3726,8 @@ QColor QgsSymbolLayerUtils::parseColorWithAlpha( const QString &colorStr, bool &
}
//color in hsl(h,s,l) format, brackets optional
const QRegularExpression hslFormatRx( "^\\s*hsl\\(?\\s*(\\d+)\\s*,\\s*(\\d+)\\s*%\\s*,\\s*(\\d+)\\s*%\\s*\\)?\\s*;?\\s*$" );
QRegularExpressionMatch match = hslFormatRx.match( colorStr );
const thread_local QRegularExpression hslFormatRx( "^\\s*hsl\\(?\\s*(\\d+)\\s*,\\s*(\\d+)\\s*%\\s*,\\s*(\\d+)\\s*%\\s*\\)?\\s*;?\\s*$" );
match = hslFormatRx.match( colorStr );
if ( match.hasMatch() )
{
int h = match.captured( 1 ).toInt();
@ -3738,12 +3742,13 @@ QColor QgsSymbolLayerUtils::parseColorWithAlpha( const QString &colorStr, bool &
}
//color in (r%,g%,b%) format, brackets and rgb prefix optional
QRegExp rgbPercentFormatRx( "^\\s*(?:rgb)?\\(?\\s*(100|0*\\d{1,2})\\s*%\\s*,\\s*(100|0*\\d{1,2})\\s*%\\s*,\\s*(100|0*\\d{1,2})\\s*%\\s*\\)?\\s*;?\\s*$" );
if ( rgbPercentFormatRx.indexIn( colorStr ) != -1 )
const thread_local QRegularExpression rgbPercentFormatRx( "^\\s*(?:rgb)?\\(?\\s*(100|0*\\d{1,2})\\s*%\\s*,\\s*(100|0*\\d{1,2})\\s*%\\s*,\\s*(100|0*\\d{1,2})\\s*%\\s*\\)?\\s*;?\\s*$" );
match = rgbPercentFormatRx.match( colorStr );
if ( match.hasMatch() )
{
int r = std::round( rgbPercentFormatRx.cap( 1 ).toDouble() * 2.55 );
int g = std::round( rgbPercentFormatRx.cap( 2 ).toDouble() * 2.55 );
int b = std::round( rgbPercentFormatRx.cap( 3 ).toDouble() * 2.55 );
int r = std::round( match.captured( 1 ).toDouble() * 2.55 );
int g = std::round( match.captured( 2 ).toDouble() * 2.55 );
int b = std::round( match.captured( 3 ).toDouble() * 2.55 );
parsedColor.setRgb( r, g, b );
if ( parsedColor.isValid() )
{
@ -3753,13 +3758,14 @@ QColor QgsSymbolLayerUtils::parseColorWithAlpha( const QString &colorStr, bool &
}
//color in (r,g,b,a) format, brackets and rgba prefix optional
QRegExp rgbaFormatRx( "^\\s*(?:rgba)?\\(?\\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\s*,\\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\s*,\\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\s*,\\s*(0|0?\\.\\d*|1(?:\\.0*)?)\\s*\\)?\\s*;?\\s*$" );
if ( rgbaFormatRx.indexIn( colorStr ) != -1 )
const thread_local QRegularExpression rgbaFormatRx( "^\\s*(?:rgba)?\\(?\\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\s*,\\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\s*,\\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\s*,\\s*(0|0?\\.\\d*|1(?:\\.0*)?)\\s*\\)?\\s*;?\\s*$" );
match = rgbaFormatRx.match( colorStr );
if ( match.hasMatch() )
{
int r = rgbaFormatRx.cap( 1 ).toInt();
int g = rgbaFormatRx.cap( 2 ).toInt();
int b = rgbaFormatRx.cap( 3 ).toInt();
int a = std::round( rgbaFormatRx.cap( 4 ).toDouble() * 255.0 );
int r = match.captured( 1 ).toInt();
int g = match.captured( 2 ).toInt();
int b = match.captured( 3 ).toInt();
int a = std::round( match.captured( 4 ).toDouble() * 255.0 );
parsedColor.setRgb( r, g, b, a );
if ( parsedColor.isValid() )
{
@ -3769,13 +3775,14 @@ QColor QgsSymbolLayerUtils::parseColorWithAlpha( const QString &colorStr, bool &
}
//color in (r%,g%,b%,a) format, brackets and rgba prefix optional
QRegExp rgbaPercentFormatRx( "^\\s*(?:rgba)?\\(?\\s*(100|0*\\d{1,2})\\s*%\\s*,\\s*(100|0*\\d{1,2})\\s*%\\s*,\\s*(100|0*\\d{1,2})\\s*%\\s*,\\s*(0|0?\\.\\d*|1(?:\\.0*)?)\\s*\\)?\\s*;?\\s*$" );
if ( rgbaPercentFormatRx.indexIn( colorStr ) != -1 )
const thread_local QRegularExpression rgbaPercentFormatRx( "^\\s*(?:rgba)?\\(?\\s*(100|0*\\d{1,2})\\s*%\\s*,\\s*(100|0*\\d{1,2})\\s*%\\s*,\\s*(100|0*\\d{1,2})\\s*%\\s*,\\s*(0|0?\\.\\d*|1(?:\\.0*)?)\\s*\\)?\\s*;?\\s*$" );
match = rgbaPercentFormatRx.match( colorStr );
if ( match.hasMatch() )
{
int r = std::round( rgbaPercentFormatRx.cap( 1 ).toDouble() * 2.55 );
int g = std::round( rgbaPercentFormatRx.cap( 2 ).toDouble() * 2.55 );
int b = std::round( rgbaPercentFormatRx.cap( 3 ).toDouble() * 2.55 );
int a = std::round( rgbaPercentFormatRx.cap( 4 ).toDouble() * 255.0 );
int r = std::round( match.captured( 1 ).toDouble() * 2.55 );
int g = std::round( match.captured( 2 ).toDouble() * 2.55 );
int b = std::round( match.captured( 3 ).toDouble() * 2.55 );
int a = std::round( match.captured( 4 ).toDouble() * 255.0 );
parsedColor.setRgb( r, g, b, a );
if ( parsedColor.isValid() )
{
@ -3785,7 +3792,7 @@ QColor QgsSymbolLayerUtils::parseColorWithAlpha( const QString &colorStr, bool &
}
//color in hsla(h,s%,l%,a) format, brackets optional
const QRegularExpression hslaPercentFormatRx( "^\\s*hsla\\(?\\s*(\\d+)\\s*,\\s*(\\d+)\\s*%\\s*,\\s*(\\d+)\\s*%\\s*,\\s*([\\d\\.]+)\\s*\\)?\\s*;?\\s*$" );
const thread_local QRegularExpression hslaPercentFormatRx( "^\\s*hsla\\(?\\s*(\\d+)\\s*,\\s*(\\d+)\\s*%\\s*,\\s*(\\d+)\\s*%\\s*,\\s*([\\d\\.]+)\\s*\\)?\\s*;?\\s*$" );
match = hslaPercentFormatRx.match( colorStr );
if ( match.hasMatch() )
{

View File

@ -765,7 +765,10 @@ class TestQgsExpression: public QObject
QTest::newRow( "like 2" ) << "'hello' like '_el%'" << false << QVariant( 1 );
QTest::newRow( "like 3" ) << "'hello' like 'lo'" << false << QVariant( 0 );
QTest::newRow( "like 4" ) << "'hello' like '%LO'" << false << QVariant( 0 );
QTest::newRow( "like 5" ) << "'QGIS' like '%G%'" << false << QVariant( 1 );
QTest::newRow( "like 6" ) << "'[testing]' like '[testing%'" << false << QVariant( 1 );
QTest::newRow( "ilike" ) << "'hello' ilike '%LO'" << false << QVariant( 1 );
QTest::newRow( "ilike with dot" ) << "'QGIS .123' ilike 'qgis .123'" << false << QVariant( 1 );
// the \\\\ is like \\ in the interface
QTest::newRow( "like escape 1" ) << "'1%' like '1\\\\%'" << false << QVariant( 1 );
QTest::newRow( "like escape 2" ) << "'1_' like '1\\\\%'" << false << QVariant( 0 );