QString replace only first occurrence - c++

Is there simple way of replacing only first occurrence of some substring by other substring in QString? It can be at any position.

You could try this:
QString str("this is a string"); // The initial string.
QString subStr("is"); // String to replace.
QString newStr("at"); // Replacement string.
str.replace(str.indexOf(subStr), subStr.size(), newStr);
Resulting string will be:
that at a string

There is no convenience method for the operation you wish to have. However, you can use the following two methods to build your custom operation:
int QString::indexOf(const QString & str, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
Returns the index position of the first occurrence of the string str in this string, searching forward from index position from. Returns -1 if str is not found.
If cs is Qt::CaseSensitive (default), the search is case sensitive; otherwise the search is case insensitive.
and
QString & QString::replace(int position, int n, const QString & after)
Replaces n characters beginning at index position with the string after and returns a reference to this string.
Note: If the specified position index is within the string, but position + n goes outside the strings range, then n will be adjusted to stop at the end of the string.
Now, putting all that into practice, you could write something as follows:
main.cpp
#include <QString>
#include <QDebug>
int main()
{
QString initialString = QLatin1String("foo bar baz");
QString fooString = QLatin1String("foo");
initialString.replace(initialString.indexOf(fooString),
fooString.size(), QLatin1String("stuff"));
qDebug() << initialString;
return 0;
}
main.pro
TEMPLATE = app
TARGET = main
QT = core
SOURCES += main.cpp
Build and Run
qmake && make && ./main
Output
"stuff bar baz"

This is pretty much the way QString::replace(QRegularExpression, ... does it. Since it's possible that literal backslashes could be part of replace pattern, those need to be captured differently. Note that actual replacement happens right-to-left to preserve leftward offset validity. It's possible to put this more compactly, but easier to debug in this form.
QRegularExpression regex = QRegularExpression(regex_pattern);
if (regex.isValid() and
(regex_pattern.length() > 0)) {
QRegularExpressionMatchIterator regex_iterator =
regex.globalMatch(target_text, Apply_Target_Offset,
QRegularExpression::PartialPreferCompleteMatch);
if (regex_iterator.hasNext()) {
// At least one found
QRegularExpressionMatch match = regex_iterator.next();
if (match.hasMatch() and (not match.hasPartialMatch())) {
// This is the first match, and it's complete
int match_begin = match.capturedStart();
int match_end = match.capturedEnd();
int match_length = match.capturedLength();
QStringList captured;
const int capture_groups_count = regex.captureCount() + 1;
for (int capture_group_idx = 0; capture_group_idx < capture_groups_count; ++capture_group_idx) {
captured.append(match.captured(capture_group_idx));
}
QString replace_pattern = Apply_Replace_Pattern->toPlainText();
QString replace_text = replace_pattern;
QList<QRegularExpressionMatch> replace_pattern_match_list;
QRegularExpression replace_pattern_regex = QRegularExpression("(?:\\\\\\\\)+|(?:\\\\(\\d+))");
if (replace_pattern_regex.isValid()) {
QRegularExpressionMatchIterator replace_pattern_regex_iterator =
replace_pattern_regex.globalMatch(replace_pattern);
while (replace_pattern_regex_iterator.hasNext()) {
QRegularExpressionMatch replace_pattern_match = replace_pattern_regex_iterator.next();
bool no_error;
replace_pattern_match.captured().right(1).toInt(&no_error);
// Only accept backreferences w/ numbers
if (no_error) replace_pattern_match_list.append(replace_pattern_match);
}
while (replace_pattern_match_list.count() > 0) {
QRegularExpressionMatch replace_pattern_match = replace_pattern_match_list.takeLast();
int cap_idx = replace_pattern_match.captured(1).toInt();
if (cap_idx < captured.count()) {
replace_text.replace(replace_pattern_match.capturedStart(),
(replace_pattern_match.capturedEnd() -
replace_pattern_match.capturedStart()),
captured[cap_idx]);
}
}
// Render '\' characters properly
replace_text.replace("\\\\", "\\");
}
target_text.replace(match_begin, (match_end - match_begin), replace_text);
}
}
}

//------------------------------------------------------------------
QString & replace_first(QString &io_haystack, const QString & sub_str, const QString & new_str)
{
io_haystack.replace(io_haystack.indexOf(sub_str), sub_str.size(), new_str);
return io_haystack;
} // replace_first
//------------------------------------------------------------------
QString & replace_first(QString &io_haystack, const QRegularExpression & sub_regx, const QString & new_str)
{
QRegularExpressionMatch match;
match = sub_regx.match(io_haystack);
if (match.hasMatch()) {
QString sub_str = match.captured(0);
io_haystack.replace(io_haystack.indexOf(sub_str), sub_str.size(), new_str);
}
return io_haystack;
} // replace_first

Related

QT regex display the full text instead of what is asked

i'm having an issue with my regex here where i'm trying to get the longitude of a gps data and instead it's giving me the entire coordinate
my code
QRegularExpression GPSLong("((?<=,\\s)([0-9](.*?)+(W|E)))");
while (!file.atEnd())
{
QString line = file.readLine();
i++;
QRegularExpressionMatch matchGPSLong = GPSLong.match(line);
if ( matchGPSLong.hasMatch())
{
QString GPSLongCoordinates = matchGPSLong.captured(0);
qDebug()<< "Longitude : " <<GPSLongCoordinates;
}
//....
}
An example line is
43° 31' 8.3" N, 5° 3' 13.2" E, 0m
And the result I'm getting is
Longitude : 43° 31' 8.3" N, 5° 3' 13.2" E
But I was expecting
Longitude : 5° 3' 13.2" E
i'm using Qt 5.9.2 on Windows10 and can't update to a newer version because of the software i'm working on
EDIT : i managed to find a solution, instead of getting DMS(Degrees, Minute, Second) coordinates i switched to DD (Decimal Degrees) and then used global match to obtain a QRegularExpressionMatchIterator
here's the fixed and working code :
QRegularExpression GPSRegex("-|[0-9]+\\.+[0-9]+");
while (!file.atEnd()) {
QString line = file.readLine();
i++;
QRegularExpressionMatch matchGPSLat = GPSRegex.match(line);
auto matchIterator = CoordinateRegex.globalMatch(line);
if (matchGPSLat.hasMatch()) {
QString GPSLatCoordinates = matchGPSLat.captured(0);
while(matchIterator.hasNext())
{
auto result = matchIterator.next();
if (!matchIterator.hasNext())
{
GPSLongCoordinates = result.captured(0);
}
}
double GPSlat = GPSLatCoordinates.toDouble();
double GPSLong = GPSLongCoordinates.toDouble();
}
}
You want:
QString GPSLongCoordinates = matchGPSLong.captured(1);
instead of:
QString GPSLongCoordinates = matchGPSLong.captured(0);
The 0-index of a capture is the entire match. If any groups match, those groups starting at index 1 are the respective matches.

Search a string against multiple string arrays

I have a input string and need to run through it and see if it matches certain words. I have multiple string arrays but not sure whats an efficient way to check the string agianst all the arrays.
String Arrays:
string checkPlayType(string printDescription)
{
const string DeepPassRight[3] = {"deep" , "pass" , "right"};
const string DeepPassLeft[3] = {"deep" , "pass" , "left"};
const string DeepPassMiddle[3] = {"deep" , "pass" , "middle"};
const string ShortPassRight[3] = {"short" , "pass" , "right"};
const string ShortPassLeft[3] = {"short" , "pass" , "left"};
const string ShortPassMiddle[3] = {"short" , "pass" , "middle"};
//Must contain right but not pass
const string RunRight = "right";
//Must contain right but not pass
const string RunLeft = "left";
//Must contain middle but not pass
const string RunMiddle = "middle";
const string FieldGoalAttempt[2] = {"field" , "goal" };
const string Punt = "punt";
}
Sample Input: (13:55) (Shotgun) P.Manning pass incomplete short right to M.Harrison.
Assuming this is our only input...
Sample Output:
Deep Pass Right: 0%
Deep Pass Left: 0%
Deep Pass Middle: 0%
Short Pass Right: 100%
Shor Pass Left:0%
...
..
..
you may want something similar to:
void checkPlayType(const std::vector<std::string>& input)
{
std::set<std::string> s;
for (const auto& word : input) {
s.insert(word);
}
const bool deep_present = s.count("deep");
const bool pass_present = s.count("pass");
const bool right_present = s.count("right");
const bool left_present = s.count("left");
// ...
if (deep_present && pass_present && right_present) { /* increase DeepPassRight counter */}
if (deep_present && pass_present && left_present) { /* increase DeepPassLeft counter */}
// ...
}
Try regular expressions:
if found "pass" then
if regexp "(deep|short).*(left|right|middle)"
Hooray!
else if regexp "(left|right|middle).*(deep|short)"
Hooray!
else
Aye, Caramba!
else
Aye, Caramba!
You can go over your arrays and search for the words are stored in the array within the input string. Use std functions for better performance. For example:
const string DeepPassRight[3] = {"deep" , "pass" , "right"};
int i = 0;
for(;i<3;i++)
{
string s = " ";
s.append(DeepPassRight[i]);
s.append(" ");
std::size_t found = printDescription.find(s);
if (found ==std::string::npos)
break;
}
if(i == 3)
// printDescription contains all DeepPassRight's members!
if(i== 2)
// just two words were found

QString parse system variables

How I should parse QString, which contains system variables ?What I want:
QString path = "%WINDIR%\\System32\\";
QString output = parse(path);
QDebug()<<output; \\ output is "C:\\Windows\\System32\\"
I think you want something like this:
// Untested
QString parse(QString str)
{
int pos = 0;
QRegExp rx("%([^%]+)%"); // Match env var between two '%'
rx.setMinimal(true);
while((pos = rx.indexIn(str, pos)) != -1)
{
// Replace env var
QString capture = rx.cap(1);
QString replacement = getenv(capture.toAscii());
str.replace("%" + capture + "%", replacement);
// Skip env var + two '%'
pos += rx.matchedLength() + 2;
}
return str;
}
QString path = parse("%WINDIR%\\System32");
I think, this is what you looking for. Please try this
QString windir = getenv ("WINDIR"); // Expanded
if (windir.isEmpty()) {
fprintf(stderr, "Generator requires WINDIRto be set\n");
}
windir += "\\System32";
qDebug()<<windir;

extract domain between two words

I have in a log file some lines like this:
11-test.domain1.com Logged ...
37-user1.users.domain2.org Logged ...
48-me.server.domain3.net Logged ...
How can I extract each domain without the subdomains? Something between "-" and "Logged".
I have the following code in c++ (linux) but it doesn't extract well. Some function which is returning the extracted string would be great if you have some example of course.
regex_t preg;
regmatch_t mtch[1];
size_t rm, nmatch;
char tempstr[1024] = "";
int start;
rm=regcomp(&preg, "-[^<]+Logged", REG_EXTENDED);
nmatch = 1;
while(regexec(&preg, buffer+start, nmatch, mtch, 0)==0) /* Found a match */
{
strncpy(host, buffer+start+mtch[0].rm_so+3, mtch[0].rm_eo-mtch[0].rm_so-7);
printf("%s\n", tempstr);
start +=mtch[0].rm_eo;
memset(host, '\0', strlen(host));
}
regfree(&preg);
Thank you!
P.S. no, I cannot use perl for this because this part is inside of a larger c program which was made by someone else.
EDIT:
I replace the code with this one:
const char *p1 = strstr(buffer, "-")+1;
const char *p2 = strstr(p1, " Logged");
size_t len = p2-p1;
char *res = (char*)malloc(sizeof(char)*(len+1));
strncpy(res, p1, len);
res[len] = '\0';
which is extracting very good the whole domain including subdomains.
How can I extract just the domain.com or domain.net from abc.def.domain.com ?
is strtok a good option and how can I calculate which is the last dot ?
#include <vector>
#include <string>
#include <boost/regex.hpp>
int main()
{
boost::regex re(".+-(?<domain>.+)\\s*Logged");
std::string examples[] =
{
"11-test.domain1.com Logged ...",
"37-user1.users.domain2.org Logged ..."
};
std::vector<std::string> vec(examples, examples + sizeof(examples) / sizeof(*examples));
std::for_each(vec.begin(), vec.end(), [&re](const std::string& s)
{
boost::smatch match;
if (boost::regex_search(s, match, re))
{
std::cout << match["domain"] << std::endl;
}
});
}
http://liveworkspace.org/code/1983494e6e9e884b7e539690ebf98eb5
something like this with boost::regex. Don't know about pcre.
Is the in a standard format?
it appears so, is there a split function?
Edit:
Here is some logic.
Iterate through each domain to be parsed
Find a function to locate the index of the first string "-"
Next find the index of the second string minus the first string "Logged"
Now you have the full domain.
Once you have the full domain "Split" the domain into your object of choice (I used an array)
now that you have the array broken apart locate the index of the value you wish to reassemble (concatenate) to capture only the domain.
NOTE Written in C#
Main method which defines the first value and the second value
`static void Main(string[] args)
{
string firstValue ="-";
string secondValue = "Logged";
List domains = new List { "11-test.domain1.com Logged", "37-user1.users.domain2.org Logged","48-me.server.domain3.net Logged"};
foreach (string dns in domains)
{
Debug.WriteLine(Utility.GetStringBetweenFirstAndSecond(dns, firstValue, secondValue));
}
}
`
Method to parse the string:
`public string GetStringBetweenFirstAndSecond(string str, string firstStringToFind, string secondStringToFind)
{
string domain = string.Empty;
if(string.IsNullOrEmpty(str))
{
//throw an exception, return gracefully, whatever you determine
}
else
{
//This can all be done in one line, but I broke it apart so it can be better understood.
//returns the first occurrance.
//int start = str.IndexOf(firstStringToFind) + 1;
//int end = str.IndexOf(secondStringToFind);
//domain = str.Substring(start, end - start);
//i.e. Definitely not quite as legible, but doesn't create object unnecessarily
domain = str.Substring((str.IndexOf(firstStringToFind) + 1), str.IndexOf(secondStringToFind) - (str.IndexOf(firstStringToFind) + 1));
string[] dArray = domain.Split('.');
if (dArray.Length > 0)
{
if (dArray.Length > 2)
{
domain = string.Format("{0}.{1}", dArray[dArray.Length - 2], dArray[dArray.Length - 1]);
}
}
}
return domain;
}
`

How can i convert entity character(Escape character) to HTML in QT?

I want to convert entity character(Escape character) to HTML in QT, please help me....
i.e: I want to replace " with ", > with >
=====This is my code that not worked====
QString MyApp::ReplaceString(const QString Data, const QString &Before, const QString &After)
{
QString Result = Data;
Result.replace(Before, After, Qt::CaseInsensitive);
return Result;
}
========
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
QByteArray data=pReply->readAll();
QString str = codec->toUnicode((const char *)data);
str = Qt::escape(str);
str = ReplaceString(str, """, "\"");
str = ReplaceString(str,">", ">");
I'm not sure I understand what you want, just guessing. You can use QTextDocument. Try something like this:
QTextDocument text;
text.setHtml("<>"");
QString plain = text.toPlainText();
qDebug("%s.", qPrintable(plain));
Remember that QTextDocument needs the gui module.
I think this will solve your problem.
QString escaped=
QString(myhtml).replace("&","&").replace(">",">").replace("<","<");
Test escape() function:
QString plain = "#include <QtCore>"
QString html = Qt::escape(plain);
// html == "#include <QtCore>"
and convertFromPlainText() function:
QString Qt::convertFromPlainText ( const QString & plain, WhiteSpaceMode mode = WhiteSpacePre )
Hello to convert non ASCII character to &#XXX; (where XXX is a number):
/***************************************************************************//*!
* #brief Encode all non ASCII characters into &#...;
* #param[in] src Text to analyze
* #param[in,opt] force Force the characters "list" to be converted.
* #return ASCII text compatible.
*
* #note Original code: http://www.qtforum.org/article/3891/text-encoding.html
*
* #warning Do not forget to use QString::fromUtf8()
*/
QString encodeEntities( const QString& src, const QString& force=QString() )
{
QString tmp(src);
uint len = tmp.length();
uint i = 0;
while( i<len )
{
if( tmp[i].unicode() > 128 || force.contains(tmp[i]) ){
QString rp = "&#"+QString::number(tmp[i].unicode())+";";
tmp.replace(i,1,rp);
len += rp.length()-1;
i += rp.length();
}else{
++i;
}
}
return tmp;
}
/***************************************************************************//*!
* #brief Allows decode &#...; into UNICODE (utf8) character.
* #param[in] src Text to analyze
* #return UNICODE (utf8) text.
*
* #note Do not forget to include QRegExp
*/
QString decodeEntities( const QString& src )
{
QString ret(src);
QRegExp re("&#([0-9]+);");
re.setMinimal(true);
int pos = 0;
while( (pos = re.indexIn(src, pos)) != -1 )
{
ret = ret.replace(re.cap(0), QChar(re.cap(1).toInt(0,10)));
pos += re.matchedLength();
}
return ret;
}
Basic usage:
qDebug() << encodeEntities(QString::fromUtf8("éà#<>hello the world €"),QString("<>"));
// Will print: éà#<>hello the world €
qDebug() << decodeEntities("aßéplopéàçê€");
// Will print: hello world