我正在嘗試構建一個給定串列(例如['1', '2', '3', '.', ... , '2'])的謂詞,它必須將其識別為 IP 字串的格式(NNN.NNN.NNN.NNN),其中N是一個數字(介于0和之間9),如果格式正確,則回傳 true。它還必須接受 IP 僅為(N.N.N.N或NNN.NNN.N.N和其他組合)的情況。
這是我到目前為止所做的
test([X,Y,Z,D | String]) :- digit(X), digit(Y), digit(Z), dot(D), test(String).
其中數字是一樣的事實清單digit('0').從0到9; 并且 dot 是一個定義為的事實dot('.')。我的代碼缺乏模塊化(它無法識別 single N)。你能幫我實作這個目標嗎?
謝謝!
uj5u.com熱心網友回復:
歡迎來到 SO。我會這樣做:
將輸入串列分成 4 個“塊”,其中點是分隔符,并且只接受其中包含 1-3 位數字元素的塊。由于數字長度 (1-3) 和點數(正好 3 個點)的限制,執行此序言可能有點棘手。所以我的方法看起來像這樣(基本但有點扭曲):
test(In):-
digits123(In,['.'|R1]),
digits123(R1,['.'|R2]),
digits123(R2,['.'|R3]),
digits123(R3,[]).
digits123([A,B,C|R],R):-
digit(A),
digit(B),
digit(C).
digits123([A,B|R],R):-
digit(A),
digit(B).
digits123([A|R],R):-
digit(A).
它有什么作用?digits123/2獲取一個串列作為輸入,并檢查前 3、2 或一個元素是否為數字。此外,串列的其余部分與第二個引數統一,使其成為數字的測驗和其余串列的生成器/測驗。digits123/2單獨會出錯,因為三位數可能會被誤認為是 2 位或一位數。所以呼叫使它變得特別:首先digits123/2在 inputlist 中呼叫In,回傳包含剩余元素的串列。但是剩下的這個串列必須以點 ( ['.'|R1])開頭。寫成這樣,R1是沒有點作為分隔符的剩余串列。再重復兩次以檢查第二個和第三個塊。最后一個塊是不同的:它有 1-3 位數字,但后面沒有點(或其他任何東西)。換句話說:不應該留下任何元素(空串列,[])。
用 SWISH 測驗:
?- test(['1', '2', '3', '.', '2', '3', '.', '2', '.' , '2']).
true;
false.
?- test(['1', '2', '3', '.', '2', '3', '.', '2', '.' ]).
false.
uj5u.com熱心網友回復:
最簡單的方法是使用 DCG 語法來指定虛線四邊形的樣子。IPv4 地址為 4 個八位位元組,以十進制表示,并以“.”分隔。我們可以將其表示為 DCG 規則,如下所示:
dotted_quad --> octet, dot, octet, dot, octet, dot, octet.
a 的規則.很簡單:
dot --> ['.'].
八位位元組的規則更復雜。八位位元組被限制在域 0–255 中。可以用十進制表示
- 0-9:
一位十進制數字0–9 - 10-99:
兩位十進制數字,域中的第一位1–9,域中的第二位0–9。 - 100-199:
三位十進制數字。第一個是1,第二個和第三個在域中0–9。 - 200-249:
三位十進制數字。第一個是2,第二個有域0–4,第三個是0–9。 - 250-255:
三位十進制數字。第一個是2,第二個是5,第三個被限制為0–5。
我們可以撰寫很多特殊規則來涵蓋這一點,或者為十進制數字的規則添加一些背景關系。讓我們為該規則添加一些背景關系(因為為什么輸入比您需要的更多):
digit(D) --> [D].
digit(Min,Max) --> [D], { D @>= Min, D @=< Max }.
這些讓我們說一些事情,比如digit('0','5')表明域 0-5 中的數字是允許的,或者digit('2')說只允許數字 2。
現在我們可以定義八位位元組的規則了:
octet --> digit('0','9') .
octet --> digit('1','9') , digit('0','9').
octet --> digit('1') , digit('0','9') , digit('0','9').
octet --> digit('2') , digit('0','4') , digit('0','9').
octet --> digit('2') , digit('5') , digit('0','5').
現在我們可以定義我們的測驗謂詞。它需要做的就是呼叫我們定義的 DCG:
is_dotted_quad(Cs) :- phrase(dotted_quad, Cs).
但是因為輸入類似的東西
[ '1','2','3', '.', '2','3','4', '.', '7','8', '.', '9' ]`
既乏味又容易出錯,讓我們添加一些便利,讓我們使用字串或原子:
is_dotted_quad(X) :- atom(X) , atom_chars(X,Cs) , is_dotted_quad(Cs) .
is_dotted_quad(X) :- string(X) , atom_chars(X,Cs) , is_dotted_quad(Cs) .
is_dotted_quad(Cs) :- phrase(dotted_quad, Cs).
把它們放在一起,你會得到這個:
is_dotted_quad(X) :- atom(X) , atom_chars(X,Cs) , is_dotted_quad(Cs).
is_dotted_quad(X) :- string(X) , string_chars(X,Cs) , is_dotted_quad(Cs).
is_dotted_quad(Cs) :- phrase(dotted_quad, Cs).
dotted_quad --> octet, dot, octet, dot, octet, dot, octet.
dot --> ['.'].
octet --> digit('0','9') .
octet --> digit('1','9') , digit('0','9') .
octet --> digit('1') , digit('0','9') , digit('0','9').
octet --> digit('2') , digit('0','4') , digit('0','9').
octet --> digit('2') , digit('5') , digit('0','5').
digit(V) --> [V].
digit(Min,Max) --> [D], { D @>= Min, D @=< Max }.
你可以在https://swish.swi-prolog.org/p/dotted-quad-dcg.pl擺弄它
或者,如果您不想使用 DCG,那么@Dudas 的這個即興演奏也將起作用——但人們應該意識到,這本質上就是上面的 DCG(DCG 本質上是一種簡單的語法糖香草序言的頂部),只是不那么宣告意圖:
is_dotted_quad(X) :- atom(X) , atom_chars(X,Cs) , is_dotted_quad(Cs).
is_dotted_quad(X) :- string(X) , string_chars(X,Cs) , is_dotted_quad(Cs).
is_dotted_quad(Cs) :- octet(Cs,T1),
dot(T1,T2), octet(T2,T3),
dot(T3,T4), octet(T4,T5),
dot(T5,T6), octet(T6,[]).
chars( [] , [] ) .
chars( [C|Cs] , [C|Cs] ) .
chars( X , Cs ) :- atom(X) , atom_chars(X,Cs) .
chars( X , Cs ) :- string(X) , string_chars(X,Cs) .
dot(['.'|T],T).
octet( [ Z | T ], T ) :- range(Z,'0','9') .
octet( [ Y , Z | T ], T ) :- range(Y,'1','9') , range(Z,'0','9') .
octet( [ '1' , Y , Z | T ], T ) :- range(Y,'0','9') , range(Z,'0','9') .
octet( [ '2' , Y , Z | T ], T ) :- range(Y,'0','4') , range(Z,'0','9') .
octet( [ '2' , '5' , Z | T ], T ) :- range(Z,'0','5') .
range(X,Min,Max) :- X @>= Min, X @=< Max .
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/375922.html
