2011-03-09 46 views
4

需要編碼&解碼字節流(可能包含非ascii字符),從/到uint16,uint32,uint64(它們的典型C/C++含義)關心排序。什麼是有效的&有希望跨平臺的方式在Lua做這樣的事情?Lua處理非ASCII字節流,字節序改變

我的目標拱是64位的x86_64,但想保持它的便攜性(如果它不會在性能方面花費我)。

例如

解碼(比如目前在一個Lua字符串) - 爲0x00,0x1d,0xFF時,0×23,×44,0x32(小端) 爲 - UINT16:(0x1d00)= 7424 UINT32:(0x324423ff)= 843326463

如果有人可以用一個例子來解釋會很好。

回答

4

看看structlpack庫。

在這個例子中,我使用struct.unpack到Lua的字符串解碼成兩個整數強迫小尾數編碼:

require 'struct' 
-- convert character codes to a Lua string - this may come from your source 
local str = string.char(0x00, 0x1d, 0xff, 0x23, 0x44, 0x32) 
-- format string: < = little endian, In = unsigned int (n bytes) 
local u16, u32 = struct.unpack('<I2I4', str) 
print(u16, u32) --> 7424 843326463 
+0

看起來很簡單和優雅,但我似乎沒有'結構'擴展模塊。 luarocks無法通過錯誤來編譯/安裝。將嘗試解決這個問題,並嘗試這一點。謝謝! – 2011-03-09 20:24:18

+0

@ michal-kottman,在修復luarocks並安裝'struct'之後嘗試了代碼,但是對於第二個參數解包(即str)不是字符串的第二個參數。調試我試過這個小代碼(這不小心,但似乎並沒有像預期的那樣工作 - '> str = string.char(0x00,0xff)' '> local u16 = struct.unpack( ' print(u16)' 'nil' – 2011-03-10 14:30:19

+0

@ michal-kottman,對不起!修正了它,需要在Lua 5.1中稍作修改(至少在我的系統中)。 a:'struct = require(「struct」)' – 2011-03-10 15:35:29

6

從字節轉換爲int(注意字節序的字節級和符號性):

function bytes_to_int(str,endian,signed) -- use length of string to determine 8,16,32,64 bits 
    local t={str:byte(1,-1)} 
    if endian=="big" then --reverse bytes 
     local tt={} 
     for k=1,#t do 
      tt[#t-k+1]=t[k] 
     end 
     t=tt 
    end 
    local n=0 
    for k=1,#t do 
     n=n+t[k]*2^((k-1)*8) 
    end 
    if signed then 
     n = (n > 2^(#t*8-1) -1) and (n - 2^(#t*8)) or n -- if last bit set, negative. 
    end 
    return n 
end 

雖然我們在這也向另一個方向:

function int_to_bytes(num,endian,signed) 
    if num<0 and not signed then num=-num print"warning, dropping sign from number converting to unsigned" end 
    local res={} 
    local n = math.ceil(select(2,math.frexp(num))/8) -- number of bytes to be used. 
    if signed and num < 0 then 
     num = num + 2^n 
    end 
    for k=n,1,-1 do -- 256 = 2^8 bits per char. 
     local mul=2^(8*(k-1)) 
     res[k]=math.floor(num/mul) 
     num=num-res[k]*mul 
    end 
    assert(num==0) 
    if endian == "big" then 
     local t={} 
     for k=1,n do 
      t[k]=res[n-k+1] 
     end 
     res=t 
    end 
    return string.char(unpack(res)) 
end 

任何歡迎您發表評論,但已經過測試,但不會太透徹...

+0

非常具有教學意義。我似乎已經通過你的說明性例子認真學習了一大堆Lua。 – 2011-03-09 19:43:37

+1

在函數bytes_to_int中,行 n =(n> 2 ^(#t-1)-1)和(n-2 ^#t)或者n 我想應該是#t * 8而不是#t。是你想要的位數,而不是字節。 – 2014-02-10 11:04:40

+0

看來你是對的!感謝您的建議,我在我的回答中糾正了它。 – jpjacobs 2014-02-10 15:22:48

0

我的建議爲「Int16ToByte」 - 函數沒有參數檢查:

function Int16ToBytes(num, endian) 
    if num < 0 then 
     num = num & 0xFFFF 
    end 

    highByte = (num & 0xFF00) >> 8 
    lowByte = num & 0xFF 

    if endian == "little" then 
     lowByte, highByte = highByte, lowByte 
    end 

    return string.char(highByte,lowByte) 
end