Announcement
Collapse
No announcement yet.
Case insensitive INSTR
Collapse
X
-
RegxprMichael Mattias
Tal Systems (retired)
Port Washington WI USA
[email protected]
http://www.talsystems.com
-
Only tested slightly, but looking pretty good so far. See notes in functions.
Code:#COMPILE EXE #DIM ALL FUNCTION PBMAIN () AS LONG LOCAL ii, ii2, ii3, htxt AS LONG, line1, line2 AS STRING LOCAL t, t2 AS QUAD TXT.WINDOW("Bakerware", 150, 100) TO hTxt OPEN "filename.dat" FOR BINARY LOCK WRITE AS #1 line1 = REPEAT$(10000 ,"QWERTYUIOP[]ASDFGHJKL;'ZXCVBNM,./qwertyuiop[]asdfghjkl;'zxcvbnm,./1234567890-=") & "HeLLo THErE!" line2 = "Hello There!" TIX t ii = INSTR(UCASE$(line1), UCASE$(line2)) TIX END t TXT.PRINT "PB UCASE$ tix","","", t; "pos found"; ii TIX t ii = caseFreeInstr(line1, line2, 0, 0) TIX END t TXT.PRINT TXT.PRINT "1st call tix:","","", t; "pos found"; ii TXT.PRINT TIX t ii = caseFreeInstr(line1, line2, 0, 0) TIX END t TXT.PRINT "2nd+ call tix:","", t; "pos found"; ii TXT.PRINT TIX t TIX t ii = caseFreeInstr(line1, line2, 1, 0) TIX END t TXT.PRINT "2nd+ call, mainStr already UCASE tix:", t; "pos found"; ii TXT.PRINT TIX t ii = caseFreeInstr(line1, line2, 1, -1) TIX END t TXT.PRINT "2nd+ reverse srch, already UCASE tix:", t; "pos found"; ii TXT.PRINT TXT.WAITKEY$ END FUNCTION FUNCTION caseFreeInstr(mainStr AS STRING, matchStr AS STRING, mainStrIsUcase AS LONG, reverse AS LONG) AS LONG 'note1: this fcn will cap mainStr and matchStr! This can good for multiple compares on the same mainStr. 'note2: fcn allows to shortcut past UCASE'ing mainStr by setting mainStrIsUcase <> 0. If function has been called 'already, and mainStr has been used previously as a parameter to this function (and has not been altered since), 'then setting mainStrIsUcase to non-zero will speed function up many X. REGISTER ii AS LONG, ii2 AS LONG DIM sArr(LEN(mainStr)-1) AS BYTE AT STRPTR(mainStr) DIM sArr2(LEN(matchStr)-1) AS BYTE AT STRPTR(matchStr) DIM translateArr(255) AS STATIC BYTE IF translateArr(3) = 0 THEN CALL arrayAssign(translateArr()) FOR ii = 0 TO LEN(matchStr)-1 sArr2(ii) = translateArr(sArr2(ii)) 'make it uppercase NEXT IF mainStrIsUcase = 0 THEN FOR ii = 0 TO LEN(mainStr)-1 sArr(ii) = translateArr(sArr(ii)) 'make it uppercase NEXT END IF IF reverse = 0 THEN FUNCTION = INSTR(mainStr, matchStr) ELSE FUNCTION = INSTR(-1, mainStr, matchStr) END IF END FUNCTION SUB arrayAssign(translateArr() AS BYTE) ARRAY ASSIGN translateArr() = 0,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,59,60, _ 61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80, _ 81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,65,66,67,68, _ 69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88, _ 89,90,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140, _ 141,142,143,144,145,146,147,148,149,150,151,152,153,138,155,140,157,142,159,160, _ 161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180, _ 181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200, _ 201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220, _ 221,222,223,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208, _ 209,210,211,212,213,214,247,216,217,218,219,220,221,222,159 END SUB
Comment
-
John
You are of course on the right track. Intel has provided a specific instruction to handle this XLAT. So if a large number of case insensitive INSTRs are to be done setting up the translation table in advance is a great speed saving.
The PB INSTR function is actually quite complex.
Consider INSTR(start, t1, t2). So either t1 or t2 or both may be the changing variables or both and of course there are the options on start.
A specific case where either t1 or t2 is always constant and start is always 1 is a good case for using assembler particularly if the variable string remains unchanged.
If the required filter was shown (as MCM didn't say "code not shown") then I suspect a number of BMs could post assembler to quickly handle a specific use.
Comment
-
If string is ANSI you can create your 'upppercase' version by treating each char as a byte and AND'ing off bit 5.
Code:LOCAL pSrc, pTAR as BYTE PTR TargetString = SPACE$(LEN(SourceString)) pSrc = STRPTR (SourceString) pTar = STRPTR (TargetString) FOR registervar = 1 to LEN (SourceString) @pTar = @pSrc AND &B11011111 INCR pTar INCR pSrc NEXT
MCMMichael Mattias
Tal Systems (retired)
Port Washington WI USA
[email protected]
http://www.talsystems.com
Comment
-
John P., I actually had tried some quick asm for the uppercasing trans table, but didn't see an improvement.So, I left it as is figuring it'd be more effort than payoff.
MCM, I also used the AND'ing off bit 5 technique at first, but because the string can be any of 256 chars, logic needed to be be invoked to avoid turning e.g. "8" into chr$(24).
Comment
-
So test for range of @pSRC between 97 and 122 (decimal) ( 'a' thru 'z') before ANDing.Michael Mattias
Tal Systems (retired)
Port Washington WI USA
[email protected]
http://www.talsystems.com
Comment
-
>> test for range of @pSRC between 97 and 122
And don't forget 230-255 and four or five other scattered bytes.
I already feel bad enough that the algo is over 3x slower than INSTR alone. Make it 4 or 5x slower and I'd have to consider bumping the meds 50%, or maybe even switching to one of those experimental Swiss formulations currently banned in Michigan.
Comment
-
Here's my attempt, it appears a bit slower than instr but not a lot and it does the case insensitive for free. The Boyer Moore looked like a bit more work to make case insensitive. This was a really simple implementation but it did ok for now. Tomorrow I'll see whether I can filter 1,000,000 live.
Code:[color=#0000C0]#Compile Exe #Dim All Function PBMain [/color][color=#8000FF]() [/color][color=#0000C0]As Long [/color][color=#007F00]'Call CreateTable [/color][color=#0000C0]Call [/color][color=#000000]DoTest[/color][color=#8000FF]() [/color][color=#0000C0]End Function Sub [/color][color=#000000]DoTest[/color][color=#8000FF]() [/color][color=#0000C0]Local [/color][color=#000000]hWin [/color][color=#0000C0]As Dword Local [/color][color=#000000]a [/color][color=#0000C0]As String Txt.Window[/color][color=#8000FF]([/color][color=#C020C0]"Case Insensitive Test"[/color][color=#8000FF], [/color][color=#000000]10[/color][color=#8000FF], [/color][color=#000000]10[/color][color=#8000FF]) [/color][color=#0000C0]To [/color][color=#000000]hWin [/color][color=#0000C0]Local [/color][color=#000000]i [/color][color=#0000C0]As Long Call [/color][color=#000000]TestSearch[/color][color=#8000FF]( [/color][color=#C020C0]"this is a super great test of the case insenstive isntri"[/color][color=#8000FF], [/color][color=#C020C0]"InS" [/color][color=#8000FF]) [/color][color=#0000C0]Call [/color][color=#000000]TestSearch[/color][color=#8000FF]( [/color][color=#C020C0]"short run"[/color][color=#8000FF], [/color][color=#C020C0]"RUN" [/color][color=#8000FF]) [/color][color=#0000C0]Call [/color][color=#000000]TestSearch[/color][color=#8000FF]( [/color][color=#C020C0]"Haaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaneedleaaaaaaaay"[/color][color=#8000FF], [/color][color=#C020C0]"NEEDLE" [/color][color=#8000FF]) [/color][color=#0000C0]Txt.Print [/color][color=#C020C0]"Finished" [/color][color=#0000C0]Txt.Line.Input [/color][color=#000000]a [/color][color=#0000C0]End Sub Sub [/color][color=#000000]TestSearch[/color][color=#8000FF]( [/color][color=#0000C0]ByVal [/color][color=#000000]matchString [/color][color=#0000C0]As String[/color][color=#8000FF], [/color][color=#0000C0]ByVal [/color][color=#000000]findString [/color][color=#0000C0]As String [/color][color=#8000FF]) [/color][color=#0000C0]Local [/color][color=#000000]j [/color][color=#0000C0]As Long Local [/color][color=#000000]st[/color][color=#8000FF], [/color][color=#000000]en [/color][color=#0000C0]As Quad Local [/color][color=#000000]s1#[/color][color=#8000FF], [/color][color=#000000]e1# [/color][color=#0000C0]Local [/color][color=#000000]msg [/color][color=#0000C0]As String Local [/color][color=#000000]i[/color][color=#8000FF], [/color][color=#000000]c [/color][color=#0000C0]As Long [/color][color=#000000]s1 [/color][color=#8000FF]= [/color][color=#0000C0]Timer For [/color][color=#000000]j[/color][color=#8000FF]=[/color][color=#000000]1 [/color][color=#0000C0]To [/color][color=#000000]1000000 i [/color][color=#8000FF]= [/color][color=#000000]InstrI[/color][color=#8000FF]( [/color][color=#000000]matchString[/color][color=#8000FF], [/color][color=#000000]findString [/color][color=#8000FF]) [/color][color=#0000C0]Next [/color][color=#000000]e1 [/color][color=#8000FF]= [/color][color=#0000C0]Timer Txt.Print [/color][color=#C020C0]"InstrI. "[/color][color=#8000FF]; [/color][color=#0000C0]Format$[/color][color=#8000FF]( [/color][color=#000000]i[/color][color=#8000FF], [/color][color=#C020C0]"0"[/color][color=#8000FF]); [/color][color=#C020C0]" in "[/color][color=#8000FF]; [/color][color=#0000C0]Format$[/color][color=#8000FF]( [/color][color=#000000]e1[/color][color=#8000FF]-[/color][color=#000000]s1[/color][color=#8000FF], [/color][color=#C020C0]"#,##0.0000"[/color][color=#8000FF]) [/color][color=#000000]s1 [/color][color=#8000FF]= [/color][color=#0000C0]Timer For [/color][color=#000000]j[/color][color=#8000FF]=[/color][color=#000000]1 [/color][color=#0000C0]To [/color][color=#000000]1000000 i [/color][color=#8000FF]= [/color][color=#000000]InstrI2[/color][color=#8000FF]( [/color][color=#000000]matchString[/color][color=#8000FF], [/color][color=#000000]findString [/color][color=#8000FF]) [/color][color=#0000C0]Next [/color][color=#000000]e1 [/color][color=#8000FF]= [/color][color=#0000C0]Timer Txt.Print [/color][color=#C020C0]"InstrI2 "[/color][color=#8000FF]; [/color][color=#0000C0]Format$[/color][color=#8000FF]( [/color][color=#000000]i[/color][color=#8000FF], [/color][color=#C020C0]"0"[/color][color=#8000FF]); [/color][color=#C020C0]" in "[/color][color=#8000FF]; [/color][color=#0000C0]Format$[/color][color=#8000FF]( [/color][color=#000000]e1[/color][color=#8000FF]-[/color][color=#000000]s1[/color][color=#8000FF], [/color][color=#C020C0]"#,##0.0000"[/color][color=#8000FF]) [/color][color=#000000]matchString [/color][color=#8000FF]= [/color][color=#0000C0]UCase$[/color][color=#8000FF]( [/color][color=#000000]matchString [/color][color=#8000FF]) [/color][color=#000000]findString [/color][color=#8000FF]= [/color][color=#0000C0]UCase$[/color][color=#8000FF]( [/color][color=#000000]findString [/color][color=#8000FF]) [/color][color=#000000]s1 [/color][color=#8000FF]= [/color][color=#0000C0]Timer For [/color][color=#000000]j[/color][color=#8000FF]=[/color][color=#000000]1 [/color][color=#0000C0]To [/color][color=#000000]1000000 i [/color][color=#8000FF]= [/color][color=#0000C0]InStr[/color][color=#8000FF]( [/color][color=#000000]matchString[/color][color=#8000FF], [/color][color=#000000]findString [/color][color=#8000FF]) [/color][color=#0000C0]Next [/color][color=#000000]e1 [/color][color=#8000FF]= [/color][color=#0000C0]Timer Txt.Print [/color][color=#C020C0]"Instr.. "[/color][color=#8000FF]; [/color][color=#0000C0]Format$[/color][color=#8000FF]( [/color][color=#000000]i[/color][color=#8000FF], [/color][color=#C020C0]"0"[/color][color=#8000FF]); [/color][color=#C020C0]" in "[/color][color=#8000FF]; [/color][color=#0000C0]Format$[/color][color=#8000FF]( [/color][color=#000000]e1[/color][color=#8000FF]-[/color][color=#000000]s1[/color][color=#8000FF], [/color][color=#C020C0]"#,##0.0000"[/color][color=#8000FF]) [/color][color=#0000C0]Txt.Print [/color][color=#C020C0]"-------------------------------------------------" [/color][color=#0000C0]Txt.Print Format$[/color][color=#8000FF]( [/color][color=#000000]en[/color][color=#8000FF]-[/color][color=#000000]st[/color][color=#8000FF], [/color][color=#C020C0]"#,##0" [/color][color=#8000FF]) [/color][color=#0000C0]End Sub Sub [/color][color=#000000]CreateTable[/color][color=#8000FF]() [/color][color=#0000C0]Local [/color][color=#000000]i [/color][color=#0000C0]As Long Local [/color][color=#000000]x [/color][color=#0000C0]As IStringBuilderA [/color][color=#000000]x [/color][color=#8000FF]= [/color][color=#0000C0]Class [/color][color=#C020C0]"StringBuilderA" [/color][color=#000000]x.Add[/color][color=#8000FF]( [/color][color=#0000C0]$Tab [/color][color=#8000FF]) [/color][color=#000000]x.Add[/color][color=#8000FF]( [/color][color=#0000C0]$Tab [/color][color=#8000FF]) [/color][color=#000000]x.Add[/color][color=#8000FF]( [/color][color=#C020C0]"DB " [/color][color=#8000FF]) [/color][color=#0000C0]For [/color][color=#000000]i [/color][color=#8000FF]= [/color][color=#000000]0 [/color][color=#0000C0]To [/color][color=#000000]255 x.Add[/color][color=#8000FF]( [/color][color=#0000C0]Right$[/color][color=#8000FF]([/color][color=#C020C0]" "[/color][color=#8000FF]+[/color][color=#0000C0]Str$[/color][color=#8000FF]([/color][color=#0000C0]Asc[/color][color=#8000FF]([/color][color=#0000C0]UCase$[/color][color=#8000FF]([/color][color=#0000C0]Chr$[/color][color=#8000FF]([/color][color=#000000]i[/color][color=#8000FF])))), [/color][color=#000000]3[/color][color=#8000FF]) ) [/color][color=#0000C0]If [/color][color=#000000]i [/color][color=#8000FF]Mod [/color][color=#000000]16[/color][color=#8000FF]=[/color][color=#000000]15 [/color][color=#0000C0]Then [/color][color=#000000]x.Add[/color][color=#8000FF]( [/color][color=#0000C0]$CrLf [/color][color=#8000FF]) [/color][color=#0000C0]If [/color][color=#000000]i[/color][color=#8000FF]<[/color][color=#000000]255 [/color][color=#0000C0]Then [/color][color=#000000]x.Add[/color][color=#8000FF]( [/color][color=#0000C0]$Tab [/color][color=#8000FF]) [/color][color=#000000]x.Add[/color][color=#8000FF]( [/color][color=#0000C0]$Tab [/color][color=#8000FF]) [/color][color=#000000]x.Add[/color][color=#8000FF]( [/color][color=#C020C0]"DB " [/color][color=#8000FF]) [/color][color=#0000C0]End If Else [/color][color=#000000]x.Add[/color][color=#8000FF]( [/color][color=#C020C0]", " [/color][color=#8000FF]) [/color][color=#0000C0]End If Next Clipboard Set Text [/color][color=#000000]x.String [/color][color=#0000C0]End Sub [/color][color=#007F00]' Uses ucase collation [/color][color=#0000C0]AsmData [/color][color=#000000]xlatTable [/color][color=#0000C0]DB [/color][color=#000000]0[/color][color=#8000FF], [/color][color=#000000]1[/color][color=#8000FF], [/color][color=#000000]2[/color][color=#8000FF], [/color][color=#000000]3[/color][color=#8000FF], [/color][color=#000000]4[/color][color=#8000FF], [/color][color=#000000]5[/color][color=#8000FF], [/color][color=#000000]6[/color][color=#8000FF], [/color][color=#000000]7[/color][color=#8000FF], [/color][color=#000000]8[/color][color=#8000FF], [/color][color=#000000]9[/color][color=#8000FF], [/color][color=#000000]10[/color][color=#8000FF], [/color][color=#000000]11[/color][color=#8000FF], [/color][color=#000000]12[/color][color=#8000FF], [/color][color=#000000]13[/color][color=#8000FF], [/color][color=#000000]14[/color][color=#8000FF], [/color][color=#000000]15 [/color][color=#0000C0]DB [/color][color=#000000]16[/color][color=#8000FF], [/color][color=#000000]17[/color][color=#8000FF], [/color][color=#000000]18[/color][color=#8000FF], [/color][color=#000000]19[/color][color=#8000FF], [/color][color=#000000]20[/color][color=#8000FF], [/color][color=#000000]21[/color][color=#8000FF], [/color][color=#000000]22[/color][color=#8000FF], [/color][color=#000000]23[/color][color=#8000FF], [/color][color=#000000]24[/color][color=#8000FF], [/color][color=#000000]25[/color][color=#8000FF], [/color][color=#000000]26[/color][color=#8000FF], [/color][color=#000000]27[/color][color=#8000FF], [/color][color=#000000]28[/color][color=#8000FF], [/color][color=#000000]29[/color][color=#8000FF], [/color][color=#000000]30[/color][color=#8000FF], [/color][color=#000000]31 [/color][color=#0000C0]DB [/color][color=#000000]32[/color][color=#8000FF], [/color][color=#000000]33[/color][color=#8000FF], [/color][color=#000000]34[/color][color=#8000FF], [/color][color=#000000]35[/color][color=#8000FF], [/color][color=#000000]36[/color][color=#8000FF], [/color][color=#000000]37[/color][color=#8000FF], [/color][color=#000000]38[/color][color=#8000FF], [/color][color=#000000]39[/color][color=#8000FF], [/color][color=#000000]40[/color][color=#8000FF], [/color][color=#000000]41[/color][color=#8000FF], [/color][color=#000000]42[/color][color=#8000FF], [/color][color=#000000]43[/color][color=#8000FF], [/color][color=#000000]44[/color][color=#8000FF], [/color][color=#000000]45[/color][color=#8000FF], [/color][color=#000000]46[/color][color=#8000FF], [/color][color=#000000]47 [/color][color=#0000C0]DB [/color][color=#000000]48[/color][color=#8000FF], [/color][color=#000000]49[/color][color=#8000FF], [/color][color=#000000]50[/color][color=#8000FF], [/color][color=#000000]51[/color][color=#8000FF], [/color][color=#000000]52[/color][color=#8000FF], [/color][color=#000000]53[/color][color=#8000FF], [/color][color=#000000]54[/color][color=#8000FF], [/color][color=#000000]55[/color][color=#8000FF], [/color][color=#000000]56[/color][color=#8000FF], [/color][color=#000000]57[/color][color=#8000FF], [/color][color=#000000]58[/color][color=#8000FF], [/color][color=#000000]59[/color][color=#8000FF], [/color][color=#000000]60[/color][color=#8000FF], [/color][color=#000000]61[/color][color=#8000FF], [/color][color=#000000]62[/color][color=#8000FF], [/color][color=#000000]63 [/color][color=#0000C0]DB [/color][color=#000000]64[/color][color=#8000FF], [/color][color=#000000]65[/color][color=#8000FF], [/color][color=#000000]66[/color][color=#8000FF], [/color][color=#000000]67[/color][color=#8000FF], [/color][color=#000000]68[/color][color=#8000FF], [/color][color=#000000]69[/color][color=#8000FF], [/color][color=#000000]70[/color][color=#8000FF], [/color][color=#000000]71[/color][color=#8000FF], [/color][color=#000000]72[/color][color=#8000FF], [/color][color=#000000]73[/color][color=#8000FF], [/color][color=#000000]74[/color][color=#8000FF], [/color][color=#000000]75[/color][color=#8000FF], [/color][color=#000000]76[/color][color=#8000FF], [/color][color=#000000]77[/color][color=#8000FF], [/color][color=#000000]78[/color][color=#8000FF], [/color][color=#000000]79 [/color][color=#0000C0]DB [/color][color=#000000]80[/color][color=#8000FF], [/color][color=#000000]81[/color][color=#8000FF], [/color][color=#000000]82[/color][color=#8000FF], [/color][color=#000000]83[/color][color=#8000FF], [/color][color=#000000]84[/color][color=#8000FF], [/color][color=#000000]85[/color][color=#8000FF], [/color][color=#000000]86[/color][color=#8000FF], [/color][color=#000000]87[/color][color=#8000FF], [/color][color=#000000]88[/color][color=#8000FF], [/color][color=#000000]89[/color][color=#8000FF], [/color][color=#000000]90[/color][color=#8000FF], [/color][color=#000000]91[/color][color=#8000FF], [/color][color=#000000]92[/color][color=#8000FF], [/color][color=#000000]93[/color][color=#8000FF], [/color][color=#000000]94[/color][color=#8000FF], [/color][color=#000000]95 [/color][color=#0000C0]DB [/color][color=#000000]96[/color][color=#8000FF], [/color][color=#000000]65[/color][color=#8000FF], [/color][color=#000000]66[/color][color=#8000FF], [/color][color=#000000]67[/color][color=#8000FF], [/color][color=#000000]68[/color][color=#8000FF], [/color][color=#000000]69[/color][color=#8000FF], [/color][color=#000000]70[/color][color=#8000FF], [/color][color=#000000]71[/color][color=#8000FF], [/color][color=#000000]72[/color][color=#8000FF], [/color][color=#000000]73[/color][color=#8000FF], [/color][color=#000000]74[/color][color=#8000FF], [/color][color=#000000]75[/color][color=#8000FF], [/color][color=#000000]76[/color][color=#8000FF], [/color][color=#000000]77[/color][color=#8000FF], [/color][color=#000000]78[/color][color=#8000FF], [/color][color=#000000]79 [/color][color=#0000C0]DB [/color][color=#000000]80[/color][color=#8000FF], [/color][color=#000000]81[/color][color=#8000FF], [/color][color=#000000]82[/color][color=#8000FF], [/color][color=#000000]83[/color][color=#8000FF], [/color][color=#000000]84[/color][color=#8000FF], [/color][color=#000000]85[/color][color=#8000FF], [/color][color=#000000]86[/color][color=#8000FF], [/color][color=#000000]87[/color][color=#8000FF], [/color][color=#000000]88[/color][color=#8000FF], [/color][color=#000000]89[/color][color=#8000FF], [/color][color=#000000]90[/color][color=#8000FF], [/color][color=#000000]123[/color][color=#8000FF], [/color][color=#000000]124[/color][color=#8000FF], [/color][color=#000000]125[/color][color=#8000FF], [/color][color=#000000]126[/color][color=#8000FF], [/color][color=#000000]127 [/color][color=#0000C0]DB [/color][color=#000000]128[/color][color=#8000FF], [/color][color=#000000]129[/color][color=#8000FF], [/color][color=#000000]130[/color][color=#8000FF], [/color][color=#000000]131[/color][color=#8000FF], [/color][color=#000000]132[/color][color=#8000FF], [/color][color=#000000]133[/color][color=#8000FF], [/color][color=#000000]134[/color][color=#8000FF], [/color][color=#000000]135[/color][color=#8000FF], [/color][color=#000000]136[/color][color=#8000FF], [/color][color=#000000]137[/color][color=#8000FF], [/color][color=#000000]138[/color][color=#8000FF], [/color][color=#000000]139[/color][color=#8000FF], [/color][color=#000000]140[/color][color=#8000FF], [/color][color=#000000]141[/color][color=#8000FF], [/color][color=#000000]142[/color][color=#8000FF], [/color][color=#000000]143 [/color][color=#0000C0]DB [/color][color=#000000]144[/color][color=#8000FF], [/color][color=#000000]145[/color][color=#8000FF], [/color][color=#000000]146[/color][color=#8000FF], [/color][color=#000000]147[/color][color=#8000FF], [/color][color=#000000]148[/color][color=#8000FF], [/color][color=#000000]149[/color][color=#8000FF], [/color][color=#000000]150[/color][color=#8000FF], [/color][color=#000000]151[/color][color=#8000FF], [/color][color=#000000]152[/color][color=#8000FF], [/color][color=#000000]153[/color][color=#8000FF], [/color][color=#000000]138[/color][color=#8000FF], [/color][color=#000000]155[/color][color=#8000FF], [/color][color=#000000]140[/color][color=#8000FF], [/color][color=#000000]157[/color][color=#8000FF], [/color][color=#000000]142[/color][color=#8000FF], [/color][color=#000000]159 [/color][color=#0000C0]DB [/color][color=#000000]160[/color][color=#8000FF], [/color][color=#000000]161[/color][color=#8000FF], [/color][color=#000000]162[/color][color=#8000FF], [/color][color=#000000]163[/color][color=#8000FF], [/color][color=#000000]164[/color][color=#8000FF], [/color][color=#000000]165[/color][color=#8000FF], [/color][color=#000000]166[/color][color=#8000FF], [/color][color=#000000]167[/color][color=#8000FF], [/color][color=#000000]168[/color][color=#8000FF], [/color][color=#000000]169[/color][color=#8000FF], [/color][color=#000000]170[/color][color=#8000FF], [/color][color=#000000]171[/color][color=#8000FF], [/color][color=#000000]172[/color][color=#8000FF], [/color][color=#000000]173[/color][color=#8000FF], [/color][color=#000000]174[/color][color=#8000FF], [/color][color=#000000]175 [/color][color=#0000C0]DB [/color][color=#000000]176[/color][color=#8000FF], [/color][color=#000000]177[/color][color=#8000FF], [/color][color=#000000]178[/color][color=#8000FF], [/color][color=#000000]179[/color][color=#8000FF], [/color][color=#000000]180[/color][color=#8000FF], [/color][color=#000000]181[/color][color=#8000FF], [/color][color=#000000]182[/color][color=#8000FF], [/color][color=#000000]183[/color][color=#8000FF], [/color][color=#000000]184[/color][color=#8000FF], [/color][color=#000000]185[/color][color=#8000FF], [/color][color=#000000]186[/color][color=#8000FF], [/color][color=#000000]187[/color][color=#8000FF], [/color][color=#000000]188[/color][color=#8000FF], [/color][color=#000000]189[/color][color=#8000FF], [/color][color=#000000]190[/color][color=#8000FF], [/color][color=#000000]191 [/color][color=#0000C0]DB [/color][color=#000000]192[/color][color=#8000FF], [/color][color=#000000]193[/color][color=#8000FF], [/color][color=#000000]194[/color][color=#8000FF], [/color][color=#000000]195[/color][color=#8000FF], [/color][color=#000000]196[/color][color=#8000FF], [/color][color=#000000]197[/color][color=#8000FF], [/color][color=#000000]198[/color][color=#8000FF], [/color][color=#000000]199[/color][color=#8000FF], [/color][color=#000000]200[/color][color=#8000FF], [/color][color=#000000]201[/color][color=#8000FF], [/color][color=#000000]202[/color][color=#8000FF], [/color][color=#000000]203[/color][color=#8000FF], [/color][color=#000000]204[/color][color=#8000FF], [/color][color=#000000]205[/color][color=#8000FF], [/color][color=#000000]206[/color][color=#8000FF], [/color][color=#000000]207 [/color][color=#0000C0]DB [/color][color=#000000]208[/color][color=#8000FF], [/color][color=#000000]209[/color][color=#8000FF], [/color][color=#000000]210[/color][color=#8000FF], [/color][color=#000000]211[/color][color=#8000FF], [/color][color=#000000]212[/color][color=#8000FF], [/color][color=#000000]213[/color][color=#8000FF], [/color][color=#000000]214[/color][color=#8000FF], [/color][color=#000000]215[/color][color=#8000FF], [/color][color=#000000]216[/color][color=#8000FF], [/color][color=#000000]217[/color][color=#8000FF], [/color][color=#000000]218[/color][color=#8000FF], [/color][color=#000000]219[/color][color=#8000FF], [/color][color=#000000]220[/color][color=#8000FF], [/color][color=#000000]221[/color][color=#8000FF], [/color][color=#000000]222[/color][color=#8000FF], [/color][color=#000000]223 [/color][color=#0000C0]DB [/color][color=#000000]192[/color][color=#8000FF], [/color][color=#000000]193[/color][color=#8000FF], [/color][color=#000000]194[/color][color=#8000FF], [/color][color=#000000]195[/color][color=#8000FF], [/color][color=#000000]196[/color][color=#8000FF], [/color][color=#000000]197[/color][color=#8000FF], [/color][color=#000000]198[/color][color=#8000FF], [/color][color=#000000]199[/color][color=#8000FF], [/color][color=#000000]200[/color][color=#8000FF], [/color][color=#000000]201[/color][color=#8000FF], [/color][color=#000000]202[/color][color=#8000FF], [/color][color=#000000]203[/color][color=#8000FF], [/color][color=#000000]204[/color][color=#8000FF], [/color][color=#000000]205[/color][color=#8000FF], [/color][color=#000000]206[/color][color=#8000FF], [/color][color=#000000]207 [/color][color=#0000C0]DB [/color][color=#000000]208[/color][color=#8000FF], [/color][color=#000000]209[/color][color=#8000FF], [/color][color=#000000]210[/color][color=#8000FF], [/color][color=#000000]211[/color][color=#8000FF], [/color][color=#000000]212[/color][color=#8000FF], [/color][color=#000000]213[/color][color=#8000FF], [/color][color=#000000]214[/color][color=#8000FF], [/color][color=#000000]247[/color][color=#8000FF], [/color][color=#000000]216[/color][color=#8000FF], [/color][color=#000000]217[/color][color=#8000FF], [/color][color=#000000]218[/color][color=#8000FF], [/color][color=#000000]219[/color][color=#8000FF], [/color][color=#000000]220[/color][color=#8000FF], [/color][color=#000000]221[/color][color=#8000FF], [/color][color=#000000]222[/color][color=#8000FF], [/color][color=#000000]159 [/color][color=#0000C0]End AsmData Function [/color][color=#000000]InstrI2[/color][color=#8000FF]( [/color][color=#000000]mainStr [/color][color=#0000C0]As String[/color][color=#8000FF], [/color][color=#000000]matchStr [/color][color=#0000C0]As String [/color][color=#8000FF]) [/color][color=#0000C0]As Long #Register None [/color][color=#C00000]! MOV EDX, 1 ! MOV ESI, mainStr ! MOV ESI, [ESI] ; ESI = StrPtr( mainStr ) ! MOV EDI, matchStr ! MOV EDI, [EDI] ; EDI = StrPtr( matchStr ) ! LEA EBX, xlatTable ; Translate table ! XOR EAX, EAX ; EAX = 0 ! MOV AL, BYTE PTR[EDI] ; AL = @matchStr[0] ! XLATB ; AL = UCase$( @matchStr[0] ) ! MOV ECX, EAX ; ECX = UCase$( @matchStr[0] ) [/color][color=#000000]InstrI2_Loop[/color][color=#8000FF]: [/color][color=#C00000]! MOV AL, BYTE PTR[ESI] ; EAX = @a ! OR AL, AL ; If @mainStr = 0 ! JZ InstrI2_NoMatch ; Goto Exit ! XLATB ; EAX = UCase$( @mainStr ) ! SUB EAX, ECX ; if @mainStr = @matchStr ! JZ InstrI2_Cmp ; Goto Compare ! XOR EAX, EAX ; Clear upper registers of A ! INC ESI ; Incr mainStr ! INC EDX ; Incr Pos ! JMP SHORT InstrI2_Loop ; Try next byte [/color][color=#000000]InstrI2_Cmp[/color][color=#8000FF]: [/color][color=#C00000]! PUSH ESI ; Save mainStr ! PUSH EDI ; Save findStr ! PUSH ECX ; Save UCase$( @findStr ) ! INC ESI ; Already compared this byte ! INC EDI ; Already compared this byte [/color][color=#000000]InstrI2_CmpLoop[/color][color=#8000FF]: [/color][color=#C00000]! MOV AL, BYTE PTR[EDI] ; AL = @matchStr ! OR AL, AL ; If @matchStr=0 ! JZ InstrI2_Match ; Then Goto Match! yay ! XLATB ; AL = UCase$( @matchStr ) ! MOV ECX, EAX ; ECX = UCase$( @matchStr ) ! MOV AL, BYTE PTR[ESI] ; EAX = @mainStr ! OR AL, AL ; If @matchStr=0 ! JZ InstrI2_CmpEnd ; Then we finish failed (no match) ! XLATB ; EAX = UCase$( @mainStr ) ! SUB EAX, ECX ; if @mainStr<>@matchStr ! JNZ InstrI2_CmpFail ; Then Goto Compare Failed ! INC EDI ; Incr matchStr ! INC ESI ; Incr mainStr ! JMP SHORT InstrI2_CmpLoop ; Try next byte [/color][color=#000000]InstrI2_CmpFail[/color][color=#8000FF]: [/color][color=#C00000]! POP ECX ; Restore UCase$( @findStr ) ! POP EDI ; Restore findStr ! POP ESI ; Restore mainStr ! INC ESI ; Incr mainStr ! INC EDX ; Incr pos ! JMP SHORT InstrI2_Loop [/color][color=#000000]InstrI2_Match[/color][color=#8000FF]: [/color][color=#C00000]! POP ECX ; Restore UCase$( @findStr ) ! POP EDI ; Restore findStr ! POP ESI ; Restore mainStr ! JMP SHORT InstrI2_Finish ; Return Position [/color][color=#000000]InstrI2_CmpEnd[/color][color=#8000FF]: [/color][color=#C00000]! POP ECX ; Restore UCase$( @findStr ) ! POP EDI ; Restore findStr ! POP ESI ; Restore mainStr [/color][color=#000000]InstrI2_NoMatch[/color][color=#8000FF]: [/color][color=#C00000]! XOR EDX, EDX ; Pos = 0 (No match) [/color][color=#000000]InstrI2_Finish[/color][color=#8000FF]: [/color][color=#C00000]! MOV FUNCTION, EDX ; Function = pos [/color][color=#0000C0]End Function Function [/color][color=#000000]InstrI[/color][color=#8000FF]( [/color][color=#000000]mainStr [/color][color=#0000C0]As String[/color][color=#8000FF], [/color][color=#000000]matchStr [/color][color=#0000C0]As String [/color][color=#8000FF]) [/color][color=#0000C0]As Long Register [/color][color=#000000]i [/color][color=#0000C0]As Long Register [/color][color=#000000]j [/color][color=#0000C0]As Long Local [/color][color=#000000]mainPtr[/color][color=#8000FF], [/color][color=#000000]matchPtr[/color][color=#8000FF], [/color][color=#000000]xptr [/color][color=#0000C0]As Byte Ptr Local [/color][color=#000000]ch [/color][color=#0000C0]As Byte [/color][color=#000000]mainPtr [/color][color=#8000FF]= [/color][color=#0000C0]StrPtr[/color][color=#8000FF]( [/color][color=#000000]mainStr [/color][color=#8000FF]) [/color][color=#000000]matchPtr [/color][color=#8000FF]= [/color][color=#0000C0]StrPtr[/color][color=#8000FF]( [/color][color=#000000]matchStr [/color][color=#8000FF]) [/color][color=#000000]xptr [/color][color=#8000FF]= [/color][color=#0000C0]CodePtr[/color][color=#8000FF]( [/color][color=#000000]xlatTable [/color][color=#8000FF]) [/color][color=#000000]ch [/color][color=#8000FF]= @[/color][color=#000000]xptr[/color][color=#8000FF][ @[/color][color=#000000]matchPtr [/color][color=#8000FF]] [/color][color=#0000C0]For [/color][color=#000000]i[/color][color=#8000FF]=[/color][color=#000000]1 [/color][color=#0000C0]To Len[/color][color=#8000FF]([/color][color=#000000]mainStr[/color][color=#8000FF])-[/color][color=#0000C0]Len[/color][color=#8000FF]([/color][color=#000000]matchStr[/color][color=#8000FF])+[/color][color=#000000]1 [/color][color=#0000C0]If [/color][color=#8000FF]@[/color][color=#000000]xptr[/color][color=#8000FF][ @[/color][color=#000000]mainPtr [/color][color=#8000FF]] = [/color][color=#000000]ch [/color][color=#0000C0]Then [/color][color=#000000]j [/color][color=#8000FF]= [/color][color=#000000]1 [/color][color=#0000C0]While [/color][color=#8000FF]@[/color][color=#000000]xptr[/color][color=#8000FF][ @[/color][color=#000000]mainPtr[/color][color=#8000FF][[/color][color=#000000]j[/color][color=#8000FF]] ] = @[/color][color=#000000]xptr[/color][color=#8000FF][ @[/color][color=#000000]matchPtr[/color][color=#8000FF][[/color][color=#000000]j[/color][color=#8000FF]] ] And @[/color][color=#000000]matchPtr[/color][color=#8000FF][[/color][color=#000000]j[/color][color=#8000FF]] And @[/color][color=#000000]mainPtr[/color][color=#8000FF][[/color][color=#000000]j[/color][color=#8000FF]] [/color][color=#0000C0]Incr [/color][color=#000000]j [/color][color=#0000C0]Wend If [/color][color=#8000FF]@[/color][color=#000000]matchPtr[/color][color=#8000FF][[/color][color=#000000]j[/color][color=#8000FF]]=[/color][color=#000000]0 [/color][color=#0000C0]Then Function [/color][color=#8000FF]= [/color][color=#000000]i [/color][color=#0000C0]Exit Function End If End If Incr [/color][color=#000000]mainPtr [/color][color=#0000C0]Next Function [/color][color=#8000FF]= [/color][color=#000000]0 [/color][color=#0000C0]End Function [/color]
Comment
-
Geez Larry, that's a pretty sweet "attempt"! My version only can time with instrI on longer strings, and gets whomped elsewhere.
There are a couple mismatch glitches still tho somewhere. My quick glance at the code produced no joy, so maybe give it a perusal. (There's some dead code in there from other tests, so just ignore that.)
Added: Oops, changing 78000 to 7800 caused an error in my algo. For this mismatch demo, I've changed to all forward searching.
Code:#COMPILE EXE #DIM ALL FUNCTION PBMAIN () AS LONG RANDOMIZE 'Call CreateTable CALL DoTest() END FUNCTION SUB DoTest() LOCAL hWin AS DWORD, ii2, ii3, r1,r2,r3,r4 AS LONG LOCAL a, line1,line2,line3,exitStr AS STRING TXT.WINDOW("Case Insensitive Test", 10, 10) TO hWin LOCAL i AS LONG line1 = REPEAT$(100 ,"QWERTYUIOP[]ASDFGHJKL;'ZXCVBNM,./qwertyuiop[]asdfghjkl;'zxcvbnm,./1234567890-=") & "HeLLo THErE!" line3 = line1 line2 = "Hello There!" DO line1 = line3 line2 = CHR$(RND(0,255),RND(0,255),RND(0,255),RND(0,255),RND(0,255))', _ ii2 = RND(1, 7800): IF ii2 > 7800\2 THEN ii3 = -1 ELSE ii3 = 0 MID$(line1, ii2) = line2 r3 = INSTR(UCASE$(line1), UCASE$(line2)) r1 = InstrI(line1, line2) r2 = InstrI2(line1, line2) r4 = caseFreeInstr(line1, line2, 0, 0) 'has to be last because it caps line1 & line2 IF r1 = r2 AND r1 = r3 AND r1 = r4 THEN ii3 = 0 ELSE TXT.PRINT "mismatch";r1;r2;r3;r4: TXT.WAITKEY$ TO exitStr: IF exitStr = "x" OR exitStr = CHR$(27) THEN EXIT SUB ITERATE DO IF INSTR(line1, line2) = caseFreeInstr(line1, line2, 0, ii3) THEN ' pcps(line1) ' pcwait ! nop ' pcpss(line2) ELSE IF INSTR(line1, line2) = caseFreeInstr(line1, line2, 0, ii3) THEN 'pcpss(line2 & "ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok") ELSE 'pcps(line1) 'pcps(line2) ' ? "oooooo" END IF END IF LOOP CALL TestSearch( "this is a super great test of the case insenstive isntri", "InS" ) CALL TestSearch( "short run", "RUN" ) CALL TestSearch(REPEAT$(20, "Haaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaay") & "needle", "NEEDLE" ) TXT.PRINT "Finished" TXT.LINE.INPUT a END SUB SUB TestSearch( BYVAL matchString AS STRING, BYVAL findString AS STRING ) LOCAL j AS LONG LOCAL st, en AS QUAD LOCAL s1#, e1# LOCAL msg AS STRING LOCAL i, c AS LONG s1 = TIMER FOR j=1 TO 1000000 i = caseFreeInstr( matchString, findString, 0, 0 ) NEXT e1 = TIMER TXT.PRINT "cFInstr "; FORMAT$( i, "0"); " in "; FORMAT$( e1-s1, "#,##0.0000") s1 = TIMER FOR j=1 TO 1000000 i = InstrI( matchString, findString ) NEXT e1 = TIMER TXT.PRINT "InstrI. "; FORMAT$( i, "0"); " in "; FORMAT$( e1-s1, "#,##0.0000") s1 = TIMER FOR j=1 TO 1000000 i = InstrI2( matchString, findString ) NEXT e1 = TIMER TXT.PRINT "InstrI2 "; FORMAT$( i, "0"); " in "; FORMAT$( e1-s1, "#,##0.0000") matchString = UCASE$( matchString ) findString = UCASE$( findString ) s1 = TIMER FOR j=1 TO 1000000 i = INSTR( matchString, findString ) NEXT e1 = TIMER TXT.PRINT "Instr.. "; FORMAT$( i, "0"); " in "; FORMAT$( e1-s1, "#,##0.0000") TXT.PRINT "-------------------------------------------------" TXT.PRINT FORMAT$( en-st, "#,##0" ) END SUB SUB CreateTable() LOCAL i AS LONG LOCAL x AS ISTRINGBUILDERA x = CLASS "StringBuilderA" x.Add( $TAB ) x.Add( $TAB ) x.Add( "DB " ) FOR i = 0 TO 255 x.Add( RIGHT$(" "+STR$(ASC(UCASE$(CHR$(i)))), 3) ) IF i MOD 16=15 THEN x.Add( $CRLF ) IF i<255 THEN x.Add( $TAB ) x.Add( $TAB ) x.Add( "DB " ) END IF ELSE x.Add( ", " ) END IF NEXT CLIPBOARD SET TEXT x.String END SUB ' Uses ucase collation ASMDATA xlatTable DB 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 DB 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 DB 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47 DB 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 DB 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79 DB 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95 DB 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79 DB 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123, 124, 125, 126, 127 DB 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143 DB 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 138, 155, 140, 157, 142, 159 DB 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175 DB 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191 DB 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207 DB 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223 DB 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207 DB 208, 209, 210, 211, 212, 213, 214, 247, 216, 217, 218, 219, 220, 221, 222, 159 END ASMDATA FUNCTION InstrI2( mainStr AS STRING, matchStr AS STRING ) AS LONG #REGISTER NONE ! MOV EDX, 1 ! MOV ESI, mainStr ! MOV ESI, [ESI] ; ESI = StrPtr( mainStr ) ! MOV EDI, matchStr ! MOV EDI, [EDI] ; EDI = StrPtr( matchStr ) ! LEA EBX, xlatTable ; Translate table ! XOR EAX, EAX ; EAX = 0 ! MOV AL, BYTE PTR[EDI] ; AL = @matchStr[0] ! XLATB ; AL = UCase$( @matchStr[0] ) ! MOV ECX, EAX ; ECX = UCase$( @matchStr[0] ) InstrI2_Loop: ! MOV AL, BYTE PTR[ESI] ; EAX = @a ! OR AL, AL ; If @mainStr = 0 ! JZ InstrI2_NoMatch ; Goto Exit ! XLATB ; EAX = UCase$( @mainStr ) ! SUB EAX, ECX ; if @mainStr = @matchStr ! JZ InstrI2_Cmp ; Goto Compare ! XOR EAX, EAX ; Clear upper registers of A ! INC ESI ; Incr mainStr ! INC EDX ; Incr Pos ! JMP SHORT InstrI2_Loop ; Try next byte InstrI2_Cmp: ! PUSH ESI ; Save mainStr ! PUSH EDI ; Save findStr ! PUSH ECX ; Save UCase$( @findStr ) ! INC ESI ; Already compared this byte ! INC EDI ; Already compared this byte InstrI2_CmpLoop: ! MOV AL, BYTE PTR[EDI] ; AL = @matchStr ! OR AL, AL ; If @matchStr=0 ! JZ InstrI2_Match ; Then Goto Match! yay ! XLATB ; AL = UCase$( @matchStr ) ! MOV ECX, EAX ; ECX = UCase$( @matchStr ) ! MOV AL, BYTE PTR[ESI] ; EAX = @mainStr ! OR AL, AL ; If @matchStr=0 ! JZ InstrI2_CmpEnd ; Then we finish failed (no match) ! XLATB ; EAX = UCase$( @mainStr ) ! SUB EAX, ECX ; if @mainStr<>@matchStr ! JNZ InstrI2_CmpFail ; Then Goto Compare Failed ! INC EDI ; Incr matchStr ! INC ESI ; Incr mainStr ! JMP SHORT InstrI2_CmpLoop ; Try next byte InstrI2_CmpFail: ! POP ECX ; Restore UCase$( @findStr ) ! POP EDI ; Restore findStr ! POP ESI ; Restore mainStr ! INC ESI ; Incr mainStr ! INC EDX ; Incr pos ! JMP SHORT InstrI2_Loop InstrI2_Match: ! POP ECX ; Restore UCase$( @findStr ) ! POP EDI ; Restore findStr ! POP ESI ; Restore mainStr ! JMP SHORT InstrI2_Finish ; Return Position InstrI2_CmpEnd: ! POP ECX ; Restore UCase$( @findStr ) ! POP EDI ; Restore findStr ! POP ESI ; Restore mainStr InstrI2_NoMatch: ! XOR EDX, EDX ; Pos = 0 (No match) InstrI2_Finish: ! MOV FUNCTION, EDX ; Function = pos END FUNCTION FUNCTION InstrI( mainStr AS STRING, matchStr AS STRING ) AS LONG REGISTER i AS LONG REGISTER j AS LONG LOCAL mainPtr, matchPtr, xptr AS BYTE PTR LOCAL ch AS BYTE mainPtr = STRPTR( mainStr ) matchPtr = STRPTR( matchStr ) xptr = CODEPTR( xlatTable ) ch = @xptr[ @matchPtr ] FOR i=1 TO LEN(mainStr)-LEN(matchStr)+1 IF @xptr[ @mainPtr ] = ch THEN j = 1 WHILE @xptr[ @mainPtr[j] ] = @xptr[ @matchPtr[j] ] AND @matchPtr[j] AND @mainPtr[j] INCR j WEND IF @matchPtr[j]=0 THEN FUNCTION = i EXIT FUNCTION END IF END IF INCR mainPtr NEXT FUNCTION = 0 END FUNCTION FUNCTION caseFreeInstr(mainStr AS STRING, matchStr AS STRING, mainStrIsUcase AS LONG, reverse AS LONG) AS LONG 'note1: this fcn will cap mainStr and matchStr! This can good for multiple compares on the same mainStr. 'note2: fcn allows to shortcut past UCASE'ing mainStr by setting mainStrIsUcase <> 0. If function has been called 'already, and mainStr has been used previously as a parameter to this function (and has not been altered since), 'then setting mainStrIsUcase to non-zero will speed function up many X. REGISTER ii AS LONG STATIC oneTime AS LONG DIM sArr(LEN(mainStr)-1) AS BYTE AT STRPTR(mainStr) DIM sArr2(LEN(matchStr)-1) AS BYTE AT STRPTR(matchStr) IF oneTime = 0 THEN oneTime = 1 DIM translateArr(255) AS STATIC BYTE CALL arrayAssign(translateArr()) END IF FOR ii = 0 TO LEN(matchStr)-1 sArr2(ii) = translateArr(sArr2(ii)) 'make it uppercase NEXT IF mainStrIsUcase = 0 THEN FOR ii = 0 TO LEN(mainStr)-1 sArr(ii) = translateArr(sArr(ii)) 'make it uppercase NEXT END IF IF reverse = 0 THEN FUNCTION = INSTR(mainStr, matchStr) ELSE FUNCTION = INSTR(-1, mainStr, matchStr) END IF END FUNCTION SUB arrayAssign(translateArr() AS BYTE) ARRAY ASSIGN translateArr() = 0,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,59,60, _ 61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80, _ 81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,65,66,67,68, _ 69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88, _ 89,90,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140, _ 141,142,143,144,145,146,147,148,149,150,151,152,153,138,155,140,157,142,159,160, _ 161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180, _ 181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200, _ 201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220, _ 221,222,223,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208, _ 209,210,211,212,213,214,247,216,217,218,219,220,221,222,159 END SUB
Comment
-
Larry, here is another problem with instrI2 demo'd. It seems to find the string even tho only a partial string is present. The previous mismatches mentioned in post #13 are ignored here.
Code:#COMPILE EXE #DIM ALL FUNCTION PBMAIN () AS LONG RANDOMIZE 'Call CreateTable CALL DoTest() END FUNCTION SUB DoTest() LOCAL hWin AS DWORD, ii2, ii3, r1,r2,r3,r4,rlen AS LONG LOCAL a, line1,line2,line3,exitStr AS STRING TXT.WINDOW("Case Insensitive Test", 10, 10) TO hWin LOCAL i AS LONG line1 = REPEAT$(100 ,"QWERTYUIOP[]ASDFGHJKL;'ZXCVBNM,./qwertyuiop[]asdfghjkl;'zxcvbnm,./1234567890-=") & "HeLLo THErE!" line3 = line1 line2 = "Hello There!" DO line1 = line3 RESET line2 FOR rLen = 1 TO RND(1, 48) line2 &= CHR$(RND(0,255))',rnd(0,255),rnd(0,255),rnd(0,255),rnd(0,255))', _x NEXT ii2 = RND(1, 7800): IF ii2 > 7800\2 THEN ii3 = -1 ELSE ii3 = 0 MID$(line1, ii2) = line2 r3 = INSTR(UCASE$(line1), UCASE$(line2)) r1 = InstrI(line1, line2) r2 = InstrI2(line1, line2) r4 = caseFreeInstr(line1, line2, 0, 0) 'has to be last because it caps line1 & line2 ' IF r1 xor r2 xor r3 xor r4 THEN TXT.PRINT "mismatch";r1;r2;r3;r4: TXT.WAITKEY$ TO exitStr: IF exitStr = "x" OR exitStr = CHR$(27) THEN EXIT SUB '!wait '!wait IF r2 = 0 THEN ITERATE DO IF r1 = r2 AND r1 <> r3 THEN ITERATE DO IF r1 = r2 AND r1 = r3 AND r1 = r4 THEN ii3 = 0 ELSE TXT.PRINT "mismatch";r1;r2;r3;r4: TXT.WAITKEY$ TO exitStr: IF exitStr = "x" OR exitStr = CHR$(27) THEN EXIT SUB ITERATE DO IF INSTR(line1, line2) = caseFreeInstr(line1, line2, 0, ii3) THEN ' pcps(line1) ' pcwait ! nop ' pcpss(line2) ELSE IF INSTR(line1, line2) = caseFreeInstr(line1, line2, 0, ii3) THEN 'pcpss(line2 & "ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok") ELSE 'pcps(line1) 'pcps(line2) ' ? "oooooo" END IF END IF LOOP CALL TestSearch( "this is a super great test of the case insenstive isntri", "InS" ) CALL TestSearch( "short run", "RUN" ) CALL TestSearch(REPEAT$(20, "Haaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaay") & "needle", "NEEDLE" ) TXT.PRINT "Finished" TXT.LINE.INPUT a END SUB SUB TestSearch( BYVAL matchString AS STRING, BYVAL findString AS STRING ) LOCAL j AS LONG LOCAL st, en AS QUAD LOCAL s1#, e1# LOCAL msg AS STRING LOCAL i, c AS LONG s1 = TIMER FOR j=1 TO 1000000 i = caseFreeInstr( matchString, findString, 0, 0 ) NEXT e1 = TIMER TXT.PRINT "cFInstr "; FORMAT$( i, "0"); " in "; FORMAT$( e1-s1, "#,##0.0000") s1 = TIMER FOR j=1 TO 1000000 i = InstrI( matchString, findString ) NEXT e1 = TIMER TXT.PRINT "InstrI. "; FORMAT$( i, "0"); " in "; FORMAT$( e1-s1, "#,##0.0000") s1 = TIMER FOR j=1 TO 1000000 i = InstrI2( matchString, findString ) NEXT e1 = TIMER TXT.PRINT "InstrI2 "; FORMAT$( i, "0"); " in "; FORMAT$( e1-s1, "#,##0.0000") matchString = UCASE$( matchString ) findString = UCASE$( findString ) s1 = TIMER FOR j=1 TO 1000000 i = INSTR( matchString, findString ) NEXT e1 = TIMER TXT.PRINT "Instr.. "; FORMAT$( i, "0"); " in "; FORMAT$( e1-s1, "#,##0.0000") TXT.PRINT "-------------------------------------------------" TXT.PRINT FORMAT$( en-st, "#,##0" ) END SUB SUB CreateTable() LOCAL i AS LONG LOCAL x AS ISTRINGBUILDERA x = CLASS "StringBuilderA" x.Add( $TAB ) x.Add( $TAB ) x.Add( "DB " ) FOR i = 0 TO 255 x.Add( RIGHT$(" "+STR$(ASC(UCASE$(CHR$(i)))), 3) ) IF i MOD 16=15 THEN x.Add( $CRLF ) IF i<255 THEN x.Add( $TAB ) x.Add( $TAB ) x.Add( "DB " ) END IF ELSE x.Add( ", " ) END IF NEXT CLIPBOARD SET TEXT x.String END SUB ' Uses ucase collation ASMDATA xlatTable DB 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 DB 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 DB 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47 DB 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 DB 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79 DB 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95 DB 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79 DB 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123, 124, 125, 126, 127 DB 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143 DB 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 138, 155, 140, 157, 142, 159 DB 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175 DB 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191 DB 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207 DB 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223 DB 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207 DB 208, 209, 210, 211, 212, 213, 214, 247, 216, 217, 218, 219, 220, 221, 222, 159 END ASMDATA FUNCTION InstrI2( mainStr AS STRING, matchStr AS STRING ) AS LONG #REGISTER NONE ! MOV EDX, 1 ! MOV ESI, mainStr ! MOV ESI, [ESI] ; ESI = StrPtr( mainStr ) ! MOV EDI, matchStr ! MOV EDI, [EDI] ; EDI = StrPtr( matchStr ) ! LEA EBX, xlatTable ; Translate table ! XOR EAX, EAX ; EAX = 0 ! MOV AL, BYTE PTR[EDI] ; AL = @matchStr[0] ! XLATB ; AL = UCase$( @matchStr[0] ) ! MOV ECX, EAX ; ECX = UCase$( @matchStr[0] ) InstrI2_Loop: ! MOV AL, BYTE PTR[ESI] ; EAX = @a ! OR AL, AL ; If @mainStr = 0 ! JZ InstrI2_NoMatch ; Goto Exit ! XLATB ; EAX = UCase$( @mainStr ) ! SUB EAX, ECX ; if @mainStr = @matchStr ! JZ InstrI2_Cmp ; Goto Compare ! XOR EAX, EAX ; Clear upper registers of A ! INC ESI ; Incr mainStr ! INC EDX ; Incr Pos ! JMP SHORT InstrI2_Loop ; Try next byte InstrI2_Cmp: ! PUSH ESI ; Save mainStr ! PUSH EDI ; Save findStr ! PUSH ECX ; Save UCase$( @findStr ) ! INC ESI ; Already compared this byte ! INC EDI ; Already compared this byte InstrI2_CmpLoop: ! MOV AL, BYTE PTR[EDI] ; AL = @matchStr ! OR AL, AL ; If @matchStr=0 ! JZ InstrI2_Match ; Then Goto Match! yay ! XLATB ; AL = UCase$( @matchStr ) ! MOV ECX, EAX ; ECX = UCase$( @matchStr ) ! MOV AL, BYTE PTR[ESI] ; EAX = @mainStr ! OR AL, AL ; If @matchStr=0 ! JZ InstrI2_CmpEnd ; Then we finish failed (no match) ! XLATB ; EAX = UCase$( @mainStr ) ! SUB EAX, ECX ; if @mainStr<>@matchStr ! JNZ InstrI2_CmpFail ; Then Goto Compare Failed ! INC EDI ; Incr matchStr ! INC ESI ; Incr mainStr ! JMP SHORT InstrI2_CmpLoop ; Try next byte InstrI2_CmpFail: ! POP ECX ; Restore UCase$( @findStr ) ! POP EDI ; Restore findStr ! POP ESI ; Restore mainStr ! INC ESI ; Incr mainStr ! INC EDX ; Incr pos ! JMP SHORT InstrI2_Loop InstrI2_Match: ! POP ECX ; Restore UCase$( @findStr ) ! POP EDI ; Restore findStr ! POP ESI ; Restore mainStr ! JMP SHORT InstrI2_Finish ; Return Position InstrI2_CmpEnd: ! POP ECX ; Restore UCase$( @findStr ) ! POP EDI ; Restore findStr ! POP ESI ; Restore mainStr InstrI2_NoMatch: ! XOR EDX, EDX ; Pos = 0 (No match) InstrI2_Finish: ! MOV FUNCTION, EDX ; Function = pos END FUNCTION FUNCTION InstrI( mainStr AS STRING, matchStr AS STRING ) AS LONG REGISTER i AS LONG REGISTER j AS LONG LOCAL mainPtr, matchPtr, xptr AS BYTE PTR LOCAL ch AS BYTE mainPtr = STRPTR( mainStr ) matchPtr = STRPTR( matchStr ) xptr = CODEPTR( xlatTable ) ch = @xptr[ @matchPtr ] FOR i=1 TO LEN(mainStr)-LEN(matchStr)+1 IF @xptr[ @mainPtr ] = ch THEN j = 1 WHILE @xptr[ @mainPtr[j] ] = @xptr[ @matchPtr[j] ] AND @matchPtr[j] AND @mainPtr[j] INCR j WEND IF @matchPtr[j]=0 THEN FUNCTION = i EXIT FUNCTION END IF END IF INCR mainPtr NEXT FUNCTION = 0 END FUNCTION FUNCTION caseFreeInstr(mainStr AS STRING, matchStr AS STRING, mainStrIsUcase AS LONG, reverse AS LONG) AS LONG 'note1: this fcn will cap mainStr and matchStr! This can good for multiple compares on the same mainStr. 'note2: fcn allows to shortcut past UCASE'ing mainStr by setting mainStrIsUcase <> 0. If function has been called 'already, and mainStr has been used previously as a parameter to this function (and has not been altered since), 'then setting mainStrIsUcase to non-zero will speed function up many X. REGISTER ii AS LONG STATIC oneTime AS LONG DIM sArr(LEN(mainStr)-1) AS BYTE AT STRPTR(mainStr) DIM sArr2(LEN(matchStr)-1) AS BYTE AT STRPTR(matchStr) IF oneTime = 0 THEN oneTime = 1 DIM translateArr(255) AS STATIC BYTE CALL arrayAssign(translateArr()) END IF FOR ii = 0 TO LEN(matchStr)-1 sArr2(ii) = translateArr(sArr2(ii)) 'make it uppercase NEXT IF mainStrIsUcase = 0 THEN FOR ii = 0 TO LEN(mainStr)-1 sArr(ii) = translateArr(sArr(ii)) 'make it uppercase NEXT END IF IF reverse = 0 THEN FUNCTION = INSTR(mainStr, matchStr) ELSE FUNCTION = INSTR(-1, mainStr, matchStr) END IF END FUNCTION SUB arrayAssign(translateArr() AS BYTE) ARRAY ASSIGN translateArr() = 0,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,59,60, _ 61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80, _ 81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,65,66,67,68, _ 69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88, _ 89,90,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140, _ 141,142,143,144,145,146,147,148,149,150,151,152,153,138,155,140,157,142,159,160, _ 161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180, _ 181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200, _ 201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220, _ 221,222,223,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208, _ 209,210,211,212,213,214,247,216,217,218,219,220,221,222,159 END SUB
Comment
-
You found an issue with embedded zero bytes Chr$(0). I use a Chr$(0) to indicate the end of string so InstrI will terminate earlier than a normal PB user might expect if you have these embedded.
That would make this unusable for things like UDT's with binary fields embedded. I might consider a different approach but for my current use case (scanning arrays of text strings), it doesn't present an issue.
If r1 = r2 And r1 = r3 And r1 = r4 Then
ii3 = 0
Else
Txt.Print "mismatch";r1;r2;r3;r4:
If InStr(line2, Chr$(0))>0 Then Txt.Print "ZERO"
Txt.WaitKey$ To exitStr:
If exitStr = "x" Or exitStr = Chr$(27) Then Exit Sub
End If
Comment
-
This is code from my PwrDev tool, it results in:
(Is this fast?)
Code:--------------------------- PowerBASIC --------------------------- 7800001 .035 --------------------------- OK ---------------------------
Code:FUNCTION PBMAIN Local line1 As String Local line2 As String Local result As Long Local tmr1 As Single Local tmr2 As Single line1 = Repeat$(100000 ,"QWERTYUIOP[]ASDFGHJKL;'ZXCVBNM,./qwertyuiop[]asdfghjkl;'zxcvbnm,./1234567890-=") & "HeLLo THErE!" line2 = "Hello There!" tmr1 = Timer result = InStr_ByMem( 0, StrPtr( line1 ), Len( line1 ), line2, 0 ) tmr2 = Timer ? Format$( result ) & $CrLf & Format$( Round( tmr2 - tmr1, 3 ) ) end function
Code:Function InStr_ByMem( _ ByVal nStartPos As Long _ , ByVal pData As Long _ , ByVal nDataLen As Long _ , ByVal sMatchString As String _ , ByVal bMatchCase As Long _ ) As Long Local pBYT As Byte Ptr Local pBYTASCII As Byte Ptr Local nByte As Long Local nLenMatch As Long Local bStartByte As Byte Local pBYTMatch As Byte Ptr Local nByteMatch As Long Local bFalse As Long Static sAscii As String If pData < 0 Then Exit Function If nDataLen < 1 Then Exit Function If nDataLen < Len( sMatchString ) Then Exit Function nLenMatch = Len( sMatchString ) If nLenMatch = 0 Then Exit Function nStartPos = Max( 1, nStartPos ) If nStartPos + nLenMatch - 1 > nDataLen Then Exit Function Decr nStartPos If Len( sAscii ) = 0 Then sAscii = Chr$( 0 To 255 ): CharUpperBuff ByVal StrPtr( sAscii ), Len( sAscii ) pBYTASCII = StrPtr( sAscii ) ' Make uppercase if case isn't important. If bMatchCase = 0 Then pBYT = StrPtr( sMatchString ) For nByte = 0 To Len( sMatchString ) - 1: @pBYT[nByte] = @pBYTASCII[@pBYT[nByte]]: Next nByte End If pBYT = pData pBYTMatch = StrPtr( sMatchString ) bStartByte = @pBYTMatch[0] If bMatchCase Then For nByte = nStartPos To nDataLen - nLenMatch - 0 If @pBYT[nByte] = bStartByte Then bFalse = 0 For nByteMatch = 1 To nLenMatch - 1 If @pBYT[nByte+nByteMatch] <> @pBYTMatch[nByteMatch] Then bFalse = 1: Exit For Next nByteMatch If bFalse = 0 Then Function = nByte + 1: Exit For End If Next Else For nByte = nStartPos To nDataLen - nLenMatch - 0 If @pBYTASCII[@pBYT[nByte]] = bStartByte Then bFalse = 0 For nByteMatch = 1 To nLenMatch - 1 If @pBYTASCII[@pBYT[nByte+nByteMatch]] <> @pBYTMatch[nByteMatch] Then bFalse = 1: Exit For Next nByteMatch If bFalse = 0 Then Function = nByte + 1: Exit For End If Next End If End Function
Comment
-
I'm still getting an error even with strictly text string searches chrs 32-122 in InstrI2. Here it's being compared to the output from the *gold standard* INSTR(UCASE$(line1), UCASE$(line2)). InstrI so far looks good for text.
Code:#COMPILE EXE #DIM ALL FUNCTION PBMAIN () AS LONG RANDOMIZE 'Call CreateTable CALL DoTest() END FUNCTION SUB DoTest() LOCAL hWin AS DWORD, ii2, ii3, r1,r2,r3,r4,rlen AS LONG LOCAL a, line1,line2,line3,exitStr AS STRING TXT.WINDOW("Case Insensitive Test", 10, 10) TO hWin LOCAL i AS LONG line1 = REPEAT$(100 ,"QWERTYUIOP[]ASDFGHJKL;'ZXCVBNM,./qwertyuiop[]asdfghjkl;'zxcvbnm,./1234567890-=") & "HeLLo THErE!" line3 = line1 line2 = "Hello There!" DO line1 = line3 RESET line2 FOR rLen = 1 TO RND(1, 32) line2 &= CHR$(RND(32,122))'97,25))',rnd(0,255),rnd(0,255),rnd(0,255),rnd(0,255))', _x NEXT ii2 = RND(1, 7800): IF ii2 > 7800\2 THEN ii3 = -1 ELSE ii3 = 0 MID$(line1, ii2) = line2 r3 = INSTR(UCASE$(line1), UCASE$(line2)) r1 = InstrI(line1, line2) r2 = InstrI2(line1, line2) ' r4 = caseFreeInstr(line1, line2, 0, 0) 'has to be last because it caps line1 & line2 ' IF r1 xor r2 xor r3 xor r4 THEN TXT.PRINT "mismatch";r1;r2;r3;r4: TXT.WAITKEY$ TO exitStr: IF exitStr = "x" OR exitStr = CHR$(27) THEN EXIT SUB '!wait '!wait 'IF r2 = 0 THEN ITERATE DO 'IF r1 = r2 AND r1 <> r3 THEN ITERATE DO IF r1 = r2 AND r1 = r3 THEN ii3 = 0 ELSE TXT.PRINT "mismatch";r1;r2;r3: TXT.WAITKEY$ TO exitStr: IF exitStr = "x" OR exitStr = CHR$(27) THEN EXIT SUB ' IF r1 <> r3 then TXT.PRINT "mismatch";r1;r2;r3;r4: TXT.WAITKEY$ TO exitStr: IF exitStr = "x" OR exitStr = CHR$(27) THEN EXIT SUB ITERATE DO IF INSTR(line1, line2) = caseFreeInstr(line1, line2, 0, ii3) THEN ' pcps(line1) ' pcwait ! nop ' pcpss(line2) ELSE IF INSTR(line1, line2) = caseFreeInstr(line1, line2, 0, ii3) THEN 'pcpss(line2 & "ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok") ELSE 'pcps(line1) 'pcps(line2) ' ? "oooooo" END IF END IF LOOP CALL TestSearch( "this is a super great test of the case insenstive isntri", "InS" ) CALL TestSearch( "short run", "RUN" ) CALL TestSearch(REPEAT$(20, "Haaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaay") & "needle", "NEEDLE" ) TXT.PRINT "Finished" TXT.LINE.INPUT a END SUB SUB TestSearch( BYVAL matchString AS STRING, BYVAL findString AS STRING ) LOCAL j AS LONG LOCAL st, en AS QUAD LOCAL s1#, e1# LOCAL msg AS STRING LOCAL i, c AS LONG s1 = TIMER FOR j=1 TO 1000000 i = caseFreeInstr( matchString, findString, 0, 0 ) NEXT e1 = TIMER TXT.PRINT "cFInstr "; FORMAT$( i, "0"); " in "; FORMAT$( e1-s1, "#,##0.0000") s1 = TIMER FOR j=1 TO 1000000 i = InstrI( matchString, findString ) NEXT e1 = TIMER TXT.PRINT "InstrI. "; FORMAT$( i, "0"); " in "; FORMAT$( e1-s1, "#,##0.0000") s1 = TIMER FOR j=1 TO 1000000 i = InstrI2( matchString, findString ) NEXT e1 = TIMER TXT.PRINT "InstrI2 "; FORMAT$( i, "0"); " in "; FORMAT$( e1-s1, "#,##0.0000") matchString = UCASE$( matchString ) findString = UCASE$( findString ) s1 = TIMER FOR j=1 TO 1000000 i = INSTR( matchString, findString ) NEXT e1 = TIMER TXT.PRINT "Instr.. "; FORMAT$( i, "0"); " in "; FORMAT$( e1-s1, "#,##0.0000") TXT.PRINT "-------------------------------------------------" TXT.PRINT FORMAT$( en-st, "#,##0" ) END SUB SUB CreateTable() LOCAL i AS LONG LOCAL x AS ISTRINGBUILDERA x = CLASS "StringBuilderA" x.Add( $TAB ) x.Add( $TAB ) x.Add( "DB " ) FOR i = 0 TO 255 x.Add( RIGHT$(" "+STR$(ASC(UCASE$(CHR$(i)))), 3) ) IF i MOD 16=15 THEN x.Add( $CRLF ) IF i<255 THEN x.Add( $TAB ) x.Add( $TAB ) x.Add( "DB " ) END IF ELSE x.Add( ", " ) END IF NEXT CLIPBOARD SET TEXT x.String END SUB ' Uses ucase collation ASMDATA xlatTable DB 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 DB 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 DB 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47 DB 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 DB 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79 DB 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95 DB 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79 DB 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123, 124, 125, 126, 127 DB 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143 DB 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 138, 155, 140, 157, 142, 159 DB 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175 DB 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191 DB 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207 DB 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223 DB 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207 DB 208, 209, 210, 211, 212, 213, 214, 247, 216, 217, 218, 219, 220, 221, 222, 159 END ASMDATA FUNCTION InstrI2( mainStr AS STRING, matchStr AS STRING ) AS LONG #REGISTER NONE ! MOV EDX, 1 ! MOV ESI, mainStr ! MOV ESI, [ESI] ; ESI = StrPtr( mainStr ) ! MOV EDI, matchStr ! MOV EDI, [EDI] ; EDI = StrPtr( matchStr ) ! LEA EBX, xlatTable ; Translate table ! XOR EAX, EAX ; EAX = 0 ! MOV AL, BYTE PTR[EDI] ; AL = @matchStr[0] ! XLATB ; AL = UCase$( @matchStr[0] ) ! MOV ECX, EAX ; ECX = UCase$( @matchStr[0] ) InstrI2_Loop: ! MOV AL, BYTE PTR[ESI] ; EAX = @a ! OR AL, AL ; If @mainStr = 0 ! JZ InstrI2_NoMatch ; Goto Exit ! XLATB ; EAX = UCase$( @mainStr ) ! SUB EAX, ECX ; if @mainStr = @matchStr ! JZ InstrI2_Cmp ; Goto Compare ! XOR EAX, EAX ; Clear upper registers of A ! INC ESI ; Incr mainStr ! INC EDX ; Incr Pos ! JMP SHORT InstrI2_Loop ; Try next byte InstrI2_Cmp: ! PUSH ESI ; Save mainStr ! PUSH EDI ; Save findStr ! PUSH ECX ; Save UCase$( @findStr ) ! INC ESI ; Already compared this byte ! INC EDI ; Already compared this byte InstrI2_CmpLoop: ! MOV AL, BYTE PTR[EDI] ; AL = @matchStr ! OR AL, AL ; If @matchStr=0 ! JZ InstrI2_Match ; Then Goto Match! yay ! XLATB ; AL = UCase$( @matchStr ) ! MOV ECX, EAX ; ECX = UCase$( @matchStr ) ! MOV AL, BYTE PTR[ESI] ; EAX = @mainStr ! OR AL, AL ; If @matchStr=0 ! JZ InstrI2_CmpEnd ; Then we finish failed (no match) ! XLATB ; EAX = UCase$( @mainStr ) ! SUB EAX, ECX ; if @mainStr<>@matchStr ! JNZ InstrI2_CmpFail ; Then Goto Compare Failed ! INC EDI ; Incr matchStr ! INC ESI ; Incr mainStr ! JMP SHORT InstrI2_CmpLoop ; Try next byte InstrI2_CmpFail: ! POP ECX ; Restore UCase$( @findStr ) ! POP EDI ; Restore findStr ! POP ESI ; Restore mainStr ! INC ESI ; Incr mainStr ! INC EDX ; Incr pos ! JMP SHORT InstrI2_Loop InstrI2_Match: ! POP ECX ; Restore UCase$( @findStr ) ! POP EDI ; Restore findStr ! POP ESI ; Restore mainStr ! JMP SHORT InstrI2_Finish ; Return Position InstrI2_CmpEnd: ! POP ECX ; Restore UCase$( @findStr ) ! POP EDI ; Restore findStr ! POP ESI ; Restore mainStr InstrI2_NoMatch: ! XOR EDX, EDX ; Pos = 0 (No match) InstrI2_Finish: ! MOV FUNCTION, EDX ; Function = pos END FUNCTION FUNCTION InstrI( mainStr AS STRING, matchStr AS STRING ) AS LONG REGISTER i AS LONG REGISTER j AS LONG LOCAL mainPtr, matchPtr, xptr AS BYTE PTR LOCAL ch AS BYTE mainPtr = STRPTR( mainStr ) matchPtr = STRPTR( matchStr ) xptr = CODEPTR( xlatTable ) ch = @xptr[ @matchPtr ] FOR i=1 TO LEN(mainStr)-LEN(matchStr)+1 IF @xptr[ @mainPtr ] = ch THEN j = 1 WHILE @xptr[ @mainPtr[j] ] = @xptr[ @matchPtr[j] ] AND @matchPtr[j] AND @mainPtr[j] INCR j WEND IF @matchPtr[j]=0 THEN FUNCTION = i EXIT FUNCTION END IF END IF INCR mainPtr NEXT FUNCTION = 0 END FUNCTION FUNCTION caseFreeInstr(mainStr AS STRING, matchStr AS STRING, mainStrIsUcase AS LONG, reverse AS LONG) AS LONG 'note1: this fcn will cap mainStr and matchStr! This can good for multiple compares on the same mainStr. 'note2: fcn allows to shortcut past UCASE'ing mainStr by setting mainStrIsUcase <> 0. If function has been called 'already, and mainStr has been used previously as a parameter to this function (and has not been altered since), 'then setting mainStrIsUcase to non-zero will speed function up many X. REGISTER ii AS LONG STATIC oneTime AS LONG DIM sArr(LEN(mainStr)-1) AS BYTE AT STRPTR(mainStr) DIM sArr2(LEN(matchStr)-1) AS BYTE AT STRPTR(matchStr) IF oneTime = 0 THEN oneTime = 1 DIM translateArr(255) AS STATIC BYTE CALL arrayAssign(translateArr()) END IF FOR ii = 0 TO LEN(matchStr)-1 sArr2(ii) = translateArr(sArr2(ii)) 'make it uppercase NEXT IF mainStrIsUcase = 0 THEN FOR ii = 0 TO LEN(mainStr)-1 sArr(ii) = translateArr(sArr(ii)) 'make it uppercase NEXT END IF IF reverse = 0 THEN FUNCTION = INSTR(mainStr, matchStr) ELSE FUNCTION = INSTR(-1, mainStr, matchStr) END IF END FUNCTION SUB arrayAssign(translateArr() AS BYTE) ARRAY ASSIGN translateArr() = 0,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,59,60, _ 61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80, _ 81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,65,66,67,68, _ 69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88, _ 89,90,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140, _ 141,142,143,144,145,146,147,148,149,150,151,152,153,138,155,140,157,142,159,160, _ 161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180, _ 181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200, _ 201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220, _ 221,222,223,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208, _ 209,210,211,212,213,214,247,216,217,218,219,220,221,222,159 END SUB
Comment
-
re the UCASE/LCASE thing...
You could always test "as is" and see if you get a hit, then only if that fails you UCASE$ it and test.
Saves a UCASE operation (=create string + move data (converting) + destroy string) whenever there is a 'natural' hit.
Might produce some interesting results.Michael Mattias
Tal Systems (retired)
Port Washington WI USA
[email protected]
http://www.talsystems.com
Comment
-
> *gold standard* INSTR(UCASE$(line1), UCASE$(line2)).
How do you know that is the "gold standard" using "pure" PowerBASIC statements?
REGEXPR might be the true gold standard for "case insensitive string search usng simple PowerBASIC syntax."Michael Mattias
Tal Systems (retired)
Port Washington WI USA
[email protected]
http://www.talsystems.com
Comment
-
Originally posted by John Gleason View PostI'm still getting an error even with strictly text string searches chrs 32-122 in InstrI2. Here it's being compared to the output from the *gold standard* INSTR(UCASE$(line1), UCASE$(line2)). InstrI so far looks good for text.
Code:#COMPILE EXE #DIM ALL FUNCTION PBMAIN () AS LONG RANDOMIZE 'Call CreateTable CALL DoTest() END FUNCTION SUB DoTest() LOCAL hWin AS DWORD, ii2, ii3, r1,r2,r3,r4,rlen AS LONG LOCAL a, line1,line2,line3,exitStr AS STRING TXT.WINDOW("Case Insensitive Test", 10, 10) TO hWin LOCAL i AS LONG line1 = REPEAT$(100 ,"QWERTYUIOP[]ASDFGHJKL;'ZXCVBNM,./qwertyuiop[]asdfghjkl;'zxcvbnm,./1234567890-=") & "HeLLo THErE!" line3 = line1 line2 = "Hello There!" DO line1 = line3 RESET line2 FOR rLen = 1 TO RND(1, 32) line2 &= CHR$(RND(32,122))'97,25))',rnd(0,255),rnd(0,255),rnd(0,255),rnd(0,255))', _x NEXT ii2 = RND(1, 7800): IF ii2 > 7800\2 THEN ii3 = -1 ELSE ii3 = 0 MID$(line1, ii2) = line2 r3 = INSTR(UCASE$(line1), UCASE$(line2)) r1 = InstrI(line1, line2) r2 = InstrI2(line1, line2) ' r4 = caseFreeInstr(line1, line2, 0, 0) 'has to be last because it caps line1 & line2 ' IF r1 xor r2 xor r3 xor r4 THEN TXT.PRINT "mismatch";r1;r2;r3;r4: TXT.WAITKEY$ TO exitStr: IF exitStr = "x" OR exitStr = CHR$(27) THEN EXIT SUB '!wait '!wait 'IF r2 = 0 THEN ITERATE DO 'IF r1 = r2 AND r1 <> r3 THEN ITERATE DO IF r1 = r2 AND r1 = r3 THEN ii3 = 0 ELSE TXT.PRINT "mismatch";r1;r2;r3: TXT.WAITKEY$ TO exitStr: IF exitStr = "x" OR exitStr = CHR$(27) THEN EXIT SUB ' IF r1 <> r3 then TXT.PRINT "mismatch";r1;r2;r3;r4: TXT.WAITKEY$ TO exitStr: IF exitStr = "x" OR exitStr = CHR$(27) THEN EXIT SUB ITERATE DO IF INSTR(line1, line2) = caseFreeInstr(line1, line2, 0, ii3) THEN ' pcps(line1) ' pcwait ! nop ' pcpss(line2) ELSE IF INSTR(line1, line2) = caseFreeInstr(line1, line2, 0, ii3) THEN 'pcpss(line2 & "ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok ok") ELSE 'pcps(line1) 'pcps(line2) ' ? "oooooo" END IF END IF LOOP CALL TestSearch( "this is a super great test of the case insenstive isntri", "InS" ) CALL TestSearch( "short run", "RUN" ) CALL TestSearch(REPEAT$(20, "Haaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaay") & "needle", "NEEDLE" ) TXT.PRINT "Finished" TXT.LINE.INPUT a END SUB SUB TestSearch( BYVAL matchString AS STRING, BYVAL findString AS STRING ) LOCAL j AS LONG LOCAL st, en AS QUAD LOCAL s1#, e1# LOCAL msg AS STRING LOCAL i, c AS LONG s1 = TIMER FOR j=1 TO 1000000 i = caseFreeInstr( matchString, findString, 0, 0 ) NEXT e1 = TIMER TXT.PRINT "cFInstr "; FORMAT$( i, "0"); " in "; FORMAT$( e1-s1, "#,##0.0000") s1 = TIMER FOR j=1 TO 1000000 i = InstrI( matchString, findString ) NEXT e1 = TIMER TXT.PRINT "InstrI. "; FORMAT$( i, "0"); " in "; FORMAT$( e1-s1, "#,##0.0000") s1 = TIMER FOR j=1 TO 1000000 i = InstrI2( matchString, findString ) NEXT e1 = TIMER TXT.PRINT "InstrI2 "; FORMAT$( i, "0"); " in "; FORMAT$( e1-s1, "#,##0.0000") matchString = UCASE$( matchString ) findString = UCASE$( findString ) s1 = TIMER FOR j=1 TO 1000000 i = INSTR( matchString, findString ) NEXT e1 = TIMER TXT.PRINT "Instr.. "; FORMAT$( i, "0"); " in "; FORMAT$( e1-s1, "#,##0.0000") TXT.PRINT "-------------------------------------------------" TXT.PRINT FORMAT$( en-st, "#,##0" ) END SUB SUB CreateTable() LOCAL i AS LONG LOCAL x AS ISTRINGBUILDERA x = CLASS "StringBuilderA" x.Add( $TAB ) x.Add( $TAB ) x.Add( "DB " ) FOR i = 0 TO 255 x.Add( RIGHT$(" "+STR$(ASC(UCASE$(CHR$(i)))), 3) ) IF i MOD 16=15 THEN x.Add( $CRLF ) IF i<255 THEN x.Add( $TAB ) x.Add( $TAB ) x.Add( "DB " ) END IF ELSE x.Add( ", " ) END IF NEXT CLIPBOARD SET TEXT x.String END SUB ' Uses ucase collation ASMDATA xlatTable DB 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 DB 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 DB 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47 DB 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 DB 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79 DB 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95 DB 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79 DB 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123, 124, 125, 126, 127 DB 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143 DB 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 138, 155, 140, 157, 142, 159 DB 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175 DB 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191 DB 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207 DB 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223 DB 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207 DB 208, 209, 210, 211, 212, 213, 214, 247, 216, 217, 218, 219, 220, 221, 222, 159 END ASMDATA FUNCTION InstrI2( mainStr AS STRING, matchStr AS STRING ) AS LONG #REGISTER NONE ! MOV EDX, 1 ! MOV ESI, mainStr ! MOV ESI, [ESI] ; ESI = StrPtr( mainStr ) ! MOV EDI, matchStr ! MOV EDI, [EDI] ; EDI = StrPtr( matchStr ) ! LEA EBX, xlatTable ; Translate table ! XOR EAX, EAX ; EAX = 0 ! MOV AL, BYTE PTR[EDI] ; AL = @matchStr[0] ! XLATB ; AL = UCase$( @matchStr[0] ) ! MOV ECX, EAX ; ECX = UCase$( @matchStr[0] ) InstrI2_Loop: ! MOV AL, BYTE PTR[ESI] ; EAX = @a ! OR AL, AL ; If @mainStr = 0 ! JZ InstrI2_NoMatch ; Goto Exit ! XLATB ; EAX = UCase$( @mainStr ) ! SUB EAX, ECX ; if @mainStr = @matchStr ! JZ InstrI2_Cmp ; Goto Compare ! XOR EAX, EAX ; Clear upper registers of A ! INC ESI ; Incr mainStr ! INC EDX ; Incr Pos ! JMP SHORT InstrI2_Loop ; Try next byte InstrI2_Cmp: ! PUSH ESI ; Save mainStr ! PUSH EDI ; Save findStr ! PUSH ECX ; Save UCase$( @findStr ) ! INC ESI ; Already compared this byte ! INC EDI ; Already compared this byte InstrI2_CmpLoop: ! MOV AL, BYTE PTR[EDI] ; AL = @matchStr ! OR AL, AL ; If @matchStr=0 ! JZ InstrI2_Match ; Then Goto Match! yay ! XLATB ; AL = UCase$( @matchStr ) ! MOV ECX, EAX ; ECX = UCase$( @matchStr ) ! MOV AL, BYTE PTR[ESI] ; EAX = @mainStr ! OR AL, AL ; If @matchStr=0 ! JZ InstrI2_CmpEnd ; Then we finish failed (no match) ! XLATB ; EAX = UCase$( @mainStr ) ! SUB EAX, ECX ; if @mainStr<>@matchStr ! JNZ InstrI2_CmpFail ; Then Goto Compare Failed ! INC EDI ; Incr matchStr ! INC ESI ; Incr mainStr ! JMP SHORT InstrI2_CmpLoop ; Try next byte InstrI2_CmpFail: ! POP ECX ; Restore UCase$( @findStr ) ! POP EDI ; Restore findStr ! POP ESI ; Restore mainStr ! INC ESI ; Incr mainStr ! INC EDX ; Incr pos ! JMP SHORT InstrI2_Loop InstrI2_Match: ! POP ECX ; Restore UCase$( @findStr ) ! POP EDI ; Restore findStr ! POP ESI ; Restore mainStr ! JMP SHORT InstrI2_Finish ; Return Position InstrI2_CmpEnd: ! POP ECX ; Restore UCase$( @findStr ) ! POP EDI ; Restore findStr ! POP ESI ; Restore mainStr InstrI2_NoMatch: ! XOR EDX, EDX ; Pos = 0 (No match) InstrI2_Finish: ! MOV FUNCTION, EDX ; Function = pos END FUNCTION FUNCTION InstrI( mainStr AS STRING, matchStr AS STRING ) AS LONG REGISTER i AS LONG REGISTER j AS LONG LOCAL mainPtr, matchPtr, xptr AS BYTE PTR LOCAL ch AS BYTE mainPtr = STRPTR( mainStr ) matchPtr = STRPTR( matchStr ) xptr = CODEPTR( xlatTable ) ch = @xptr[ @matchPtr ] FOR i=1 TO LEN(mainStr)-LEN(matchStr)+1 IF @xptr[ @mainPtr ] = ch THEN j = 1 WHILE @xptr[ @mainPtr[j] ] = @xptr[ @matchPtr[j] ] AND @matchPtr[j] AND @mainPtr[j] INCR j WEND IF @matchPtr[j]=0 THEN FUNCTION = i EXIT FUNCTION END IF END IF INCR mainPtr NEXT FUNCTION = 0 END FUNCTION FUNCTION caseFreeInstr(mainStr AS STRING, matchStr AS STRING, mainStrIsUcase AS LONG, reverse AS LONG) AS LONG 'note1: this fcn will cap mainStr and matchStr! This can good for multiple compares on the same mainStr. 'note2: fcn allows to shortcut past UCASE'ing mainStr by setting mainStrIsUcase <> 0. If function has been called 'already, and mainStr has been used previously as a parameter to this function (and has not been altered since), 'then setting mainStrIsUcase to non-zero will speed function up many X. REGISTER ii AS LONG STATIC oneTime AS LONG DIM sArr(LEN(mainStr)-1) AS BYTE AT STRPTR(mainStr) DIM sArr2(LEN(matchStr)-1) AS BYTE AT STRPTR(matchStr) IF oneTime = 0 THEN oneTime = 1 DIM translateArr(255) AS STATIC BYTE CALL arrayAssign(translateArr()) END IF FOR ii = 0 TO LEN(matchStr)-1 sArr2(ii) = translateArr(sArr2(ii)) 'make it uppercase NEXT IF mainStrIsUcase = 0 THEN FOR ii = 0 TO LEN(mainStr)-1 sArr(ii) = translateArr(sArr(ii)) 'make it uppercase NEXT END IF IF reverse = 0 THEN FUNCTION = INSTR(mainStr, matchStr) ELSE FUNCTION = INSTR(-1, mainStr, matchStr) END IF END FUNCTION SUB arrayAssign(translateArr() AS BYTE) ARRAY ASSIGN translateArr() = 0,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,59,60, _ 61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80, _ 81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,65,66,67,68, _ 69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88, _ 89,90,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140, _ 141,142,143,144,145,146,147,148,149,150,151,152,153,138,155,140,157,142,159,160, _ 161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180, _ 181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200, _ 201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220, _ 221,222,223,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208, _ 209,210,211,212,213,214,247,216,217,218,219,220,221,222,159 END SUB
Code:! SUB EAX, ECX ; if @mainStr<>@matchStr ! JNZ InstrI2_CmpFail ; Then Goto Compare Failed [COLOR=red] ! XOR EAX, EAX[/COLOR] ! INC EDI ; Incr matchStr ! INC ESI ; Incr mainStr ! JMP SHORT InstrI2_CmpLoop ; Try next byte InstrI2_CmpFail:
Comment
Comment