Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

MyDC.ru _ Программирование на Lua _ Функции Для Разработчиков

Автор: Setuper 6.9.2008, 15:58

Привожу полное преобразование на lua из кодировки cp1251 (Ansi) в utf-8 и обратно, с помощью функций AnsiToUtf8 и Utf8ToAnsi соответственно:

Код
local ansi_decode={
  [128]='\208\130',[129]='\208\131',[130]='\226\128\154',[131]='\209\147',[132]='\226\128\158',[133]='\226\128\166',
  [134]='\226\128\160',[135]='\226\128\161',[136]='\226\130\172',[137]='\226\128\176',[138]='\208\137',[139]='\226\128\185',
  [140]='\208\138',[141]='\208\140',[142]='\208\139',[143]='\208\143',[144]='\209\146',[145]='\226\128\152',
  [146]='\226\128\153',[147]='\226\128\156',[148]='\226\128\157',[149]='\226\128\162',[150]='\226\128\147',[151]='\226\128\148',
  [152]='\194\152',[153]='\226\132\162',[154]='\209\153',[155]='\226\128\186',[156]='\209\154',[157]='\209\156',
  [158]='\209\155',[159]='\209\159',[160]='\194\160',[161]='\209\142',[162]='\209\158',[163]='\208\136',
  [164]='\194\164',[165]='\210\144',[166]='\194\166',[167]='\194\167',[168]='\208\129',[169]='\194\169',
  [170]='\208\132',[171]='\194\171',[172]='\194\172',[173]='\194\173',[174]='\194\174',[175]='\208\135',
  [176]='\194\176',[177]='\194\177',[178]='\208\134',[179]='\209\150',[180]='\210\145',[181]='\194\181',
  [182]='\194\182',[183]='\194\183',[184]='\209\145',[185]='\226\132\150',[186]='\209\148',[187]='\194\187',
  [188]='\209\152',[189]='\208\133',[190]='\209\149',[191]='\209\151'
}
local utf8_decode={
  [128]={[147]='\150',[148]='\151',[152]='\145',[153]='\146',[154]='\130',[156]='\147',[157]='\148',[158]='\132',[160]='\134',[161]='\135',[162]='\149',[166]='\133',[176]='\137',[185]='\139',[186]='\155'},
  [130]={[172]='\136'},
  [132]={[150]='\185',[162]='\153'},
  [194]={[152]='\152',[160]='\160',[164]='\164',[166]='\166',[167]='\167',[169]='\169',[171]='\171',[172]='\172',[173]='\173',[174]='\174',[176]='\176',[177]='\177',[181]='\181',[182]='\182',[183]='\183',[187]='\187'},
  [208]={[129]='\168',[130]='\128',[131]='\129',[132]='\170',[133]='\189',[134]='\178',[135]='\175',[136]='\163',[137]='\138',[138]='\140',[139]='\142',[140]='\141',[143]='\143',[144]='\192',[145]='\193',[146]='\194',[147]='\195',[148]='\196',
    [149]='\197',[150]='\198',[151]='\199',[152]='\200',[153]='\201',[154]='\202',[155]='\203',[156]='\204',[157]='\205',[158]='\206',[159]='\207',[160]='\208',[161]='\209',[162]='\210',[163]='\211',[164]='\212',[165]='\213',[166]='\214',
    [167]='\215',[168]='\216',[169]='\217',[170]='\218',[171]='\219',[172]='\220',[173]='\221',[174]='\222',[175]='\223',[176]='\224',[177]='\225',[178]='\226',[179]='\227',[180]='\228',[181]='\229',[182]='\230',[183]='\231',[184]='\232',
    [185]='\233',[186]='\234',[187]='\235',[188]='\236',[189]='\237',[190]='\238',[191]='\239'},
  [209]={[128]='\240',[129]='\241',[130]='\242',[131]='\243',[132]='\244',[133]='\245',[134]='\246',[135]='\247',[136]='\248',[137]='\249',[138]='\250',[139]='\251',[140]='\252',[141]='\253',[142]='\254',[143]='\255',[144]='\161',[145]='\184',
    [146]='\144',[147]='\131',[148]='\186',[149]='\190',[150]='\179',[151]='\191',[152]='\188',[153]='\154',[154]='\156',[155]='\158',[156]='\157',[158]='\162',[159]='\159'},[210]={[144]='\165',[145]='\180'}
}

local nmdc = {
  [36] = '$',
  [124] = '|'
}

function AnsiToUtf8(s)
  local r, b = ''
  for i = 1, s and s:len() or 0 do
    b = s:byte(i)
    if b < 128 then
      r = r..string.char(b)
    else
      if b > 239 then
        r = r..'\209'..string.char(b - 112)
      elseif b > 191 then
        r = r..'\208'..string.char(b - 48)
      elseif ansi_decode[b] then
        r = r..ansi_decode[b]
      else
        r = r..'_'
      end
    end
  end
  return r
end

function Utf8ToAnsi(s)
  local a, j, r, b = 0, 0, ''
  for i = 1, s and s:len() or 0 do
    b = s:byte(i)
    if b < 128 then
      if nmdc[b] then
        r = r..nmdc[b]
      else
        r = r..string.char(b)
      end
    elseif a == 2 then
      a, j = a - 1, b
    elseif a == 1 then
      a, r = a - 1, r..utf8_decode[j][b]
    elseif b == 226 then
      a = 2
    elseif b == 194 or b == 208 or b == 209 or b == 210 then
      j, a = b, 1
    else
      r = r..'_'
    end
  end
  return r
end

big_smile.gif

Автор: Setuper 13.9.2008, 18:06

Функция приведения к нижнему регистру:

Код
function String2Lower(s)
  local r, b = ''
  s = s:lower()
  for i = 1, s:len() do
    b = s:byte(i)
    if b > 191 and b < 224 then
      b = b + 32
    elseif b == 168 or b == 184 then
      b = 229
    end
    r = r.._G.string.char(b)
  end
  return r
end

Функция приведения к верхнему регистру:
Код
function String2Upper(s)
  local r, b = ''
  s = s:upper()
  for i = 1, s:len() do
    b = s:byte(i)
    if b > 223 then
      b = b - 32
    elseif b == 168 or b == 184 then
      b = 197
    end
    r = r.._G.string.char(b)
  end
  return r
end



Более оптимальные по выполнению функции:
Код
String2Lower = function(s)
  for i = 192, 223 do
    s = s:gsub(_G.string.char(i), _G.string.char(i + 32))
  end
  s = s:gsub(_G.string.char(168), _G.string.char(184))
  return s:lower()
end

Код
String2Upper = function(s)
  for i = 224, 255 do
    s = s:gsub(_G.string.char(i), _G.string.char(i - 32))
  end
  s = s:gsub(_G.string.char(184), _G.string.char(168))
  return s:upper()
end

Автор: Setuper 14.9.2008, 11:36

Функции форматирования шары:

Код
function GetNormalShare(s)
  s = tonumber(s) or 0
  if s >= 1125899906842624 then return (math.floor(1000 * s / 1125899906842624) / 1000).." ПБ"
  elseif s >= 1099511627776 then return (math.floor(1000 * s / 1099511627776) / 1000).." TБ"
  elseif s >= 1073741824 then return (math.floor(1000 * s / 1073741824) / 1000).." ГБ"
  elseif s >= 1048576 then return (math.floor(1000 * s / 1048576) / 1000).." МБ"
  elseif s >= 1024 then return (math.floor(1000 * s / 1024) / 1000).." КБ"
  else return s.." Б" end
end

Код
function GetLongShare(s)
  s = tonumber(s) or 0
  local r = ''
  if s >= 1125899906842624 then r = r ~= '' and r..(" %s ПБ"):format(math.floor(s / 1125899906842624)) or r..math.floor(s / 1125899906842624).." ПБ" s = math.fmod(s, 1125899906842624) end
  if s >= 1099511627776 then r = r ~= '' and r..(" %s ТБ"):format(math.floor(s / 1099511627776)) or r..math.floor(s / 1099511627776).." ТБ" s = math.fmod(s, 1099511627776) end
  if s >= 1073741824 then r = r ~= '' and r..(" %s ГБ"):format(math.floor(s / 1073741824)) or r..math.floor(s / 1073741824).." ГБ" s = math.fmod(s, 1073741824) end
  if s >= 1048576 then r = r ~= '' and r..(" %s МБ"):format(math.floor(s / 1048576)) or r..math.floor(s / 1048576).." МБ" s = math.fmod(s, 1048576) end
  if s >= 1024 then r = r ~= '' and r..(" %s КБ"):format(math.floor(s / 1024)) or r..math.floor(s / 1024).." КБ" s = math.fmod(s, 1024) end
  if s < 1024 then r = r ~= '' and r..(" %s Б"):format(s) or r..s.." Б" end
  return r
end

Автор: Setuper 15.9.2008, 22:31

Функции преобразования ip адреса в число и обратно:

Код
function Ip2Num(sIP)
  local a, b, c, d = sIP:match"^(%d+)%.(%d+)%.(%d+)%.(%d+)$"
  return a * 16777216 + b * 65536 + c * 256 + d
end
function Num2Ip(i)
  i = tonumber(i) or 0
  local r, d, zd = '', '.', "0."
  if i >= 16777216 then r = math.floor(i / 16777216)..d i = math.fmod(i, 16777216) else r = zd end
  if i >= 65536 then r = r..math.floor(i / 65536)..d i = math.fmod(i, 65536) else r = r..zd end
  if i >= 256 then r = r..math.floor(i / 256)..d i = math.fmod(i, 256) else r = r..zd end
  return r..i
end
Можно использовать для проверки рангов ip и для оптимального хранения ip адресов в бд.

Автор: Setuper 23.9.2008, 17:05

Еще несколько интересных методов. Может кому понадобятся, может кого заинтересует (Я использую их в больших проектах. Они несколько сворачивают длинные выкладки).

Код
tSys={}
function tSys:Table(t)                return type(t)=="table" and t end
function tSys:TableNoVoid(t)             return self:Table(t) and next(t) and t end
function tSys:TableOrDef(t,d)         return self:Table(t) or d or {} end
function tSys:TableNoVoidOrDef(t,d)        return self:TableNoVoid(t) or self:TableOrDef(t,d) end
function tSys:Table2(t,s)             return self:Table(t) and self:Table(t[s]) and t[s] end
function tSys:TableNoVoid2(t,s)         return self:Table2(t,s) and next(t[s]) and t[s] end
function tSys:TableOrDef2(t,s,d)        return self:Table(t) and (self:Table(t[s]) and t[s] or d or rawset(t,s,{}) and t[s]) or {} end
function tSys:TableNoVoidOrDef2(t,d)    return self:TableNoVoid2(t) or self:TableOrDef2(t,d) end
function tSys:String(s)             return type(s)=="string" and s end
function tSys:StringNoVoid(s)         return self:String(s) and s~="" and s end
function tSys:StringOrDef(s,d)         return self:String(s) or d or "" end
function tSys:StringNoVoidOrDef(s,d)     return self:StringNoVoid(s) or self:StringOrDef(s,d) end
function tSys:String2(t,s)             return self:Table(t) and self:String(t[s]) and t[s] end
function tSys:StringNoVoid2(t,s)         return self:String2(t,s) and t[s]~="" and t[s] end
function tSys:StringOrDef2(t,s,d)        return self:Table(t) and (self:String(t[s]) and t[s] or d or rawset(t,s,"") and t[s]) or "" end
function tSys:StringNoVoidOrDef2(s,d)     return self:StringNoVoid2(s) or self:StringOrDef2(s,d) end
function tSys:Number(i)             return type(i)=="number" and i end
function tSys:NumberOrDef(i,d)         return self:Number(i) or d or 0 end
function tSys:StringOrNumber(s)         return self:String(s) or self:Number(s) end
function tSys:NumberOfString(s)         return self:String(s) and tonumber(s) and s end
function tSys:ToNumber(s)             return self:String(s) and tonumber(s) or self:Number(s) end
function tSys:NoVoid(s)             return self:StringNoVoid(s) or self:Number(s) end
function tSys:Eq0(s)                 return self:Number(s) and s==0 and s end
function tSys:Eq1(s)                 return self:Number(s) and s==1 and s end
function tSys:Eq2(s)                 return self:Number(s) and s==2 and s end
function tSys:Eq01(s)                 return self:Number(s) and (s==0 or s==1) and s end

--метод возвращает количество ВСЕХ полей таблицы (а не только количество индексных полей как функции table.getn или table.maxn)
function tSys:GetN(t)
    local c=0 for _ in pairs(t) do c=c+1 end return c
end


P.S. Существуют различия между методами и функциями. tSys:GetN(t) - метод, tSys.GetN(t) - функция

Автор: Sephiroth_Lukaw 3.12.2008, 19:05

Часто их теряю. Так что здесь оставлю. Надеюсь никто не против(знаю, что функция всем известная).
/*
Serialize(tTable - Сама таблица, sTableName - Имя таблицы, hFile - Хендлер файла, т.е. нужен уже открытый файл) - Сохраняет таблицу в файле.
--------------------
SaveTable(sFile - Путь к файлу, tTable - Сама таблица, sTableName - Имя таблицы) - Сохраняет таблицу в файле с помощью функции Serialize - т.е. она должна быть уже определена! -, отличие в том, что она сама открывает файл и закрывает его после выполнения поставленной задачи(т.е. нужен уже не hFile, а путь к нему).
*/

Код
function Serialize(tTable, sTableName, hFile, sTab)
  sTab = sTab or ''
  hFile:write(sTab..sTableName.." = {\n")
  for k, v in pairs(tTable) do
    if type(v) ~= "function" then
      local sKey = type(k) == "string" and ("[%q]"):format(k) or ("[%d]"):format(k)
      if type(v) == "table" then
        Serialize(v, sKey, hFile, sTab..'\t')
      else
        local sValue = type(v) == "string" and ("%q"):format(v) or tostring(v)
        hFile:write(sTab..'\t'..sKey.." = "..sValue)
      end
      hFile:write(",\n")
    end
  end
  hFile:write(sTab.."}")
end

function SaveTable(sFile, tTable, sTableName)
  local hFile = io.open(sFile, "w+")
  Serialize(tTable, sTableName, hFile)
  hFile:close()
end

Автор: Setuper 30.1.2009, 13:21

Функция коррекции данных пользователя.
Если клиент неизвестен для хаба, то тэг клиента дописывается в описание. Данная функция извлекает тэг из описания и корректно прописывает данные пользователя (такие как слоты, хабы, режим и тд.).
Данная функция корректно воспринимает тэг Авалинка.

Код
function GetNormalValue(tUser)
  if not tUser.sTag and tUser.sDescription then
    local sDescription,sTag,sClient,sClientVersion,sMode,iNormalHubs,iRegHubs,iOpHubs,iSlots,iLlimit = tUser.sDescription:match"(.*)(<(.+)%sV?:?(.-),M:(.-),H:(%d+)/(%d+)/(%d+),S:(%d+)>)$"
    if not sDescription then
      sDescription,sTag,sClient,sClientVersion,sMode,iNormalHubs,iRegHubs,iOpHubs,iSlots,iLlimit = tUser.sDescription:match"(.*)(<(.+)%sV?:?(.-),M:(.-),H:(%d+)/(%d+)/(%d+),S:(%d+),L:(%d+)>)$"
    end
    if not sDescription then
      sDescription,sTag,sClient,sClientVersion,sMode,iNormalHubs,iRegHubs,iOpHubs,iSlots,iLlimit = tUser.sDescription:match"(.*)(<(.+)%sV?:?(.-),M:(.-),H:(%d+)/(%d+)/(%d+),S:(%d+),B:(%d+)>)$"
    end
    tUser.sDescription=sDescription
    tUser.sTag=sTag
    tUser.sClient=sClient
    tUser.sClientVersion=sClientVersion
    tUser.sMode=sMode
    tUser.iNormalHubs=tonumber(iNormalHubs)
    tUser.iRegHubs=tonumber(iRegHubs)
    tUser.iOpHubs=tonumber(iOpHubs)
    tUser.iHubs=tonumber(iNormalHubs and iRegHubs and iOpHubs and (iNormalHubs + iRegHubs + iOpHubs))
    tUser.iSlots=tonumber(iSlots)
    tUser.iLlimit=tonumber(iLlimit)
  end
  return tUser
end


Использование метода:
Код
function UserConnected(tUser)
  tUser=GetNormalValue(tUser)
  ...
end

Автор: alex82 7.2.2009, 17:28

Функция форматирования шары, решающая сию проблему чисто математически.

Код
function GetNormalSize(size, num)
    size = size or 0
    local tSize, sSize = {" B"," kB"," MB"," GB"," TB"," PB"}, ""
    for i in pairs(tSize) do
        if size < 1000 then
            sSize = tSize[i]
            break
        end
        size = size/1024
    end
    local tmp1, tmp2 = 1, 0
    if size > 0 then
        num = num or 3
        while size < 10^num do
            size, tmp1 = size*10, tmp1*10
        end
        size, tmp2 = math.modf(math.floor(size)/10); tmp2 = tmp2*10
        if tmp2 >=5 then size = size+1 end
        size = size/tmp1*10
    end
    return tostring(size)..sSize
end

Первый аргумент - собственно размер шары в байтах, второй - до скольки знаков округлить значение шары. Если второй аргумент отсутствует, шара округляется до 3-х знаков.

Автор: Setuper 7.2.2009, 18:25

Недоработанный алгоритм. Простейшая проверка GetNormalSize(1052, 4) не даёт 4 знака после запятой (1.0273), а округляет до 1.027, то есть до третьего знака.

Автор: alex82 7.2.2009, 18:52

Цитата(Setuper @ 7.2.2009, 17:25) *
Недоработанный алгоритм. Простейшая проверка GetNormalSize(1052, 4) не даёт 4 знака после запятой (1.0273), а округляет до 1.027, то есть до третьего знака.

А там разве сказано "после запятой"?

Автор: Setuper 7.2.2009, 19:07

А что тогда означает выражение: "до скольки знаков округлить значение шары" ??

Код
function GetNormalSize(s, n)
    s=s and tonumber(s) or 0
    n=n and "%."..n.."f" or "%.3f"
    if s>=1125899906842624 then return string.format(n,s/1125899906842624).." ПБ"
    elseif s>=1099511627776 then return string.format(n,s/1099511627776).." TБ"
    elseif s>=1073741824 then return string.format(n,s/1073741824).." ГБ"
    elseif s>=1048576 then return string.format(n,s/1048576).." МБ"
    elseif s>=1024 then return string.format(n,s/1024).." КБ"
    else return s.." Б" end
end

Автор: sphinx 7.2.2009, 19:16

Код
function getNormalShare(share)
    local i,tUnits = 1, {"B","KB","MB","GB","TB","PB","EB"}
    while share > 1024 do share = share / 1024 i = i + 1 end
    return string.format("%.3f",share).." "..(tUnits[i] or "??")
end

Автор: alex82 7.2.2009, 19:22

Цитата(Setuper @ 7.2.2009, 18:07) *
А что тогда означает выражение: "до скольки знаков округлить значение шары" ??

Это означает что если значение 543.905234 GB, то вернётся 544 GB, а если 1.1834456 GB, то 1.18 GB

Автор: Setuper 7.2.2009, 20:33

Не знаю для чего нужно округлять до количества цифр, обычно округляют до какого-то знака после запятой, ну да ладно.

Самый быстрый по выполнению мой код, так как в ветке выполнения содержится минимальное количество операций, однако очень порадовал код sphinx-а))) :

Код
function GetNormalShare(s,n)
  local i,t=1,{"Б","КБ","МБ","ГБ","ТБ","ПБ"}
  s=s and tonumber(s) or 0
  n=n and "%."..n.."f " or "%.3f "
  while s>0x400 do s,i=s/0x400,i+1 end
  return n:format(s)..(t[i] or "??")
end

1) Цикл пробегается от меньшего значения - оптимизация прохода (большинство пользователей не имеют большой шары)
2) Цикл while, а не for, поэтому для выхода из цикла не нужен оператор break (в случае прохода по for i=1,6 нужен был оператор break)
3) Код не громоздкий

Автор: alex82 7.2.2009, 21:05

Цитата
Не знаю для чего нужно округлять до количества цифр, обычно округляют до какого-то знака после запятой

Из соображений целесообразности. Ведь если шара 954.542324234 GB, то имеет смысл избавиться от всех знаков после запятой, поскольку такая точность в большинстве случаев не нужна. Ну а если 1.978678, то нужно оставить хотябы 2 знака потому что 1.978678 и 1 отличаются почти в 2 раза (хотя, юзеров с такой шарой надо банить, а не формарировать их шару big_smile.gif)

PS. Какой смысл в этом выражении:
Код
s=s and tonumber(s) or 0

Не проще ли?
Код
s=s or 0

Автор: Setuper 7.2.2009, 21:10

дело в том, что в некоторых случаях шара из себя представляет строку: "47345783456", поэтому строка приводится к числу, хотя это можно выбросить, если контролировать это.

Автор: alex82 9.2.2009, 22:54

Код
function ValidateNickArrival(user,data)
    Core.SendToUser(user, "Здесь пишем наше сообщение")
end
Функция отправляет юзеру сообщение при входе на хаб. При этом сообщение отправляется раньше, чем остальные, в том числе и "копирайт" PtokaX. Выглядит это примерно так:


Автор: Setuper 15.2.2009, 22:40

Аналог стандартной LUA функции для PtokaX:

Код
function _G.print(...)
  local m = ''
  for i = 1, _G.select('#', ...) do
    m = m..tostring(_G.select(i, ...))
  end
  Core.SendToAll(m)
end


Использование:
Код
print("55 qwerty ", 34, " ", 66, " str ", 12, " 78 ", 0x22b==555)





Функции работы с бинарными числами.

Функция, преобразующая десятичное число в бинарную строку:
Код
function tobin(n)
  local m, x = ''
  while n >= 2 do
    n, x = _G.math.modf(n / 2)
    m = 2 * x..m
  end
  return n ~= 0 and '1'..m or '0'
end


Функция, преобразующая бинарную строку в десятичное число:
Код
tonumber(str, 2)


Можно использовать для раздачи собственных прав профилям хаба. Например, на хабе профили: 0 - Master, 1 - Operator, 2 - VIP, 3 - Reg, -1 - UnReg. Профили можно записать в двоичную строку. Будем полагать, что строка "11111" разрешает всем пяти профилям то или иное действие, строка "10000" разрешает действие только профилю Master. Думаю, что ясен смысл.

Автор: Setuper 16.2.2009, 14:17

Работа со стеком:

Код
  top=0;
  data={};
  push=function(name,...)
    top=top+1
    name=name or top
    data[top]=name
    data[tostring(name)]=top
    return name
  end
  pop=function(...)
    local name=table.remove(data)
    top=top-1
    if data[name] then
      data[name]=nil
    end
    return name
  end
  getindex=function(name,...)
    return name and -top+data[tostring(name)]-1 or 0
  end
  clean=function()
    top,data=0,{}
  end


Функция push помещает элемент в стек, функция pop извлекает последний элемент из стека, функция getindex возвращает глубину элемента в стеке, функция clean очищает стек.

Автор: Setuper 18.2.2009, 21:17

Очередная интересная по реализации функция форматирования шары:

Код
local t={"Б","КБ","МБ","ГБ","ТБ","ПБ"}
local function loop(i,n,c)
  if i<0x400 then coroutine.yield(n:format(i)..(t[c] or "??"))end
  return loop(i/0x400,n,c+1)
end
GetNormalShare=coroutine.wrap(function(s,n)return loop(s and tonumber(s) or 0,n and "%."..n.."f " or "%.3f ",1)end)


Использование:
Код
Core.SendToAll(GetNormalShare(142589996842624,4))

Автор: Setuper 1.4.2009, 17:20

Пример работы с переменным числом параметров:

Код
function MyFunc1(...)
  local m=''
  for i=1,select('#',...) do
    m=m..tostring(select(i,...))
  end
  Core.SendToAll(m)
end


Вызов функции:
Код
MyFunc1("qwerty", "5", 1, 0x22b==555)

Результат вызова:
Код
qwerty51true


Если параметры функции состоят только из строк и/или чисел, то функцию можно упростить, записав так:
Код
function MyFunc2(...)
  Core.SendToAll(table.concat({...}))
end


Вызов функции:
Код
MyFunc2("qwerty", "5", 1)

Результат вызова:
Код
qwerty51

Автор: Setuper 3.4.2009, 19:25

Булева алгебра.

Код
x inverse
1 0
0 1

x y and
0 0 0
1 0 0
0 1 0
1 1 1

x y or
0 0 0
1 0 1
0 1 1
1 1 1

x y xor
0 0 0
1 0 1
0 1 1
1 1 0

x y xnor
0 0 1
1 0 0
0 1 0
1 1 1

x xor y = x and inverse y or inverse x and y
x xnor y = x and y or inverse(x and y)
x xnor y = inverse(x xor y)
x xor y = inverse(x xnor y)
(x xor y) and (x xnor y) = 0
(x xor y) or (x xnor y) = 1


Функции для работы с бинарным представлением чисел, хотя числа подставляются в десятичном виде big_smile.gif
Код
function odd(x)
  return math.floor(x / 2) * 2 ~= x
end

function bit_inverse(x)
  local c, s = 0, 1
  while x > 0 do
    if not odd(x) then
      c = c + s
    end
    s = s * 2
    x = math.floor(x / 2)
  end
  return c
end

function bit_or(x, y)
  local c, s = 0, 1
  while x > 0 or y > 0 do
    if odd(x) or odd(y) then
      c = c + s
    end
    s = s * 2
    x = math.floor(x / 2)
    y = math.floor(y / 2)
  end
  return c
end

function bit_and(x, y)
  local c, s = 0, 1
  while x > 0 or y > 0 do
    if odd(x) and odd(y) then
      c = c + s
    end
    s = s * 2
    x = math.floor(x / 2)
    y = math.floor(y / 2)
  end
  return c
end

function bit_xor(x, y)
  local c, s = 0, 1
  while x > 0 or y > 0 do
    if odd(x) and not odd(y) or odd(y) and not odd(x) then
      c = c + s
    end
    s = s * 2
    x = math.floor(x / 2)
    y = math.floor(y / 2)
  end
  return c
end

function bit_xnor(x, y)
  local c, s = 0, 1
  while x > 0 or y > 0 do
    if odd(x) and odd(y) or not odd(y) and not odd(x) then
      c = c + s
    end
    s = s * 2
    x = math.floor(x / 2)
    y = math.floor(y / 2)
  end
  return c
end

Автор: zangriEBP 22.4.2009, 16:45

Функции для перевода DEC в HEX и обратно

CODE
function to_hex(n)
if(type(n) ~= "number") then
error("non-number type passed in.")
end
-- checking not float
if(n - math.floor(n) > 0) then
error("trying to apply bitwise operation on non-integer!")
end
if(n < 0) then
-- negative
n = bit.tobits(bit.bnot(math.abs(n)) + 1)
n = bit.tonumb(n)
end
hex_tbl = {'A','B','C','D','E','F'}
hex_str = ""
while(n ~= 0) do
last = math.mod(n, 16)
if(last < 10) then
hex_str = tostring(last) .. hex_str
else
hex_str = hex_tbl[last-10+1] .. hex_str
end
n = math.floor(n/16)
end
if(hex_str == "") then
hex_str = "0"
end
return hex_str
end
function to_dec(hex)
if(type(hex) ~= "string") then
error("non-string type passed in.")
end
head = string.sub(hex, 1, 2)
if( head ~= "0x" and head ~= "0X") then
error("wrong hex format, should lead by 0x or 0X.")
end
v = tonumber(string.sub(hex, 3), 16)
return v;
end
-- hex lib interface
hex = {
to_dec = to_dec,
to_hex = to_hex,
}


Функции для перевода BIN в HEX и обратно

CODE
function hex2bin(hex)
local bin_tbl = {[48]='0000',[49]='0001',[50]='0010',[51]='0011',[52]='0100',[53]='0101',[54]='0110',[55]='0111',[56]='1000',[57]='1001',[65]='1010',[66]='1011',[67]='1100',[68]='1101',[69]='1110',[70]='1111'}
local r,j, b = ''
for i=1,#hex do
b=hex:byte(i)
if (b>47 and b<58) or (b>64 and b<71) then j=bin_tbl[b] else return -1 end
if i==1 then j=tonumber(j) end
r=r..j
end
return r;
end

function bin2hex(bin)
local hex_tbl = {['0000']='0',['0001']='1',['0010']='2',['0011']='3',['0100']='4',['0101']='5',['0110']='6',['0111']='7',['1000']='8',['1001']='9',['1010']='A',['1011']='B',['1100']='C',['1101']='D',['1110']='E',['1111']='F'}
local r,b=''
for i=#bin,1,-4 do
b=bin:sub(i-3,i)
if i<4 then b=string.rep('0',4-i)..bin:sub(1,i):sub(-1*i) end
r=r..hex_tbl[b]
end
return r:reverse()
end

Автор: Setuper 22.4.2009, 19:01

Во-первых, видимо math.fmod, а не math.mod.
Во-вторых, что за таблица bit? Её и функции tobits, tonumb и bnot нужно определять!
В-третьих, к чему все эти проверки и вызовы функции error? Ведь если человек использует подобного рода функции, то он явно понимает, что делает, а эти проверки только делают медленнее алгоритм перевода чисел.
В-четвёртых, таблица hex тоже непонятно для чего тут написана.
В-пятых, переменные внутри функции надо объявлять локальными

Код
local hex_str = ""

Автор: Setuper 27.4.2009, 12:07

Функция explode разбивает строку указанным разделителем на подстроки. Возвращает таблицу с подстроками.

Код
_G.string.explode = function(self, Sep)
  local ret = {}
  for k in (self..Sep):gmatch(("(.-)%s+"):format(Sep)) do
    _G.table.insert(ret, k)
  end
  return ret
end

Автор: alex82 27.4.2009, 14:48

Вопрос.

Код
_G.string.explode

Зачем использовать переменную _G, если можно просто string.explode?

Автор: Setuper 27.4.2009, 14:56

http://mydc.ru/ipb.html?s=&showtopic=1508&view=findpost&p=14327

Автор: district 4.5.2009, 6:50

Рискну и я три копеечки добавить. Решал проблему разбиения на части длинных посылок (отчетов) Оператору, содержащих более 128000 символов, и вот попутно соорудил такое нехитрое форматирование. Когда нужно упихнуть длинный текст в заданные рамки ( переменная iMargin ). Не шедевр мирового программирования, но, может быть, кому-нибудь пригодится big_smile.gif

Код
function CutText(s)
local txt,sReturn = s.." ",""
local Len,Ln,ln,stemp = txt:len(),0,0,""
for word in string.gmatch(txt, "%S+%s+" ) do
    local wlen = word:len(); Ln,ln = Ln + wlen,ln+wlen
    if ln >= iMargin then
        sReturn = sReturn..stemp.."\r\n\t"; stemp = word; ln = wlen
    else
        stemp = stemp..word
    end    
    if Ln == Len then sReturn = sReturn..stemp; end
end
return sReturn
end


На картинке результат форматирования Описания хаба при разном заданном значении предельной длины подстроки.

 

Автор: Setuper 26.5.2009, 17:44

Очень не стандартный, но классный метод записи мультистрок:

Код
do
  local mt = {}
  function mt:__call(str)
    table.insert(self, str) return self
  end
  function mt:__unm()
    return table.concat(self, "\n")
  end
  function L(...)
    return setmetatable({...}, mt)
  end
end

local p = -L "line 1" "line 2" "line 3"

Core.SendToAll(p)


Попробуйте разобраться, что происходит в данном примере big_smile.gif



Ещё одна достаточно интересная реализация:
Код
function prnt(x)
  if x then
    Core.SendToAll(x)
    return prnt
  end
end
prnt "one" "two" "three"

Автор: Wariner 8.6.2009, 16:17

функция форматирования времени

Код
function GetNormalTime(s)
    s=tonumber(s) or 0
    local r=""
    if s>=31104000 then r=math.floor(s/31104000).." г. " s=math.fmod(s,31104000) end
    if s>=2592000 then r=r..math.floor(s/2592000).." мес. " s=math.fmod(s,2592000) end
    if s>=86400 then r=r..math.floor(s/86400).." д. " s=math.fmod(s,86400) end
    if s>=3600 then r=r..math.floor(s/3600).." ч. " s=math.fmod(s,3600) end
    if s>=60 then r=r..math.floor(s/60).." мин. " s=math.fmod(s,60) end
    return r..s.." сек."
end

Автор: Setuper 8.2.2010, 19:47

Функция побитового "и":

Код
function bin_and(x, y)
  if y <= x then
    local i, r, a, b = 1, 0, 0, 0
    while 0 < y do
      x, a = math.modf(x / 2)
      y, b = math.modf(y / 2)
      if 0 < a and 0 < b then
        r = r + i
      end
      i = 2 * i
    end
    return r
  end
  return bin_and(y, x)
end

Автор: Serx 25.2.2010, 22:03

Если у файла в названии есть кириллица, то его имя преобразовывается в какой-то код (в магнет-ссылке)
Например "мистер" в %D0%BC%D0%B8%D1%81%D1%82%D0%B5%D1%80
Нагуглил только то, что это URI Кодирование, но откуда берутся "%D0" или "%D1" не понимаю...
Ну и сам вопрос: как в LUA произвести эту конвертацию?

Автор: Setuper 26.2.2010, 0:35

Всё достаточно просто.
Переводим текст в UTF8 и каждый "нужный" байт представляем в 16-ричном виде big_smile.gif

Функцию AnsiToUtf8 берём из первого поста.

Код
function URICoding(sText)
  local function Check(i)
    if i < 33 or 126 < i then return nil end
    if i == 33 then return true
    elseif 38 < i and i < 43 then return true
    elseif 44 < i and i < 47 then return true
    elseif 47 < i and i < 58 then return true
    elseif 64 < i and i < 91 then return true
    elseif 96 < i and i < 123 then return true
    elseif i == 126 then return true end
  end
  local s, r = AnsiToUtf8(sText), ''
  for i = 1, #s do
    local b = s:byte(i)
    if Check(b) then
      r = r..string.char(b)
    else
      r = r..("%%%X"):format(b)
    end
  end
  return r
end

Автор: Nickolya 26.2.2010, 11:01

В библиотеке LuaSocket есть модуль URL в котором есть функция заменяющая URICoding:

Цитата
url.escape(content)

Applies the URL escaping content coding to a string Each byte is encoded as a percent character followed by the two byte hexadecimal representation of its integer value.

Content is the string to be encoded.

The function returns the encoded string.
Код
-- load url module
url = require("socket.url")

code = url.escape("/#?;")
-- code = "%2f%23%3f%3b"

Аналогично можно перевести из полученной строки в обычный текст, надо перекодировать из утф, заменить + на пробел и применить к строке функцию url.unescape

Автор: Ksan 5.5.2010, 5:27

Ещё одна функция приведения к нижнему регистру (ранее нигде не встречал):

Код
function StringLower(arg)
    os.setlocale"Russian_Russia.1251"  -- (русс.локаль)
    arg = string.lower(arg)
    os.setlocale("C")  -- (возврат на станд.локаль)
    return arg
end

Работает как с кириллицей, так и с латиницей.
Аналогично же и для приведения к верхнему регистру:

Код
function StringUpper(arg)
    os.setlocale"Russian_Russia.1251"  -- (русс.локаль)
    arg = string.upper(arg)
    os.setlocale("C")  -- (возврат на станд.локаль)
    return arg
end


PS: Уж больно подозрительно простенький код получился, но работает. Если у кода есть побочные вредные эффекты, умные товарищи, надеюсь, не пропустят и подскажут. big_smile.gif

Автор: Nickolya 5.5.2010, 13:39

А смысл тасовать локали? При старте скрипта обозначил на русскую и пользуйся себе чисто string.lower и string.upper

Автор: Ksan 5.5.2010, 13:40

Если так, то ещё лучше. Это я и хотел услышать от старшего товарища. big_smile.gif

Автор: Setuper 5.5.2010, 20:14

Играть с локалями нужно в функциях сохранения в файл, так как в Русской локали разделителем дробной и целой части в числе является запятая, а не точка!

Я это уже объяснял на хабе и повторяю для тех, кто не видел эти разъяснения.

Автор: Nickolya 5.5.2010, 22:13

Т.е. если локаль не русская и мы загружаем файл, который сохранялся из-под русской локали, мы получим ошибку, так? Но если обозначить локаль до загрузки файла в скрипт, будет ли ошибка при загрузке?

Автор: Setuper 5.5.2010, 23:54

Дело в том, что в lua разделителем дробной и целой части является точка (и этот символ не зависит от локали, а является синтаксическим правилом).
Поэтому для того чтобы загружать файл при помощи lua функции dofile нужно чтобы внутри файла был исключительно lua формат.

Однако если мы сохраняем файл и при этом установлена русская локаль, то явно или неявно функция tostring преобразует разделитель из точки в запятую и после этого загрузить такой файл функцией dofile уже не удастся.

Поэтому делаем так: везде используем русскую локаль, установленную один раз, но перед тем как сохранить в файл устанавливаем локаль "C", сохраняем в файл, и после сохранения опять возвращаем русскую локаль. Таким образом стандартную локаль нужно устанавливать только на время сохранения информации в файл (для того чтобы оставить в сохранности lua синтаксис в файле).

Автор: Ksan 6.5.2010, 1:03

Как это ни странно, установка локали на русскую именно при старте скрипта не помогает (пробовал включить и в StartUp и до него отдельной строкой).
Приходится это делать в ChatArrival'е, перед применением функции string.lover(s).. (либо выносить отдельной функцией, как я выше показывал).
Хотя вроде не должно бы иметь значения, переключать в начале скрипта до ЧатАрривала или перед применением.

Автор: alex82 6.5.2010, 12:54

Цитата
Как это ни странно, установка локали на русскую именно при старте скрипта не помогает


Наверное один из нижестоящих скриптов меняет локаль обратно на "C". Дело в том, что локаль меняется глобально - для всего приложения. Поэтому не рекомендуется менять локаль в скриптах для птоки - изменив ее в одном скрипте, ты рискуешь нарушить работу всех остальных.

Автор: alex82 6.5.2010, 16:12

Функции преобразования регистров:

Код
function string.lower2(s)
    return s:gsub("([А-Я])",function(str) return string.char(str:byte()+32) end):gsub("Ё", "ё"):lower()
end

function string.upper2(s)
    return s:gsub("([а-я])",function(str) return string.char(str:byte()-32) end):gsub("ё", "Ё"):upper()
end

Работают быстрее, чем все аналогичные функции, выложенные ранее в этой теме.
__________________________________________________

Функция экранирования "волшебных" символов регулярных выражений Lua (собственно, даже не функция, а метод):
Код
:gsub("[%^%$%(%)%%%.%[%]%*%+%-%?]","%%%1")

Метод необходим при использовании произвольных строк в качестве второго аргумента функций string.gsub(), string.match(), string.gmatch(). Пример:
Код
local result = data:gsub(str:gsub("[%^%$%(%)%%%.%[%]%*%+%-%?]","%%%1"),repl)

Стоит напомнить, что в третьем аргументе функции string.gsub() необходимо экранировать символ %, иначе функция будет "съедать" этот символ, или вызывать ошибку "Invalid capture index". Экранирование производится так:
Код
repl:gsub("%%","%%%%")

Автор: Setuper 6.5.2010, 20:20

А чем так не устраивает установка локали?

Автор: alex82 6.5.2010, 20:24

Setuper

http://mydc.ru/index.html?showtopic=334&view=findpost&p=30144

Автор: Setuper 6.5.2010, 21:00

Единственное препятствие - это функции сохранения.
Однако это легко устраняется.

Поэтому не вижу никаких препятствий в установки русской локали.

Автор: Ksan 6.5.2010, 23:33

Не вижу проблему в установке локали - поставил локаль, инвертнул регистр, вернул локаль. Всё это делается в 1 микросекунду. Не понимаю, чем это может помешать остальным скриптам?
Только разве что религия не позволяет...

Автор: alex82 7.5.2010, 4:26

Цитата(Ksan @ 6.5.2010, 23:33) *
Не вижу проблему в установке локали - поставил локаль, инвертнул регистр, вернул локаль.
Только работать такая функция будет раза в 2 медленнее, чем те, что выложил я.

PS. Если вам не нравятся функции, выложенные мной - используйте другие. Я выложил их в надежде, что они окажутся полезными кому-нибудь, а вовсе не для того, чтобы развязать холивар.

Автор: Phazeus 18.6.2010, 2:39

Анализ производительности участка кода:

Код
local test_counter=0
local test_startTime=os.time()
while test_startTime==os.time() do end
test_startTime=os.time()
while os.time()==test_startTime do
  test_counter=test_counter+1
  [КОД_ДЛЯ_АНАЛИЗА]
end
return tostring(test_counter)

Внутри цикла, вместо "[КОД_ДЛЯ_АНАЛИЗА]" помещаем исследуемый код, который будет выполняться в цикле ровно 1 секунду. Затем возврат переменной test_counter, в которой содержится число итераций цикла за секунду. Чем быстрее выполняется исследуемый участок кода, тем больше это число.

Подсчёт количества строк в тексте (строки разделяются символом новой строки):
Код
function GetLinesCount(str) return #str:gsub("[^\010]","")+1 end

Вернёт число строк в тексте "str", причём если строка пустая, просто 2 раза перевод строки, то будет засчитана как отдельная строка.

Автор: Phazeus 28.6.2010, 2:25

Имейте в виду, что...

Метод

Код
for i in pairs(t) do
работает примерно в 6 раз медленее, чем
Код
for i=1,#t do
Таким образом, для перебора элементов таблицы с последовательными числовыми индексами лучше пользоваться вторым способом.

Ещё интересный факт. Если мы имеем строку, которую нужно преобразовать в число (строка заведомо является корректным числом), то быстрее работает метод преобразования в число проведением какой-либо математической операции, например, сложения. Таким образом, вариант:
Код
local str="12345"
str=str+0

работает примерно в 1,8 раза быстрее, чем такой вариант:
Код
local str="12345"
str=tonumber(str)
Это касается и метода tostring(n), который, хоть и совсем немного, но медленнее, чем n.."".

Автор: Setuper 28.6.2010, 9:01

При этом функция tostring отработает корректно вне зависимости от содержимого, то есть даже если не определён метаметод __tostring, что нельзя сказать о неявном преобразовании, которое происходит при конкатенации.
Поэтому тут палка с двумя концами: либо быстродействие, либо стабильная работа скрипта.

Кстати, сравнивать цикл

Код
for i=1,#t do
и цикл
Код
for i in pairs(t) do
как минимум не корректно, так как второй является более широким. Если уж и сравнивать, то с циклом
Код
for i in ipairs(t) do

Кроме этого также имеет значение то, что мы делаем внутри цикла. Дело в том, что в первом цикле при обращении к элементу таблицы нам нужно будет вызывать операцию получения значения по индексу t[i]. Во втором же варианте значение автоматически возвращается вторым аргументом:
Код
for i,v in ipairs(t) do
i - это индекс, v - это значение. Поэтому всё зависит от ситуации, в которой мы используем цикл big_smile.gif

Автор: ivan683 14.7.2010, 20:31

Сделал копию топика с другого форума чтобы можно было здесь продолжить начатое там дело.

Код
function new_string_builder()
    local string_table = {}
    local object = {}
    
    function object.insert(...)
        for idx, str in ipairs({...}) do
            table.insert(string_table, idx, str)
        end
    end
    
    function object.add(...)
        for idx, str in ipairs({...}) do
            table.insert(string_table, str)
        end
    end
    
    function object.get(spliter)
        spliter = spliter or ""
        return table.concat(string_table, spliter)
    end
    
    function object.empty()
        return not next(string_table)
    end
    
    function object.len()
        local len = 0
        for index, str in ipairs(string_table) do
            len = len + #str
        end
        return len
    end
    
    return object
end


Данная функция возвращает "объект" который используется как буфер при генерации очень большого текста составляемого из большого количества маленьких кусочков.

Использование.

Код
buf = new_string_builder()

for i = 0, 10 do
    buf.add(i.." ")
end

print(buf.get())


Результат.
Код
0 1 2 3 4 5 6 7 8 9 10

Автор: Setuper 14.7.2010, 22:44

Данный код годится только для старой версии lua. Для lua 5.1 нужно самому определять arg.

Код
local arg = {...}


Кстати да, для склада lua функций уже есть отдельная тема

Автор: Nickolya 26.7.2010, 0:42

ivan683, http://mydc.ru/index.html?showtopic=753&view=findpost&p=31916, в твоем посту я заменил все в соответствии с замечанием Setuper'а, если есть желание - выкладывай и те функции что были.

Автор: alex82 17.1.2011, 5:44

Оптимизированная функция Serialize:

Код
function Serialize(tTable, sTableName, hFile, sTab)
    sTab = sTab or ""
    hFile:write(sTab,sTableName," = {\n")
    for key, value in pairs(tTable) do
        local sKey = (type(key) == "string") and ("[%q]"):format(key) or ("[%d]"):format(key)
        if type(value) == "table" then
            Serialize(value, sKey, hFile, sTab.."\t")
        else
            hFile:write(sTab,"\t",sKey," = ",(type(value) == "string") and ("%q"):format(value) or tostring(value))
        end
        hFile:write(",\n")
    end
    hFile:write(sTab,"}")
end


Функция, выводящая содержимое таблицы в консоль:
Код
function table.print(tTable, sTableName, sTab, bComma)
    sTab = sTab or ""
    print(sTableName and sTab..sTableName.." = {" or sTab.."{")
    for key, value in pairs(tTable) do
        local sKey = (type(key) == "string") and ("[%q]"):format(key) or ("[%d]"):format(key)
        if type(value) == "table" then
            table.print(value, sKey, sTab.."\t",true)
        else
            print(sTab.."\t"..sKey.." = "..((type(value) == "string") and ("%q"):format(value) or tostring(value))..",")
        end
    end
    print(sTab.."}"..(bComma and "," or ""))
end
Параметр sTableName указывать не обязательно. Параметры sTab и bComma используются при рекурсивном вызове функции. Следовательно, не нужно указывать их при вызове вручную.

Автор: Setuper 17.1.2011, 10:02

Вместо tprint наверное table.print ?
И если функция print стандартная lua функция, то наверное лучше в ней тоже не использовать конкатенацию, а сделать как в Serialize.
То есть, вместо

Код
print(a..b..c..d)
юзать
Код
print(a, b, c, d)
а на вставку табов между аргументами я думаю можно забить, хотя возможно будет кривовато отображаться big_smile.gif

Автор: alex82 17.1.2011, 17:30

Цитата(Setuper @ 17.1.2011, 9:02) *
Вместо tprint наверное table.print ?
Исправил
Цитата(Setuper @ 17.1.2011, 9:02) *
И если функция print стандартная lua функция, то наверное лучше в ней тоже не использовать конкатенацию, а сделать как в Serialize.
То есть, вместо
Код
print(a..b..c..d)
юзать
Код
print(a, b, c, d)
а на вставку табов между аргументами я думаю можно забить, хотя возможно будет кривовато отображаться big_smile.gif
Оно действительно будет некрасиво отображаться. Совсем некрасиво.

Поскольку функция отладочная, на оптимизацию, думаю, можно забить.

Автор: Nickolya 17.1.2011, 21:01

Я как-то в порыве отказа от конкатенаций сделал вот такое, порой использую так же для отладки и раздаю всем для этих же целей, вот код:

Код
function SerializeToString(tTable, sTableName, sTab)
    local tTableConcat = {}
    local sTab = sTab or ""
    table.insert(tTableConcat, sTab)
    table.insert(tTableConcat, sTableName and sTableName.." = {\r\n" or "return {\r\n")
    for key, value in pairs(tTable) do
        local sKey = (type(key) == "string") and ("[%q]"):format(key) or ("[%d]"):format(key)
        if(type(value) == "table") then
            table.insert(tTableConcat, SerializeToString(value, sKey, sTab.."\t"))
        else
            local sValue = (type(value) == "string") and string.format("%q",value) or tostring(value)
            table.insert(tTableConcat, sTab)
            table.insert(tTableConcat, "\t")
            table.insert(tTableConcat, sKey)
            table.insert(tTableConcat, " = ")
            table.insert(tTableConcat, sValue)
        end
        table.insert(tTableConcat, ",\r\n")
    end
    table.insert(tTableConcat, sTab)
    table.insert(tTableConcat, "}")
    return table.concat(tTableConcat)
end

Автор: alex82 18.1.2011, 2:07

Функция преобразования кодировки cp1251 в cp866, необходимая для правильного отображения символов кириллицы в консоли Windows:

Код
local CP866 = {
    [160] = 255, [161] = 246, [162] = 247, [164] = 253, [168] = 240,
    [170] = 242, [175] = 244, [176] = 248, [178] = 73,  [179] = 105,
    [183] = 250, [184] = 241, [185] = 252, [186] = 243, [191] = 245,
}
function string.tooem(str)
    return (str:gsub("[Ђ-я]",function(c)
        c = c:byte()
        if c >= 192 and c <= 239 then
            return string.char(c-64)
        elseif c >= 240 then
            return string.char(c-16)
        elseif CP866[c] then
            return string.char(CP866[c])
        else
            return "?"
        end
    end))
end

Автор: alcorp 2.2.2011, 11:17

Цитата(Serx @ 25.2.2010, 22:03) *
Если у файла в названии есть кириллица, то его имя преобразовывается в какой-то код (в магнет-ссылке)
Например "мистер" в %D0%BC%D0%B8%D1%81%D1%82%D0%B5%D1%80
Нагуглил только то, что это URI Кодирование, но откуда берутся "%D0" или "%D1" не понимаю...
Ну и сам вопрос: как в LUA произвести эту конвертацию?


Имя файла конвертировать НЕ нужно, потому как они по умолчанию в утф8, а вот перекодировать из формата урл, можно следующей функцией:

Код
function unescape (s)
      s = string.gsub(s, "+", " ")
      s = string.gsub(s, "%%(%x%x)", function (h)
            return string.char(tonumber(h, 16))
          end)
      return s
    end

Автор: alex82 20.2.2011, 12:48

Функция проверки пароля на безопасность:

Код
tSequence = {
    {"q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "a", "s", "d", "f", "g", "h", "j", "k", "l", "z", "x", "c", "v", "b", "n", "m",},
    {"m", "n", "b", "v", "c", "x", "z", "l", "k", "j", "h", "g", "f", "d", "s", "a", "p", "o", "i", "u", "y", "t", "r", "e", "w", "q",},
    {"й", "ц", "у", "к", "е", "н", "г", "ш", "щ", "з", "х", "ъ", "ф", "ы", "в", "а", "п", "р", "о", "л", "д", "ж", "э", "я", "ч", "с", "м", "и", "т", "ь", "б", "ю",},
    {"ю", "б", "ь", "т", "и", "м", "с", "ч", "я", "э", "ж", "д", "л", "о", "р", "п", "а", "в", "ы", "ф", "ъ", "х", "з", "щ", "ш", "г", "н", "е", "к", "у", "ц", "й",},
    {"1", "2", "3", "4", "5", "6", "7", "8", "9", "0",},
    {"0", "9", "8", "7", "6", "5", "4", "3", "2", "1",},
}

function CheckPassword(pass)
    local passlen = #pass
    if passlen < 2 then return true end

    local tpass = {}
    for i = 1,passlen do
        table.insert(tpass,pass:sub(i,i))
    end

    local success = false
    for i = 2,passlen do
        if tpass[i] ~= tpass[1] then
            success = true
            break
        end
    end
    if not success then
        return false, "Пароль не может состоять из одинаковых символов"
    end
    for i,v in ipairs(tSequence) do
        success = false
        local first
        for n,c in ipairs(v) do
            if c == tpass[1] then
                first = n
                break
            end
        end
        if first then
            for i = 2,passlen do
                first = first+1
                if not v[first] or v[first] ~= tpass[i] then
                    success = true
                    break
                end
            end
            if not success then
                return false, "Пароль не может состоять из клавиатурных последовательностей (qwerty, 123456, и.т.д.)"
            end
        end
    end
    return true
end

Функция возвращает false и сообщене об ошибке, если пароль состоит из одинаковых символов или клавиатурной последовательности. В противном случае возвращает true.

Обратите внимание: функция не приводит пароль к нижнему регистру. Вам необходимо сделать это самостоятельно перед вызовом функции.

http://mydc.ru/topic4691.html

Автор: ivan683 25.9.2011, 21:32

 serialize3.lua ( 8.28 килобайт ) : 22
Ловите монстра. ))

Собственно работает так:

Код
serialize(table, write_fnc)


С table я думаю понятно а вот write_fnc это функция которой по ходу выполнения передаются куски текста. Тем самым давая возможность оптимизировать способ его сборки.

Если результат нужно вывести в файл то делается так:
Код
local file = io.open("file_name.lua","w")
file:write("x = ")
serialize(_G, function(part) file:write(part) end)


Ну либо в сочетании со http://mydc.ru/topic334.html?view=findpost&p=31869
Код
var builder = new_string_builder()
builder.add("return ")
serialize(_G, builder.add)
print(builder.get())


Ах да. Забыл сказать о преимуществах.
1 Генерирует красивый и понятный код.
2 Восстанавливает внутренние связи.
3 Проверяет особые случаи (бесконечность, -бесконечность, неопределённость).
4 Дампит функции если возможно.

P.S. совсем забыл что перед результатом деятельности этой функции надо записать либо "x=" либо "return " (Исправил примеры)

Используется мной здесь: http://mydc.ru/r/?https://github.com/ivan386/lua-dht

Автор: Enyby 23.1.2012, 0:46

Функции для создания лога быстрой отладки. Строки лога содержатся в памяти, причем не более чем iMaxFastDebug строк. При добавлении новой строки самый старый вариант удалятся, т. н. ротация сообщений.

Код
local tFastDebug = {}
local iMaxFastDebug = 30

function LogFastDebug(sMsg) if #tFastDebug >= iMaxFastDebug then table.remove(tFastDebug, 1) end table.insert(tFastDebug, sMsg) end
function GetFastDebug() local sRet = "" for i, sMsg in ipairs(tFastDebug) do sRet = sRet..i..". "..sMsg.."\n" end return sRet end


Пример использования
Сообщает раз в 10 секунд операторам лог входа/выхода пользователей.
Код
function UserConnected(tUser)
    LogFastDebug(os.time().." "..tUser.sNick.." connected")
end
OpConnected, RegConnected = UserConnected, UserConnected

function UserDisconnected(tUser)
    LogFastDebug(os.time().." "..tUser.sNick.." disconnected")
end
OpDisconnected, RegDisconnected = UserDisconnected, UserDisconnected

function OnStartup()
    for _, tUser in ipairs(Core.GetOnlineUsers()) do
        UserConnected(tUser)
    end
    TmrMan.AddTimer(10*1000, "CheckPtokaX")
end

function CheckPtokaX()
    Core.SendToOps(GetFastDebug())
end

local tFastDebug = {}
local iMaxFastDebug = 30

function LogFastDebug(sMsg)
    if #tFastDebug >= iMaxFastDebug then
        table.remove(tFastDebug, 1)
    end
    table.insert(tFastDebug, sMsg)
end

function GetFastDebug()
    local sRet = ""
    for i, sMsg in ipairs(tFastDebug) do
        sRet = sRet..i..". "..sMsg.."\n"
    end
    return sRet
end

Автор: Alexey 30.1.2013, 20:56

В Lua5.2 удалили функцию table.maxn и предлагают писать её на Луа самостоятельно, если она действительно нужна. Вот три варианта этой функции, если кому надо:

Код
table.maxn = function(t)
    local maxn = 0
    for i in pairs(t) do
        if type(i) == "number" and i > maxn then
            maxn = i
        end
    end
    return maxn
end
Код
table.maxn = function(t)
    local maxn, i = 0
    repeat
        i = next(t,i)
        if type(i) == "number" and i > maxn then
            maxn = i
        end
    until not i
    return maxn
end
Код
table.maxn = function(t)
    local maxn, i = 0, next(t)
    while i do
        if type(i) == "number" and i > maxn then
            maxn = i
        end
        i = next(t,i)
    end
    return maxn
end


PS: Понимаю, что в большинстве случаев можно прекрасно обойтись без этой функции, внося минимум правок, но не всегда хочется погружаться в глубины старого чужого говнокода.

Автор: Setuper 31.1.2013, 9:05

Эм... функцию ipairs похоже тоже удалили.

Интересно а оператор #t будет работать?

Автор: Alexey 31.1.2013, 12:11

Функция ipairs на месте, но она тут не подходит, как и оператор #.
Стояла цель написать замену table.maxn с максимально похожим поведением, а не что-то другое. Проверка идентичности результатов работы функций на Lua 5.1.4:

Код
local t = {"aaa", "bbb", ["a1"] = "xxx", [5] = "zzz"}
print(table.maxn1(t), table.maxn2(t), table.maxn3(t), table.maxn(t), #t)

5       5       5       5       2

Предполагается, что авторы скриптов знали как работает эта функция и применяли её с умом, иначе — ССЗБ и не я им доктор.

Автор: Setuper 31.1.2013, 20:18

http://mydc.ru/r/?http://www.corsix.org/content/look-lua-52-work3

Цитата
19. ipairs, table.maxn, and math.log10 all deprecated

Автор: Alexey 31.1.2013, 21:31

Зачем ссылаться на обсуждение черновой версии, вышедшей за полтора года до релиза? Давай лучше посмотрим в официальное эталонное руководство по Lua 5.2.

Не все изменения из черновика попали в релиз
http://mydc.ru/r/?http://www.lua.org/manual/5.2/manual.html#8.2

ipairs осталась в 5.2
http://mydc.ru/r/?http://www.lua.org/manual/5.2/manual.html#pdf-ipairs

Автор: Tsd 22.2.2014, 12:35

Может кому пригодится...
Функция автоматически определяет кодировку (ansi\utf-8) в сообщении и возвращает сообщение в ansi, если оно в utf-8 или nil при ошибке конвертации.
Для правильной работы необходима библиотека iconv

Код
local tRus = {
"А","Б","В","Г","Д","Е",--[["Ё",]]"Ж","З","И","Й","К","Л","М","Н","О","П",--[["Р","С",]]"Т","У","Ф","Х","Ц","Ч","Ш","Щ","Ы","Ъ","Ь","Э","Ю","Я",
"а","б","в","г","д","е",--[["ё",]]"ж","з","и","й","к","л","м","н","о","п",--[["р","с",]]"т","у","ф","х","ц","ч","ш","щ","ь","ы","ъ","э","ю","я"
}

function DecodeMsg(s)
    for _,v in pairs (tRus) do
        if string.find(s,v) then return s end
    end
    s = (s:convert("utf-8","cp1251"))
    return s
end


 iconv.zip ( 34.76 килобайт ) : 20
 

Автор: MIKHAIL 25.2.2019, 0:06

Для функции Utf8ToAnsi(s) из http://mydc.ru/topic334.html?view=findpost&p=2276

Код
function Utf8ToAnsi(s)
    ...
    if b < 128 then
        if nmdc[b] then
            r = r..nmdc[b]
        else
            r = r..string.char(b)
        end
    ...
end

несовсем очевидна необходимость подобного преобразования протокольных разделителей "$" и "|", ведь вплоть до 128 ASCII-символа ничего не меняется, да и не экранируются они тут – как были в UTF-8 так и остались в ANSI.

Я это вижу так:

Код
function Utf8ToAnsi(s)
    ...
    if b < 128 then
        r = r..string.char(b)
    ...
end

Подскажите, где я не прав?

Автор: Ksan 25.2.2019, 19:51

MIKHAIL, ну проверьте сами. Какие проблемы?
(вдаваться в тонкости не стал, сейчас не до того, но добрый совет "проверьте сами" я всегда готов дать)..

Автор: Sacrificer 10.8.2022, 11:16

Добрый день
Прошу помощи в такой проблеме. Нужена функция (именно lua) которая берет английские буквы и переделывает их в русские и функция с обратным процессом. Кодировка UTF-8 в обоих случаях. Простая транслитерация.
Шаблон такой:
'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd', 'е' => 'e', 'ж' => 'zh', 'з' => 'z', 'и' => 'i', 'й' => 'y', 'к' => 'k', 'л' => 'l', 'м' => 'm', 'н' => 'n','о' => 'o', 'п' => 'p', 'р' => 'r',
'с' => 's', 'т' => 't', 'у' => 'u', 'ф' => 'f', 'х' => 'h', 'ц' => 'ts', 'ч' => 'ch', 'ш' => 'sh', 'щ' => 'sch', 'ь' => '', 'ы' => 'y', 'ъ' => '','э' => 'e', 'ю' => 'yu', 'я' => 'ya','А' => 'A',
'Б' => 'B', 'В' => 'V', 'Г' => 'G','Д' => 'D','Е' => 'E', 'Ж' => 'Zh', 'З' => 'Z', 'И' => 'I','Й' => 'Y', 'К' => 'K', 'Л' => 'L', 'М' => 'M', 'Н' => 'N','О' => 'O', 'П' => 'P', 'Р' => 'R',
'С' => 'S', 'Т' => 'T','У' => 'U', 'Ф' => 'F', 'Х' => 'H', 'Ц' => 'Ts', 'Ч' => 'Ch','Ш' => 'Sh', 'Щ' => 'Sch', 'Ь' => '', 'Ы' => 'Y', 'Ъ' => '','Э' => 'E', 'Ю' => 'Yu', 'Я' => 'Ya'