19 #include <QStringList>    20 #include <QTextBoundaryFinder>    21 #include <QRegularExpression>    26   if ( 
string.isEmpty() )
    29   switch ( capitalization )
    35       return string.toUpper();
    38       return string.toLower();
    42       QString temp = string;
    44       QTextBoundaryFinder wordSplitter( QTextBoundaryFinder::Word, 
string.constData(), 
string.length(), 
nullptr, 0 );
    45       QTextBoundaryFinder letterSplitter( QTextBoundaryFinder::Grapheme, 
string.constData(), 
string.length(), 
nullptr, 0 );
    47       wordSplitter.setPosition( 0 );
    49       while ( ( first && wordSplitter.boundaryReasons() & QTextBoundaryFinder::StartOfItem )
    50               || wordSplitter.toNextBoundary() >= 0 )
    53         letterSplitter.setPosition( wordSplitter.position() );
    54         letterSplitter.toNextBoundary();
    55         QString substr = 
string.mid( wordSplitter.position(), letterSplitter.position() - wordSplitter.position() );
    56         temp.replace( wordSplitter.position(), substr.length(), substr.toUpper() );
    65       static QStringList smallWords;
    66       static QStringList newPhraseSeparators;
    67       static QRegularExpression splitWords;
    68       if ( smallWords.empty() )
    70         smallWords = QObject::tr( 
"a|an|and|as|at|but|by|en|for|if|in|nor|of|on|or|per|s|the|to|vs.|vs|via" ).split( 
'|' );
    71         newPhraseSeparators = QObject::tr( 
".|:" ).split( 
'|' );
    72         splitWords = QRegularExpression( QStringLiteral( 
"\\b" ), QRegularExpression::UseUnicodePropertiesOption );
    75       const QStringList parts = 
string.split( splitWords, QString::SkipEmptyParts );
    77       bool firstWord = 
true;
    79       int lastWord = parts.count() - 1;
    80       for ( 
const QString &word : qgis::as_const( parts ) )
    82         if ( newPhraseSeparators.contains( word.trimmed() ) )
    87         else if ( firstWord || ( i == lastWord ) || !smallWords.contains( word ) )
    89           result += word.at( 0 ).toUpper() + word.mid( 1 );
   103       result.remove( 
' ' );
   114   for ( 
int i = 0; i < 
string.size(); ++i )
   116     QChar ch = 
string.at( i );
   117     if ( ch.unicode() > 160 )
   118       encoded += QStringLiteral( 
"&#%1;" ).arg( static_cast< int >( ch.unicode() ) );
   119     else if ( ch.unicode() == 38 )
   120       encoded += QStringLiteral( 
"&" );
   121     else if ( ch.unicode() == 60 )
   122       encoded += QStringLiteral( 
"<" );
   123     else if ( ch.unicode() == 62 )
   124       encoded += QStringLiteral( 
">" );
   133   int length1 = string1.length();
   134   int length2 = string2.length();
   137   if ( string1.isEmpty() )
   141   else if ( string2.isEmpty() )
   147   QString s1( caseSensitive ? string1 : string1.toLower() );
   148   QString s2( caseSensitive ? string2 : string2.toLower() );
   150   const QChar *s1Char = s1.constData();
   151   const QChar *s2Char = s2.constData();
   154   int commonPrefixLen = 0;
   155   while ( length1 > 0 && length2 > 0 && *s1Char == *s2Char )
   165   while ( length1 > 0 && length2 > 0 && s1.at( commonPrefixLen + length1 - 1 ) == s2.at( commonPrefixLen + length2 - 1 ) )
   176   else if ( length2 == 0 )
   182   if ( length1 > length2 )
   185     std::swap( length1, length2 );
   190   col.fill( 0, length2 + 1 );
   191   QVector< int > prevCol;
   192   prevCol.reserve( length2 + 1 );
   193   for ( 
int i = 0; i < length2 + 1; ++i )
   197   const QChar *s2start = s2Char;
   198   for ( 
int i = 0; i < length1; ++i )
   202     for ( 
int j = 0; j < length2; ++j )
   204       col[j + 1] = std::min( std::min( 1 + col[j], 1 + prevCol[1 + j] ), prevCol[j] + ( ( *s1Char == *s2Char ) ? 0 : 1 ) );
   210   return prevCol[length2];
   215   if ( string1.isEmpty() || string2.isEmpty() )
   222   QString s1( caseSensitive ? string1 : string1.toLower() );
   223   QString s2( caseSensitive ? string2 : string2.toLower() );
   231   int *currentScores = 
new int [ s2.length()];
   232   int *previousScores = 
new int [ s2.length()];
   233   int maxCommonLength = 0;
   234   int lastMaxBeginIndex = 0;
   236   const QChar *s1Char = s1.constData();
   237   const QChar *s2Char = s2.constData();
   238   const QChar *s2Start = s2Char;
   240   for ( 
int i = 0; i < s1.length(); ++i )
   242     for ( 
int j = 0; j < s2.length(); ++j )
   244       if ( *s1Char != *s2Char )
   246         currentScores[j] = 0;
   250         if ( i == 0 || j == 0 )
   252           currentScores[j] = 1;
   256           currentScores[j] = 1 + previousScores[j - 1];
   259         if ( maxCommonLength < currentScores[j] )
   261           maxCommonLength = currentScores[j];
   262           lastMaxBeginIndex = i;
   267     std::swap( currentScores, previousScores );
   271   delete [] currentScores;
   272   delete [] previousScores;
   273   return string1.mid( lastMaxBeginIndex - maxCommonLength + 1, maxCommonLength );
   278   if ( string1.isEmpty() && string2.isEmpty() )
   284   if ( string1.length() != string2.length() )
   291   QString s1( caseSensitive ? string1 : string1.toLower() );
   292   QString s2( caseSensitive ? string2 : string2.toLower() );
   301   const QChar *s1Char = s1.constData();
   302   const QChar *s2Char = s2.constData();
   304   for ( 
int i = 0; i < string1.length(); ++i )
   306     if ( *s1Char != *s2Char )
   317   if ( 
string.isEmpty() )
   320   QString tmp = 
string.toUpper();
   323   QChar *char1 = tmp.data();
   324   QChar *char2 = tmp.data();
   326   for ( 
int i = 0; i < tmp.length(); ++i, ++char2 )
   328     if ( ( *char2 ).unicode() >= 0x41 && ( *char2 ).unicode() <= 0x5A && ( i == 0 || ( ( *char2 ).unicode() != 0x41 && ( *char2 ).unicode() != 0x45
   329          && ( *char2 ).unicode() != 0x48 && ( *char2 ).unicode() != 0x49
   330          && ( *char2 ).unicode() != 0x4F && ( *char2 ).unicode() != 0x55
   331          && ( *char2 ).unicode() != 0x57 && ( *char2 ).unicode() != 0x59 ) ) )
   338   tmp.truncate( outLen );
   340   QChar *tmpChar = tmp.data();
   342   for ( 
int i = 1; i < tmp.length(); ++i, ++tmpChar )
   344     switch ( ( *tmpChar ).unicode() )
   350         tmp.replace( i, 1, QChar( 0x31 ) );
   361         tmp.replace( i, 1, QChar( 0x32 ) );
   366         tmp.replace( i, 1, QChar( 0x33 ) );
   370         tmp.replace( i, 1, QChar( 0x34 ) );
   375         tmp.replace( i, 1, QChar( 0x35 ) );
   379         tmp.replace( i, 1, QChar( 0x36 ) );
   389   for ( 
int i = 1; i < tmp.length(); ++i, ++char2 )
   391     if ( *char2 != *char1 )
   400   tmp.truncate( outLen );
   401   if ( tmp.length() < 4 )
   412   QString converted = string;
   416   static QRegExp urlRegEx( 
"(\\b(([\\w-]+://?|www[.])[^\\s()<>]+(?:\\([\\w\\d]+\\)|([^!\"#$%&'()*+,\\-./:;<=>?@[\\\\\\]^_`{|}~\\s]|/))))" );
   417   static QRegExp protoRegEx( 
"^(?:f|ht)tps?://|file://" );
   418   static QRegExp emailRegEx( 
"([\\w._%+-]+@[\\w.-]+\\.[A-Za-z]+)" );
   422   while ( urlRegEx.indexIn( converted, offset ) != -1 )
   425     QString url = urlRegEx.cap( 1 );
   426     QString protoUrl = url;
   427     if ( protoRegEx.indexIn( protoUrl ) == -1 )
   429       protoUrl.prepend( 
"http://" );
   431     QString anchor = QStringLiteral( 
"<a href=\"%1\">%2</a>" ).arg( protoUrl.toHtmlEscaped(), url.toHtmlEscaped() );
   432     converted.replace( urlRegEx.pos( 1 ), url.length(), anchor );
   433     offset = urlRegEx.pos( 1 ) + anchor.length();
   436   while ( emailRegEx.indexIn( converted, offset ) != -1 )
   439     QString email = emailRegEx.cap( 1 );
   440     QString anchor = QStringLiteral( 
"<a href=\"mailto:%1\">%1</a>" ).arg( email.toHtmlEscaped() );
   441     converted.replace( emailRegEx.pos( 1 ), email.length(), anchor );
   442     offset = emailRegEx.pos( 1 ) + anchor.length();
   454   QString converted = html;
   455   converted.replace( QLatin1String( 
"<br>" ), QLatin1String( 
"\n" ) );
   456   converted.replace( QLatin1String( 
"<b>" ), QLatin1String( 
"**" ) );
   457   converted.replace( QLatin1String( 
"</b>" ), QLatin1String( 
"**" ) );
   459   static QRegExp hrefRegEx( 
"<a\\s+href\\s*=\\s*([^<>]*)\\s*>([^<>]*)</a>" );
   461   while ( hrefRegEx.indexIn( converted, offset ) != -1 )
   463     QString url = hrefRegEx.cap( 1 ).replace( QStringLiteral( 
"\"" ), QString() );
   464     url.replace( QStringLiteral( 
"'" ), QString() );
   465     QString name = hrefRegEx.cap( 2 );
   466     QString anchor = QStringLiteral( 
"[%1](%2)" ).arg( name, url );
   467     converted.replace( hrefRegEx, anchor );
   468     offset = hrefRegEx.pos( 1 ) + anchor.length();
   474 QString 
QgsStringUtils::wordWrap( 
const QString &
string, 
const int length, 
const bool useMaxLineLength, 
const QString &customDelimiter )
   476   if ( 
string.isEmpty() || length == 0 )
   481   int delimiterLength = 0;
   483   if ( !customDelimiter.isEmpty() )
   485     rx.setPatternSyntax( QRegExp::FixedString );
   486     rx.setPattern( customDelimiter );
   487     delimiterLength = customDelimiter.length();
   492     rx.setPattern( QStringLiteral( 
"[\\s\\x200B]" ) );
   496   const QStringList lines = 
string.split( 
'\n' );
   497   int strLength, strCurrent, strHit, lastHit;
   499   for ( 
int i = 0; i < lines.size(); i++ )
   501     strLength = lines.at( i ).length();
   506     while ( strCurrent < strLength )
   510       if ( useMaxLineLength )
   513         strHit = lines.at( i ).lastIndexOf( rx, strCurrent + length );
   514         if ( strHit == lastHit || strHit == -1 )
   517           strHit = lines.at( i ).indexOf( rx, strCurrent + std::abs( length ) );
   523         strHit = lines.at( i ).indexOf( rx, strCurrent + std::abs( length ) );
   527         newstr.append( lines.at( i ).midRef( strCurrent, strHit - strCurrent ) );
   528         newstr.append( 
'\n' );
   529         strCurrent = strHit + delimiterLength;
   533         newstr.append( lines.at( i ).midRef( strCurrent ) );
   534         strCurrent = strLength;
   537     if ( i < lines.size() - 1 )
   538       newstr.append( 
'\n' );
   546   string = 
string.replace( 
',', QChar( 65040 ) ).replace( QChar( 8229 ), QChar( 65072 ) ); 
   547   string = 
string.replace( QChar( 12289 ), QChar( 65041 ) ).replace( QChar( 12290 ), QChar( 65042 ) ); 
   548   string = 
string.replace( 
':', QChar( 65043 ) ).replace( 
';', QChar( 65044 ) );
   549   string = 
string.replace( 
'!', QChar( 65045 ) ).replace( 
'?', QChar( 65046 ) );
   550   string = 
string.replace( QChar( 12310 ), QChar( 65047 ) ).replace( QChar( 12311 ), QChar( 65048 ) ); 
   551   string = 
string.replace( QChar( 8230 ), QChar( 65049 ) ); 
   552   string = 
string.replace( QChar( 8212 ), QChar( 65073 ) ).replace( QChar( 8211 ), QChar( 65074 ) ); 
   553   string = 
string.replace( 
'_', QChar( 65075 ) ).replace( QChar( 65103 ), QChar( 65076 ) ); 
   554   string = 
string.replace( 
'(', QChar( 65077 ) ).replace( 
')', QChar( 65078 ) );
   555   string = 
string.replace( 
'{', QChar( 65079 ) ).replace( 
'}', QChar( 65080 ) );
   556   string = 
string.replace( 
'<', QChar( 65087 ) ).replace( 
'>', QChar( 65088 ) );
   557   string = 
string.replace( 
'[', QChar( 65095 ) ).replace( 
']', QChar( 65096 ) );
   558   string = 
string.replace( QChar( 12308 ), QChar( 65081 ) ).replace( QChar( 12309 ), QChar( 65082 ) );   
   559   string = 
string.replace( QChar( 12304 ), QChar( 65083 ) ).replace( QChar( 12305 ), QChar( 65084 ) );   
   560   string = 
string.replace( QChar( 12298 ), QChar( 65085 ) ).replace( QChar( 12299 ), QChar( 65086 ) ); 
   561   string = 
string.replace( QChar( 12300 ), QChar( 65089 ) ).replace( QChar( 12301 ), QChar( 65090 ) );   
   562   string = 
string.replace( QChar( 12302 ), QChar( 65091 ) ).replace( QChar( 12303 ), QChar( 65092 ) );   
   568   , mReplacement( replacement )
   569   , mCaseSensitive( caseSensitive )
   570   , mWholeWordOnly( wholeWordOnly )
   572   if ( mWholeWordOnly )
   573     mRx = QRegExp( QString( 
"\\b%1\\b" ).arg( mMatch ),
   574                    mCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive );
   579   QString result = input;
   580   if ( !mWholeWordOnly )
   582     return result.replace( mMatch, mReplacement, mCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive );
   586     return result.replace( mRx, mReplacement );
   593   map.insert( QStringLiteral( 
"match" ), mMatch );
   594   map.insert( QStringLiteral( 
"replace" ), mReplacement );
   595   map.insert( QStringLiteral( 
"caseSensitive" ), mCaseSensitive ? 
"1" : 
"0" );
   596   map.insert( QStringLiteral( 
"wholeWord" ), mWholeWordOnly ? 
"1" : 
"0" );
   603                                properties.value( QStringLiteral( 
"replace" ) ),
   604                                properties.value( QStringLiteral( 
"caseSensitive" ), QStringLiteral( 
"0" ) ) == QLatin1String( 
"1" ),
   605                                properties.value( QStringLiteral( 
"wholeWord" ), QStringLiteral( 
"0" ) ) == QLatin1String( 
"1" ) );
   610   QString result = input;
   611   const auto constMReplacements = mReplacements;
   614     result = r.process( result );
   621   const auto constMReplacements = mReplacements;
   625     QDomElement propEl = doc.createElement( QStringLiteral( 
"replacement" ) );
   626     QgsStringMap::const_iterator it = props.constBegin();
   627     for ( ; it != props.constEnd(); ++it )
   629       propEl.setAttribute( it.key(), it.value() );
   631     elem.appendChild( propEl );
   637   mReplacements.clear();
   638   QDomNodeList nodelist = elem.elementsByTagName( QStringLiteral( 
"replacement" ) );
   639   for ( 
int i = 0; i < nodelist.count(); i++ )
   641     QDomElement replacementElem = nodelist.at( i ).toElement();
   642     QDomNamedNodeMap nodeMap = replacementElem.attributes();
   645     for ( 
int j = 0; j < nodeMap.count(); ++j )
   647       props.insert( nodeMap.item( j ).nodeName(), nodeMap.item( j ).nodeValue() );
 static QString longestCommonSubstring(const QString &string1, const QString &string2, bool caseSensitive=false)
Returns the longest common substring between two strings. 
 
A representation of a single string replacement. 
 
static QString substituteVerticalCharacters(QString string)
Returns a string with characters having vertical representation form substituted. ...
 
static QString wordWrap(const QString &string, int length, bool useMaxLineLength=true, const QString &customDelimiter=QString())
Automatically wraps a string by inserting new line characters at appropriate locations in the string...
 
Simple title case conversion - does not fully grammatically parse the text and uses simple rules only...
 
Convert the string to upper camel case. Note that this method does not unaccent characters. 
 
QMap< QString, QString > QgsStringMap
 
static QString soundex(const QString &string)
Returns the Soundex representation of a string. 
 
void writeXml(QDomElement &elem, QDomDocument &doc) const
Writes the collection state to an XML element. 
 
static QgsStringReplacement fromProperties(const QgsStringMap &properties)
Creates a new QgsStringReplacement from an encoded properties map. 
 
static QString capitalize(const QString &string, Capitalization capitalization)
Converts a string by applying capitalization rules to the string. 
 
static int levenshteinDistance(const QString &string1, const QString &string2, bool caseSensitive=false)
Returns the Levenshtein edit distance between two strings. 
 
Convert just the first letter of each word to uppercase, leave the rest untouched. 
 
Convert all characters to uppercase. 
 
Capitalization
Capitalization options. 
 
QgsStringMap properties() const
Returns a map of the replacement properties. 
 
static QString ampersandEncode(const QString &string)
Makes a raw string safe for inclusion as a HTML/XML string literal. 
 
QString process(const QString &input) const
Processes a given input string, applying any valid replacements which should be made. 
 
Mixed case, ie no change. 
 
Convert all characters to lowercase. 
 
void readXml(const QDomElement &elem)
Reads the collection state from an XML element. 
 
QString process(const QString &input) const
Processes a given input string, applying any valid replacements which should be made using QgsStringR...
 
QgsStringReplacement(const QString &match, const QString &replacement, bool caseSensitive=false, bool wholeWordOnly=false)
Constructor for QgsStringReplacement. 
 
static QString insertLinks(const QString &string, bool *foundLinks=nullptr)
Returns a string with any URL (e.g., http(s)/ftp) and mailto: text converted to valid HTML <a ...
 
static QString htmlToMarkdown(const QString &html)
Convert simple HTML to markdown. 
 
static int hammingDistance(const QString &string1, const QString &string2, bool caseSensitive=false)
Returns the Hamming distance between two strings.