Reputation: 1053
I have a URL string and need to get certain word from a match.
Example:
/school/student/studentname1/detail/55/address/address1
I am able to pass to fetch detail of the needed one like,
local s1,s2,s3 =myString:match("/school/student/(.-)/detail/(.-)/address/(.-)")
Now the problem is that my string can be
myString = /school/student/studentname1
or
myString = /school/student/studentname1/detail/55
In that case my regex is failing, any help ?
Upvotes: 3
Views: 350
Reputation: 18950
This is the best one-liner I could come up with:
local s1,s2,s3 =myString:match("/[^/]+/[^/]+/([^/]+)/?[^/]*/?([^/]*)/?[^/]*/?([^/]*)")
Explanation:
I use negated character classes to get the text between slashes in a generic way. This makes it easier to flag the later parts as optional using *
for classes and ?
for slashes (you can make the initial part less generic and just use /school/student/
).
This would be easy using (PC)RE, however, Lua Patterns do not support optional capture groups as well as alternations. Instead, you can use PCRE patterns in Lua with the rex_pcre library or use the pattern-matching library Lpeg.
Upvotes: 2
Reputation: 5308
To begin with, your original patter was not working as expected since it did not capture the address (because you used .-
which is not greedy)
So one way to fix the original patter could be using /school/student/([^/]+)/detail/([^/]+)/address/([^/]+)
where [^/]
means any character except /
Then, in order to optionally match some options and since lua patterns does not allow optional groups, you may need to use several steps like this:
myString = "/school/student/studentname1/detail/55"
local s1,s2,s3
s1 =myString:match("/school/student/([^/]+)")
if (s1 ~= nil) then
print(s1)
s2 =myString:match("/detail/([^/]+)")
if (s2 ~= nil) then
print(s2)
s3 =myString:match("/address/([^/]+)")
if (s3 ~= nil) then
print(s3)
end
end
end
Finally, if you want to make sure that detail and address appear exactly on that order, you may use this:
myString = "/school/student/studentname1/address/myaddress"
local s1,s2,s3
s1 =myString:match("/school/student/([^/]+)")
if (s1 ~= nil) then
print(s1)
s1,s2 =myString:match("/school/student/([^/]+)/detail/([^/]+)")
if (s2 ~= nil) then
print(s2)
s1,s2,s3 =myString:match("/school/student/([^/]+)/detail/([^/]+)/address/([^/]+)")
if (s3 ~= nil) then
print(s3)
end
end
end
That way it will find /school/student/studentname1/detail/55
but it will not find /school/student/studentname1/address/myaddress
. If you don't need it like this, just use the first version.
Upvotes: 2
Reputation: 974
local all_fields = { student = 1, detail = 2, address = 3 }
local function parse(str)
local info = {}
local index
for w in str:gmatch"/([^/]+)" do
if index then
info[index] = w
index = nil
else
index = all_fields[w]
end
end
return (table.unpack or unpack)(info, 1, 3)
end
local myString = '/school/student/studentname1/detail/55/address/address1'
local s1, s2, s3 = parse(myString)
print(s1, s2, s3)
myString = '/school/student/studentname1/address/address1'
s1, s2, s3 = parse(myString)
print(s1, s2, s3)
myString = '/school/student/studentname1/detail/55'
s1, s2, s3 = parse(myString)
print(s1, s2, s3)
Upvotes: 3