I wanted to make a shortcut character that will make the text inside it italic. But I needed to make a end character. And I don't know if it's possible to have 2 string.gsub()'s in a single local statement.
What I tried so far.
I tried to use or keyword statements to replicate the same thing as another argument.
local RunService = game:GetService("RunService")
RunService.Heartbeat:Connect(function()
local customtext = string.gsub(script.Parent.Parent.Parent.Parent.Core.ScrollingFrame.TextBox.Text, 'italic' or '/italic', '\<i>' or '\</i>') -- That didn't work...
script.Parent.Text = customtext
end)
I also tried to return it as a table and tostring() it but it instead sent a random table function to my text.
Any help is appreciated!
Also just make sure to remind me if I forgot to add more details in.
This uses a capture to reuse the slash if there is one. The question mark makes the slash optional, letting it match either way. (It just won’t include the slash in the replacement if there’s none in the original.)
To answer your question, you can’t put two string.gsub()s. That alone doesn’t make sense. The closest to that would be calling gsub twice. However, that is not the solution. You need to construct a string pattern that matches what is intended and a replacement string that works as intended.
First, you’ll need to capture the characters between the start and end of the italicization. The () symbols can do that for us.
Our pattern so far:
"italic(.*)/italic"
The .* means match 0 or more characters.
Now, we need the replacement string. We can access our captured pattern in the replacement string using %n. N, being a number.
Our replacement:
"<i>%1</i>"
What it looks like in code in the end…
-- ...
local CustomText = string.gsub(script.Parent.Parent.Parent.Parent.Core.ScrollingFrame.TextBox.Text, "italic(.*)/italic", "<i>%1</i>")
-- ...
Read more about string matching here and captures specifically here as well.
Out of scope advice
Heartbeat should be limited to only actions that must be done every frame. Try using the property changed signal instead and listen for whenever the text property changes.
Use consistent variable casings. I recommend PascalCase, I think this is what Roblox uses.
Replace magic constants with variables. It’s cleaner code and gives much better meaning. Example:
local InputBox = script.Parent.Parent.Parent.Parent.Core.ScrollingFrame.TextBox
local MatchingString = "italic(.*)/italic"
local ReplacementString = "<i>%1</i>"
-- ... then ...
local CustomText = string.gsub(InputBox.Text, MatchingString, ReplacementString) -- Much cleaner.
The pattern provided won’t work because you aren’t capturing what needs to be italicized. What’s being captured is an optional forward slash with a requirement of the substring italic in the front. Additionally, the replacement provided doesn’t follow the format for italicizing characters using RichText (even if there was a capture).
Edit: I misread the question and I was thinking the question was different. Your solution works as intended.
If you’re using that approach, it’s worth considering non-greedy matching (“.-”) so that “italic this /italic a lot of stuff italic that /italic” won’t have “a lot of stuff” italicized. Your pattern replaces that with "\<i> *this /italic a lot of stuff italic that* </i>". Even if you use non-greedy though, that brings up the issue of nested tags (“italic a italic b /italic c /italic d” would be "<i> a italic b </i> c /italic d"). Mine avoids both issues by ignoring whether the tags are valid and just replacing as-is.
And in the end, it’s a malformed formatting either case. I’d think that a greedy match would be more “correct” in handling that. But, it’s a moot point since there is a solution now.