Can someone look over "my" regex and maybe probably simplify it?

Hello everyone! I’m making a textbox where you enter a color. I need to restrict the text the user enters so that it doesn’t break anything down the line. It turned out harder than I expected, but I got it to work in the end.

Barebones file: ColorTextBox.rbxl (62.1 KB)

The behavior is exactly as I want. Now it just needs to be shortened and simplified, if possible of course. Half of this was written by myself, a quarter with ChatGPT, and a quarter with Gemini. I’m just glad it works :sweat_smile:

Thank you all in advance!

2 Likes
local ColorTextBox = script.Parent
local previous = ""
local textChangedConnection = nil

-- -- -- -- --

local function clamp(n)
	n = tonumber(n)
	if not n then return 0 end
	return math.clamp(n, 0, 255)
end

local function matchRGBformat(str)
	-- Single consolidated pattern: matches 1-3 groups of 1-3 digits separated by comma+optional space
	-- Allows partial entry: "255" or "255," or "255, 128" or "255, 128," or "255, 128, 64"
	return str:match("^%d%d?%d?$")                              -- Just first number
		or str:match("^%d%d?%d?,%s?$")                          -- First number + comma
		or str:match("^%d%d?%d?,%s?%d%d?%d?$")                  -- Two numbers
		or str:match("^%d%d?%d?,%s?%d%d?%d?,%s?$")              -- Two numbers + comma
		or str:match("^%d%d?%d?,%s?%d%d?%d?,%s?%d%d?%d?$")      -- Complete RGB
end

local function isPartialHex(text)
	if text:sub(1,1) ~= "#" then return false end
	local hex = text:sub(2)
	-- More specific: hex must be only valid hex chars and 1-6 characters long
	return hex:match("^[A-Fa-f0-9]+$") and #hex >= 1 and #hex <= 6
end

-- -- -- -- --

ColorTextBox.Focused:Connect(function()
	ColorTextBox.Name = ColorTextBox.Text
	previous = ColorTextBox.Text

	if textChangedConnection then
		textChangedConnection:Disconnect()
	end

	textChangedConnection = ColorTextBox:GetPropertyChangedSignal("Text"):Connect(function()
		local text = ColorTextBox.Text

		if text == "" then
			previous = ""
			return
		end

		local first = text:sub(1,1)

		if first:match("%d") then
			-- More efficient: only remove invalid characters once
			text = text:gsub("[^%d,%s]", "")

			if matchRGBformat(text) then
				previous = text
			end

		elseif first == "#" then
			-- Keep only one # at the start, remove everything else invalid
			local hex = text:sub(2):gsub("[^A-Fa-f0-9]", "")
			text = "#" .. hex

			if isPartialHex(text) then
				previous = text
			end
		end

		ColorTextBox.Text = previous
	end)
end)

ColorTextBox.FocusLost:Connect(function(EnterPressed)
	if textChangedConnection then
		textChangedConnection:Disconnect()
		textChangedConnection = nil
	end

	if EnterPressed then
		local text = ColorTextBox.Text
		local first = text:sub(1,1)

		if first == "#" then
			repeat
				text = text .. "0"
			until #text == 7

			ColorTextBox.Text = text
		else
			local components = {}

			for match in string.gmatch(text, "%d+") do -- Simpler pattern	
				table.insert(components, clamp(tonumber(match)))
			end

			-- Ensure we have exactly 3 components, pad with 0 if needed
			while #components < 3 do
				table.insert(components, 0)
			end

			ColorTextBox.Text = table.concat(components, ", ")
		end
	else
		ColorTextBox.Text = ColorTextBox.Name
	end

	ColorTextBox.Name = "TextBox"
end)

4 Likes

I apologize if I insult you, but I can tell this was done with an AI chatbot because the comments are way too detailed in their punctuation and capitalization, and it replaced all my (spaces) with %s (whitespaces)
I had to manually keep changing them every time back to spaces.
Also the line breaks (if that’s what they’re called) they’re in the same style, no line breaks after if’s or else’s.

I will however look into the changes and see if I agree with them, and add them accordingly. Thank you, but I’ll wait for an actual experienced human to review my code before I move on, sorry…

1 Like

if you need string.match(pattern), then:

  1. Regular color values (like 0, 82, 255):
    (%d+), *(%d+), *(%d+)
  2. HEX values (#FF00b5):
    %x%x%x%x%x%x (cuz 6 is max used)
2 Likes

That’s not how you can tell. I comment my code similarly to that. The actual way you can tell based on comments is things like this:

Of course, that’s not perfect but AI does that all the time—just like I use em dashes, I’m sure there are people that prefix comments like that.

1 Like

When you write code I would use OPUS 4.5 thinking if you’re going to vibe code.

Also, the AI didn’t make all of those changes, I put the code I wrote into the model to add comments. You wanted an experienced developer to review your code, I did that. I just simply don’t have time to comment my code after I write it. There are tools that speed the process up.

As for your regex, decimal regex is messy by nature, I’m not sure if you can clean it up. You may be able to write a regex combining your or logic, but at what point is that over complicated the implementation. I think the code you had was fine and isn’t worth modifying in accordance to your original question.

Now, there were tons of memory leak and objects not being cleaned up. I fixed those issues.

1 Like

Good to know :D
Are you sure the AI didn’t mess anything up when it added those comments?
Also, what were the memory leaks? I’d love to know about them, to look out for the in the future.
Thanks!

Edit: it appears to be a textChangedConnection. I think I agree with your change there, you’re disconnecting the function if the focus gets lost. good change :grin:

1 Like

Question:

It doesn’t say textChangedConnection = nil here. Is that intentional?

Edit: I looked over everything else, and it’s exactly what I was hoping for, simplification. Thank you!
I initially dismissed your message because I thought it was made by AI, and I’ve already ran it by an AI and it’s given me the final result seen in my initial post.

1 Like

There could be an edge case where it nul, if there is, it would crash the event.

We want to disconnect that if it exists and that by nature converts it to nul.

1 Like

I test it again after AI does anything, always, always, test!

Here is a wiki link about memory leaks, it directly applies here,

1 Like

Could you test out trying to enter a hex value? It doesn’t work for me.
I think the issue is the match, since after inputting the #, it matches "", which returns nil. :thinking:

1 Like

for hex codes, you can use %x. And if you need #, then use #?

1 Like

Woah, I didn’t know this even existed. Let me see what I can figure out.

Does that mean I can do this:
image
top two lines are before, bottom two lines are after

3 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.