Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

How do I index an abbreviated name?

I'm creating a custom admin script and I'm at lost with finding abbreviated names.

This is what I currently have where you have to type the full username.

function findPlayer(name)
	local players = {}
	
	for _, player in ipairs(game.Players:GetPlayers()) do
		 -- if Data[player.Name .. "'s Data"].FakeName.Value:lower() == name:lower() then --
		if player.Name:lower() == name:lower() then
			table.insert(players, player)
		end
	end
	
	if "all" == name:lower() then 
		for i,v in pairs(game.Players:GetPlayers()) do
			table.insert(players, v)
		end
	end
	
	return players
end

In addition I want to also index fake usernames that will often times have spaces in them or maybe even be similar.

Ex: We have three fake names in game: Sarah Law, Sarah Lau, and Jimmy Neutron

:Kill Jimmy - kills Jimmy Neutron

:Kill Sarah - returns invalid because there are two names starting with sarah

:Kill Sarah Law - kills stated name

3 comments

0

Don't use names for admin commands, use UserId

0

I have, this is for finding in-game players. ":Kill Sarah L" I want this to be able to find Sarah Law.

0

oh. for that you'll need string.sub

1 answer

✓ Accepted answer

You can take a substring of a string with the string.sub function. If you have string A equal to "Player1" and string B equal to "pla", you can take a substring of string A with the length of string B. These two strings can then be lowered with the string.lower function and compared.

local stringA = "Player1"
local stringB = "pla"
local abbreviatedA = stringA:sub(1, #stringB)
print(abbreviatedA:lower() == stringB:lower())

This functionality is quite simple to implement into your program:

local Players = game:GetService("Players")

local findPlayerKeywords = {
	all = function()
		local players = {}
		for _, player in next, Players:GetPlayers() do
			table.insert(players, player)
		end
		return players
	end,
}

local function getPlayersWithMatchingName(str)
	str = str:lower()	--	the findPlayer function has already lowered the passed string but not doing so here is considered a bad practice as we cannot assume all other functions to do it for us
	local matches = {}
	for _, player in next, Players:GetPlayers() do
		local abbreviatedName = player.Name:sub(1, #str)
		if abbreviatedName:lower() == str then
			table.insert(matches, player)
		end
	end
	return matches
end

local function findPlayer(str, allowMultipleMatches)
	str = str:lower()
	if findPlayerKeywords[str] then
		return findPlayerKeywords[str]()
	else
		local players = getPlayersWithMatchingName(str)
		if allowMultipleMatches or #players <= 1 then
			return players
		else
			return {}	--	alternatively nil can be returned, just keep in mind all the functions calling "findPlayer" have to take that possible outcome into account
		end
	end
end

Your code and actual question did have two contradicting statements. Your code hints that you do want to get a table of players as the output, yet your text states you either want nothing or possibly a player object. Thus I added the allowMultipleMatches option.

2 comments

0

Would there be anyway to not cache the stuff after the name. So :place Jimmy Neutron 454364634. Without the str being the whole lines after the name?

0

You'd need to split the string into multiple substrings (the command, the target(s), the parameters). It is up to you to decide the rules on how the string is split. You can use the string.gmatch iterator and string patterns to grab all the parts you want. You'd then call "findPlayer" with the "target" substring.

This discussion is preserved as it was. New answers, comments, and votes are closed.