Recent

Author Topic: Parsing ip string within a TextBox  (Read 35417 times)

jolix

  • Jr. Member
  • **
  • Posts: 60
Re: Parsing ip string within a TextBox
« Reply #15 on: October 23, 2010, 02:07:51 am »
Quote
Ah, you're using regular expressions now
Yes, I hate wasting time on things that do not work or work in some particulary circumstances that seems me is the case here.

Thanks and Regards,
jolix

jolix

  • Jr. Member
  • **
  • Posts: 60
Re: Parsing ip string within a TextBox
« Reply #16 on: October 23, 2010, 02:34:25 pm »
Even far of a perfect solution, however it works for my needs for now.
Valid IP Return True/False depending on valid IP and is called by OnEditingDone event whenever ENter key is pressed.
In my case, EditBox is cleaned if no valid IP.
Code: [Select]
{==============================================================================}
{ IsNumber: Returns True/False depending on valid number                       }
{------------------------------------------------------------------------------}
function TForm1.IsNumber( ipchar: char ): boolean;
begin
    Result:=False;
    if ipchar in ['0'..'9'] then Result:=True;
end;

{==============================================================================}
{ ValidIp: Returns True/False depending on valid IP                            }
{------------------------------------------------------------------------------}
function TForm1.ValidIp: boolean;
const
    MAXIP = 254;   // max acceptable number for each part
var
    x, y: integer;
    s: string;
begin

    s:=Edit1.Text;   // EditBox where ip is writen
    begin
        x:=1;
        y:=1;
        if(Length(s)<7)or(Length(s)>15) then y:=16;
        repeat
            case y of
                1:  if IsNumber(s[x])=True then begin  // 1st IP part
                        y:=2;
                        inc(x);
                    end
                    else y:=16;

                2:  if IsNumber(s[x])=True then begin
                        y:=3;
                        inc(x);
                    end
                    else y:=4;

                3:  if IsNumber(s[x])=True then begin  // Validate max ip number
                        if StrToInt(copy(s,x-2,3))>MAXIP then begin
                            y:=16;
                        end
                        else begin
                            y:=4;
                            inc(x);
                        end;
                    end
                    else y:=4;

                4:  if s[x]='.' then begin  // First Separator
                        y:=5;
                        inc(x);
                    end
                    else y:=16;

                5:  if IsNumber(s[x])=True then begin  // 2nd IP part
                        y:=6;
                        inc(x);
                    end
                    else y:=8;

                6:  if IsNumber(s[x])=True then begin
                        y:=7;
                        inc(x);
                    end
                    else y:=8;

                7:  if IsNumber(s[x])=True then begin  // Validate max ip number
                        if StrToInt(copy(s,x-2,3))>MAXIP then begin
                            y:=16;
                        end
                        else begin
                            y:=8;
                            inc(x);
                        end;
                    end
                    else y:=8;

                8:  if s[x]='.' then begin // 2nd Separator
                        y:=9;
                        inc(x);
                    end
                    else y:=16;

                9:  if IsNumber(s[x])=True then begin  // 3th IP part
                        y:=10;
                        inc(x);
                    end
                    else y:=12;

                10: if IsNumber(s[x])=True then begin
                        y:=11;
                        inc(x);
                    end
                    else y:=12;

                11: if IsNumber(s[x])=True then begin  // Validate max IP number
                        if StrToInt(copy(s,x-2,3))>MAXIP then begin
                            y:=16;
                        end
                        else begin
                            y:=12;
                            inc(x);
                        end;
                    end
                    else y:=12;

                12: if s[x]='.' then begin  // 3th (last) Separator
                        y:=13;
                        inc(x);
                    end
                    else y:=16;

                13: if IsNumber(s[x])=True then begin  // Last IP part
                        y:=17;
                        inc(x);
                        if Length(s)>=x then y:=14
                    end
                    else y:=16;

                14: if IsNumber(s[x])=True then begin
                        y:=17;
                        inc(x);
                        if Length(s)>=x then y:=15;
                    end
                    else y:=16;

                15: if IsNumber(s[x])=True then begin  // Validate max IP number
                        if StrToInt(copy(s,x-2,3))>MAXIP then begin
                            y:=16;
                        end
                        else begin
                            y:=17;
                            inc(x);
                            if Length(s)>=x then y:=16;
                        end;
                    end
                    else y:=16;

                16: begin  // IP NOT VALID: in my case i clean EditBox
                        Edit1.Text:='';
                        y:=18;
                        Result:=False;
                    end;

                17: begin  // IP VALID
                        y:=18;
                        Result:=True;
                    end;
            end;
        until y>17;
    end;
end;

I Notice the event below executes twice, i don't know why. So First thing i do is turn of the event and turn it on again at the end.

Event code:
Code: [Select]
procedure TForm1.Edit1EditingDone( Sender : TObject);
begin
    Edit1.OnEditingDone:=nil;  // event OFF
    if ValidIp then RefreshIPList;   // This is my own work, doesn't matter for this example
    Edit1.OnEditingDone:=@Edit1EditingDone;  // event ON
end;

Meanwhile i still open to forum ideas.

Thanks and Regards
jolix
« Last Edit: October 23, 2010, 02:39:36 pm by jolix »

IndianaJones

  • Hero Member
  • *****
  • Posts: 509
Re: Parsing ip string within a TextBox
« Reply #17 on: October 23, 2010, 06:40:13 pm »

could you test this code?

Code: [Select]
var
   r         : tregexprengine;
   index,len : longint;
   initok    : boolean;                                             

   initok:=GenerateRegExprEngine('^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$',[],r);

  if not(RegExprPos(r, PChar(Edit1.Text),index,len)) then
     Showmessage('Wrong IP Address.')
     else
     Showmessage('Correct IP.');                                                                                         

  DestroyregExprEngine(r);                       

Add the regexpr to the uses clause.
Thanks.

ivan17

  • Full Member
  • ***
  • Posts: 173
Re: Parsing ip string within a TextBox
« Reply #18 on: October 23, 2010, 11:56:16 pm »
if you are making a windows-only application, there is an ip-address-editbox control in version 4.71 or higher of comctl32.dll (since windows 98 i think), so just get one of a dozen wrapper components that exist for delphi, install the component and you're good.

it's the one you see in the connection properties dialog (where you set dns servers)

Bart

  • Hero Member
  • *****
  • Posts: 5290
    • Bart en Mariska's Webstek
Re: Parsing ip string within a TextBox
« Reply #19 on: October 24, 2010, 09:49:36 am »
Whats happen is:
Since i place TMaskEdit on the form and apply the mask, everything runs bad.
This happens with any version of Lazarus 0.9.26, 0.9.28.2, 0.9.28.3 or 0.9.29.

I'm running 0.9.29 r27368 and have no problem with maskedit.
I have an extensive test program to test TMaskEdit, since I re-wrote  large parts of this component.
TMaskEdit in any Lazarus versions before januari 2009 is seriously flawed.


Bart, i google for MaskEdit and not found nothing related with mask options.
You know where i can find it? For instance, why '!' and why ...;1; '.

In the file ($LazDir)/lcl/maskedit.pp you can see what all the different mask characters do.

If a ! is in the mask, leading blanks don't appear in the data, if it is not, trailing blanks don't appear. This behaviour depends on the the presence or absence of MaskNoSave in the mask.
It also controls th alligning of the text when setting the text property in case the mask contains literals (as is the case with this mask.
(Read the comments in GetText and SetText in maskedit.pp)

;1;_ at the end of the mask means that the mask is saved in the data (in GetText) and that an underscore is used to represent blanks in the control.

Bart

eny

  • Hero Member
  • *****
  • Posts: 1634
Re: Parsing ip string within a TextBox
« Reply #20 on: October 24, 2010, 01:11:29 pm »
Maskedits are a pain for end users.
Ever tried copy/pasting something into a masked editfield?  >:D

KISS: use a simple 15-character edit box (assuming IPv4) and verify the input with a simple function that uses well formatted regular expressions.
All posts based on: Win10 (Win64); Lazarus 2.0.10 'stable' (x64) unless specified otherwise...

IndianaJones

  • Hero Member
  • *****
  • Posts: 509
Re: Parsing ip string within a TextBox
« Reply #21 on: October 24, 2010, 02:26:32 pm »

Example code tested with Linux and Mac OSX and works ok.

jolix

  • Jr. Member
  • **
  • Posts: 60
Re: Parsing ip string within a TextBox
« Reply #22 on: October 24, 2010, 07:41:36 pm »
Hi
First of all, thank you all.
I will try to answer by order, thanks.

Indiana Jones,
I tested your piece of code (copy(paste) and the results are unstable, given me the correct message but finishing with "Project rised exception SIGSEGV" staff.
By other hand if i fill EditBox with trash like "1.1." or something close, the program stops only with rised exception SIGSEGV.

Code: [Select]
procedure TForm1. Edit1EditingDone( Sender : TObject);
var
   r         : tregexprengine;
   index,len : longint;
   initok    : boolean;
begin
    initok:=GenerateRegExprEngine('^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$',[],r);

    if not(RegExprPos(r, PChar(Edit1.Text),index,len)) then <<--- 2nd case, stops here
        Showmessage('Wrong IP Address.')
    else
        Showmessage('Correct IP.');

    DestroyregExprEngine(r); <<--- 1st case, debugger stops here
end;
By the way, event OnEditingDone is triggered twice, why?
I experience this behavior with most of key/mouse events.

ivan17
By now, i only have the code on windows and when i have time i will google for what you suggest, no just before study how use it.

Bart,
Only after my last post, i remember to look the code maskedit.pp. Thanks.
Are you trying fill MaskEdit with no sense string, like "1.1." ?
As i said all versions greater than 9.26 when try Maskedit Lazarus inserts i don't know what in the project files that is no more possible compile even after delete the MaskEdit component from the form. Note that i have analyzed file.lpr and don't see nothing bad.
No matter if i restart the Lazarus or even windows, the result is all the same.
By other hand, trying the same in Lazarus 9.26, i can compile after delete MaskEdit from the form. So, Lazarus 0.9.26 is more stable i think.
I will try copy fpc 2.4 to Lazarus 0.9.26 instead of 2.2.2 to conclude where the issue is.
All this if  i can do it, of course.

Eny,
I like KISS philosophy.
When the solutions tend to grow stupidly in terms of software/hardware, or when i walk in circles, generally is time to start thinking in another approach.

IndianaJones,
As i said before i only use Windows by now.

Final notes:
Remember what Eny said about pain, the simple code i publish,  being far from perfect, has at least one virtue, is immune to typos and never falls to system errors.
This is the behavior i try all the time.

Thanks,
jolix

jolix

  • Jr. Member
  • **
  • Posts: 60
Re: Parsing ip string within a TextBox
« Reply #23 on: October 24, 2010, 08:38:05 pm »
Hi,

And what you say about another approach?
To do this job in real time Edit component needed something like SetCaretPos, enable me have the cursor under control, method that not exists.
Edit1 only have CaretPos that give me cursor current position.

Any ideas?

Thanks,
Regards,
jolix

Bart

  • Hero Member
  • *****
  • Posts: 5290
    • Bart en Mariska's Webstek
Re: Parsing ip string within a TextBox
« Reply #24 on: October 24, 2010, 08:48:55 pm »
Quote from: jolix
are you trying fill MaskEdit with no sense string, like "1.1." ?

What do you mean by that?, Typing 1.1 in the control, setting by code the Text property to '1.1' or what?
What then goes wrong?

If you type 1.1. in the control and then leave the control (meaning the control looses focus) an exception is raised as by design, since the text does not meet the specified mask.
Setting the Text property to '1.1' does not raise any error here. (It did in previous versions of Lazarus, but this behaviour was wrong (as in not the way Delphi does it)).

Here's another suggestion: use an EditMask like '!999.999.999.999;1;0'
Now '0' is used as the blank char.
It should be virtual impossible now for the user to type or paste anything in the control that would result in an EDBEditError exception when leaving the control.

Then when you read the Text (as in IP := MaskEdit1.Text) replace all spaces with zero's (or simply read EditText) and you have an IP adress.
Next you must make sure that all 4 parts are <= 255.
A MaskEdit cannot do that for you (it cannot force the user to enter only values between 0 and 255). It is a relative limited control.

Another crazy way of doing this is placing 4 TSpinEdit boxes on your form, setting Min and Max value to 0 and 255. Then use the value property of TSpinEdit when reading the control.
Now you can be sure no value will be < 0 or > 255, and you can compose the IP-adress from the 4 values.

With a TMaskEdit and a TSpinEdit you restrain the users input, which can help in forcing the user to enter a valid text, especially if the end-user is not a PC expert and has no understanding of the right format inwhich an IP-adress must be entered.
If the end user is a PC tech for example, he/she will now the correct format for an IP-adress and you can us a simple TEdit and verify input when needed.

So, a TMaskEdit is one option, but for your needs it might not be the correct or most suitable one.
However I cannot reproduce the SIGSEVS you describe with a TMaskEdit.

Bart

Bart

  • Hero Member
  • *****
  • Posts: 5290
    • Bart en Mariska's Webstek
Re: Parsing ip string within a TextBox
« Reply #25 on: October 24, 2010, 08:54:38 pm »
And what you say about another approach?
To do this job in real time Edit component needed something like SetCaretPos, enable me have the cursor under control, method that not exists.
Edit1 only have CaretPos that give me cursor current position.

Now you are just trying to re-inevent some kind of MaskEdit control.
Take a look at it's code just to see how much effort goes into having absolute control over where the cursor must go, what is allowed to be pasted or cut etc. etc.

Again: you must decide how you want to treat the end user. Restrain his input(methods), or simply inform him his input was wrong when he is done editing.
You are over-complicating the problem IMHO.

Bart

jolix

  • Jr. Member
  • **
  • Posts: 60
Re: Parsing ip string within a TextBox
« Reply #26 on: October 24, 2010, 09:10:27 pm »
Bart,
Quote
Now you are just trying to re-inevent some kind of MaskEdit control.
Take a look at it's code just to see how much effort goes into having absolute control over where the cursor must go, what is allowed to be pasted or cut etc. etc.
This make sense.
Quote
You are over-complicating the problem IMHO.
Absolutely and in a certain way this make no sense with what i said about KISS.

Thanks for your comments and suggestions

Regards
jolix

IndianaJones

  • Hero Member
  • *****
  • Posts: 509
Re: Parsing ip string within a TextBox
« Reply #27 on: October 25, 2010, 04:10:28 am »

hi jolix, I have to mention about the problem, sorry my mistake, the given example is just a test case so here is the correction, dont call the DestroyregExprEngine(r); in the function or procedure
just call this statement before exiting the application.

ivan17

  • Full Member
  • ***
  • Posts: 173
Re: Parsing ip string within a TextBox
« Reply #28 on: October 25, 2010, 05:21:55 am »
I will try to answer by order, thanks.
...
By now, i only have the code on windows and when i have time i will google for what you suggest, no just before study how use it.
just search torry for "ip address" >> here you go
TphIPAddress doesn't draw it's lower portion well on my system but just change height from 25 to 21 pixel and it's fine.

eny

  • Hero Member
  • *****
  • Posts: 1634
Re: Parsing ip string within a TextBox
« Reply #29 on: October 25, 2010, 06:34:57 am »
Use Andrey V. Sorokin's regular expression library (see attachment) and create a function like the one below.
Or better yet, create a validating class that can be reused and do not mix it with a visual component!

Code: Pascal  [Select][+][-]
  1. uses RegExprEngine;
  2. ...
  3. function IP4OK(const pText: string): boolean;
  4. var reg: TRegExpr;
  5.     i  : integer;
  6. begin
  7.   // 1. Create a simple IP format matcher and evaluate the expression
  8.   reg := TRegExpr.Create;
  9.   reg.Expression := '^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$';
  10.   result := reg.Exec(pText);
  11.  
  12.   // 2. basic test for valid range of numbers (0..255)
  13.   if result then
  14.     for i := 1 to 4 do                       // 4 = the number of digit groups
  15.       if StrToInt(reg.Match[i]) > 255 then   // numbers are in the range 0..255
  16.         begin
  17.           result := false;
  18.           break
  19.         end;
  20.  
  21.   // 3. Clean up
  22.   reg.Free;
  23. end;
  24. ...
  25. // Bug in the forum? Not sure what this i-token below does...
  26.  
« Last Edit: October 25, 2010, 06:56:48 am by eny »
All posts based on: Win10 (Win64); Lazarus 2.0.10 'stable' (x64) unless specified otherwise...

 

TinyPortal © 2005-2018