PDA

View Full Version : Ip Address Validation



bruccutler
23rd March 2007, 20:33
I've checked a lot of sites, but haven't found a definitive IP Address validation routine. I'm using the IPAddress mask, but is there a better way to validate the address than capturing the finishedEditing signal and doing it via code (x > 0 && x< 256)?

Also, how do I tell Qt to keep the focus in the current field if the entry is in error? lineEdit.SetFocus() gives me recursion problems with my finishedEditing signal.

- BRC

Jimmy2775
23rd March 2007, 20:50
...is there a better way to validate the address than capturing the finishedEditing signal and doing it via code (x > 0 && x< 256)?

Also, how do I tell Qt to keep the focus in the current field if the entry is in error? lineEdit.SetFocus() gives me recursion problems with my finishedEditing signal.

A QRegExpValidator might be what you're looking for in both cases here.

bruccutler
23rd March 2007, 21:08
No - reg expression will check the values, but won't do a full check for 1-255 for all values. At least not one that I've ever seen.
- Bruce

Brandybuck
23rd March 2007, 21:39
No - reg expression will check the values, but won't do a full check for 1-255 for all values.
You could, but it would be a fairly complex regular expression.

bruccutler
23rd March 2007, 21:54
So - what is the right way to do this? I think I will set it aside, since I'm sure someone out there has solved this problem with Qt.
- BRC

Jimmy2775
24th March 2007, 00:12
I think you could do it with the combination of a masked line edit, and a QRegExpValidator that checks for a regex like this: (?:1\d?\d?|2(?:[0-4]\d?|[6789]|5[0-5]?)?|[3-9]\d?|0)(?:\.(?:1\d?\d?|2(?:[0-4]\d?|[6789]|5[0-5]?)?|[3-9]\d?|0)){3}

That said, I haven't tried this myself, so who knows... ;)

wysota
24th March 2007, 00:31
Oh my God, what an expression.... How about:

class IP4Validator : public QValidator {
public:
IP4Validator(QObject *parent=0) : QValidator(parent){}
void fixup(QString &input) const {}
State validate(QString &input, int &pos) const {
if(input.isEmpty()) return Acceptable;
QStringList slist = input.split(".");
int s = slist.size();
if(s>4) return Invalid;
bool emptyGroup = false;
for(int i=0;i<s;i++){
bool ok;
if(slist[i].isEmpty()){
emptyGroup = true;
continue;
}
int val = slist[i].toInt(&ok);
if(!ok || val<0 || val>255) return Invalid;
}
if(s<4 || emptyGroup) return Intermediate;
return Acceptable;
}
};

bruccutler
6th April 2007, 23:16
This worked perfectly! Thanks so much! It took me a while to get back to it, but this really did the job!

przemoc
14th March 2008, 19:15
I think you could do it with the combination of a masked line edit, and a QRegExpValidator that checks for a regex like this: (?:1\d?\d?|2(?:[0-4]\d?|[6789]|5[0-5]?)?|[3-9]\d?|0)(?:\.(?:1\d?\d?|2(?:[0-4]\d?|[6789]|5[0-5]?)?|[3-9]\d?|0)){3}

That said, I haven't tried this myself, so who knows... ;)
I know that problem is already solved, but... it's definetely too long regexp. I love the power of regular expressions, so here is my shorter version (w/o non-capturing parentheses (http://doc.trolltech.com/latest/qregexp.html#capturing-text), for increased readability), where each octet range from 0 to 255:

^0*(2(5[0-5]|[0-4]\d)|1?\d{1,2})(\.0*(2(5[0-5]|[0-4]\d)|1?\d{1,2})){3}$

QRegExpValidator of course doesn't need ^ and $ assertions.

longtrue
19th March 2008, 04:17
But how to combine with setMask("000.000.000.000;")?

wysota
19th March 2008, 06:32
You can't. But the validator does almost the same job, especially if you implement its fixup method.

fruzzo
7th May 2008, 15:36
Hi I've the same problem...I've to implement a dialog like WinXp TCP/IP Properties of Network Connections->MyConnection Properties:

http://www.windowsnetworking.com/img/gifics/winrlcl1.gif

How use IP4Validator with that kind of masks (IP Address and Subnet Mask) and how to implemet them?

wysota
7th May 2008, 18:25
You can cheat by having four frameless line edits and three labels grouped in a horizontal layout and with overriden key events to move to the next group when the previous one is filled or when arrow keys are used. That's probably what the mentioned dialog does, too.

fruzzo
9th May 2008, 09:59
You can cheat by having four frameless line edits and three <a href="http://www.ntsearch.com/search.php?q=labels&v=56">labels</a> grouped in a horizontal layout and with overriden key events to move to the next group when the previous one is filled or when arrow keys are used. That's probably what the mentioned dialog does, too.

Ah ok thanks...that's what I suppose!

And...about reimplementing the fixup function? what's the idea?

wysota
9th May 2008, 10:40
That you can change an invalid entry to a valid entry. For instance decimal point in some countries is the dot character and in others it is comma. Thanks to fixup you can detect a comma instead of a dot (or the other way round) and change it to something you consider valid.

fruzzo
9th May 2008, 14:19
That you can change an invalid entry to a valid entry. For instance decimal point in some countries is the dot character and in others it is comma. Thanks to fixup you can detect a comma instead of a dot (or the other way round) and change it to something you consider valid.


ah ok thanks...and about fixup to format string like inputmask?

wysota
9th May 2008, 15:24
You can do there whatever you like.

rajveer
11th November 2008, 05:13
can u please write the same code of urs for IP address validation.I cannt understand the code written here .

please help me out .

thanks

rajveer
14th November 2008, 05:50
how can i use fix up in Ip address validation

wysota
14th November 2008, 09:06
You get an invalid address as an argument and you need to change it to a valid one, for example change all values greater than 255 to 255.

Jothay
17th September 2010, 01:09
I realize this wins me necro-poster of the year, but I felt that this information would be beneficial to a lot of people.

The IP Address Validation (by Regex) and Mask issue was a tough cookie to crack. Setting one without the other usually worked but was flawed. I'd either not get the visual effect of having dots in the box or the user could enter invalid addresses (octets with values >255). Setting them together made it impossible to enter any value.

I found that the Class provided by Wysota solved the problem, but there was another limitation: it required you to use blanks as 0's, when I would prefer to use spaces.

Side-Note: I know a lot of people are looking for a good IP Address RegEx and here's the best one I've found so far:

\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b

What I ended up doing was expanding the code that Wysota provided to allow for spaces. Here is the excerpt:

if (slist[i].isEmpty() || slist[i] == " ") {
emptyGroup = true;
continue;
}

Now that fully works with a Mask of "000.000.000.000; " and your users cannot physically enter an invalid address.

Yay! That is settled. Now for my next problem. My specific programming needs also include being able to enter in a CIDR, which has a Mask of "009.009.009.009\/09". The first part of that works just like IP Addresses and the last part is limited to integers of 0-32.

To accomplish this, I duplicated Wysota's IP Address class to CIDRValidator. Here is the full code (tested and works):


class CIDRValidator : public QValidator {
public:
CIDRValidator(QObject *parent=0) : QValidator(parent) { }
void fixup(QString &/*input*/) const { }
State validate(QString &input, int &/*pos*/) const {
if(input.isEmpty()) { return Acceptable; }
QStringList slist = input.split(".");
int s = slist.size();
if (s > 4) { return Invalid; }
bool emptyGroup = false;
for (int i=0; i<s; i++) {
bool ok, ok2 = true;
QStringList ssplit = slist[i].split('/');
if (slist[i].isEmpty()
|| slist[i] == " "
|| ssplit.count() > 1 && (ssplit[0] == " " || ssplit[1] == " "))
{
emptyGroup = true;
continue;
}
int val = (ssplit.count() > 1 ? ssplit[0].toInt(&ok) : slist[i].toInt(&ok));
int cidval = (ssplit.count() > 1 ? ssplit[1].toInt(&ok2) : -1);
if((!ok || val<0 || val>255) || (ssplit.count() > 1 && (!ok2 || cidval<0 || cidval>32))) { return Invalid; }
}
if(s<4 || emptyGroup) return Intermediate;
return Acceptable;
}
};

I hope this information helps future searchers with setting up their own IP Address and CIDR Address boxes.

pavanbarot
5th October 2010, 07:38
With * support class C and D

class IPV4Validator : public QValidator {
public:
IPV4Validator(QObject *parent=0) : QValidator(parent){}
State validate ( QString & input, int & pos ) const {
if(input.isEmpty()) return Intermediate;
QStringList sections = input.split(".");
if(sections.count()>4)
return Invalid;
int newPos = pos;
int grp = 0;
bool isEmpty = false;
while(grp<sections.count()){
QString txt = sections[grp];
if(txt.count()>3){
if(sections.count()==4) return Invalid;
sections[grp] = txt.left(3);
sections.insert(grp+1, txt.mid(3));
newPos++;
} else if(txt.count()==0){
isEmpty = true;
grp++;
continue;
}
txt = sections[grp];
if(txt[0]=='0' && txt[1]=='0'){
sections[grp] = '0';
if(sections.count()<4){
sections.insert(grp+1, sections[grp]);
newPos++;
}
} else if(txt[0]=='0' && txt.count()>1){
sections[grp] = txt.mid(1);
newPos--;
}
bool ok;
int val = txt.toInt(&ok);
if(!ok)
{
if(grp < 2)
return Invalid;

if(txt != "*")
return Invalid;
}
if(val>255 && sections.count()<4){
sections[grp] = txt.left(2);
sections.insert(grp+1, txt.mid(2));
val = txt.left(2).toInt();
newPos++;
}
if(val>255||val<0) return Invalid;
grp++;
}
input = sections.join(".");
// if(newPos==input.count() && sections.count()<4 && input[input.count()-1]!='.' && sections.last().count()==3){
// newPos++;
// input += ".";
// }
pos = newPos;
if(sections.count()==4 && !isEmpty) return Acceptable;
return Intermediate;
}
};

Cotlone
1st November 2010, 00:31
Hey everyone,

Thanks for all the great help.
I've written some code based on Wysota's work in the previous post. I am implementing the QValidator::fixup() to do some simple alignment and checking of integer checking (The only case when a non integer can be entered is such as "a b", this must be intermediate). The problem is that fixup gets called twice if I press <Enter> to commit the changes to the QLineEdit - displaying two error pop ups. It gets called through two separate events, a keyPressEvent and a focusOutEvent. fixup() is called the second time before it has finished running the first time.




void IP4Validator::fixup(QString &input) const
{
QStringList slist = input.split(".");

bool intOk;
bool nonIntFound = false;
int s = slist.size();
for(int i=0;i<s;i++){
slist[i].toInt(&intOk);
if(!intOk){
// replace non-integers with a zero value
slist[i] = " 0";
nonIntFound = true;
}
else {
// force right align
slist[i].remove(" ");
slist[i] = slist[i].rightJustified(3,' ');
}
}
input = slist.join(".");
if(nonIntFound){
QMessageBox msgBox;
msgBox.setText("Error: The IPv4 address entered is incorrect");
msgBox.setInformativeText("At least one byte of the address was non-integer, it has now been set to 0. Please check the address");
msgBox.exec();
QApplication::processEvents();
}

}

IP4Validator::State IP4Validator::validate(QString &input, int &/*pos*/) const {
if(input.isEmpty()) return Acceptable;
QStringList slist = input.split(".");
int s = slist.size();
if(s>4) return Invalid;
bool emptyGroup = false;
bool ok;
for(int i=0;i<s;i++){

// This cannot be true with the inputMask set, as there will be space characters
if(slist[i].isEmpty()){
emptyGroup = true;
continue;
}

int val = slist[i].toInt(&ok);
if(!ok)
return Intermediate;
else
if(val<0 || val>255)
return Invalid;

}
if(s<4 || emptyGroup) return Intermediate;
input = slist.join(".");
return Acceptable;
}

I considered accessing the type() of the event which called fixup() to filter it but I'm not sure if this is the best way to get around this. Is there something more fundamental with my logic that I have missed here?

What is the best way to handle this?

Thanks in advance for your help!

- Cotlone

wysota
2nd November 2010, 19:24
IMO fixup() should not display any pop-ups. It should convert an invalid entry to a valid one. If you want to display a popup, you can handle focusOut()/returnPressed()/whatever, call the validator from there manually and display a popup if the validator claims the entry to be invalid.

Cotlone
2nd November 2010, 23:53
I agree, actually, I was thinking that earlier today.
What do you think about fixup() emitting a signal which can be handled elsewhere? Thanks for your help.

wysota
3rd November 2010, 00:45
What do you think about fixup() emitting a signal which can be handled elsewhere?
Bad idea. You never know when fixup() might be called and if it started emitting signals in arbitrary moments, it might not be what your users expect.

Cotlone
3rd November 2010, 04:58
Ok, good. It did seem a little like bad practise to me.
Looks like I'll be learning about events now then :)