讀取寫入格式

lua-users home
wiki

整數清單

將整數清單壓縮為二進位資料字串通常有其必要性,例如讀取/寫入二進位檔案或實作通訊協定。可以透過很多方式達成。此實作只是假設相對容易使用。

此函式無法處理負數,例如 -86000!

-- This format function packs a list of integers into a binary string.
-- The sizes of the integers can be specified, both little and big endian
-- ordering are supported. The format parameter is a string composed of 
-- ASCII digit numbers, the size in bytes of the corresponding value.
-- Example:
--   write_format(true, "421", 0x12345678, 0x432931, 0x61) returns "xV41)a",
--     a 7 bytes string whose characters are in hex: 78 56 34 12 31 29 61
function write_format(little_endian, format, ...)
  local res = ''
  local values = {...}
  for i=1,#format do
    local size = tonumber(format:sub(i,i))
    local value = values[i]
    local str = ""
    for j=1,size do
      str = str .. string.char(value % 256)
      value = math.floor(value / 256)
    end
    if not little_endian then
      str = string.reverse(str)
    end
    res = res .. str
  end
  return res
end

-- This format function does the inverse of write_format. It unpacks a binary
-- string into a list of integers of specified size, supporting big and little 
-- endian ordering. Example:
--   read_format(true, "421", "xV4.1)a") returns 0x12345678, 0x2931 and 0x61.
function read_format(little_endian, format, str)
  local idx = 0
  local res = {}
  for i=1,#format do
    local size = tonumber(format:sub(i,i))
    local val = str:sub(idx+1,idx+size)
    local value = 0
    idx = idx + size
    if little_endian then
      val = string.reverse(val)
    end
    for j=1,size do
      value = value * 256 + val:byte(j)
    end
    res[i] = value
  end
  return unpack(res)
end

更多整數

此函式無法處理負數,例如 -86000!

Tom N Harris 撰寫的讀取和寫入整數的另一種方式。

-- Read an integer in LSB order.
function stringtonumber(str)
  local function _b2n(exp, num, digit, ...)
    if not digit then return num end
    return _b2n(exp*256, num + digit*exp, ...)
  end
  return _b2n(256, string.byte(str, 1, -1))
end

-- Read an integer in MSB order.
function stringtonumber(str)
  local function _b2n(num, digit, ...)
    if not digit then return num end
    return _b2n(num*256 + digit, ...)
  end
  return _b2n(0, string.byte(str, 1, -1))
end

-- Write an integer in LSB order using width bytes.
function numbertobytes(num, width)
  local function _n2b(width, num, rem)
    rem = rem * 256
    if width == 0 then return rem end
    return rem, _n2b(width-1, math.modf(num/256))
  end
  return string.char(_n2b(width-1, math.modf(num/256)))
end

-- Write an integer in MSB order using width bytes.
function numbertobytes(num, width)
  local function _n2b(t, width, num, rem)
    if width == 0 then return table.concat(t) end
    table.insert(t, 1, string.char(rem * 256))
    return _n2b(t, width-1, math.modf(num/256))
  end
  return _n2b({}, width, math.modf(num/256))
end

位元域

將數字中的位元解壓縮為布林值的函式。
function unpackbits(bits, width)
  local fl = {}
  local num,rem = flags
  for i = 1,width do
    num,rem = math.modf(num/2)
    fl[#fl+1] = rem>=0.5
  end
  return unpack(fl)
end

浮點數

轉換 MSB 順序的 IEEE-754 浮點數。
function convertfloat(str)
  -- Change to b4,b3,b2,b1 to unpack an LSB float
  local b1,b2,b3,b4 = string.byte(str, 1, 4)
  local exponent = (b1 % 128) * 2 + math.floor(b2 / 128)
  if exponent == 0 then return 0 end
  local sign = (b1 > 127) and -1 or 1
  local mantissa = ((b2 % 128) * 256 + b3) * 256 + b4
  mantissa = (math.ldexp(mantissa, -23) + 1) * sign
  return math.ldexp(mantissa, exponent - 127)
end

函式庫

有 C 函式庫可用於壓縮和解壓縮二進位資料。這些函式庫可以處理從 8 至 32 位元的整數(帶正負號或不帶正負號)、IEEE-754 浮點數,外加各種形式的字串等等。請參閱 結構體壓縮

原始引文,Sirmabus:2009 年 9 月 13 日


最新變更 · 偏好設定
編輯 · 歷程
最後編輯時間:格林威治標準時間 2013 年 9 月 18 日,下午 2:02 (差異)