Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Match funktion? (https://www.delphipraxis.net/45125-match-funktion.html)

Pseudemys Nelsoni 30. Apr 2005 07:13


Match funktion?
 
Moin,

hat jemand eine Idee wie ich eine Funktion schreiben könnte die 2 strings auf übereinstimmung prüft?
Als Joke sollen * und ? benutzt werden koennen.

Das heisst das wenn die Maske z.b:

Zitat:

???
ist, das Wort 3 Zeichen haben muss und bei:

Zitat:

blah*irgendwas
muss der string auf jedenfall mit "blah" beginnen und mit "irgendwas" enden.

Jemand ne Idee?

die MatchesMask() Funktion geht hierfür nicht, da der Joker "?" dort heisst das ein Zeichen vorkommen KANN, aber nicht MUSS.... ich brauch aber das "muss".

malo 30. Apr 2005 07:16

Re: Match funktion?
 
Eine Möglichkeit wäre, dass man mit einer Schleife bei jedem "*" alle 255 ACII-Codes einsetzt und dann prüft. ;)

MathiasSimmack 30. Apr 2005 07:27

Re: Match funktion?
 
Zitat:

Zitat von Pseudemys Nelsoni
hat jemand eine Idee wie ich eine Funktion schreiben könnte die 2 strings auf übereinstimmung prüft?
Als Joke sollen * und ? benutzt werden koennen.

Wenn das so bleibt, dann kannst du ja mal die Shell-Funktion MSDN-Library durchsuchenPathMatchSpec zweckentfremden, so wie ich das auch mache. Die ist eigentlich dazu da, zu prüfen, ob ein Ordner- oder Dateiname einem bestimmten Wildcard entspricht. Wenn du allerdings andere Strings übergibt, dann stört sie sich auch nicht daran. Hier die Deklarationen:
Delphi-Quellcode:
function PathMatchSpec(pszFile, pszSpec: PAnsiChar): bool; stdcall;

const
  shlwapi = 'shlwapi.dll';

function PathMatchSpec; external shlwapi name 'PathMatchSpecA';
Code:
[DllImport("shlwapi.dll")]
static extern bool PathMatchSpec(string pwszFile, string pwszSpec);
wobei mich in dem Zusammenhang gleich interessieren würde, ob es eine im .NET Framework eingebaute Möglichkeit gibt. Das Einbinden der API-Funktion (s. zweiter Codeauszug) ist zwar bequem und funktioniert, aber auf lange Sicht ist sie fürs .NET Framework doch eher ungeeignet. Und reguläre Ausdrücke sind gleich ein bisschen zu dick.

Wie dem auch sei, Anwendungsmöglichkeit:
Delphi-Quellcode:
if PathMatchSpec('blahierstehteinvölligsinnloserstringirgendwas','bla*irgendwas') then
  ShowMessage('Passt');

if PathMatchSpec('abc','???') then
  ShowMessage('Passt');

mirage228 30. Apr 2005 10:02

Re: Match funktion?
 
Hi Mathias,

Also in .NET könntest Du doch einfach mit regulären Ausdrücken arbeiten - so "dick" sind die ja nun auch nicht.
Selbst wenn im Ausgangstring nur ein "*" ist, könnte man das doch problemlos in ein "(.*)" umwandeln und damit könnte man auch mit Windows ähnlichen Wildcards arbeiten.

mfG
mirage228

Christian Seehase 30. Apr 2005 22:43

Re: Match funktion?
 
Moin Mathias,

eine kleine Einschränkung für die "Zweckentfremdung" sollte aber nicht unerwähnt bleiben:
Der erste Parameter darf maximal MAX_PATH Byte lang sein (MAX_PATH = 260)

Robert_G 30. Apr 2005 22:53

Re: Match funktion?
 
Zitat:

Zitat von mirage228
Also in .NET könntest Du doch einfach mit regulären Ausdrücken arbeiten - so "dick" sind die ja nun auch nicht.

Wenn man es geschickt anstellt sind sie überhaupt nicht "dick".
Einfach von Regex ableten und eine versteckte statische Liste führen.
Der Constructor wird versteckt und nach außen ist nur ein GetInstance sichtbar, dass einen RegEx string schluckt und eine Instanz deiner Klasse auspuckt.
Jetzt braucht er in der internen List nur noch eine Regex mit dem string suchen (für die Liste wäre eine HashTable ganz nett ;) ) die Instanz zurückgeben oder eine neue Instanz für den string anlegen, kompilieren ( :!: ), in die Liste schmeißen und zurückgeben.

Auf die Art hast du sackschnelle, kompiliere RegEchsen OHNE dass dir die Kompilierung die Zyklen vom Kopf frisst (wird ja nur einmal pro pattern gemacht :) ).

Dax 30. Apr 2005 22:57

Re: Match funktion?
 
Um mal was zu fragen.. ich mag .NET ja auch, und Robert ist ganz klar der Guru ;) Aber.. @Robert, was hast du grade gesagt? :gruebel: Liegts vielleicht daran, das es so spät ist? Ich kapiers irgendwie nicht :(

Robert_G 30. Apr 2005 23:05

Re: Match funktion?
 
Zitat:

Zitat von Dax
Liegts vielleicht daran, das es so spät ist? Ich kapiers irgendwie nicht :(

Du kannst RegExen in .Net kompilieren...
Dumm ist nur, dass er jede Regex Instanz kompiliert (und nebenbei eine temporäre Assembly anlegt :? ) egal, ob es nicht schon eine kompilierte Regex für dieses pattern gibt.
Wenn du eine private statische HashTable (Key: pattern / Value: DeinRegex) führst, kannst du doch darin nachschauen, ob du für dieses pattern schon eine kompilierte Regex "rumliegt".
Um zu verhindern, dass du dich aus Versehen an dem Mechanismus vorbeimogelst sollte der Constructor private sein. Öffentlich wäre dann nur ein
Code:
public static DeinRegex CreateInstance(string pattern)
.
Bin gerade etwas in Eile... wenn ich's diesmal nicht genau erklären konnte... Pech gehabt. :P

nachtrag: "static" vergessen...

Dax 30. Apr 2005 23:06

Re: Match funktion?
 
Nein, das reicht schon, habs verstanden :kiss:

Muetze1 1. Mai 2005 00:28

Re: Match funktion?
 
Moin!

/EDIT: ok, hat sich erledigt - einen kleinen Satz überlesen...

MfG
Muetze1

Robert_G 1. Mai 2005 00:32

Re: Match funktion?
 
Zitat:

Zitat von Pseudemys Nelsoni
die MatchesMask() Funktion geht hierfür nicht, da der Joker "?" dort heisst das ein Zeichen vorkommen KANN, aber nicht MUSS.... ich brauch aber das "muss".

;)

...und mein erster Post war eigentlich nur eine Reaktion auf mirages, der auf einen Satz in Mthias' Beitrag reagiert hat... :freak:

yankee 1. Mai 2005 01:13

Re: Match funktion?
 
ohne jetzt wirklich alles gelesen zu haben. Hast du schonmal versucht statt einem ? ein + zu verwenden? Ich meine, das wäre nämlcih für diesen Zweck...

MathiasSimmack 1. Mai 2005 07:41

Re: Match funktion?
 
Mit "zu dick" meinte ich, dass ich reguläre Ausdrücke gleich für zu aufwändig halte. In meinem Fall. Außerdem müsste ich dann vermutlich die Syntax meiner XML-Datei ändern (schon wieder :?), weil die Strings aus einer solchen kommen. Darum dachte ich, es gibt vllt. eine einfach Möglichkeit, schnell zwei Strings miteinander zu vergleichen, wenn einer die typischen DOS-Wildcards * und ? benutzt. Ich habe nichts gegen reguläre Ausdrücke, aber in dem Fall wäre es für mich wie "mit Kanonen auf Spatzen ..." ;)

Muss ich Robert jetzt etwa auch küssen? :gruebel:

sECuRE 1. Mai 2005 08:25

Re: Match funktion?
 
Hi,

ich hab dafür folgenden Code geschrieben, den ich allerdings erst 2 Wochen testen konnte, also ohne Gewähr ;) Für Verbesserungen bin ich jederzeit offen:
Delphi-Quellcode:
// Erlaubte Wildcards:
// * = alles oder nichts
// ? = einzelnes zeichen MUSS vorkommen
// # = Zahl MUSS vorkommen
function WildCardMatch(const check, mask:string):boolean;
var _next_wc:integer;
    a,b:string;
function find_wildcard(const _check:string):integer;
begin
if (Pos('*',_check) = 0) then
  if (Pos('?',_check) = 0) then
    if (Pos('#',_check) = 0) then
      result:=-1
    else result:=Pos('#',_check)
  else result:=Pos('?',_check)
else result:=Pos('*',_check);
end;
function parse_from_wc(const wildcard, _check:string):boolean;
var next_wc,off_set,first_of:integer;
    t,tmp:string;
begin
result:=true;
if (copy(wildcard,1,1) = '#') then begin
  if (length(_check) = 0) or (not IsNumber(copy(_check,1,1))) then begin
    result:=false;
    exit;
  end;
  t:=copy(wildcard,2,length(wildcard));
  next_wc:=find_wildcard(t);
  if (next_wc = -1) then
    result:=true
  else begin
    tmp:=copy(wildcard,2,next_wc-1);
    if (length(tmp) = 0) then begin
      result:=false;
      exit;
    end else
      if (IsNumber(copy(_check,1,length(tmp)))) then
        if (not parse_from_wc(copy(wildcard,next_wc+1,length(wildcard)),copy(_check,next_wc+1,length(_check)))) then begin
          result:=false;
          exit;
        end else
      else begin
        result:=false;
        exit;
      end;
  end;
end else if (copy(wildcard,1,1) = '?') then begin
if (length(_check) = 0) then begin
    result:=false;
    exit;
  end;
  t:=copy(wildcard,2,length(wildcard));
  next_wc:=find_wildcard(t);
  if (next_wc = -1) then
    result:=(t = copy(_check,2,length(_check)))
  else begin
    tmp:=copy(wildcard,2,next_wc-1);
    if (length(tmp) = 0) then begin
      result:=false;
      exit;
    end else
      if (not parse_from_wc(copy(wildcard,next_wc+1,length(wildcard)),copy(_check,next_wc+1,length(_check)))) then begin
        result:=false;
        exit;
      end;
  end;
end else if (copy(wildcard,1,1) = '*') then begin
  t:=copy(wildcard,2,length(wildcard));
  next_wc:=find_wildcard(t);
  if (next_wc = -1) then begin
    if (length(_check) >= length(t)) then
      result:=(copy(_check,1+length(_check)-length(t),length(_check)) = t)
    else result:=false;
    exit;
  end else begin
    if (next_wc = 0) then begin
      result:=parse_from_wc(copy(wildcard,2,length(wildcard)),_check);
      exit;
    end else begin
      off_set:=1;
      tmp:=copy(wildcard,2,next_wc-1);
      while (true) do begin
        first_of:=Pos(tmp,copy(_check,off_set,length(_check)));
        if (first_of = 0) then begin
          result:=false;
          exit;
        end else begin
          off_set:=first_of+length(tmp);
          if (parse_from_wc(copy(wildcard,next_wc+2,length(wildcard)),
                            copy(_check,off_set,length(_check)))) then begin
            result:=true;
            exit;
          end;
        end;
      end;
    end;
  end;
end;
end;
begin
if (length(check) = 0) then begin
  result:=false;
  exit;
end;
result:=true;
_next_wc:=find_wildcard(mask);
if (_next_wc = 0) then
  result:=parse_from_wc(mask,check)
else if (_next_wc = -1) then
  result:=(check = mask)
else begin
  a:=copy(check,1,_next_wc-1);
  b:=copy(mask,1,_next_wc-1);
  if (a <> b) then begin
    result:=false;
    exit;
  end;
  if (not parse_from_wc(copy(mask,_next_wc,length(mask)-_next_wc+1),
                        copy(check,_next_wc,length(check)-_next_wc+1))) then begin
    result:=false;
    exit;
  end;
end;
end;
Edit: Folgende Funktion wird auch benötigt:
Delphi-Quellcode:
function IsNumber(const s:string): Boolean;
var c:integer;
const nums:string = '0123456789';
begin
 result:=(length(s) > 0);
 for c:=1 to length(s) do
  if (Pos(copy(s,c,1),nums) = 0) then begin
   result:=false;
   Break;
  end;
end;
Viel Spaß ;)
cu

MathiasSimmack 1. Mai 2005 08:32

Re: Match funktion?
 
Zitat:

Zitat von sECuRE
Edit: Folgende Funktion wird auch benötigt:
Delphi-Quellcode:
function IsNumber(const s:string): Boolean;
var c:integer;
const nums:string = '0123456789';
begin
 result:=(length(s) > 0);
 for c:=1 to length(s) do
  if (Pos(copy(s,c,1),nums) = 0) then begin
   result:=false;
   Break;
  end;
end;
Viel Spaß ;)

Mach dich mal über Delphi-Referenz durchsuchenVal schlau. Das dürfte einfacher sein. :stupid: Delphi-Referenz durchsuchenStrToInt in Verbindung mit try/except ginge auch. Deine andere Funktion habe ich mir nicht angeschaut. Zuviel für mich am Sonntag Morgen. :mrgreen:

sECuRE 1. Mai 2005 12:24

Re: Match funktion?
 
Hi,

@MathiasSimmack: Ich programmiere nicht so gern mit Exceptions, das ist für mich so die Hau-Drauf-Methode à la "Frag ihn nicht ob das eine Platzwunde ist, drück drauf und wenn er schreit ist es eine" ;) Ist die Methode mit Exceptions denn erheblich schneller als meine?

cu

MathiasSimmack 1. Mai 2005 12:31

Re: Match funktion?
 
Was heißt schneller? Es ging nur um die Ziffernerkennung:
Delphi-Quellcode:
try
  StrToInt(stringVariable);
  Result := true;
except
  Result := false;
end;
ist ebenso elegant wie
Delphi-Quellcode:
Val(stringVariable, integerVariable, errorCode);
Result := errorCode = 0;
Auf jeden Fall ist beides vermutlich besser als der Weg, den du gewählt hast. :stupid: Zumal deine Funktion bei einer negativen Zahl wie -1,-2, ... versagen würde. ;)

Robert_G 1. Mai 2005 12:34

Re: Match funktion?
 
Zitat:

Zitat von sECuRE
Ist die Methode mit Exceptions denn erheblich schneller als meine?

Ganz sicher ist sie das. ;)
Wenn du das ganze Stringkopieren sein lässt und einfach einen PChar auf den Eingabe string legst (Durch den kannst du easy per increment iterieren. ;) ),dürfte auch deine nicht mehr so lagsam sein, bzw. nicht mehr so viel Speicher verbraten.

Und wie MS schon sagte... bei deiner gehen nur positive ints. ;)

sECuRE 1. Mai 2005 13:07

Re: Match funktion?
 
Hi,

gut, mag sein. In meinem Fall will ich aber nur positive Ganzzahlen zulassen, von daher brauch ich die negativen gar nicht zu beachten ;) Wer in den Wildcards auch negative Zahlen zulassen will kann ja den von MathiasSimmack geposteten Vorschlag verwenden.

Danke für die Vorschläge,
cu

Pseudemys Nelsoni 10. Mai 2005 04:41

Re: Match funktion?
 
danke euch allen :)

Ich hab mich für Mathias Simmacks's Funktion entschieden.

@Mathias: Kannst du mir noch erklären, wie bzw warum die funktion 2mal existiert? bzw sie unterteilt ist?



Edit: Und kann ich die Funktion irgendwie in eine Klasse packen so das sie von aussen nicht sichtbar ist?

Hier:

Delphi-Quellcode:
  TIAL = class(TObject)
  private
    function PathMatchSpec(pszFile, pszSpec: PAnsiChar): bool; stdcall; external 'shlwapi.dll' name 'PathMatchSpecA';
  public

  end;
meint der compiler das external ein feld sei und es damit nicht nach einer funktion erlaubt ist...

Alexander Roth 23. Okt 2005 15:13

Re: Match funktion?
 
Ich kaper euer Anfangsproblem irgendwie nicht.
Zitat:

die MatchesMask() Funktion geht hierfür nicht, da der Joker "?" dort heisst das ein Zeichen vorkommen KANN, aber nicht MUSS.... ich brauch aber das "muss".
Komisch wieso macht er dann
Zitat:

nein
wenn ich das ausprobiere
Delphi-Quellcode:
if matchesmask('','?') then showmessage('jo')
  else showmessage ('nein');
oh is schon ok.

denn das gibt jo aus
Delphi-Quellcode:
if matchesmask('a','??') then showmessage('jo')
  else showmessage ('nein');


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:16 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz