Help speeding up a search

Hello,

I have a list of strings about 2500, that consists of names, email addresses and Telephone numbers in a TextArea.

I have a pushbutton with the following code to search for the string that contains, lets say, the email address.

Dim ItemFound as Boolean
Dim i as Integer
Dim myArray() as String
myArray = Split(TextArea1.Text, Chr(13))

For i = 0 to CountFields(TextArea1.Text, Chr(13))
if Instr(myArray(i), TextField1.Text) > 0 then
ItemFound = True
exit
end if
next

If ItemFound = True then
TextField1.Text = myArray(i)
else
TextField1.Text = TextField1.Text + " was not found"
end if

It takes about 60 seconds to find a string that is close to the bottom of the TextArea, how can I speed this up?

Thanks Lennox

CountFields is a very slow function. It’s also possible that it’s doing it every time through the For Next loop. So at a minimum do that before the loop.

On another note though, I’m confused on why you do the split on chr(13) and then use CountFields on the TextArea. It seems redundant.

dim myArray() as string = TextArea1.Text.split(chr(13)) for each s as string in myArray if s.instr(TextField1.text) > 0 then ItemFound = true exit next

That should be faster. There’s probably an even faster way.

[quote=145181:@Lennox Jacob]Hello,

I have a list of strings about 2500, that consists of names, email addresses and Telephone numbers in a TextArea.

I have a pushbutton with the following code to search for the string that contains, lets say, the email address.

Dim ItemFound as Boolean
Dim i as Integer
Dim myArray() as String
myArray = Split(TextArea1.Text, Chr(13))

For i = 0 to CountFields(TextArea1.Text, Chr(13))
if Instr(myArray(i), TextField1.Text) > 0 then
ItemFound = True
exit
end if
next

If ItemFound = True then
TextField1.Text = myArray(i)
else
TextField1.Text = TextField1.Text + " was not found"
end if

It takes about 60 seconds to find a string that is close to the bottom of the TextArea, how can I speed this up?

Thanks Lennox[/quote]

Instant :

dim Position as integer = instr(TextArea1.Text,"Needle") if Position = 0 then return // Not found dim Endline as integer = instr( instr(TextArea1.Text,"Needle"),TextArea1.Text,chr(13)) // End of line //Find preceding EndOfLine While mid(TextArea1.Text,Position,1) <> chr(13) Position = Position-1 system.DebugLog str(Position) Wend Position = Position+1 dim result as string = Mid(TextArea1.Text,Position,Endline-Position) Msgbox str(Position)+" "+str(Endline)+" "+Result

This displays the line in which is the term searched for.

You can also use a regular expression for this.

dim pattern as string = _
  "^.*\\Q" + TextField1.Text.ReplaceAllB( "\\E", "\\\\EE\\Q" ) + "\\E.*$"
dim rx as new RegEx
rx.SearchPattern = pattern
dim match as RegExMatch = rx.Search( TextArea1.Text )
if match is nil then
  TextField1.Text = TextField1.Text + " was not found"
else
  TextField1.Text = match.SubExpressionString( 0 )
end if

There is no need to split anything.
You can just search the whole textarea

[quote=145217:@Horacio Vilches]There is no need to split anything.
You can just search the whole textarea[/quote]

Exactly what I and Kem did :wink:

i got Kem’s version working right away but Micheal’s version went into a endless loop

If you are on PC the EndOfLine in TextArea is probably not chr(13), so the routine that seeks the previous line end indeed never ends. If Kem’s code works for you that is perfect.

Thanks,

Both Michel and Kem versions works flawlessly and quickly on Mac, did not try on PC (as yet).

Thanks again.

Lennox

i try it on the mac and even try changing to chr(13) + chr(10) and still does not work

I created what I posted on Mac, and verified it worked.

chr(13)+chr(10) will certainly not work, since there is no chr(10) in a Mac TextArea.

I slightly modified the code so it does not go into an endless loop, and also placed a beep if for some reason the TextArea does not contain any carriage return, which may very well be the issue you have. What I posted was based on the description of the OP, who has thousand of lines, all separated by chr(13). Incidentally, that is also the case for Bob’s code.

[code] if instr(TextArea1.Text,chr(13)) = 0 then beep

dim Position as integer = instr(TextArea1.Text,“Needle”) // We are looking for Needle, case insensitive
if Position = 0 then return // Not found
dim Endline as integer = instr( instr(TextArea1.Text,“Needle”),TextArea1.Text,chr(13)) // End of line
//Find preceding EndOfLine
While mid(TextArea1.Text,Position,1) <> chr(13) and Position > 0
Position = Position-1
system.DebugLog str(Position)
Wend
Position = Position+1
dim result as string = Mid(TextArea1.Text,Position,Endline-Position)
Msgbox str(Position)+" “+str(Endline)+” "+Result[/code]

You got to understand this was in no way intended as a bullet proof method, but rather a principle to apply to have the fastest result possible. Placing error checking like making sure the Position variable does not go negative or making sure there are chr(13) in the text are just examples of what needs to be done to get to a polished result.

This works on Windows
modified Michel Bujardet Code

TextArea1.Text = ReplaceAll(TextArea1.Text, EndOfLine, Chr(13))

dim Position as integer =  instr(TextArea1.Text, TextField1.Text)
if Position = 0 then return // Not found

dim Endline as integer = instr( instr(TextArea1.Text, TextField1.Text), TextArea1.Text, Chr(13)) // End of line

//Find preceding EndOfLine
While mid(TextArea1.Text, Position,1) <> chr(13)
  Position = Position-1
  system.DebugLog str(Position)
Wend

Position = Position+1

dim result as string = Mid(TextArea1.Text, Position, Endline-Position)
TextField1.Text = Result

Lennox

it work lennox… by adding in the first line with the replaceall.

i also replace this

dim Endline as integer = instr( instr(TextArea1.Text, TextField1.Text), TextArea1.Text, Chr(13)) // End of line

with this

dim Endline as integer = instr( Position,TextArea1.Text,chr(13)) // End of line

This works on both Mac and PC …

If Keyboard.AsyncControlKey or IsContextualClick then
// from Kem Tekinay’s Code
'MsgBox “KT”

// https://forum.xojo.com/17526-help-speeding-up-a-search/0#p145182

dim pattern as string = _
"^.*\\Q" + TextField1.Text.ReplaceAllB( "\\E", "\\\\EE\\Q" ) + "\\E.*$"
dim rx as new RegEx
rx.SearchPattern = pattern
dim match as RegExMatch = rx.Search( TextArea1.Text )
if match is nil then
  TextField1.Text = TextField1.Text + " was not found"
else
  TextField1.Text = match.SubExpressionString( 0 )
end if

else
// modified Michel Bujardet’s Code
'MsgBox “MB”

// https://forum.xojo.com/17526-help-speeding-up-a-search/0#p145182

TextArea1.Text = ReplaceAll(TextArea1.Text, EndOfLine, Chr(13))

dim Position as integer =  instr(TextArea1.Text, TextField1.Text)
if Position = 0 then return // Not found

dim Endline as integer = instr( instr(TextArea1.Text, TextField1.Text), TextArea1.Text, Chr(13)) // End of line

//Find preceding EndOfLine
While mid(TextArea1.Text, Position,1) <> chr(13)
  Position = Position-1
  system.DebugLog str(Position)
Wend

Position = Position+1

dim result as string = Mid(TextArea1.Text, Position, Endline-Position)
TextField1.Text = Result

end if

Lennox

Congratulations, Lennox.

As an aside, look at the LR for ReplaceLineEndings. A very useful function, and better than trying to do it yourself.

[quote=145375:@Lennox Jacob]//Find preceding EndOfLine
While mid(TextArea1.Text, Position,1) <> chr(13)
Position = Position-1
system.DebugLog str(Position)
Wend
[/quote]

If the found text is on the first line, this will go into an endless loop, won’t it? Seems like it should be:

//Find preceding EndOfLine
While Position > 0 and mid(TextArea1.Text, Position,1) <> chr(13)
Position = Position-1
system.DebugLog str(Position)
Wend

[quote=145403:@Kem Tekinay]If the found text is on the first line, this will go into an endless loop, won’t it? Seems like it should be:

//Find preceding EndOfLine While Position > 0 and mid(TextArea1.Text, Position,1) <> chr(13) Position = Position-1 system.DebugLog str(Position) Wend [/quote]

Indeed. That is what I posted on the second time.

I have

//Find preceding EndOfLine
While mid(TextArea1.Text, Position,1) <> chr(13)
  Position = Position-1
  system.DebugLog str(Position)
Wend

and it does not go into an infinite loop when I search for something in the first line

Lennox

The only way that’s possible is if TextArea1.Text starts with Chr( 13 ). Otherwise, nothing will stop that loop.

You can emulate the results with this code:

  dim s as string = "12345"
  dim position as integer = 5
  while s.Mid( position, 1 ) <> chr( 13 )
    position = position - 1
  wend
  MsgBox str( position )