Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to match a floating point number when reading a string

How can I match floating point numbers like 1.234 or that use the "E notation" like 1.23e04 when dealing with strings?

As an example, let's say that I would like to read numbers from a data file like the following:

0.0 1.295e-03
0.1 1.276e-03
0.2 1.261e-03
0.3 1.247e-03
0.4 1.232e-03
0.5 1.218e-03

At the moment I wrote my own function to convert each line in the numbers it contains, but it's not very elegant and not portable at all: data files with a different "layout" will give errors.

Here is a simple example that reads the data file already presented and prints to screen the numbers:

function read_line(str)
   local a, b, c, d, e = str:match(
      "^%s*(%d+)%.(%d+)%s+(%d+)%.(%d+)[Ee]%-*(%d+)")
   if str:match("%-") then
      e = -tonumber(e)
   end
   local v1 = a + .1*b
   local v2 = (c + .001*d) * 10^e
   return v1, v2
end

for line in io.lines("data.txt") do
   print(read_line(line))
end

and this gives as a result:

0   0.001295
0.1 0.001276
0.2 0.001261
0.3 0.001247
0.4 0.001232
0.5 0.001218

This is indeed the result I want to achieve, but is there a more elegant and general way to deal with this problem?

Note: Data files can have more than two columns of numbers and can have both the floating point representation and the "E notation".

like image 305
Pier Paolo Avatar asked Mar 17 '23 12:03

Pier Paolo


2 Answers

Assuming every line contains only whitespace separated numbers, you can let tonumber do the heavy work instead of matching numbers manually:

function split_number(str)
    local t = {}
    for n in str:gmatch("%S+") do
        table.insert(t, tonumber(n))
    end
    return table.unpack(t)
end

for line in io.lines("data.txt") do
    print(split_number(line))
end
like image 182
Yu Hao Avatar answered Mar 19 '23 02:03

Yu Hao


Lua can read numbers directly:

f=assert(io.open("data.txt"))
while true do
    local a,b=f:read("*n","*n")
    if b==nil then break end
    print(a,b)
end
f:close()
like image 37
lhf Avatar answered Mar 19 '23 00:03

lhf