Is there a way to find the position of a matched string?

Suppose I have a string (PlayerCodeString) that a player defines, but I know what the string is in this case: “Hey, the code is 123. I repeat: the code is 123.”

The code can be anything as the player defines, but I know it’s a number, so I know I can use string.match(PlayerCodeString, "%d+") to get the code. I can also use string.gmatch(PlayerCodeString, "%d+") to verify that the code the player defines is the same.

But I want to get the position of the matches. I know I can use string.find(PlayerCodeString, "%d+") to find the position of the first occurrence, but I don’t think I can find the second one by simply using this function.

Is there a way to find the positions of the matches?

1 Like

string.find has an argument where you can tell it the nth occurrence of the pattern

you could use something like this

local occurrence = 2
local s, e = string.find(PlayerCodeString, "%d+", occurrence)
2 Likes

I think the third argument in string.find() is the position of the string of where to start looking for a substring.

> print(string.find("Hey, the code is 123. I repeat: the code is 123.", "%d+",2))

18 20

> print(string.find("Hey, the code is 123. I repeat: the code is 123.", "%d+"));

18 20

This returns the same position.

bruh i am a idiot

u could do something like this then

local str = ""
local pat = ""
local len_offset = 0
local occurs = {}
repeat
	local s, e = string.find(str, pat)
	if e then
		table.insert(occurs, #occurs + 1, {s+len_offset, e+len_offset})
		str = string.sub(str, e+1)
		len_offset = len_offset + e
	end
until (not s)

I would imagine there is a better way but I am not really friends with strings

5 Likes

Works for me; just wanted to know if it was possible.

Thank you!

1 Like

I know this has been solved, but…

if you want to get the position of a certain character in a string then there’s more than one method, way more than 1.

  1. Using string.find()

this is probably the canonical way to do get the position of an element :

str = "I repeat the code is 123"
 
 local position = string.find(str,"r")
 print(position) --> 3 , as whitespaces count as characters

A function for it,

  function getPosition(str,char) 
    	
    assert(str:find(char),"\r\r"..char.." not found in string \r\r")
         local find = string.find(str,char)
    return find 
end

My own invented function, made this a long time ago (ignore parameter init) (also uncertain about it's efficiency)
   function nmatch(s,pattern,init)        	 
        	  if type(s) == "string"    then
           else  
        	  return nil
        	end
        	 if init  then
        	    local sub = s:sub(init)
        	      if  sub:match(pattern) 
        	        then for i = 1,#sub do
        		     if sub:sub(i,i) == pattern then
        		else 
        			 i = nil
        		       return i
        			
        		  	end  
        	     end
           
        		 return 
        	  end
           end
        	
        	 if not init then
        	    if s:match(pattern) then
        		   for i = 1,#s do
        		     if s:sub(i,i) == pattern then
        		    return i
        		    end
        	    end
            else  
        		return nil  
        	   end
        	 end
          end   


print(nmatch("strring","r")) ---> first occurence is at 3, so 3 prints
2 Likes

There’s even a way to do it with gmatch, using the empty capture pattern. This pattern, (), captures the position it’s before. For example,

for start, word, end_plus_one in string.gmatch("hello world", "()(%w+)()") do
 	print(word, start, end_plus_one - 1)
end

prints hello 1 5 and world 7 11.

5 Likes

Woah! That’s the simplest one I’ve seen! I wish I could mark multiple solutions.

1 Like

Although the solution is correct. I tried to use it on my “HighlightTheSameText” Script and then it almost crashed my game when I highlighted the text that will detect if there is more and then find it’s position. :confused:

At least the script timed out for throwing 50,000 events very fast.


Script.

wait(1)
local textBox = script.Parent.Parent

local function showSelection()
    local Found = 0
    if textBox.CursorPosition == -1 or textBox.SelectionStart == -1 then return end

    local selectedText = string.lower(string.sub(
	    textBox.Text,
	    math.min(textBox.CursorPosition, textBox.SelectionStart),
	    math.max(textBox.CursorPosition, textBox.SelectionStart)
    ))
    local TextboxText = string.lower(textBox.Text)
    if selectedText == "" then return end

    local matches = {}
    local matchesPosition = {}
    for m in string.gmatch(textBox.Text, selectedText) do
	    local str = textBox.Text
	    local len_offset = 0
	    local occurs = {}
	    repeat
		    local s, e = string.find(str, selectedText)
		    if e then
			    table.insert(occurs, #occurs + 1, {s+len_offset, e+len_offset})
			    str = string.sub(str, e+1)
			    len_offset = len_offset + e
		    end
	    until (not s)
	    -- table.insert(matchesPosition, str)
	    table.insert(matches, m)
    end
    for i,v in pairs(matches) do
	    Found = Found + 1
    end

    if Found >= 1 then
	    -- Event will happen here.
   end
end

textBox:GetPropertyChangedSignal("CursorPosition"):Connect(showSelection)
textBox:GetPropertyChangedSignal("SelectionStart"):Connect(showSelection)

Is there any way I can fix this bug so my game does not crash and timeout?