lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On 27 April 2016 at 04:21, Roberto Ierusalimschy <roberto@inf.puc-rio.br> wrote:
>> Doesn't it get called once per floating point number encountered while lexing?
>
> No; it caches the 'decpoint' in the 'decpoint' field. It only calls
> 'trydecpoint' (and then 'lua_getlocaledecpoint') if the conversion
> fails *after* replacing the dot with the cached 'decpoint'.
>
>
>> I guess you could do something like:
>>
>> local function safe_tonumber(s, b)
>>     if b ~= nil then
>>         return tonumber(s, b)
>>     else
>>         local func = load("return " .. s)
>>         if not func then return nil end
>>         return func()
>>     end
>> end
>>
>> Which is slightly less bad than the example earlier that uses setlocale.
>> But still.... I consider this an issue with lua.
>
> This seems quite inefficient.
>
> Couldn't you do what Lua does? Something along these lines:
>
>   local function safe_tonumber(s)
>     local locale_dec_point = string.sub(tostring(1.1), 2, 2)
>     s = string.gsub(s, "%.", locale_dec_point)
>     return tonumber(s)
>   end
>
> (You might try to avoid computing 'locale_dec_point' every time,
> doing what Lua does: cache its result once and update when conversion
> fails...)
>
> -- Roberto
>

Today I was reading through dkjson and found it does what you said (so
at least I'm not the first person to run into this):
https://github.com/LuaDist/dkjson/blob/746c00a27fdf5f8c77d735a4490f83040c4434c2/dkjson.lua#L170

-- locale independent num2str and str2num functions
local decpoint, numfilter
local function updatedecpoint ()
    decpoint = strmatch(tostring(0.5), "([^05+])")
    -- build a filter that can be used to remove group separators
    numfilter = "[^0-9%-%+eE" .. gsub(decpoint,
"[%^%$%(%)%%%.%[%]%*%+%-%?]", "%%%0") .. "]+"
end
updatedecpoint()
local function num2str (num)
    return replace(fsub(tostring(num), numfilter, ""), decpoint, ".")
end
local function str2num (str)
    local num = tonumber(replace(str, ".", decpoint))
    if not num then
        updatedecpoint()
        num = tonumber(replace(str, ".", decpoint))
    end
    return num
end