Password checking with prolog/2

383 views Asked by At

I've got this Prolog program below that examines if a password fulfills certain rules (the password must contain a letter(a-z), a number(0-9),a double letter (aa,ll,ww etc.), must start with a letter (a, aa, c etc.), must be at least 6 characters long).

How can I expand it so that double letters would be counted as one letter? (For example, aa25b1 wouldn't be a correct password as it's only five characters long).

contains_letter(Password) :- wildcard_match('*[a-zA-Z]*', Password).

contains_number(Password) :- wildcard_match('*[0-9]*', Password).

contains_double_letter(Password) :-
    (between(65, 90, Letter) ; between(97, 122, Letter)),
    append([_, [Letter, Letter], _], Password),
    !.

starts_with_letter(Password) :- wildcard_match('[a-zA-Z]*', Password).

long_enough(Password) :-
    length(Password, Length),
    Length >= 6.

check_everything(Password) :-
    contains_letter(Password),
    contains_number(Password),
    contains_double_letter(Password),
    starts_with_letter(Password),
    long_enough(Password).
3

There are 3 answers

1
m09 On

First and as I precised in your first question, note that you can combine that :

contains_letter(Password) :- wildcard_match('*[a-zA-Z]*', Password).

contains_number(Password) :- wildcard_match('*[0-9]*', Password).

starts_with_letter(Password) :- wildcard_match('[a-zA-Z]*', Password).

Into that :

letter_start_and_number(Password) :-
    wildcard_match('[a-zA-Z]*[0-9]*', Password).

Now, you can handle double letters and length as follows :

length_double_letters([], Acc, yes, Acc).
length_double_letters([Char, Char|Password], Acc, _Contains, Length) :-
    !,
    NewAcc is Acc + 1,
    length_double_letters(Password, NewAcc, yes, Length).
length_double_letters([_Char|Password], Acc, Contains, Length) :-
    NewAcc is Acc + 1,
    length_double_letters(Password, NewAcc, Contains, Length).

Using that predicate into this main predicate :

check_everything(Password) :-
    letter_start_and_number(Password),
    length_double_letters(Password, 0, no, Length),
    Length >= 6.

PS : please take the time to accept the answers you find the most constructive and upvote the ones that helped you.

0
Fred Foo On

Preprocess the password with a predicate that squashes together equal characters, e.g.

uniq([], []).
uniq([X], [X]).
uniq([X,X|L], R) :-
     !,
     uniq([X|L], R).
uniq([X,Y|L], [X|R]) :-
     uniq([Y|L], R).

(I named this after the Unix tool uniq; you might want to rename it without_adjacent_repetitions or something more to your taste.)

3
Sergey Kalinichenko On

Write your own lengthWithDoubleLetters/2 rule taking a list of characters and returning its length counting double letters as one:

lengthWithDoubleLetters([],0).
lengthWithDoubleLetters([F,F|T],C) :-
    lengthWithDoubleLetters(T,TC),
    !,
    C is TC + 1.
lengthWithDoubleLetters([H|T], C) :-
    lengthWithDoubleLetters(T,TC),
    C is TC + 1.