[delphi] wildcard search

Pagina: 1
Acties:
  • 207 views sinds 30-01-2008
  • Reageer

  • Parcye
  • Registratie: Maart 2001
  • Laatst online: 24-08-2017
Hoi

Ik ben bezig met mijn editor voor ChampionShip Manager 2001/2002 en wil nu eens een wildcard search inbouwen, dus * is maakt niet uit en ? is een willekeurig char.

Hier is naar mijn weten geen standaard functie voor, iemand die het al ooit heeft geprobeer te maken of weet hoe het moet?

Want ik kan alleen gruwelijk lange en langzame oplossing verzinnen.

Grtz
Colin

http://www.parcye.com/vb/

"Als je het kan bedenken, kan het gemaakt worden" Parcye - 14 januari 2002


Verwijderd

Bedoel je bestanden zoeken? Dat kan gewoon met FindFirst, FindNext...

  • Parcye
  • Registratie: Maart 2001
  • Laatst online: 24-08-2017
Nee, ik sla alle clubs stadions en spelers op in een TStringList en daar wil ik door zoeken met wildcards

"Als je het kan bedenken, kan het gemaakt worden" Parcye - 14 januari 2002


Verwijderd

Zoeken bij Google op "delphi regular expression" levert 10 pagina's aan hits op. Zal best wel iets bruikbaars tussen zitten... :)

Verwijderd

Of bv hier

Verwijderd

Op dinsdag 04 december 2001 20:12 schreef DiFool het volgende:
Of bv hier
Beetje overdreven dat 'ie daar een eigen class voor in 't leven roept, maar alla...

Wanneer je (net als ik was) alleen maar geinteresseerd bent in 'is gelijk', 'bevat', 'begint met' en 'eindigt op', dan is dit functietje misschien wel bruikbaar:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
function FindString(ASearch, AString: string): boolean;
  {
  Case insensitive search in a string.
  ASearch can start and/or end with a '*' as a wildcard.
  'ABCD'    -> ASearch matches AString.
  'ABCD*'   -> AString starts with ASearch (without the asterix).
  '*ABCD'   -> AString ends with ASearch.
  '*ABCD*'  -> AString contains ASearch.
  }
var
  bAtBegin, bAtEnd: boolean;
begin
  Result := False;
  if (ASearch = '*') or (ASearch = '**') then
    Result := True
  else if AString > '' then begin
    bAtBegin := (ASearch[1] <> '*');
    bAtEnd := (ASearch[Length(ASearch)] <> '*');

    // strip leading and trailing asterixes
    if (Length(ASearch) > 0) and (ASearch[1] = '*') then
    ASearch := Copy(ASearch, 2, Length(ASearch) - 1);
    if (Length(ASearch) > 0) and (ASearch[Length(ASearch)] = '*') then
    ASearch := Copy(ASearch, 1, Length(ASearch) - 1);

    if Length(AString) < Length(ASearch) then Exit;
    if bAtBegin and bAtEnd then
    // whole word match
    Result := (AnsiCompareText(ASearch, AString) = 0)
    else begin
    if bAtBegin then
      // at beginning of string
      Result := (AnsiCompareText(ASearch, Copy(AString, 1, Length(ASearch))) = 0)
    else if bAtEnd then
      // at end of string
      Result := (AnsiCompareText(ASearch, Copy(AString, Length(AString) - Length(ASearch) + 1,
                         Length(ASearch))) = 0)
    else
      // somewhere in string
      Result := Pos(UpperCase(ASearch), UpperCase(AString)) > 0;
    end;
  end;
end;

Verwijderd

Ik heb die code uit die link die ik gaf wat verbeterd, en volgens mij doet ie het nog :)
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
function IsSame(const S, WildCard: string; const CaseSensitive: Boolean):
Boolean;

  function SameName(P, WildCard: PChar): Boolean;
  begin
    Result := True;

    while Result and (P^ <> #0) and (WildCard^ <> #0) do
    case WildCard^ of
      '?':
        begin
        Inc(P);
        Inc(WildCard);
        end;
      '*':
        begin
        Inc(WildCard);
        if WildCard^ <> #0 then
        begin
          while (P^ <> #0) and not SameName(P, WildCard) do
            Inc(P);
          if P^ = #0 then
            Result := False
          else
          begin
            while P^ <> #0 do
            Inc(P);
            while WildCard^ <> #0 do
            Inc(WildCard);
          end;
        end
        else
          while P^ <> #0 do
            Inc(P);
        end
    else
      begin
        Result := P^ = WildCard^;
        if Result then
        begin
        Inc(P);
        Inc(WildCard);
        end;
      end;
    end;

    if Result then
    while WildCard^ = '*' do
      Inc(WildCard);
    Result := Result and (P^ = #0) and (WildCard^ = #0);
  end;

begin
  if CaseSensitive then
    Result := SameName(PChar(UpperCase(S)), PChar(UpperCase(WildCard)))
  else
    Result := SameName(PChar(S), PChar(WildCard));
end;

Verwijderd

Op dinsdag 04 december 2001 21:32 schreef DiFool het volgende:
Ik heb die code uit die link die ik gaf wat verbeterd, en volgens mij doet ie het nog :)
Nadeel bij PChars en recursie is dat je 12x moet lezen voor je snapt wat er staat, maar volgens mij moet 'ie 't ook nog doen. Al ben ik er nog niet zeker van wat er gebeurt wanneer je een '*' midden in een zoekstring zet...
Zoeken we nog uit. :)

Verwijderd

Ik vind PChar's wel makkelijk werken met zoeken in strings enz. Vooral door de Inc(P) en de laatste #0 in een string.

Recursie is meestal niet zo moeilijk om te zien. Het volgt gewoon een inductief bewijs.

Dus in dit geval berekent IsSame of string met lengte n gelijk is aan een wildcard. In de functie ga je ervan uit [en kun je ervan uitgaan] dat de functie IsSame klopt voor strings met lengte n-1. Je moet dus zorgen dat de functie klopt voor strings met lengte n, maar je kunt gebruik maken van IsSame voor strings met lengte n-1. In dit geval doe je dat door te kijken naar de eerste char van de string; bij een char anders dan * kun je die skippen en kun je de functie IsSame weer aanroepen. Bij * moet je iets meer doen... :)

Nu ik dit zo opschrijf bedenk ik me dat die while-loop niet echt nodig is, omdat je daarvoor ook recursie kan gebruiken...

[edit: en wel zo]
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
function SameName(P, WildCard: PChar): Boolean;
begin
  { Is P een lege string? }
  if P^ = #0 then
  begin
    { Zo ja, dan is P gelijk aan de WildCard als die leeg
    is of uit alleen maar *'tjes bestaat }

    while WildCard^ = '*' do
    Inc(WildCard);
    Result := WildCard^ = #0;
  end
  else
    { P is niet de lege string, wat is de eerste char van
    de WildCard string }
    case WildCard^ of
    '?':
      { Bij een ? doet het er niet toe wat de eerste char
        van P is dus is het resultaat gelijk aan ... of
        andersom: als string P' gelijk is aan de wildcard
        W' dan is Ch + P' gelijk aan '?' + W' met Ch een
        willekeurige char.}
      Result := SameName(P + 1, WildCard + 1);
    '*':
      begin
        Inc(WildCard);

        { Is WildCard alleen maar '*'? }
        if WildCard^ <> #0 then
        begin
        { We kunnen een willekeurig aantal eerste tekens
          uit P skippen; als die string gelijk is aan de
          WildCard zonder de eerste * dan is P gelijk
          aan de WildCard string met * , of andersom:
          als P' gelijk is aan W' dan is P'' + P' gelijk
          aan '*' + W' met P'' een willekeurige string}
        while (P^ <> #0) and not SameName(P, WildCard) do
          Inc(P);
        Result := P^ <> #0;
        end
        else
        { WildCard = '*', dan is P altijd gelijk aan 
          WildCard }
        Result := True;
      end
    else
    { De eerste char van WildCard is niet ? of *, dan is
      WildCard gelijk aan P, als de eerste tekens gelijk
      zijn, én als WildCard zonder de eerste char en P 
      zonder de eerste char gelijk zijn.
      [WildCard kan ook de lege string zijn dan is 
       P^ <> WildCard^ omdat P^ <> #0] }
    Result := (P^ = WildCard^) and SameName(P + 1, WildCard + 1);
    end;
end;

Verwijderd

Op dinsdag 04 december 2001 23:48 schreef DiFool het volgende:
Nu ik dit zo opschrijf bedenk ik me dat die while-loop niet echt nodig is, omdat je daarvoor ook recursie kan gebruiken...
Ik ben benieuwd! :)
En ondertussen zou 't misschien voor de oplettende meelezertjes ook niet zoveel kwaad kunnen om zo hier en daar een commentaarregeltje in te lassen?

  • Onno
  • Registratie: Juni 1999
  • Niet online
Op dinsdag 04 december 2001 23:48 schreef DiFool het volgende:
Nu ik dit zo opschrijf bedenk ik me dat die while-loop niet echt nodig is, omdat je daarvoor ook recursie kan gebruiken...
Het is alleen de vraag of dat efficienter is. (qua snelheid, en geheugengebruik (stack))

  • Elissen
  • Registratie: Januari 2000
  • Laatst online: 27-07 15:54
Waarom het wiel opnieuw uitvinden? Kijk eens naar TMask:
TMask allows the comparison of strings containing wildcards to a file mask.

Unit
Masks

Description
Use TMask to determine if a string matches the format described by a mask. The mask contains literal characters, wildcards that can match any character, and sets that match a single character that is included in the set.

Note:Do not confuse TMask with the EditMask of a field or masked edit object. While both are used for comparing strings to a symbolic description of valid values, the special mask symbols and matching rules are completely different.
Er staat wel 'file mask', maar je kan het natuurlijk ook gewoon voor strings gebruiken.
Pagina: 1