Non matching number Regex in Qt - c++

I am working on a number parser for q Qt calculator. I have create a few regex in order to match with the different kinds of number:
Rationnal : ^[+-]?\d+\/[+-]?\d+$
Integer : ^[+-]?\d+\.?0*$
Real : ^[+-]?\d*\.0*[1-9][0-9]*$
Complexe : ^[+-]?[0-9]*(\.[0-9]*|\/[+-]?[0-9]+)?\$[+-]?[0-9]*(\.[0-9]*|\/[+-]?[0-9]+)?$
I try to use them with the following fuction on QString:
parser.h :
bool isRationnal(const QString s)
{
QRegExp ratioExp ("^[+-]?\d+\/[+-]?\d+$");
return ratioExp.exactMatch(s);
}
bool isInteger(const QString s)
{
QRegExp regExp ("^[+-]?\d+\.?0*$");
return regExp.exactMatch(s);
}
bool isReal(const QString s)
{
QRegExp regExp ("^[+-]?\d*\.0*[1-9][0-9]*$");
return regExp.exactMatch(s);
}
bool isComplex(const QString s)
{
QRegExp regExp ("^[+-]?[0-9]*(\.[0-9]*|\/[+-]?[0-9]+)?\$[+-]?[0-9]*(\.[0-9]*|\/[+-]?[0-9]+)?$");
return regExp.exactMatch(s);
}
bool isNumber(const QString s){
bool ok=false;
s.toInt(&ok);
return ok;
}
main.c :
QString test ="6/90";
if(isReal(test))
printf("real\n");
if(isInteger(test))
printf("Integer\n");
if(isRationnal(test))
printf("Rationnal\n");
if(isNumber(test))
printf("Number\n");
else printf("et merde\n");
QRegExp ratioExp ("^[+-]?\d+\/[+-]?\d+$");
QRegExp IntExp ("^[+-]?\d+\.?0*$");
QRegExp RealExp ("^[+-]?\d*\.0*[1-9][0-9]*$");
QRegExp CplxExp ("^[+-]?[0-9]*(\.[0-9]*|\/[+-]?[0-9]+)?\$[+-]?[0-9]*(\.[0-9]*|\/[+-]?[0-9]+)?$");
if(ratioExp.isValid())
printf("ratio valide\n");
if(IntExp.isValid())
printf("int valide\n");
if(RealExp.isValid())
printf("real valide\n");
if(CplxExp.isValid())
printf("cplx valide\n");
return 0;
}
I tried to run this code with several QString which are numbers, but it usually fail. Especially : it doesn't mathc with number if there is only one caracter like test="4".
Do you know why are those boolean function failing? Maybe I am using the wrong Qt function but after trying several this one looks like what I am searching for.
Feel free to give constructive critism,
Thank you very much,
Théophile

Your expression is fine, but replace \d with \\d. Tested you code in my program.
And I really recommend to this site which can debug your expression online.
Details from Qt Official Documentation :
Note: The C++ compiler transforms backslashes in strings. To include a
\ in a regexp, enter it twice, i.e. \. To match the backslash
character itself, enter it four times, i.e. \\.

Related

How to split QString based on a given character length?

I am trying to split QString based on 19 characters per group.
Here is the string:
+1.838212011719E+04-1.779050827026E+00 3.725290298462E-09 0.000000000000E+00
I wish to split it into:
+1.838212011719E+04
-1.779050827026E+00
3.725290298462E-09
0.000000000000E+00
I have tryed using QRegularExpression, but I could not come up with a solution.
How to do this?
Solution
I would suggest you to use a loop instead of a regular expression.
Example
Here is an example I have prepared for you of how to implement this in C++:
bool splitString(const QString &str, int n, QStringList &list)
{
if (n < 1)
return false;
QString tmp(str);
list.clear();
while (!tmp.isEmpty()) {
list.append(tmp.left(n));
tmp.remove(0, n);
}
return true;
}
Note: Optionally you can use QString::trimmed(), i.e. list.append(tmp.left(n).trimmed());, in order to get rid of the leading whitespace.
Result
Testing the example with your input:
QStringList list;
if (splitString("+1.838212011719E+04-1.779050827026E+00 3.725290298462E-09 0.000000000000E+00", 19, list))
qDebug() << list;
produces the following results:
without QString::trimmed()
("+1.838212011719E+04", "-1.779050827026E+00", " 3.725290298462E-09", " 0.000000000000E+00")
with QString::trimmed()
("+1.838212011719E+04", "-1.779050827026E+00", "3.725290298462E-09", "0.000000000000E+00")
Use this regular expression:
^(.{19})(.{19})(.{19})(.{19})
I would also recommend using a tool like RegEx101. Give it a try ans see what happens.

In Qt, what takes the least amount of code to replace string matches with regular expression captures?

I was hoping that QString would allow this:
QString myString("School is LameCoolLame and LameRadLame");
myString.replace(QRegularExpression("Lame(.+?)Lame"),"\1");
Leaving
"School is Cool and Rad"
Instead from what I saw in the docs, doing this is a lot more convoluted requiring you to do (from the docs):
QRegularExpression re("\\d\\d \\w+");
QRegularExpressionMatch match = re.match("abc123 def");
if (match.hasMatch()) {
QString matched = match.captured(0); // matched == "23 def"
// ...
}
Or in my case something like this:
QString myString("School is LameCoolLame and LameRadLame");
QRegularExpression re("Lame(.+?)Lame");
QRegularExpressionMatch match = re.match(myString);
if (match.hasMatch()) {
for (int i = 0; i < myString.count(re); i++) {
QString newString(match.captured(i));
myString.replace(myString.indexOf(re),re.pattern().size, match.captured(i));
}
}
And that doesn't even seem to work, (I gave up actually). There must be an easier more convenient way. For the sake of simplicity and code readability, I'd like to know the methods which take the least lines of code to accomplish this.
Thanks.
QString myString("School is LameCoolLame and LameRadLame");
myString.replace(QRegularExpression("Lame(.+?)Lame"),"\\1");
Above code works as you expected. In your version, you forgot to escape the escape character itself.

Qt5 Qregexp : why my pattern can't work?

I get this problem When I open a text file, I can't get any matched string. Then I test this pattern: .* but I can either get nothing. I'm sure the text file can be read, and the pattern can be accepted in grep. Thank you.
QList<Nmap_result> ans;
QFile file(path);
if(!file.open(QFile::ReadOnly|QFile::Text))
{
exit(1);
}
QString text = file.readAll();
QRegExp reg(QRegExp::escape(".*"));
reg.indexIn(text);
qDebug()<<reg.capturedTexts().join("|")<<endl<<reg.captureCount()<<endl;
Sorry, I should not use escape. But when I change it like this:
QString text = file.readAll();
qDebug()<<text<<endl;
QRegExp reg("[0-9]");
//reg.indexIn(text); //first bind expr test
reg.exactMatch(text); //second bind expr test
qDebug()<<reg.capturedTexts().join("|!!!!!|")<<endl<<reg.captureCount()<<endl;
I use
reg.indexIn(text);
to bind this string to regexp, it return a number,but when I use the next expr
reg.exeacMatch(text);
I get nothing.
Why do you call QRegExp::escape method ?
Try this instead:
QRegExp reg(".*");
Calling QRegExp::escape, your regular expression becomes similar to this string: "\\.\\*". This string indicates that you want to match a dot immediatly followed by a star. This is not the intented use here: match zero or more characters (.*).

Comparing regex in qt

I have a regex which I hope means any file with extension listed:
((\\.cpp$)|(\\.cxx$)|(\\.c$)|(\\.hpp$)|(\\.h$))
How to compare it in Qt against selected file?
Your actual RegEx itself doesn't have double backslashes (just when you fit it into a string literal). And you'll need some kind of wildcard if you want to use it to match full filenames. There's a semantic issue of whether you want a file called just ".cpp" to match or not. What about case sensitivity?
I'll assume for the moment that you want at least one other character in the beginning and use .+:
.+((\.cpp$)|(\.cxx$)|(\.c$)|(\.hpp$)|(\.h$))
So this should work:
QRegExp rx (".+((\\.cpp$)|(\\.cxx$)|(\\.c$)|(\\.hpp$)|(\\.h$))");
bool isMatch = rx.exactMatch(filename);
But with the expressive power of a whole C++ compiler at your beck and call, it can be a bit stifling to use regular expressions. You might have an easier time adapting code if you write it more like:
bool isMatch = false;
QStringList fileExtensionList;
fileExtensionList << "CPP" << "CXX" << "C" << "HPP" << "H";
QStringList splitFilenameList = filename.split(".");
if(splitFilenameList.size() > 1) {
QString fileExtension = splitFilenameList[splitFilenameList.size() - 1];
isMatch = fileExtensionList.contains(fileExtension.toUpper()));
}

Regex Rejecting matches because of Instr

What's the easiest way to do an "instring" type function with a regex? For example, how could I reject a whole string because of the presence of a single character such as :? For example:
this - okay
there:is - not okay because of :
More practically, how can I match the following string:
//foo/bar/baz[1]/ns:foo2/#attr/text()
For any node test on the xpath that doesn't include a namespace?
(/)?(/)([^:/]+)
Will match the node tests but includes the namespace prefix which makes it faulty.
I'm still not sure whether you just wanted to detect if the Xpath contains a namespace, or whether you want to remove the references to the namespace. So here's some sample code (in C#) that does both.
class Program
{
static void Main(string[] args)
{
string withNamespace = #"//foo/ns2:bar/baz[1]/ns:foo2/#attr/text()";
string withoutNamespace = #"//foo/bar/baz[1]/foo2/#attr/text()";
ShowStuff(withNamespace);
ShowStuff(withoutNamespace);
}
static void ShowStuff(string input)
{
Console.WriteLine("'{0}' does {1}contain namespaces", input, ContainsNamespace(input) ? "" : "not ");
Console.WriteLine("'{0}' without namespaces is '{1}'", input, StripNamespaces(input));
}
static bool ContainsNamespace(string input)
{
// a namspace must start with a character, but can have characters and numbers
// from that point on.
return Regex.IsMatch(input, #"/?\w[\w\d]+:\w[\w\d]+/?");
}
static string StripNamespaces(string input)
{
return Regex.Replace(input, #"(/?)\w[\w\d]+:(\w[\w\d]+)(/?)", "$1$2$3");
}
}
Hope that helps! Good luck.
Match on :? I think the question isn't clear enough, because the answer is so obvious:
if(Regex.Match(":", input)) // reject
You might want \w which is a "word" character. From javadocs, it is defined as [a-zA-Z_0-9], so if you don't want underscores either, that may not work....
I dont know regex syntax very well but could you not do:
[any alpha numeric]\*:[any alphanumeric]\*
I think something like that should work no?
Yeah, my question was not very clear. Here's a solution but rather than a single pass with a regex, I use a split and perform iteration. It works as well but isn't as elegant:
string xpath = "//foo/bar/baz[1]/ns:foo2/#attr/text()";
string[] nodetests = xpath.Split( new char[] { '/' } );
for (int i = 0; i < nodetests.Length; i++)
{
if (nodetests[i].Length > 0 && Regex.IsMatch( nodetests[i], #"^(\w|\[|\])+$" ))
{
// does not have a ":", we can manipulate it.
}
}
xpath = String.Join( "/", nodetests );