VB's InStrRev Xojo Equivalent

Visual Basic has a useful function called InStrRev, which is (as the name suggests) sort of an InStr in Reverse, i.e., it starts counting characters at the right rather then at the left.

I know that there are many ways that a Xojo equivalent could be written (e.g., reversing the original string, using a backwards For/Next loop (with Downto, etc.), so it shouldn’t be difficult for me to write a Xojo equivalent myself.

I don’t mind re-inventing the wheel, but what I come up with is likely NOT to be the BEST solution to the problem. I’d be much interested in what people here have come up with as the BEST answer to the question.

What I’m hoping for is something that may be an elegantly simple (or simply elegant?) solution. (Doesn’t an Xojo counterpart to VB’s InStrRev deserve to be simple and elegant?) But please post code you’ve found useful even if you aren’t convinced that it fully meets tne previous description. Thanks!

Barry Traver

I miss that too. Probably your best guess to find a substring at the end of a string is using regular expressions. Page Not Found — Xojo documentation
It’s like using a gun to kill a fly.

I don’t know why only in 2012 this request appeared: <https://xojo.com/issue/20181> . Should be older.

The following is from the Internet, few months earlier. So not sure about the source.

Function InStrRev(ByVal strSourceString As String, ByVal strFindString As String, ByVal blnMatchCase As Boolean = False) As Integer Dim k As integer Dim lastFound As Integer Dim limit As Integer If blnMatchCase =False Then k = InStr(strSourceString, strFindString ) Else k = InStrB(strSourceString, strFindString ) End If lastFound = k limit=Len(strSourceString) While k > 0 lastFound = k If k<limit Then If blnMatchCase =False Then k = InStr( lastFound+1, strSourceString, strFindString) Else k = InStrB( lastFound+1, strSourceString, strFindString) End If Else Exit While End If Wend Return lastFound End Function

Does this do what you want:

Dim s as string
Dim delimiter as string
Dim lastVal as integer

s = “This is a test”
delimiter = " "

lastVal = s.InStr( s.len - s.NthField(delimiter, s.CountFields(delimiter)).Len, delimiter)

Added to a module as a string extension method with the ‘binary’ comparison added:

Function InStrRev(extends s as string, delimiter as String, binary as boolean = false) As integer
  if binary then
    return s.InStrB( s.len - s.NthFieldB(delimiter, s.CountFieldsB(delimiter)).Len, delimiter)
  else
    return s.InStr( s.len - s.NthField(delimiter, s.CountFields(delimiter)).Len, delimiter)
  end if
End Function

Mark… doesn’t that only work if you are looking for the last occurance of a CHARACTER?

FUNCTION instrRev(s as string,t as string)
last=0
do
   x=instr(last+1,s,t)
   if x>0 then 
       last=x
   else
     exit do
   end if
loop
return last
END FUNCTION

[quote=26929:@Dave S]Mark… doesn’t that only work if you are looking for the last occurance of a CHARACTER?
[/quote]
Ah, yes, I didn’t take into account the length of the delimiter. I believe this should work:

Function InStrRev(extends s as string, delimiter as String, binary as boolean = false) As integer if binary then return s.InStrB( s.len - s.NthFieldB(delimiter, s.CountFieldsB(delimiter)).Len - (delimiter.len - 1), delimiter) else return s.InStr( s.len - s.NthField(delimiter, s.CountFields(delimiter)).Len - (delimiter.len - 1), delimiter) end if End Function

I’m glad I asked the question. The comments posted by other people here are much better and fit more situations than my faltering first steps toward a InStrRev.

To illustrate that point, here’s where I begain, which is too specific (rather than fitting different situations, including different length of delimiter as diiscussed here in this thread) and wastes time unnecessarily looking at the entire string. In short, here’s an example of bad programming, even if I had gotten from this to a more general definition:

  // The following finds the filename wIthout the extension
  //  if the filename contains one period or more than one.
  Dim I, Pos1 As Integer 
  Dim Filename, FilenameWithoutTheExtension As String
  Filename = "one.two.three.four.five"
  For I = 1 To Len (FileName)
    If Mid ( FileName, I, 1)  = "." Then
      Pos1 = I
    End If
  Next I
  MsgBox Str ( Pos1 )
  FilenameWithoutTheExtension = Left ( Filename, Pos1 -1 )
  MsgBox Filename + EndOfLine + FilenameWIthoutTheExtension

Thanks for the posts. You didn’t disappoint me.

Barry Traver

FYI, an optimized InStrRev is in my M_String module.

http://www.mactechnologies.com/index.php?page=downloads

Here is the actual code. In my tests, this turned out to be faster than anything else I tried (which is counter-intuitive, IMO). You can see my other attempts in M_String.

Function InStrRev_MTC(Extends src As String, start As Integer = 0, find As String) As Integer
  #pragma BackgroundTasks False
  #pragma BoundsChecking False
  #pragma NilObjectChecking False
  
  dim pos as integer
  dim curPos as integer = 0
  if start > 0 then src = src.Left( start )
  
  do
    curPos = src.InStr( curPos + 1, find )
    if curPos = 0 then
      exit
    else
      pos = curPos
    end if
  loop
  
  return pos
End Function