Lua supports limited Expressions and Patterns
The time stamp is variable in the format DD:HH:MM:SS,FF (Days:Hours:Minutes:Seconds,Miliseconds)
The objective is to trim/truncate the timestamp by removing any leading zeros to represent as follow:
Example timestamps includes:
timestamp = 00:00:00:00,00 => 0
timestamp = 00:01:00:00,00 => 1:00:00,00
timestamp = 00:00:01:00,00 => 1:00,00
timestamp = 00:00:00:01,00 => 1,00
timestamp = 99:23:59:59,99 => 99:23:59:59,99
I am looking for a simple solution such as using gsub, TA
This regexp gets 5/5 but it is soo long
local reg = '^[0]+[:]?[0]+[:]?[0]+[:]?[0]?'
print('1 > ' .. '00:00:00:00,00 = ' .. ('00:00:00:00,00'):gsub(reg,''))
print('2 > ' .. '00:01:00:00,00 = ' .. ('00:01:00:00,00'):gsub(reg,''))
print('3 > ' .. '00:00:01:00,00 = ' .. ('00:00:01:00,00'):gsub(reg,''))
print('4 > ' .. '00:00:00:01,00 = ' .. ('00:00:00:01,00'):gsub(reg,''))
print('5 > ' .. '99:23:59:59,99 = ' .. ('99:23:59:59,99'):gsub(reg,''))
Why not use string.match? The below code is based on the assumption that the input will be a valid timestamp. It handles all five cases correctly, but I'm not sure whether trimming something like 00:00:00:00,42 to 42 - which this does - is desired.
local function trim_timestamp(timestamp)
return timestamp:match"^[0:,]*(.+)$"
end
Otherwise, move the comma and the first digit of the seconds to the captured part:
local function trim_timestamp(timestamp)
return timestamp:match"^[0:]*(%d,.+)$"
end
Note that this will then turn the first example into 0,00; you'd have to explicitly handle the case of all zeroes:
local function trim_timestamp(timestamp)
local trimmed = timestamp:match"^[0:]*(%d,.+)$"
if trimmed == "0,00" then return "0" end -- shorten all zeroes
return trimmed
end
Related
**It takes Input as a string such as this - 'Nice one'
And Output gives - 4,3 (which is no. Of words in sentence or string)
**
function countx(str)
local count = {}
for i = 1, string.len(str) do
s = ''
while (i<=string.len(str) and string.sub(str, i, i) ~= ' ' ) do
s = s .. string.sub(str, i, i)
i = i+1
end
if (string.len(s)>0) then
table.insert(count,string.len(s))
end
end
return table.concat(count, ',')
end
You can find a simple alternative with your new requirements:
function CountWordLength (String)
local Results = { }
local Continue = true
local Position = 1
local SpacePosition
while Continue do
SpacePosition = string.find(String, " ", Position)
if SpacePosition then
Results[#Results + 1] = SpacePosition - Position
Position = SpacePosition + 1
-- if needed to print the string
-- local SubString = String:sub(Position, SpacePosition)
-- print(SubString)
else
Continue = false
end
end
Results[#Results + 1] = #String - Position + 1
return Results
end
Results = CountWordLength('I am a boy')
for Index, Value in ipairs(Results) do
print(Value)
end
Which gives the following results:
1
2
1
3
def countLenWords(s):
s=s.split(" ")
s=map(len,s)
s=map(str,s)
s=list(s)
return s
The above functions returns a list containing number of characters in each word
s=s.split(" ") splits string with delimiter " " (space)
s=map(len,s) maps the words into length of the words in int
s=map(str,s) maps the values into string
s=list(s) converts map object to list
Short version of above function (all in one line)
def countLenWords(s):
return list(map(str,map(len,s.split(" "))))
-- Localise for performance.
local insert = table.insert
local text = 'I am a poor boy straight. I do not need sympathy'
local function word_lengths (text)
local lengths = {}
for word in text:gmatch '[%l%u]+' do
insert (lengths, word:len())
end
return lengths
end
print ('{' .. table.concat (word_lengths (text), ', ') .. '}')
gmatch returns an iterator over matches of a pattern in a string.
[%l%u]+ is a Lua regular expression (see http://lua-users.org/wiki/PatternsTutorial) matching at least one lowercase or uppercase letter:
[] is a character class: a set of characters. It matches anything inside brackets, e.g. [ab] will match both a and b,
%l is any lowercase Latin letter,
%u is any uppercase Latin letter,
+ means one or more repeats.
Therefore, text:gmatch '[%l%u]+' will return an iterator that will produce words, consisting of Latin letters, one by one, until text is over. This iterator is used in generic for (see https://www.lua.org/pil/4.3.5.html); and on any iteration word will contain a full match of the regular expression.
I am writing a generic Log() function in lua which utilizes lua print function:
Log (variable, 'String: %s ', str, 'Word: %d', w)
Currently I'm using below approach:
print(string.format (variable, 'String: %s ', str, 'Word: %d', w))
I tried something like:
Log = function(...) begin
return print(string.format(...))
end
But it doesn't work, Is this correct approach? Or Is there any better more generic way to get this done?
If you just want to print a sequence of values, you can do that with print:
print(variable, 'String: %s ', str, 'Word: %d', w)
What you seem to want is something more complicated. Your algorithm seems to be:
For each argument:
If the argument is not a string, then convert it to a string and print it.
If the argument is a string, figure out how many % patterns it has (let us call this number k). Pass string.format the current argument string and the following k parameters, printing the resulting string. Advance k parameters.
That's a much more complicated algorithm than can be done in a one-line system.
Using Lua 5.3, here's what such a function would look like (note: barely tested code):
function Log(...)
local values = {}
local params = table.pack(...)
local curr_ix = 1
while (curr_ix <= params.n) do
local value = params[curr_ix]
if(type(value) == "string") then
--Count the number of `%` characters, *except* for
--sequential `%%`.
local num_formats = 0
for _ in value:gmatch("%%[^%%]") do
num_formats = num_formats + 1
end
value = string.format(table.unpack(params, curr_ix, num_formats + curr_ix))
curr_ix = curr_ix + num_formats
end
values[#values + 1] = value
curr_ix = curr_ix + 1
end
print(table.unpack(values))
end
I don't think your current approach works, because the first argument of string.format expects the format specifier, not the rest of the arguments.
Anyway, this is the way to combine formatting and printing together:
Log = function(...)
return print(string.format(...))
end
And call it like this:
Log("String: %s Number: %d", 'hello' , 42)
Also, it might be better to make the format specifier argument more explicit, and use io.write instead of print to get more control over printing:
function Log(fmt, ...)
return io.write(string.format(fmt, ...))
end
Good evening
Will you help me solve this problem?
ERROR: race/util_server.lua:440: attempt to index local 'self' (a nil value)
function string:split(separator)
if separator == '.' then
separator = '%.'
end
local result = {}
for part in self:gmatch('(.-)' .. separator) do
result[#result+1] = part
end
result[#result+1] = self:match('.*' .. separator .. '(.*)$') or self
return result
end
You're probably calling it wrong.
function string:split(separator)
Is short hand for:
function string.split(self, separator)
Given a string and separator:
s = 'This is a test'
separator = ' '
You need to call it like this:
string.split(s, separator)
Or:
s:split(separator)
If you call it like this:
s.split(separator)
You're failing to provide a value for the self argument.
Side note, you can write split more simply like this:
function string:split(separators)
local result = {}
for part in self:gmatch('[^'..separators..']+') do
result[#result + 1] = part
end
return result
end
This has the disadvantage that you can't used multi-character strings as delimiters, but the advantage that you can specify more than one delimiter. For instance, you could strip all the punctuation from a sentence and grab just the words:
s = 'This is an example: homemade, freshly-baked pies are delicious!'
for _,word in pairs(s:split(' :.,!-')) do
print(word)
end
Output:
This
is
an
example
homemade
freshly
baked
pies
are
delicious
I'm making a serialization library for Lua, and I'm using LPeg to parse the string. I've got K/V pairs working (with the key explicitly named), but now I'm going to add auto-indexing.
It'll work like so:
#"value"
#"value2"
Will evaluate to
{
[1] = "value"
[2] = "value2"
}
I've already got the value matching working (strings, tables, numbers, and Booleans all work perfectly), so I don't need help with that; what I'm looking for is the indexing. For each match of #[value pattern], it should capture the number of #[value pattern]'s found - in other words, I can match a sequence of values ("#"value1" #"value2") but I don't know how to assign them indexes according to the number of matches. If that's not clear enough, just comment and I'll attempt to explain it better.
Here's something of what my current pattern looks like (using compressed notation):
local process = {} -- Process a captured value
process.number = tonumber
process.string = function(s) return s:sub(2, -2) end -- Strip of opening and closing tags
process.boolean = function(s) if s == "true" then return true else return false end
number = [decimal number, scientific notation] / process.number
string = [double or single quoted string, supports escaped quotation characters] / process.string
boolean = P("true") + "false" / process.boolean
table = [balanced brackets] / [parse the table]
type = number + string + boolean + table
at_notation = (P("#") * whitespace * type) / [creates a table that includes the key and value]
As you can see in the last line of code, I've got a function that does this:
k,v matched in the pattern
-- turns into --
{k, v}
-- which is then added into an "entry table" (I loop through it and add it into the return table)
Based on what you've described so far, you should be able to accomplish this using a simple capture and table capture.
Here's a simplified example I knocked up to illustrate:
lpeg = require 'lpeg'
l = lpeg.locale(lpeg)
whitesp = l.space ^ 0
bool_val = (l.P "true" + "false") / function (s) return s == "true" end
num_val = l.digit ^ 1 / tonumber
string_val = '"' * l.C(l.alnum ^ 1) * '"'
val = bool_val + num_val + string_val
at_notation = l.Ct( (l.P "#" * whitesp * val * whitesp) ^ 0 )
local testdata = [[
#"value1"
#42
# "value2"
#true
]]
local res = l.match(at_notation, testdata)
The match returns a table containing the contents:
{
[1] = "value1",
[2] = 42,
[3] = "value2",
[4] = true
}
I have a program which checks for conditions some variable field, like
if(tostring(field) == '0') then {do something}
if(tostring(field) == '1') then {do something}
if(tostring(field) == '2') then {do something}
But, i think lua is interpreting '0' and '1' as TRUE/FALSE values and not checking the corresponding if conditions properly. The condition executes properly for field == '2' condition.
How can i overcome this case? How can i make it work for check conditions '0' and '1'?
Thank You in advance!
In case you are wondering why i tagged wireshark, the if check condition is checking for a field in pcap file.
My lua code for reference is as follows:
#!/usr/bin/lua
do
local pkts = 0
local stat = {}
local file = io.open("luawrite","w")
local function init_listener()
local tap = Listener.new("wlan")
local src_addr = Field.new("wlan.sa")
local type = Field.new("wlan.fc.type")
local sub_type = Field.new("wlan.fc.subtype")
local frame_length = Field.new("frame.len")
local data_rate = Field.new("wlan.data_rate")
function tap.reset()
pkts = 0;
end
function tap.packet(pinfo, tvb)
local client = src_addr()
local stype = sub_type()
local ty = type()
local ts = tostring(pinfo.rel_ts)
local fl = frame_length()
rate = data_rate()
if(tostring(ty) == '0') then
file:write(tostring(ts), "\t", tostring(fl), "\t", tostring(rate), "\n")
end
end
end
init_listener()
end
The condition i am referring to 7th line from last line. If i give the condition tostring(ty) == '2', it works properly.
From the manual:
The condition expression of a control structure can return any value.
Both false and nil are considered false. All values different from nil
and false are considered true (in particular, the number 0 and the
empty string are also true).
Both the number 0 and the empty string evaluate to true, so it's definitely not mistaking the string "0" for false. I might avoid redefining type. Also, I think frame_type returns a number so you can get rid of the tostring() in the condition.
do
local pkts = 0
local stat = {}
local file = io.open("luawrite","w")
local function init_listener()
local tap = Listener.new("wlan")
local src_addr = Field.new("wlan.sa")
-- Changed function from type to frame_type
local frame_type = Field.new("wlan.fc.type")
local sub_type = Field.new("wlan.fc.subtype")
local frame_length = Field.new("frame.len")
local data_rate = Field.new("wlan.data_rate")
function tap.reset()
pkts = 0;
end
function tap.packet(pinfo, tvb)
local client = src_addr()
local stype = sub_type()
local ty = frame_type()
local ts = tostring(pinfo.rel_ts)
local fl = frame_length()
rate = data_rate()
-- skip the tostring
if ty == 0 then
file:write(tostring(ts), "\t", tostring(fl), "\t", tostring(rate), "\n")
end
end
end
init_listener()
end
If all else fails, try writing a line regardless of the frame type and write the frame type with it:
function tap.packet(pinfo, tvb)
local client = src_addr()
local stype = sub_type()
local ty = frame_type()
local ts = tostring(pinfo.rel_ts)
local fl = frame_length()
rate = data_rate()
file:write(tostring(ty), "\t", tostring(ts), "\t", tostring(rate), "\n")
end
Then you can see which frame types you're receiving.
As Corbin said, it's definitely not interpreting "0" and "1" as TRUE/FALSE. Wireshark runs the stock Lua interpreter, and Lua only considers nil and the boolean value of false as false values. Of course you're not really checking if they're false values, you're doing a string comparison of the string-ified value of the "wlan.fc.type" field value to the string "0" or the string "1" or whatever. The actual value you get for the "wlan.fc.type" field is a number, so as Corbin said there's no need to convert it to a string and string-compare it to a string of "0" or whatever... just compare them as numbers.
Regardless, stringifying both of them should have worked too (just been less efficient), so the odds are there simply isn't an 802.11 packet with a wlan.fc.type of 0 in your capture. A wlan.fc.type of 0 is a management frame, a 1 is a control frame, and a 2 is a data frame. So the odds are you're only capturing 802.11 data packets, which is why your comparison of the string-ified wlan.fc.type to the string "2" succeeds.
One way to find out is to open your capture file in wireshark, and put in a display filter for "wlan.fc.type == 0" and see if any packets are shown. If not, then you don't have any management packets.