Discussion:
Checking characters in a string
Richard Mace
2014-03-12 13:53:16 UTC
Permalink
Hi,
I am trying to check to make sure the a string contains at least 1
uppercase character, 1 lowercase character and 1 number.
Any ideas as of the best way of coding this?

Thanks in advance

Richard
silvioprog
2014-03-12 14:03:54 UTC
Permalink
Post by Richard Mace
Hi,
I am trying to check to make sure the a string contains at least 1
uppercase character, 1 lowercase character and 1 number.
Any ideas as of the best way of coding this?
In a function, create three Boolean variables (eg. VContainsUpperCase,
VContainsLowerCase, VContainsNumber), make a loop through the string and,
the measure that finding the ocurrences, set the respective variable to
true. Finally, the result will "Result := VContainsUpperCase and
VContainsLowerCase and VContainsNumber".

You can also do this with a set of enums. The function would return the set
itself. If you are interested, I can explain how it would be with the set
too.
--
Silvio Clécio
My public projects - github.com/silvioprog
Richard Mace
2014-03-12 15:23:48 UTC
Permalink
OK. Perhaps I could just look for a string with a number in it?
Richard
Post by silvioprog
Post by Richard Mace
Hi,
I am trying to check to make sure the a string contains at least 1
uppercase character, 1 lowercase character and 1 number.
Any ideas as of the best way of coding this?
In a function, create three Boolean variables (eg. VContainsUpperCase,
VContainsLowerCase, VContainsNumber), make a loop through the string and,
the measure that finding the ocurrences, set the respective variable to
true. Finally, the result will "Result := VContainsUpperCase and
VContainsLowerCase and VContainsNumber".
You can also do this with a set of enums. The function would return the
set itself. If you are interested, I can explain how it would be with the
set too.
--
Silvio Clécio
My public projects - github.com/silvioprog
--
_______________________________________________
Lazarus mailing list
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus
silvioprog
2014-03-12 16:35:05 UTC
Permalink
Post by Richard Mace
OK. Perhaps I could just look for a string with a number in it?
Yes. See some functions that handles strings here:

https://github.com/silvioprog/rutils/blob/master/src/rutils.pas

--
Silvio Clécio
My public projects - github.com/silvioprog
Michael Schnell
2014-03-12 14:11:41 UTC
Permalink
Post by Richard Mace
I am trying to check to make sure the a string contains at least 1
uppercase character, 1 lowercase character and 1 number.
Any ideas as of the best way of coding this?
When using Unicode (under the hood) this is really difficult, as (AFAIK)
there is no decent definition what "Uppercase" is.

At best you do a list of all the characters you want to seek for (i.e. a
string for each "character", as in Unicode there is no such thging as a
character) and do a "pos()" which each of them.

But even then you can't be sure as in Unicode there are multiple ways to
code certain characters and you will only find the coding style you
defined.

-Michael
Reinier Olislagers
2014-03-12 14:37:11 UTC
Permalink
Post by Richard Mace
I am trying to check to make sure the a string contains at least 1
uppercase character, 1 lowercase character and 1 number.
Any ideas as of the best way of coding this?
<SCNR>
1. Just check for minimum length and run John the Ripper against the
password hash, and check if it breaks the password in a reasonable
amount of time
Slightly more serious:
2. Perhaps there's OS supplied functions that provide this kind of
funcationality (e.g. apparently on Windows domain controllers, there is
- haven't really read through this though:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa370661%28v=vs.85%29.aspx)


--
Howard Page-Clark
2014-03-12 16:35:58 UTC
Permalink
Post by Richard Mace
Hi,
I am trying to check to make sure the a string contains at least 1
uppercase character, 1 lowercase character and 1 number.
Any ideas as of the best way of coding this?
If you restrict yourself to Latin ansi encoding and 'number' means a
numeric digit which does not have to be a whole word, the code is fairly
simple since almost no parsing is required. Other cases and encodings
require more complex string parsing. For example:

-- code begin --

function Valid(const s: string): boolean;

function HasLowerUpperNumeric: boolean;
var
c: Char;
lower: boolean=False;
upper: boolean=False;
numeric: boolean=False;
begin
Result:=False;
for c in s do begin
if c in ['a'..'z'] then
lower:=True
else if c in ['A'..'Z'] then
upper:=True
else if c in ['0'..'9'] then
numeric:=True;
if lower and upper and numeric then
Exit(True);
end;
end;

begin
if Length(s) < 3 then
Exit(False);
Result:=HasLowerUpperNumeric;
end;

-- code end ---


--
silvioprog
2014-03-12 18:19:29 UTC
Permalink
Oops...

2014-03-12 15:08 GMT-03:00 silvioprog <***@gmail.com>:
[...]
// new
function ValidPassword(const S: string): Boolean;
var
P: PChar;
F: Boolean;
L: Boolean = False;
U: Boolean = False;
N: Boolean = False;
begin
P := PChar(S);
while P^ <> #0 do
begin
case P^ of
#48..#57: N := True;
#65..#90: U := True;
#97..#122: L := True;
else
F := P^ = #195;
if F then
case P[1] of
#128..#159: U := True;
#160..#191: L := True;
end;
end;
Inc(P);
end;
Result := L and U and N;
end;
Correct function is:

function ValidPassword(const S: string): Boolean;
var
P: PChar;
L: Boolean = False;
U: Boolean = False;
N: Boolean = False;
begin
P := PChar(S);
while P^ <> #0 do
begin
case P^ of
#48..#57: N := True;
#65..#90: U := True;
#97..#122: L := True;
else
if P^ = #195 then
case P[1] of
#128..#159: U := True;
#160..#191: L := True;
end;
end;
Inc(P);
end;
Result := L and U and N;
end;
--
Silvio Clécio
My public projects - github.com/silvioprog
silvioprog
2014-03-12 18:08:07 UTC
Permalink
Post by Howard Page-Clark
If you restrict yourself to Latin ansi encoding and 'number' means a
numeric digit which does not have to be a whole word, the code is fairly
simple since almost no parsing is required. Other cases and encodings
It is not hard to allow chars like "ã", "Ã", "ñ", "Ñ", "ç", "Ç", "ä", "Ä"
etc. I left the function a little faster too:

// old
function Valid(const s: string): boolean;

function HasLowerUpperNumeric: boolean;
var
c: char;
lower: boolean = False;
upper: boolean = False;
numeric: boolean = False;
begin
Result := False;
for c in s do
begin
if c in ['a'..'z'] then
lower := True
else if c in ['A'..'Z'] then
upper := True
else if c in ['0'..'9'] then
numeric := True;
if lower and upper and numeric then
Exit(True);
end;
end;

begin
if Length(s) < 3 then
Exit(False);
Result := HasLowerUpperNumeric;
end;

// new
function ValidPassword(const S: string): Boolean;
var
P: PChar;
F: Boolean;
L: Boolean = False;
U: Boolean = False;
N: Boolean = False;
begin
P := PChar(S);
while P^ <> #0 do
begin
case P^ of
#48..#57: N := True;
#65..#90: U := True;
#97..#122: L := True;
else
F := P^ = #195;
if F then
case P[1] of
#128..#159: U := True;
#160..#191: L := True;
end;
end;
Inc(P);
end;
Result := L and U and N;
end;

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
const
c = 20000000;
var
i: integer;
b, e: TDateTime;
s: string = 'Ãç1';
x: Boolean;
begin
// test Valid efficiency/performance
b := now;
for i := 0 to c do
begin
x := False;
x := Valid(s);
end;
e := now;
Edit1.Text := 'Valid: ' + BoolToStr(x, True) + ' - ' +
formatdatetime('hh:nn:ss:zzz', b - e);

// test ValidPassword efficiency/performance
b := now;
for i := 0 to c do
begin
x := False;
x := ValidPassword(s);
end;
e := now;
Edit1.Text := Edit1.Text + ' / ValidPassword: ' + BoolToStr(x, True) + '
- ' + formatdatetime('hh:nn:ss:zzz', b - e);
end;

Result: Valid: *False* - 00:00:00:*861* / ValidPassword: *True* - 00:00:00:
*559*

Sure, it's a function that did just for explain, then it can be easily
improved.
--
Silvio Clécio
My public projects - github.com/silvioprog
Michael Schnell
2014-03-13 09:29:17 UTC
Permalink
Post by silvioprog
It is not hard to allow chars like "ã", "Ã", "ñ", "Ñ", "ç", "Ç", "ä",
????

These beasts in UTF-8 are not "char" s (but multi-Byte codes) so your
example code "c: char" ... will not work :-( .

-Michael

--
Lukasz Sokol
2014-03-13 11:21:27 UTC
Permalink
????
These beasts in UTF-8 are not "char" s (but multi-Byte codes) so your example code "c: char" ... will not work :-( .
-Michael
He converts to PChar, then checks byte values, not characters. (see the second message where he rectifies it a bit).

-L.


--
Richard Mace
2014-03-18 06:20:30 UTC
Permalink
Thanks Howard,
Your code worked exactly as I expected.

Richard
Post by Howard Page-Clark
Post by Richard Mace
Hi,
I am trying to check to make sure the a string contains at least 1
uppercase character, 1 lowercase character and 1 number.
Any ideas as of the best way of coding this?
If you restrict yourself to Latin ansi encoding and 'number' means a
numeric digit which does not have to be a whole word, the code is fairly
simple since almost no parsing is required. Other cases and encodings
-- code begin --
function Valid(const s: string): boolean;
function HasLowerUpperNumeric: boolean;
var
c: Char;
lower: boolean=False;
upper: boolean=False;
numeric: boolean=False;
begin
Result:=False;
for c in s do begin
if c in ['a'..'z'] then
lower:=True
else if c in ['A'..'Z'] then
upper:=True
else if c in ['0'..'9'] then
numeric:=True;
if lower and upper and numeric then
Exit(True);
end;
end;
begin
if Length(s) < 3 then
Exit(False);
Result:=HasLowerUpperNumeric;
end;
-- code end ---
--
_______________________________________________
Lazarus mailing list
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus
Loading...