Split a string but ignore when within quotes

Hello.

I’ve been stuck on this problem for a couple hours.

How would I split a string by spaces but ignore spaces within quotes?

For example:

Hello1 “Hello2 Hello3” Hello4 "Hello 5 "

>>>

{
“Hello1”,
“Hello2 Hello3”,
“Hello4”,
"Hello 5 "
}

I’ve tried using for loops and bools to keep track of when inside quotes but I just can’t get it working nicely.

Any suggestions or examples would be appreciated.

Thanks.

Instead of using string.split, write your own algorithm to process chars 1 by 1

Include a boolean called inside_quote that is flipped when the presence of a quote is found

Split words by space, unless inside_quote is true, make sure to also error if a string never gets closed (since otherwise the word is never written)

You can also detect for \ chars if you want to implement escapes for the quote mark

You could try some algorithm with string.find() and string.sub().

You can also check the documentation here string documentation

You want to ignore spaces between “Hello” and “n” (n for number) ?

If so then there’s a few ways but nothing that’s super simple

Otherwise you can just remove all spaces entirely.

string.gsub(yourstring, "%s", "") -- gsub is a find/replace function for strings.

That’s pretty much what I tried initially but I have no clue what I’m doing wrong

local function GetParameters(Text)
	local Parameters = {}
	
	local WithinQuote = false
	local CurrentParameter = ""
	
	for Index,Character in pairs(string.split(Text, "")) do
		if Character == "\"" then
			WithinQuote = not WithinQuote
		end
		
		if WithinQuote then
			CurrentParameter = CurrentParameter .. Character
		else
			if Character == " " then
				table.insert(Parameters, CurrentParameter)
				CurrentParameter = ""
			end
		end
	end
	
	if CurrentParameter ~= "" then
		table.insert(Parameters, CurrentParameter)
	end
	
	print(Parameters)
end

Try this

local InQuotes = false
local str = 'Your String 1' -- will split
-- local str = '"Your String 1"' wont split
-- local str = "YourString1" wont split

if str:sub(1, 1) == '"' and str:sub(-1,-1) == '"' then
	print("String is in quotes")
	InQuotes = true
end

if InQuotes == false and string.find(str," ") then
	
	print("String contains space, no quotes")
	str = str:split(" ")
	
else
	
	--
	
end

print(str)

Sorry. Does not help my problem.

local String = '"Hello1" "Hello2 Hello3" "Hello4" "Hello 5 "'
String = string.gsub(String, '^"', "")
String = string.gsub(String, '"$', "")
local Substrings = string.split(String, '" "')
for _, Substring in ipairs(Substrings) do
	print('"'..Substring..'"')
end

image

I appreciate the help but in my string not all of the ‘phrases’ are surrounded by quotes.

With this code inputting:

“hello” hello

returns

{
“hello” hello"
}

I was using the string you provided, use backticks to correctly format your code not a quoteblock.

You used

“Hello1” “Hello2 Hello3” “Hello4” "Hello 5 "

I’m using

Hello1 “Hello2 Hello3” Hello4 "Hello 5 "

I don’t know if you were looking for something like this?

local something = {
"Hello";
"Hello";
"Hello";
"Hello";
"Hello"
}

print(table.concat(something, ", "))

Output: Hello, Hello, Hello, Hello, Hello

I managed to get it working using this extremely hard to read code which makes no sense:

local function GetParameters(Text)
	local Parameters = {}
	local WithinQuotes = false
	
	local CurrentParameter = ""
	
	for Index, Character in pairs(string.split(Text, "")) do
		if Character == "\"" then
			if WithinQuotes == false then
				WithinQuotes = true
			else -- quote ending
				WithinQuotes = false
				if CurrentParameter ~= "" then
					table.insert(Parameters, CurrentParameter)
					CurrentParameter = ""
				end
			end
		else -- character not quote
			if WithinQuotes then
				CurrentParameter = CurrentParameter .. Character
			else -- not within quote
				if Character == " " then
					if CurrentParameter ~= "" then
						table.insert(Parameters, CurrentParameter)
						CurrentParameter = ""
					end
				else -- not space
					CurrentParameter = CurrentParameter .. Character
				end
			end
		end
	end
	
	if CurrentParameter ~= "" then
		table.insert(Parameters, CurrentParameter)
	end
	
	if WithinQuotes == true then
		print("ERROR: Quote left open")
		return nil
	end
	
	return Parameters
end
GetParameters('Hello1 "Hello2 Hello3" Hello4 "Hello 5 "')

>>>

{
   [1] = "Hello1",
   [2] = "Hello2 Hello3",
   [3] = "Hello4",
   [4] = "Hello 5 "
}
{
“Hello1”,
“Hello2 Hello3”,
“Hello4”,
"Hello 5 "
}

Was the example you provided (each have quotation marks), use backticks to correctly format code otherwise you end up with these quotation characters that are not recognised by Roblox’s IDE.

That’s the example output array. Doesn’t matter whether or not the ide can recognize it.

All of the text in the original post contains those illegal quotation characters, it does matter since that’s what we’re expected to use.

Hey there! I have a much more readable function I just made!
This should be of use to you!

local function GetParameters(String)
	local Substrings = string.split(String, ' "')
	local End_Table = {}
	for i, Substring in ipairs(Substrings) do
		if string.find(Substring, '" ') then
			local ExtraSubstrings = string.split(Substring, '" ')
			for _, ExtraSubstring in ipairs(ExtraSubstrings) do
				table.insert(End_Table, ExtraSubstring)
			end
		else
			if i == #Substrings then
				table.insert(End_Table, string.sub(Substring, 0, -2))
			else
				table.insert(End_Table, Substring)
			end
		end
	end
	
	return End_Table
end

local String = 'Hello1 "Hello2 Hello3" Hello4 "Hello 5"'
local Result = GetParameters(String)
print(Result)

Output:

{
    [1] = "Hello1",
    [2] = "Hello2 Hello3",
    [3] = "Hello4",
    [4] = "Hello 5"
} 

Let me know if you need something explained @dv3v!

That’s because it was designed for strings of a particular format.

local String = 'Hello1 "Hello2 Hello3" Hello4 "Hello 5 "'
local Substrings = {}

for Substring in string.gmatch(String, '%b""') do
	table.insert(Substrings, Substring)
	String = string.gsub(String, Substring, "")
end

for Substring in string.gmatch(String, "%w+") do
	table.insert(Substrings, Substring)
end

for _, Substring in ipairs(Substrings) do
	print(Substring)
end

image

and here’s a benchmark comparison.

local function GetParameters(Text)
	local Parameters = {}
	local WithinQuotes = false

	local CurrentParameter = ""

	for Index, Character in pairs(string.split(Text, "")) do
		if Character == "\"" then
			if WithinQuotes == false then
				WithinQuotes = true
			else -- quote ending
				WithinQuotes = false
				if CurrentParameter ~= "" then
					table.insert(Parameters, CurrentParameter)
					CurrentParameter = ""
				end
			end
		else -- character not quote
			if WithinQuotes then
				CurrentParameter = CurrentParameter .. Character
			else -- not within quote
				if Character == " " then
					if CurrentParameter ~= "" then
						table.insert(Parameters, CurrentParameter)
						CurrentParameter = ""
					end
				else -- not space
					CurrentParameter = CurrentParameter .. Character
				end
			end
		end
	end

	if CurrentParameter ~= "" then
		table.insert(Parameters, CurrentParameter)
	end

	if WithinQuotes == true then
		print("ERROR: Quote left open")
		return nil
	end

	return Parameters
end

local Time = os.clock()

for _ = 1, 1000 do
	GetParameters('Hello1 "Hello2 Hello3" Hello4 "Hello 5 "')
end

print(os.clock() - Time) --0.0034617000201251358
local function GetParameters(String)
	local Substrings = {}
	
	for Substring in string.gmatch(String, '%b""') do
		table.insert(Substrings, Substring)
		String = string.gsub(String, Substring, "")
	end

	for Substring in string.gmatch(String, "%w+") do
		table.insert(Substrings, Substring)
	end

	return Substrings
end

local Time = os.clock()

for _ = 1, 1000 do
	GetParameters('Hello1 "Hello2 Hello3" Hello4 "Hello 5 "')
end

print(os.clock() - Time) --0.001576000009663403

Oooh, you even were able to make a even better solution then mine, nice! I’m not the best when it comes to fancy string manipulation.

Benchmarks:
Yours:

local function GetParameters(String)
	local Substrings = {}

	for Substring in string.gmatch(String, '%b""') do
		table.insert(Substrings, Substring)
		String = string.gsub(String, Substring, "")
	end

	for Substring in string.gmatch(String, "%w+") do
		table.insert(Substrings, Substring)
	end

	return Substrings
end

local Time = os.clock()

for _ = 1, 1000 do
	GetParameters('Hello1 "Hello2 Hello3" Hello4 "Hello 5 "')
end

print(os.clock() - Time) --0.0019285419984953478

Mine:

local function GetParameters(String)
	local Substrings = string.split(String, ' "')
	local End_Table = {}
	for i, Substring in ipairs(Substrings) do
		if string.find(Substring, '" ') then
			local ExtraSubstrings = string.split(Substring, '" ')
			for _, ExtraSubstring in ipairs(ExtraSubstrings) do
				table.insert(End_Table, ExtraSubstring)
			end
		else
			if i == #Substrings then
				table.insert(End_Table, string.sub(Substring, 0, -2))
			else
				table.insert(End_Table, Substring)
			end
		end
	end

	return End_Table
end

local Time = os.clock()

for _ = 1, 1000 do
	GetParameters('Hello1 "Hello2 Hello3" Hello4 "Hello 5"')
end

print(os.clock() - Time) --0.001910208011395298