📄 patterns.pas
字号:
unit Patterns;
interface
type
TPatPtr = ^TPattern;
mType = record case integer of
0: (ch:char);
1:(str:PChar);
2:(cset:set of char);
3:(pat:TPatPtr);
4:(index:word);
end;
TPattern = record
mf:function(Pat:TPatPtr):boolean;
m:mType;
Next:TPatPtr;
Alt:TPatPtr;
success:procedure(Pat:TPatPtr);
EndPattern:PChar;
StartPattern:PChar;
end;
function match(var Pattern:TPattern; var str:PChar):boolean;
function SpanCset(Pat:TPatPtr):Boolean;
function AnyCset(Pat:TPatPtr):Boolean;
function OneOrMoreCset(Pat:TPatPtr):Boolean;
function BrkCset(Pat:TPatPtr):Boolean;
function NotAnyCset(Pat:TPatPtr):Boolean;
function MatchStr(Pat:TPatPtr):Boolean;
function MatchiStr(Pat:TPatPtr):Boolean;
function MatchChar(Pat:TPatPtr):Boolean;
function MatchChars(Pat:TPatPtr):Boolean;
function MatchToChar(Pat:TPatPtr):Boolean;
function MatchToPat(Pat:TPatPtr):Boolean;
function ARB(Pat:TPatPtr):Boolean;
function ARBNUM(Pat:TPatPtr):Boolean;
function EOS(Pat:TPatPtr):Boolean;
function skip(Pat:TPatPtr):Boolean;
function pos(Pat:TPatPtr):Boolean;
function MatchSub(Pat:TPatPtr):Boolean;
function Succeed(Pat:TPatPtr):Boolean;
implementation
uses SysUtils;
function match(var Pattern:TPattern; var str:PChar):boolean;
begin
Pattern.StartPattern := str;
Pattern.EndPattern := str;
{ See if the current pattern matches anything at the }
{ beginning of the current string. }
if (Pattern.mf(@Pattern)) then
begin
{ If we got a match, see if there is a follow-on }
{ pattern and try to match it, if so; If no such }
{ pattern, return success. }
if (Pattern.Next <> NIL) then
begin
Result := match(Pattern.Next^, Pattern.EndPattern);
if Result then
Pattern.EndPattern := Pattern.Next^.EndPattern;
end
else Result := true;
{ If we've got a successful match, and "success" points }
{ at a procedure, execute that procedure. }
if Result and (@Pattern.Success <> NIL) then
Pattern.Success(@Pattern);
end
{ If the pattern did not match, look for an alternate }
{ pattern and try to match it if it exists. Return }
{ failure if there is no alternate pattern. }
else if (Pattern.Alt <> NIL) then
begin
Result := match(Pattern.Alt^, Pattern.EndPattern);
if (Result) then
Pattern.EndPattern := Pattern.Alt^.EndPattern;
end
else Result := false;
end;
function MatchSub(Pat:TPatPtr):Boolean;
begin
Result := Match(Pat^.m.Pat^, Pat^.EndPattern);
if (Result) then Pat^.EndPattern := Pat^.m.Pat^.EndPattern;
end;
{ Succeed- Always Succeeds }
function Succeed(Pat:TPatPtr):Boolean;
begin
Result := true;
end;
{ SpanCset- This matching function skips over any characters }
{ found in the cset field. }
function SpanCset(Pat:TPatPtr):Boolean;
begin
while (Pat^.EndPattern^ in Pat^.m.cset) do inc(Pat^.EndPattern);
Result := true;
end;
{ AnyCset- This matching function skips over a single character}
{ found in the cset field. }
function AnyCset(Pat:TPatPtr):Boolean;
begin
Result := Pat^.EndPattern^ in Pat^.m.cset;
if Result then inc(Pat^.EndPattern);
end;
{ OneOrMoreCset- This matching function skips over any chars }
{ found in the cset field. there must be at least }
{ one character for this to succeed. }
function OneOrMoreCset(Pat:TPatPtr):Boolean;
begin
Result := Pat^.EndPattern^ in Pat^.m.cset;
if Result then
begin
inc(Pat^.EndPattern);
while (Pat^.EndPattern^ in Pat^.m.cset) do
inc(Pat^.EndPattern);
end;
end;
{ BrkCset- This matching function skips over any characters }
{ that are not in the cset field. }
function BrkCset(Pat:TPatPtr):Boolean;
begin
while (Pat^.EndPattern^ <> #0) and
not (Pat^.EndPattern^ in Pat^.m.cset) do
inc(Pat^.EndPattern);
Result := true;
end;
{ NotAnyCset- This matching function skips over a single }
{ character that is not in the cset field. }
function NotAnyCset(Pat:TPatPtr):Boolean;
begin
Result := (Pat^.EndPattern^ = #0) or
not (Pat^.EndPattern^ in Pat^.m.cset);
if (Result) then inc(Pat^.EndPattern);
end;
{ MatchStr- Skips over the characters that match a string. }
function MatchStr(Pat:TPatPtr):Boolean;
function MatchPrefix(var s:PChar; t:PChar):Boolean;
var tmp:PChar;
begin
tmp := s;
while (tmp^ = t^) and (t^ <> #0) do
begin
inc(tmp);
inc(t);
end;
Result := t^ = #0;
if (Result) then s := tmp;
end;
begin
Result :=MatchPrefix(Pat^.EndPattern, Pat^.m.str);
end;
{ MatchiStr- Skips over the characters that match a string, }
{ ignoring case. }
function MatchiStr(Pat:TPatPtr):Boolean;
function MatchPrefix(var s:PChar; t:PChar):Boolean;
var tmp:PChar;
begin
tmp := s;
while (upcase(tmp^) = upcase(t^)) and (t^ <> #0) do
begin
inc(tmp);
inc(t);
end;
Result := t^ = #0;
if (Result) then s := tmp;
end;
begin
Result :=MatchPrefix(Pat^.EndPattern, Pat^.m.str);
end;
{ MatchToStr- This function scans through the string to see }
{ if it can match some string at the current }
{ character or later in the string. }
{ This is a truly disgusting algorithm. }
{ Need to clean this one up some day. }
function MatchToStr(Pat:TPatPtr):Boolean;
var tmp:PChar;
begin
with Pat^ do
begin
tmp := EndPattern;
while (EndPattern^ <> #0) and
not MatchStr(Pat) do inc(EndPattern);
Result := EndPattern^ <> #0;
if not Result then EndPattern := tmp;
end;
end;
{ MatchChar- Matches a single character in the string. }
function MatchChar(Pat:TPatPtr):Boolean;
begin
Result := Pat^.EndPattern^ = Pat^.m.ch;
if Result then inc(Pat^.EndPattern);
end;
{ MatchChars- Matches zero or more occurrences of a char- }
{ acter in the string. }
function MatchChars(Pat:TPatPtr):Boolean;
begin
while (Pat^.EndPattern^ = Pat^.m.ch) do inc(Pat^.EndPattern);
Result := true;
end;
{ MatchToChar- Matches all characters in a string up to a }
{ specified character. Fails if that character }
{ is not in the string. }
function MatchToChar(Pat:TPatPtr):Boolean;
var tmp:PChar;
begin
tmp := Pat^.EndPattern;
while (tmp^ <> #0) and (tmp^ <> Pat^.m.ch) do
inc (tmp);
Result := tmp^ = Pat^.m.ch;
if (Result) then Pat^.EndPattern := tmp;
end;
{ MatchToPat- Matches all characters in a string up to a }
{ specified pattern. This algorithm is a "shy" }
{ algorithm insofar is it will match as few chars }
{ as possible before matching the pattern. }
{ Also see ARB. }
function MatchToPat(Pat:TPatPtr):Boolean;
var tmp:PChar;
begin
tmp := Pat^.EndPattern;
repeat
Result := match(Pat^.m.pat^, tmp);
if (not Result and (tmp^ <> #0)) then inc(tmp);
until Result or (tmp^ = #0);
if (Result) then Pat^.EndPattern := tmp;
end;
{ ARB- Matches all characters in a string up to a }
{ specified pattern. This algorithm is a greedy }
{ algorithm insofar is it will match as many chars}
{ as possible before matching the pattern. }
{ Also see MatchToPat. }
function ARB(Pat:TPatPtr):Boolean;
var tmp:PChar;
begin
tmp := Pat^.EndPattern;
tmp := tmp + strlen(tmp);
repeat
Result := match(Pat^.m.pat^, tmp);
if (not Result and (tmp <> Pat^.EndPattern)) then dec(tmp);
until Result or (tmp = Pat^.EndPattern);
if (Result) then Pat^.EndPattern := Pat^.m.pat^.EndPattern;
end;
{ ARBNUM- Matches an arbitrary number of strings matching }
{ the parameter pattern. }
function ARBNUM(Pat:TPatPtr):Boolean;
begin
while (match(Pat^.m.pat^, Pat^.EndPattern)) do
Pat^.EndPattern := Pat^.m.pat^.EndPattern;
Result := true;
end;
{ EOS- Matches the end of string character (#0). }
function EOS(Pat:TPatPtr):Boolean;
begin
Result := Pat^.EndPattern^ = #0;
end;
{ Skip- Skips over "index" characters in the string if }
{ there are that many characters left in the str. }
function skip(Pat:TPatPtr):Boolean;
var LastPosn,
save :PChar;
begin
with Pat^ do begin
save := EndPattern;
LastPosn := EndPattern + m.index;
while (EndPattern^ <> #0) and (EndPattern < LastPosn) do
inc(EndPattern);
Result := EndPattern^ <> #0;
if not Result then EndPattern := save;
end;
end;
{ Pos- Returns true if the pattern matching algorithm }
{ is currently processing the character at pos- }
{ ition "index" in the string. }
function pos(Pat:TPatPtr):Boolean;
begin
with Pat^ do begin
Result := (EndPattern - StartPattern) = m.index;
end;
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -