Using negative indexes with string:sub()

The string:sub(string, start, end) function is the substring function supplied with Lua’s substring. Simple enough right? Or maybe not…

“Returns the substring of s that starts at i and continues until j; i and j can be negative. If j is absent, then it is assumed to be equal to -1 (which is the same as the string length). In particular, the call string.sub(s,1,j) returns a prefix of s with length j, and string.sub(s, -i) returns a suffix of s with length i.”

It is a very simple but clever implementation, however it differs from other languages:

  1. The start and end parameters are inclusive, end is usually exclusive in other languages
  2. It allows for negative values of start and end that count back from the end of the string (similar to slice() in java)

So let’s look at three ways we can use it:

  1. Extracting a sub-string from the start of a string
  2. Extracting a sub-string from the middle of a string
  3. Extracting a sub-string from the end of a string

Extracting a sub-string from the start of a string:

This is the simplest case, counting from the start of the string is the only option, negative indexes are not used.

Screen Shot 2014-04-07 at 15.30.02

Extracting a sub-string from the middle of a string:

You can count from the start or end of the string depending on circumstance.

Screen Shot 2014-04-07 at 15.30.43

Extracting a sub-string from the end of a string:

Once again you can count from the start or end of the string.

Screen Shot 2014-04-08 at 01.07.45

Code

function main(Data)

   -----------------------------------------------------
   -- Extracting a sub-string from the start of a string
   -----------------------------------------------------
   local S = "ABC Hello world"   
   S:sub(1,3) 

   ------------------------------------------------------
   -- Extracting a sub-string from the middle of a string
   ------------------------------------------------------
   local S = "123ABC Hello world"
   S:sub(4,6) -- counting from the start of the string

   local S = "Hello world ABC123"
   S:sub(-6,-4)     -- counting back from the end of the string
   S:sub(#S-6,#S-3) -- less succint and less obvious

   ---------------------------------------------------
   -- Extracting a sub-string from the end of a string
   ---------------------------------------------------
   local S = "Hello world ABC"

   -- Recommended syntax
   S:sub(-3,-1) -- specify the end parameter = more obvious?
   S:sub(-3)    -- succint will appeal to experienced programmers

   -- Alternatives if you prefer positive indexes
   S:sub(#S-2,#S)
   S:sub(#S-2)    -- subtract 2 from length = 3rd from last char

    -----------------
    -- What not to do
    -----------------
   -- Mixing +ve and -ve arguments is ugly *not recommended*
   S:sub(-3,#S)
   S:sub(#S-2,-1)

end