'=========================================================================== ' Subject: WILDCARD HANDLING Date: 11-11-97 (11:43) ' Author: Hauke Daempfling Code: QB, QBasic, PDS ' Origin: hcd@berlin.snafu.de Packet: TEXT.ABC '=========================================================================== DEFINT A-Z DECLARE FUNCTION WildCardCount% (WCstr$) DECLARE FUNCTION WildCardString$ (WCstr$, Istr$, Wone%) DECLARE FUNCTION WildCardMatch% (WCstr$, Istr$) ' ' *** Wildcard Handling *** ' by Hauke Daempfling ' hcd@berlin.snafu.de ' '(c)1996 Hauke Daempfling ' ' Give me credit if used... thanx! :) ' ' Not really perfected... mail any changes to me... thanx :) ' Don't ask "how does it work".... I don't remember myself :) ' 'This program will count, check matches, and retreive wildcard strings. 'Anything's valid for input, except you CANNOT put two wildcards after 'one another, the matching routine will not know how many characters 'to give to the wildcards. Invalid would is "**" and "*?". Valid IS '"??" and "?*". You would have problems with "* *" or any mask 'containing two *'s after one another with 3 or less characters 'between them, since WildCardMatch/String sorts out the wildcards 'according to the charactes between them. For a mask like "* *" and 'input string like "this is cool", WildCardString for 1 will return '"this" for the first * and "is cool" for the second *, even though 'you might want it the other way around. ' mask$ = "test * this *man? !!*" text$ = "test ABC this DmanE !!FGH IJK" CLS PRINT "Wilcard string: "; mask$ PRINT "Input string: "; text$ PRINT PRINT "Counting wildcards..." x = WildCardCount(mask$) IF x = -1 THEN PRINT ">>> Error" ELSE PRINT ">>>"; x PRINT PRINT "Checking match..." x = WildCardMatch(mask$, text$) IF x = 0 THEN PRINT ">>> No match/Error" ELSE PRINT ">>> Match" FOR a = 1 TO WildCardCount(mask$) PRINT PRINT "Getting wildcard string"; a; "..." x$ = WildCardString$(mask$, text$, a) IF x$ = "" THEN PRINT ">>> No match/Error" ELSE PRINT ">>> "; x$ NEXT a PRINT : PRINT "Press any key..." DO: LOOP UNTIL INKEY$ <> "": CLS PRINT "Please wait..." mask$ = "abc*def*ghi?jk??lm*" text$ = "abcXXXdefXghiXjkXXlmXX" sT# = TIMER FOR a = 1 TO 2000 x = WildCardMatch(mask$, text$) NEXT a eT# = TIMER PRINT "2000 wilcard strings matched in"; eT# - sT#; "seconds. " PRINT "That's about one wildcard match in"; (eT# - sT#) / 2000#; "seconds." FUNCTION WildCardCount (WCstr$) IF WCstr$ = "" THEN WildCardCount = -1: EXIT FUNCTION FOR a = 1 TO LEN(WCstr$) 'simpily count the wildcards IF MID$(WCstr$, a, 1) = "*" OR MID$(WCstr$, a, 1) = "?" THEN WCC = WCC + 1 NEXT a WildCardCount = WCC END FUNCTION FUNCTION WildCardMatch (WCstr$, Istr$) WCM = -1: Wpos = 0: Rpos = 0 'init variables IF WCstr$ = "" OR Istr$ = "" THEN WildCardMatch = 0: EXIT FUNCTION '^^^ can't process null strings IF LEFT$(WCstr$, 1) = "*" THEN WCstr$ = " " + WCstr$: Istr$ = " " + Istr$ DO '^^^ can't process * at beginning of string Rpos = Rpos + 1 'position in Istr$ Wpos = Wpos + 1 'position in WCstr$ 'for debugging, *** look at it if you don't understand WildCardMatch *** 'SLEEP 1: CLS 'PRINT WCstr$: PRINT SPACE$(Wpos - 1); "^" 'PRINT Istr$: PRINT SPACE$(Rpos - 1); "^" IF MID$(WCstr$, Wpos, 1) = "*" THEN 'if there's a * wildcard 'the idea of this is to skip over whatever characters are in ' Istr$ supplementing the * wildcard by setting Rpos according ' to the position of NextChrs$ in Istr$ so we can continue scanning 'NextChrs$ are the characters between the current wildcard and the ' next one, that is why two wildcards next to one another are not ' allowed (NextChrs$ would be "", or " ", etc.). NextPos = INSTR(Wpos + 1, WCstr$, "*") - 1 'find the next * IF NextPos <= 0 THEN NextPos = INSTR(Wpos + 1, WCstr$, "?") - 1 '^^^ if there's no * left, there might be a ? IF NextPos <= 0 THEN NextPos = LEN(WCstr$) '^^^ if there's still no ?/* found, then that was the last wildcard NextChrs$ = MID$(WCstr$, Wpos + 1, NextPos - Wpos) 'get string between IF NextChrs$ = "" THEN ' the two *'s IF Wpos = LEN(WCstr$) THEN 'if we're at the end of the string EXIT DO ' and it's matched so far, then it's ELSE ' a match WCM = 0: EXIT DO 'if not, no match END IF END IF IF INSTR(NextChrs$, "?") THEN NextPos = INSTR(Wpos + 1, WCstr$, "?") - 1 IF NextPos <= 0 THEN NextPos = LEN(WCstr$) 'this is in case NextChrs$ = MID$(WCstr$, Wpos + 1, NextPos - Wpos) ' it's a sequence IF NextChrs$ = "" THEN WCM = 0: EXIT DO ' of * ? * Cnt = 0 'find our positon FOR a = Rpos TO LEN(Istr$) - LEN(NextChrs$) + 1 ' in Istr$ IF MID$(Istr$, a, LEN(NextChrs$)) = NextChrs$ THEN Cnt = a: EXIT FOR NEXT a IF Cnt = 0 THEN WCM = 0: EXIT DO 'if we didn't find it then no match Rpos = Cnt - 1 'set the scan positon in Istr$ ELSE IF MID$(WCstr$, Wpos, 1) = MID$(Istr$, Rpos, 1) THEN 'Match ELSEIF MID$(WCstr$, Wpos, 1) = "?" THEN 'Match ELSE 'No match WCM = 0: EXIT DO END IF END IF LOOP UNTIL Rpos > LEN(Istr$) WildCardMatch = WCM END FUNCTION FUNCTION WildCardString$ (WCstr$, Istr$, Wone) IF Wone <= 0 THEN WildCardString$ = "": EXIT FUNCTION '^^^ can't process negative wildcards FOR a = 1 TO LEN(WCstr$) 'find the position of the wildcard we want IF MID$(WCstr$, a, 1) = "*" OR MID$(WCstr$, a, 1) = "?" THEN WCC = WCC + 1 IF WCC = Wone THEN WCC = a: EXIT FOR END IF NEXT a IF WCC = 0 THEN WildCardString$ = "": EXIT FUNCTION 'this routine is practically like WildCardMatch IF LEFT$(WCstr$, 1) = "*" THEN WCstr$ = " " + WCstr$: Istr$ = " " + Istr$ DO Rpos = Rpos + 1 Wpos = Wpos + 1 'debugging 'SLEEP 1: CLS 'PRINT WCstr$: PRINT SPACE$(Wpos - 1); "^" 'PRINT Istr$: PRINT SPACE$(Rpos - 1); "^" IF MID$(WCstr$, Wpos, 1) = "*" THEN NextPos = INSTR(Wpos + 1, WCstr$, "*") - 1 IF NextPos <= 0 THEN NextPos = INSTR(Wpos + 1, WCstr$, "?") - 1 IF NextPos <= 0 THEN NextPos = LEN(WCstr$) NextChrs$ = MID$(WCstr$, Wpos + 1, NextPos - Wpos) IF NextChrs$ = "" THEN IF Wpos = LEN(WCstr$) THEN WCS$ = MID$(Istr$, Rpos): EXIT DO 'get wildcard string ELSE WCS$ = "": EXIT DO END IF END IF IF INSTR(NextChrs$, "?") THEN NextPos = INSTR(Wpos + 1, WCstr$, "?") - 1 IF NextPos <= 0 THEN NextPos = LEN(WCstr$) NextChrs$ = MID$(WCstr$, Wpos + 1, NextPos - Wpos) 'get wilcard string IF NextChrs$ = "" THEN WCS$ = "": EXIT DO Cnt = 0 FOR a = Rpos TO LEN(Istr$) - LEN(NextChrs$) + 1 IF MID$(Istr$, a, LEN(NextChrs$)) = NextChrs$ THEN Cnt = a: EXIT FOR NEXT a IF Cnt = 0 THEN WCS$ = "": EXIT DO IF Wpos = WCC THEN WCS$ = MID$(Istr$, Rpos, Cnt - Rpos): EXIT DO Rpos = Cnt - 1 '^^^ get wildcard string ELSE IF MID$(WCstr$, Wpos, 1) = MID$(Istr$, Rpos, 1) THEN 'Match ELSEIF MID$(WCstr$, Wpos, 1) = "?" THEN 'Match IF Wpos = WCC THEN WCS$ = MID$(Istr$, Rpos, 1): EXIT DO ELSE '^^^ get wilcard character WCS$ = "": EXIT DO END IF END IF LOOP UNTIL Rpos > LEN(Istr$) WildCardString$ = WCS$ END FUNCTION