Question

I got this string in a Lua script:

one;two;;three;four;;five;;six;seven;

The first char will never be a semicolon. The middle separators can be a single or double semicolon, and the last char can be or not a single semicolon.

Using the Lua patterns (and string.gsub()): How can I match the double semicolons in the middle to replace those with a single one AND delete the last optional semicolon?

The output must be like this:

one;two;three;four;five;six;seven

Is this possible using a single pattern?

Was it helpful?

Solution

Using one pattern to replace multiple ; to single ;, and another to remove the last ; is like this

local str = "one;two;;three;four;;five;;six;seven;"
local result = str:gsub(';+', ';'):gsub(';*$', '')

One possible way to use a single pattern is like this:

local result = (str .. ";;;"):gsub(";+", function(s) 
                                             if s == ";" or s == ";;" then 
                                                 return ";" 
                                             else 
                                                 return "" 
                                             end 
                                         end)

What I'm trying to do is to append three ; to the end of the string, so any one or two ; should be replaced with one ;. And more ;(could be three or four and it must be at the end) is replaced to empty string.

I would prefer the solution with two patterns as it's more clear.

OTHER TIPS

How about something like this:

function remove_extra_delim(s, delim)
    local t = {}
    for each in s:gmatch("[^"..delim.."]+") do
        table.insert(t, each)
    end
    return table.concat(t, delim)
end

teststr = "one;two;;three;four;;five;;six;seven;"
print(remove_extra_delim(teststr, ";"))

Outputs:

one;two;three;four;five;six;seven

If the amount of semicolons is either 1 or 2, you can simply do

string:gsub(";;", ";")

Otherwise, the other answers will do.

Its a little hacky, but it does the trick:

x = test:gsub(";+(.?)",
  function(a)
    if a == "" then
      return ""
    else
      return ";" .. a
    end
  end)

(Note: I'm following your description exactly, so these will match one or two ; but not more than two, and final zero or one ; but not more than one)

-- Method one uses two patterns but it's simpler and my preferred one
s = 'one;two;;three;four;;five;;six;seven;'
s = s:gsub(';;',';'):gsub(';?$','')
print(s)

-- Method two uses one pattern (if you really MUST use only one pattern)
s = 'one;two;;three;four;;five;;six;seven;'
s = (s..';'):gsub(';;',';')
s = s:sub(1,#s-1)
print(s)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top