Postado Janeiro 11, 2018 7 anos Este é um post popular. Fala rapeize, eu me propus um desafio de criar uma forma de transformar uma string em números que possam ser anexados no storage. Basicamente isso resolve o problema dos TFS anteriores de não conseguir salvar nomes de personagens no storage sem ter que fazer source editing. PS: É óbvio que é mais fácil fazer source editing, mas o desafio era esse e como não é todo mundo que tem source tb pode ser bastante útil. Eu não fechei o código certinho em funções, mas pretendo fazer em breve (agora preciso dormir) e aí eu edito o tópico aqui. Nos testes q eu fiz ele conseguiu serializar e deserializar 5 mil caracteres em 0,01 segundo o que provavelmente faz dele o melhor serializador do gênero xDLimitações: Ele só funciona com um range bem específico de strings, se vc quiser serializar qualquer outra coisa procure um serializador na internet. Ele é capaz de processar tudo que tá dentro do retangulo vermelho Ele só funciona com NO MÁXIMO +- 8k de caracteres, se vc quiser mais que isso vai precisar trocar a função table.concat e talvez umas outras coisinhasO que ele faz: Transforma qualquer texto num numero, divide esse número em espaços de 32 bits e nas posições da memória consecutivas (no exemplo eu to usando uma tabela, mas poderia ser num storage, por ex). Depois ele ainda é capaz de retornar a string original a partir do serial gerado.Funcionamento: por incrivel q pareça a lógica é bem simples, pega o código ascii de cada caractere da string, subtrai 21 para deixar o numero menor (21 é o máximo que a gente consegue encurtar pq 32 - 21 é 11 e 127 - 21 é 106, aí se eu lê-se 10 eu não saberia dizer se é o código do espaço ou dos 5 ultimos ali da tabela) Os storages são int_32 então o maior valor q eu consigo colocar dentro de um storage é 2^31 - 1, aí tudo q eu faço é ir pegando os 10 ultimos numeros e vendo se eles cabem dentro desse limite máximo, se não couber eu pego os 9 ultimos, até caber dentro do limite. Aí eu jogo pra tabela e contabilizo quantas vezes eu to fazendo isso (isso vai ser importante depois qnd formos inserir ou pegar do storage) Como eu já li os lines ultimos numeros da string, eu posso retirar eles e refazer o processo até não restar mais nada. No final dentro da tabela tb vc vai ter no i o numero q vc soma no storage e no v o valor que deve ir pro storage. Pra deserializar o processo é parecido, primeiro eu percorro a tabela concatenando os numeros na ordem inversa e depois vou vendo 2 a 2 se o numero é menor que 11 (nosso menor código ascii que representaria o espaço, lembrando que removemos 21 para encurtar). Se ele for menor então significa que estamos lidando com um dos ultimos numeros da tabela (10X), nesse caso temos que ler 3 numeros ao invés de só 2. Depois de passar tudo pra caractere e concatenar, nos é retornado a string inicial.Código: Mostrar conteúdo oculto local entrada = "Night Wolf" print("String to serialize: "..entrada) local maxValue = (2^31) -1 local bench = os.clock() local function reduceQnt(r, ...) for i = 1, arg.n do arg[i] = arg[i] - r end arg.n = nil return arg end -- Serialize local summ = table.concat(reduceQnt(21, entrada:byte(1, #entrada))) local counter = 0 print("Serial: "..summ) local tb = {} repeat local lines = 10 local tmp = summ:sub(-lines) while (tonumber(tmp) > maxValue or tmp:sub(1, 1) == "0") do lines = lines - 1 tmp = summ:sub(-lines) end tb[#tb + 1] = tmp summ = summ:sub(1, -(lines+1)) counter = counter + 1 until summ == "" -- Unserialize print("Unserializing...") local serial = "" for i = #tb, 1, -1 do serial = serial..tb[i] end local index = 1 local name = "" while (index < serial:len()) do local char = serial:sub(index, index + 1) if tonumber(char) < 11 then char = serial:sub(index, index + 2) index = index + 1 end index = index + 2 name = name..string.char(char + 21) end print("-> "..name) print(string.format("Benchmark: %.5f\n", os.clock() - bench)) Quem quiser testar é só modificar a variável entrada pra qualquer texto que vc quiser e dar run. O resultado aparece na tela a direita.https://repl.it/repls/LongtermVioletTakin Editado Janeiro 13, 2018 7 anos por xWhiteWolf esqueci de colocar text highlight em Lua (veja o histórico de edições)
Postado Janeiro 11, 2018 7 anos Autor Pra quem quiser a versão como função: Mostrar conteúdo oculto local function reduceQnt(r, ...) for i = 1, arg.n do arg[i] = arg[i] - r end arg.n = nil return arg end -- Serialize local function serializeString(data) if type(data) ~= 'string' or #data == 0 then return false end local summ = table.concat(reduceQnt(21, data:byte(1, #data))) local serial = "" local maxValue = (2^31) -1 -- int32 repeat local lines = 10 local tmp = summ:sub(-lines) while (tonumber(tmp) > maxValue or tmp:sub(1, 1) == "0") do lines = lines - 1 tmp = summ:sub(-lines) end serial = tmp..serial -- this is where you can change to intput in a storage. summ = summ:sub(1, -(lines+1)) until summ == "" return serial end -- Unserialize local function unserializeString(serial) local index = 1 local data = "" while (index < serial:len()) do local char = serial:sub(index, index + 1) if tonumber(char) < 11 then char = serial:sub(index, index + 2) index = index + 1 end index = index + 2 data = data..string.char(char + 21) end return data end -- Como usar: local entrada = "Night Wolf" local sr = serializeString(entrada) print(sr) print(unserializeString(sr)) https://repl.it/repls/LongtermVioletTakin
Participe da conversa
Você pode postar agora e se cadastrar mais tarde. Se você tem uma conta, faça o login para postar com sua conta.