ShittyAdvice
ShittyAdvice

Reputation: 265

regex replace : if not followed by letter or number

Okay so I wanted a regex to parse uncontracted(if that's what it is called) ipv6 adresses

Example ipv6 adress: 1050:::600:5:1000::

What I want returned: 1050:0000:0000:600:5:1000:0000:0000

My try at this:

ip:gsub("%:([^0-9a-zA-Z])", ":0000")

The first problem with this: It replaces the first and second :

So :: gets replaced with :0000

Replacing it with :0000: wouldn't work because then it will end with a :. Also this would note parse the newly added : resulting in: 1050:0000::600:5:1000:0000:

So what would I need this regex to do?

Replace every : by :0000 if it isn't followed by a number or letter

Main problem: :: gets replaced instead of 1 :

Upvotes: 3

Views: 303

Answers (2)

tonypdmtr
tonypdmtr

Reputation: 3225

There is no single statement pattern to do this but you can use a function to do this for any possible input:

function fill_ip(s)
  local ans = {}
  for s in (s..':'):gmatch('(%x*):') do
    if s == '' then s = '0000' end
    ans[ #ans+1 ] = s
  end
  return table.concat(ans,':')
end

--examples:
print(fill_ip('1050:::600:5:1000::'))
print(fill_ip(':1050:::600:5:1000:'))
print(fill_ip('1050::::600:5:1000:1'))
print(fill_ip(':::::::'))

Upvotes: 1

ryanpattison
ryanpattison

Reputation: 6251

gsub and other functions from Lua's string library use Lua Patterns which are much simpler than regex. Using the pattern more than once will handle the cases where the pattern overlaps the replacement text. The pattern only needs to be applied twice since the first time will catch even pairings and the second will catch the odd/new pairings of colons. The trailing and leading colons can be handled separately with their own patterns.

ip = "1050:::600:5:1000::"
ip = ip:gsub("^:", "0000:"):gsub(":$", ":0000")
ip = ip:gsub("::", ":0000:"):gsub("::", ":0000:")
print(ip) -- 1050:0000:0000:600:5:1000:0000:0000

Upvotes: 1

Related Questions