Data update

This commit is contained in:
Ingy döt Net 2026-04-30 12:34:36 -04:00
parent 4bb20c9b71
commit cbaf4c4b64
12390 changed files with 318560 additions and 27248 deletions

View file

@ -0,0 +1,11 @@
package LZW is
MAX_CODE : constant := 4095;
type Codes is new Natural range 0 .. MAX_CODE;
type Compressed_Data is array (Positive range <>) of Codes;
function Compress (Cleartext : in String) return Compressed_Data;
function Decompress (Data : in Compressed_Data) return String;
end LZW;

View file

@ -0,0 +1,116 @@
with Ada.Containers.Ordered_Maps;
with Ada.Strings.Unbounded;
package body LZW is
package UStrings renames Ada.Strings.Unbounded;
use type UStrings.Unbounded_String;
--------------
-- Compress --
--------------
function Compress (Cleartext : in String) return Compressed_Data is
-- translate String to Code-ID
package String_To_Code is new Ada.Containers.Ordered_Maps (
Key_Type => UStrings.Unbounded_String,
Element_Type => Codes);
Dictionary : String_To_Code.Map;
-- Next unused Code-ID
Next_Entry : Codes := 256;
-- maximum same length as input, compression ratio always >=1.0
Result : Compressed_Data (1 .. Cleartext'Length);
-- position for next Code-ID
Result_Index : Natural := 1;
-- current and next input string
Current_Word : UStrings.Unbounded_String :=
UStrings.Null_Unbounded_String;
Next_Word : UStrings.Unbounded_String :=
UStrings.Null_Unbounded_String;
begin
-- initialize Dictionary
for C in Character loop
String_To_Code.Insert
(Dictionary,
UStrings.Null_Unbounded_String & C,
Character'Pos (C));
end loop;
for Index in Cleartext'Range loop
-- add character to current word
Next_Word := Current_Word & Cleartext (Index);
if String_To_Code.Contains (Dictionary, Next_Word) then
-- already in dictionary, continue with next character
Current_Word := Next_Word;
else
-- insert code for current word to result
Result (Result_Index) :=
String_To_Code.Element (Dictionary, Current_Word);
Result_Index := Result_Index + 1;
-- add new Code to Dictionary
String_To_Code.Insert (Dictionary, Next_Word, Next_Entry);
Next_Entry := Next_Entry + 1;
-- reset current word to one character
Current_Word := UStrings.Null_Unbounded_String &
Cleartext (Index);
end if;
end loop;
-- Last word was not entered
Result (Result_Index) :=
String_To_Code.Element (Dictionary, Current_Word);
-- return correct array size
return Result (1 .. Result_Index);
end Compress;
----------------
-- Decompress --
----------------
function Decompress (Data : in Compressed_Data) return String is
-- translate Code-ID to String
type Code_To_String is array (Codes) of UStrings.Unbounded_String;
Dictionary : Code_To_String;
-- next unused Code-ID
Next_Entry : Codes := 256;
-- initialize resulting string as empty string
Result : UStrings.Unbounded_String := UStrings.Null_Unbounded_String;
Next_Code : Codes;
-- first code has to be in dictionary
Last_Code : Codes := Data (1);
-- suffix appended to last string for new dictionary entry
Suffix : Character;
begin
-- initialize Dictionary
for C in Character loop
Dictionary (Codes (Character'Pos (C))) :=
UStrings.Null_Unbounded_String & C;
end loop;
-- output first Code-ID
UStrings.Append (Result, Dictionary (Last_Code));
for Index in 2 .. Data'Last loop
Next_Code := Data (Index);
if Next_Code <= Next_Entry then
-- next Code-ID already in dictionary -> append first char
Suffix := UStrings.Element (Dictionary (Next_Code), 1);
else
-- next Code-ID not in dictionary -> use char from last ID
Suffix := UStrings.Element (Dictionary (Last_Code), 1);
end if;
-- expand the dictionary
Dictionary (Next_Entry) := Dictionary (Last_Code) & Suffix;
Next_Entry := Next_Entry + 1;
-- output the current Code-ID to result
UStrings.Append (Result, Dictionary (Next_Code));
Last_Code := Next_Code;
end loop;
-- return String
return UStrings.To_String (Result);
end Decompress;
end LZW;

View file

@ -0,0 +1,21 @@
with LZW;
with Ada.Text_IO;
procedure Test is
package Text_IO renames Ada.Text_IO;
package Code_IO is new Ada.Text_IO.Integer_IO (LZW.Codes);
Test_Data : constant LZW.Compressed_Data :=
LZW.Compress ("TOBEORNOTTOBEORTOBEORNOT");
begin
for Index in Test_Data'Range loop
Code_IO.Put (Test_Data (Index), 0);
Text_IO.Put (" ");
end loop;
Text_IO.New_Line;
declare
Cleartext : constant String := LZW.Decompress (Test_Data);
begin
Text_IO.Put_Line (Cleartext);
end;
end Test;

View file

@ -12,7 +12,7 @@ auto compress(in string original) pure nothrow {
w = w ~ ch;
else {
result ~= dict[w];
dict[w ~ ch] = dict.length;
dict[w ~ ch] = cast(int)dict.length;
w = [ch];
}
return w.empty ? result : (result ~ dict[w]);

View file

@ -9,7 +9,7 @@ struct LZW {
enum int initDictSize = 256;
static immutable ubyte[initDictSize] bytes;
static this() {
shared static this() {
foreach (immutable T i; 0 .. initDictSize)
bytes[i] = i;
}
@ -18,7 +18,7 @@ struct LZW {
out(result) {
if (!original.empty)
assert(result[0] < initDictSize);
} body {
} do {
if (original.empty)
return [];
Tcomp[Ta] dict;
@ -57,7 +57,7 @@ struct LZW {
in {
if (!compressed.empty)
assert(compressed[0] < initDictSize, "Bad compressed");
} body {
} do {
if (compressed.empty)
return [];

View file

@ -8,7 +8,7 @@ enum Marker: ushort {
ubyte[] lzwEncode(scope const(ubyte)[] inp, in uint maxBits) pure nothrow
in {
assert(maxBits >= 9 && maxBits <= 16);
} body {
} do {
// Encode dictionary array. For encoding, entry at
// code index is a list of indices that follow current one,
// i.e. if code 97 is 'a', code 387 is 'ab', and code 1022 is 'abc',
@ -148,7 +148,7 @@ ubyte[] lzwDecode(scope const(ubyte)[] inp) pure {
}
clearTable(); // In case encoded bits didn't start with Marker.CLR.
for (len = inp.length; len;) {
for (len = cast(int)inp.length; len;) {
getCode();
if (code == Marker.EOD)
break;

View file

@ -2,7 +2,7 @@ type LzwCompression
fun compress ← List by text uncompressed
List output ← int[]
text working ← Text.EMPTY
Map symbolTable ← text%int[].with(256, <int i|text%int(chr(i) => i))
Map symbolTable ← text%int[].with(256, <int i|text%int(chr(i) i))
for each text c in uncompressed
text augmented ← working + c
if symbolTable.has(augmented)
@ -21,7 +21,7 @@ fun compress ← List by text uncompressed
return output
end
fun decompress ← text by List compressed
Map symbolTable ← int%text[].with(256, <int i|int%text(i => chr(i)))
Map symbolTable ← int%text[].with(256, <int i|int%text(i chr(i)))
text working ← symbolTable[compressed[0]]
text output ← *working
for each int i in compressed.extract(1)
@ -39,7 +39,7 @@ fun decompress ← text by List compressed
end
return output
end
List compressed = compress("TOBEORNOTTOBEORTOBEORNOT")
List compressed compress("TOBEORNOTTOBEORTOBEORNOT")
writeLine(compressed)
text decompressed = decompress(compressed)
text decompressed decompress(compressed)
writeLine(decompressed)

View file

@ -1,95 +1,95 @@
package main
import (
"fmt"
"log"
"strings"
"fmt"
"log"
"strings"
)
// Compress a string to a list of output symbols.
func compress(uncompressed string) []int {
// Build the dictionary.
dictSize := 256
// We actually want a map of []byte -> int but
// slices are not acceptable map key types.
dictionary := make(map[string]int, dictSize)
for i := 0; i < dictSize; i++ {
// Ugly mess to work around not having a []byte key type.
// Using `string(i)` would do utf8 encoding for i>127.
dictionary[string([]byte{byte(i)})] = i
}
// Build the dictionary.
dictSize := 256
// We actually want a map of []byte -> int but
// slices are not acceptable map key types.
dictionary := make(map[string]int, dictSize)
for i := 0; i < dictSize; i++ {
// Ugly mess to work around not having a []byte key type.
// Using `string(i)` would do utf8 encoding for i>127.
dictionary[string([]byte{byte(i)})] = i
}
var result []int
var w []byte
for i := 0; i < len(uncompressed); i++ {
c := uncompressed[i]
wc := append(w, c)
if _, ok := dictionary[string(wc)]; ok {
w = wc
} else {
result = append(result, dictionary[string(w)])
// Add wc to the dictionary.
dictionary[string(wc)] = dictSize
dictSize++
//w = []byte{c}, but re-using wc
wc[0] = c
w = wc[:1]
}
}
var result []int
var w []byte
for i := 0; i < len(uncompressed); i++ {
c := uncompressed[i]
wc := append(w, c)
if _, ok := dictionary[string(wc)]; ok {
w = wc
} else {
result = append(result, dictionary[string(w)])
// Add wc to the dictionary.
dictionary[string(wc)] = dictSize
dictSize++
//w = []byte{c}, but re-using wc
wc[0] = c
w = wc[:1]
}
}
if len(w) > 0 {
// Output the code for w.
result = append(result, dictionary[string(w)])
}
return result
if len(w) > 0 {
// Output the code for w.
result = append(result, dictionary[string(w)])
}
return result
}
type BadSymbolError int
func (e BadSymbolError) Error() string {
return fmt.Sprint("Bad compressed symbol ", int(e))
return fmt.Sprint("Bad compressed symbol ", int(e))
}
// Decompress a list of output symbols to a string.
func decompress(compressed []int) (string, error) {
// Build the dictionary.
dictSize := 256
dictionary := make(map[int][]byte, dictSize)
for i := 0; i < dictSize; i++ {
dictionary[i] = []byte{byte(i)}
}
// Build the dictionary.
dictSize := 256
dictionary := make(map[int][]byte, dictSize)
for i := 0; i < dictSize; i++ {
dictionary[i] = []byte{byte(i)}
}
var result strings.Builder
var w []byte
for _, k := range compressed {
var entry []byte
if x, ok := dictionary[k]; ok {
//entry = x, but ensuring any append will make a copy
entry = x[:len(x):len(x)]
} else if k == dictSize && len(w) > 0 {
entry = append(w, w[0])
} else {
return result.String(), BadSymbolError(k)
}
result.Write(entry)
var result strings.Builder
var w []byte
for _, k := range compressed {
var entry []byte
if x, ok := dictionary[k]; ok {
//entry = x, but ensuring any append will make a copy
entry = x[:len(x):len(x)]
} else if k == dictSize && len(w) > 0 {
entry = append(w, w[0])
} else {
return result.String(), BadSymbolError(k)
}
result.Write(entry)
if len(w) > 0 {
// Add w+entry[0] to the dictionary.
w = append(w, entry[0])
dictionary[dictSize] = w
dictSize++
}
w = entry
}
return result.String(), nil
if len(w) > 0 {
// Add w+entry[0] to the dictionary.
w = append(w, entry[0])
dictionary[dictSize] = w
dictSize++
}
w = entry
}
return result.String(), nil
}
func main() {
compressed := compress("TOBEORNOTTOBEORTOBEORNOT")
fmt.Println(compressed)
decompressed, err := decompress(compressed)
if err != nil {
log.Fatal(err)
}
fmt.Println(decompressed)
compressed := compress("TOBEORNOTTOBEORTOBEORNOT")
fmt.Println(compressed)
decompressed, err := decompress(compressed)
if err != nil {
log.Fatal(err)
}
fmt.Println(decompressed)
}

View file

@ -0,0 +1,51 @@
function compressLZW(decompressed::String)
dictsize = 256
dict = Dict{String,Int}(string(Char(i)) => i for i in 0:dictsize)
result = Vector{Int}(undef, 0)
w = ""
for c in decompressed
wc = string(w, c)
if haskey(dict, wc)
w = wc
else
push!(result, dict[w])
dict[wc] = dictsize
dictsize += 1
w = string(c)
end
end
if !isempty(w) push!(result, dict[w]) end
return result
end
function decompressLZW(compressed::Vector{Int})
dictsize = 256
dict = Dict{Int,String}(i => string('\0' + i) for i in 0:dictsize)
result = IOBuffer()
w = string(Char(compressed[1]))
write(result, w)
for k in compressed[2:end]
if haskey(dict, k)
entry = dict[k]
elseif k == dictsize
entry = string(w, w[1])
else
error("bad compressed k: $k")
end
write(result, entry)
dict[dictsize] = string(w, entry[1])
dictsize += 1
w = entry
end
return String(take!(result))
end
original = ["0123456789", "TOBEORNOTTOBEORTOBEORNOT", "dudidudidudida"]
compressed = compressLZW.(original)
decompressed = decompressLZW.(compressed)
for (word, comp, decomp) in zip(original, compressed, decompressed)
comprate = (length(word) - length(comp)) / length(word) * 100
println("Original: $word")
println("-> Compressed: $comp (compr.rate: $(round(comprate, digits=2))%)\n-> Decompressed: $decomp")
end

View file

@ -0,0 +1,72 @@
""" Trie node struct """
mutable struct TrieNode{T}
children::Vector{Int} # child node indices (0 = none)
code::T # LZW code for this node's phrase
end
TrieNode(code::Int) = TrieNode{Int}(zeros(Int, 256), code)
""" LZW compression """
function compressLZW(input::Vector{UInt8})
if isempty(input)
return Int[]
end
nodes = [TrieNode(i) for i in 0:255]
push!(nodes, TrieNode(-1))
root = length(nodes) # == 257
@inbounds for b in 0:255
nodes[root].children[b+1] = b + 1 # initialize root children
end
sizehint!(nodes, length(input) + root)
result = Int[]
sizehint!(result, length(input))
dictsize = 256 # next code to assign
current = nodes[root].children[input[1]+1] # guaranteed to exist
@inbounds for i in 2:length(input)
c = input[i]
nxt = nodes[current].children[c+1]
if nxt != 0
current = nxt
else
push!(result, nodes[current].code)
dictsize += 1
push!(nodes, TrieNode(dictsize - 1))
new_idx = length(nodes)
nodes[current].children[c+1] = new_idx
current = nodes[root].children[c+1]
end
end
push!(result, nodes[current].code) # add last remaining
return result
end
""" LZW decompression """
function decompressLZW(compressed::Vector{Int})
isempty(compressed) && return UInt8[]
dict = [[UInt8(i)] for i in 0:255]
dictsize = 256
w = copy(dict[compressed[1]+1])
output = copy(w)
@inbounds for k in Iterators.drop(compressed, 1)
entry = k + 1 <= length(dict) ? dict[k+1] :
k == dictsize ? vcat(w, w[1]) : error("Bad compressed code: $k")
append!(output, entry)
push!(dict, vcat(w, entry[1]))
dictsize += 1
w = entry
end
return output
end
const texts = ["0123456789", "TOBEORNOTTOBEORTOBEORNOT", "dudidudidudida"]
const inputs = [Vector{UInt8}(t) for t in texts]
const compressed = compressLZW.(inputs)
const decompressed = decompressLZW.(compressed)
for (orig, comp, decomp) in zip(texts, compressed, decompressed)
comprate = (length(orig) - length(comp)) / length(orig) * 100
println("Original: $orig")
println("→ Compressed: $comp (rate: $(round(comprate, digits=2))%)")
println("→ Decompressed: $(String(decomp))\n")
end

View file

@ -0,0 +1,49 @@
-- demo\rosetta\LZW_compression.exw
with javascript_semantics
function compress(string uncompressed)
integer dict = new_dict(), dictSize = 255, c
sequence result = {}
string word = ""
for i=0 to 255 do setd(""&i,i,dict) end for
for c in uncompressed do
if getd_index(word&c,dict) then
word &= c
else
result &= getd(word,dict)
dictSize += 1
setd(word&c,dictSize,dict)
word = ""&c
end if
end for
if word!="" then
result &= getd(word,dict)
end if
destroy_dict(dict)
return result
end function
function decompress(sequence compressed)
integer dict = new_dict(), dictSize = 255, k, ki
string dent = "", result = "", word = ""
for i=0 to 255 do setd(i,""&i,dict) end for
for k in compressed do
if getd_index(k,dict) then
dent = getd(k,dict)
elsif k=dictSize then
dent = word&word[1]
else
crash("error")
end if
result &= dent
setd(dictSize,word&dent[1],dict)
dictSize += 1
word = dent
end for
destroy_dict(dict)
return result
end function
constant example = "TOBEORNOTTOBEORTOBEORNOT"
sequence com = compress(example)
pp(com,{pp_IntCh,true,pp_Maxlen,90})
?decompress(com)

View file

@ -0,0 +1,195 @@
-- demo\rosetta\LZW_compression.exw
with javascript_semantics
constant CLR = 256, -- Clear table marker
EOD = 257, -- End-of-data marker
NEW = 258 -- New code index
integer bits, tmp, oBits
function finished_bytes(integer x)
sequence bytes = {}
tmp = (tmp << bits) + x
oBits += bits
while oBits >= 8 do
oBits -= 8
assert(floor(tmp/power(2,oBits)) <= 255)
bytes &= floor(tmp/power(2,oBits))
tmp = and_bits(tmp, power(2,oBits)-1)
end while
return bytes
end function
function lzwEncode(sequence inp, integer maxBits)
assert(maxBits>=9 and maxBits<=16)
// Encode dictionary array. For encoding, entry at code index
// is a list of indices that follow current one, for example
// if code 97 is 'a', code 287 is 'ab', and code 922 is 'abc',
// then dict[97]['b'+1] = 287, dict[287]['c'+1] = 922, etc.
sequence dict = repeat(repeat(0,256),512),
result = {}
oBits = 0
tmp = 0
bits = 9
integer nextCode = NEW,
nextShift = 512
integer code = inp[1]
for c in inp from 2 do
integer nc = dict[code+1][c+1]
if nc!=0 then
code = nc
else
result &= finished_bytes(code)
nc = nextCode
dict[code+1][c+1] = nc
nextCode += 1
code = c
end if
// Next new code would be too long for current table.
if nextCode = nextShift then
// "Early increment", matches compress and GIF use,
// some TIFF variants do a "Late increment" instead.
bits += 1
// Either reset table back to 9 bits...
if bits>maxBits then
// Table clear marker must occur before bit reset.
result &= finished_bytes(CLR)
bits = 9
nextShift = 512
nextCode = NEW
dict = repeat(repeat(0,256),512)
else // ... or extend table.
nextShift *= 2
while length(dict)<nextShift do
dict = append(dict,repeat(0,256))
end while
end if
end if
end for
result &= finished_bytes(code)
result &= finished_bytes(EOD)
if tmp!=0 then
assert(tmp<=#FFFF,"tmp > 16 bits")
result &= finished_bytes(tmp)
end if
return result
end function
--
-- For decoding, dictionary contains index of whatever prefix
-- index plus trailing ubyte. i.e. like previous example,
-- dict[1022] = { c: 'c', prev: 387 },
-- dict[387] = { c: 'b', prev: 97 },
-- dict[97] = { c: 'a', prev: 0 }
-- the "back" element is used for temporarily chaining indices
-- when resolving a code to bytes.
--
enum PREV, BACK, CH -- decode dict entry subscripts
sequence dict
integer nextShift, nextCode -- (and re-using bits)
procedure clearTable()
dict = repeat({0,0,0},512)
for j=0 to 255 do
dict[j+1][CH] = j
end for
nextCode = NEW
nextShift = 512
bits = 9
end procedure
function lzwDecode(sequence inp)
sequence result = {}
integer len = length(inp),
idx = 1,
code = 0,
nBits = 0,
tmp = 0
clearTable() // In case encoded bits didn't start with CLR.
while idx<=len do
while nBits < bits do
if idx<=len then
tmp = (tmp << 8) + inp[idx]
idx += 1
nBits += 8
else
tmp = tmp << (bits-nBits)
nBits = bits
end if
end while
nBits -= bits
code = floor(tmp/power(2,nBits))
tmp = and_bits(tmp,power(2,nBits)-1)
if code=EOD then exit end if
if code=CLR then
clearTable()
elsif code>=nextCode then
crash("Bad sequence")
else
integer c = code
dict[nextCode+1][PREV] = c
while c>255 do
integer t = dict[c+1][PREV]
dict[t+1][BACK] = c
c = t
end while
dict[nextCode][CH] = c
integer cc = c+1
while dict[cc][BACK]!=0 do
result &= dict[cc][CH]
integer t = dict[cc][BACK]
dict[cc][BACK] = 0
cc = t+1
end while
result &= dict[cc][CH]
nextCode += 1
if nextCode>=nextShift then
// "Early increment", must match encode.
bits += 1
// If input was correct, we'd have hit a CLR.
if bits>16 then crash("Too many bits") end if
nextShift *= 2
while length(dict)<nextShift do
dict = append(dict,repeat(0,3))
end while
end if
end if
end while
if code!=EOD then crash("Bits did not end in EOD") end if
return result
end function
procedure main()
sequence inputData = get_text(`demo\unixdict.txt`,GT_BINARY)
integer li = length(inputData)
printf(1,"Input size: %d\n",li)
sequence encoded = lzwEncode(inputData,12)
integer le = length(encoded)
printf(1,"Encoded size: %d (%d%%)\n",{le,le/li*100})
sequence decoded = lzwDecode(encoded)
printf(1,"Decoded size: %d\n",length(decoded))
if length(inputData)!=length(decoded) then
printf(1,"Error: decoded size differs\n")
return
end if
for i=1 to length(inputData) do
if inputData[i]!=decoded[i] then
printf(1,"Bad decode at %d\n",i)
return
end if
end for
puts(1,"Decoded OK.\n")
end procedure
main()

View file

@ -0,0 +1,62 @@
class lzw
-- Compress a string to a list of output symbols.
static function compress(uncompressed)
-- Build the dictionary.
local dict_size = 256
local dictionary = {}
for i = 0, dict_size - 1 do dictionary[string.char(i)] = i end
local w = ""
local result = {}
local len = #uncompressed
for {string.byte(uncompressed, 1, len)} as c do
local cs = string.char(c)
local wc = w .. cs
if dictionary[wc] then
w = wc
else
result:insert(dictionary[w])
-- Add wc to the dictionary.
dictionary[wc] = dict_size
dict_size += 1
w = cs
end
end
-- Output the code for w
if w != "" then result:insert(dictionary[w]) end
return result
end
-- Decompress a list of output symbols to a string.
static function decompress(compressed)
-- Build the dictionary.
local dict_size = 256
local dictionary = {}
for i = 0, dict_size - 1 do dictionary[i] = string.char(i) end
local w = string.char(compressed[1])
local result = w
for i = 2, #compressed do
local k = compressed[i]
local entry
if dictionary[k] then
entry = dictionary[k]
elseif k == dict_size then
entry = w .. string.char(string.byte(w[1]))
else
error($"Bad compressed k: {k}")
end
result ..= entry
-- Add w .. entry[1] to the dictionary.
dictionary[dict_size] = w .. string.char(string.byte(entry[1]))
dict_size += 1
w = entry
end
return result
end
end
local compressed = lzw.compress("TOBEORNOTTOBEORTOBEORNOT")
print(compressed:concat(", "))
local decompressed = lzw.decompress(compressed)
print(decompressed)

View file

@ -0,0 +1,85 @@
compressLZW <- function(decompressed) {
dictsize <- 256
# Create dictionary with characters 0-255
dict <- list()
for (i in 0:255) {
dict[[intToUtf8(i)]] <- i
}
result <- c()
w <- ""
# Split string into characters
chars <- strsplit(decompressed, "")[[1]]
for (c in chars) {
wc <- paste0(w, c)
if (!is.null(dict[[wc]])) {
w <- wc
} else {
result <- c(result, dict[[w]])
dict[[wc]] <- dictsize
dictsize <- dictsize + 1
w <- c
}
}
if (w != "") {
result <- c(result, dict[[w]])
}
return(result)
}
decompressLZW <- function(compressed) {
dictsize <- 256
# Create reverse dictionary with integers 0-255 mapping to characters
dict <- list()
for (i in 0:255) {
dict[[as.character(i)]] <- intToUtf8(i)
}
result <- ""
w <- intToUtf8(compressed[1])
result <- paste0(result, w)
if (length(compressed) > 1) {
for (i in 2:length(compressed)) {
k <- compressed[i]
if (!is.null(dict[[as.character(k)]])) {
entry <- dict[[as.character(k)]]
} else if (k == dictsize) {
entry <- paste0(w, substr(w, 1, 1))
} else {
stop(paste("bad compressed k:", k))
}
result <- paste0(result, entry)
dict[[as.character(dictsize)]] <- paste0(w, substr(entry, 1, 1))
dictsize <- dictsize + 1
w <- entry
}
}
return(result)
}
# Test the functions
original <- c("0123456789", "TOBEORNOTTOBEORTOBEORNOT", "dudidudidudida")
compressed <- lapply(original, compressLZW)
decompressed <- lapply(compressed, decompressLZW)
# Print results
for (i in 1:length(original)) {
word <- original[i]
comp <- compressed[[i]]
decomp <- decompressed[[i]]
comprate <- (nchar(word) - length(comp)) / nchar(word) * 100
cat("Original:", word, "\n")
cat("-> Compressed:", paste(comp, collapse=" "),
sprintf("(compr.rate: %.2f%%)", comprate), "\n")
cat("-> Decompressed:", decomp, "\n\n")
}

View file

@ -0,0 +1,4 @@
bin: compress "TOBEORNOTTOBEORTOBEORNOT" 'lzw
;== #{07544F42454F524E4F54FBF6F3F3A77FDFFEFF}
to string! decompress bin 'lzw
;== "TOBEORNOTTOBEORTOBEORNOT"

View file

@ -0,0 +1,74 @@
Rebol [
title: "Rosetta code: LZW compression"
file: %LZW_compression.r3
url: https://rosettacode.org/wiki/LZW_compression
]
lzw-compress: function [str [string! binary!]] [
;; Initialize dictionary with all single-byte entries (0-255)
;; Keys are binary! series (e.g. #{00}, #{01}, ..., #{FF})
;; Values are their corresponding integer codes
;; Using binary! keys avoids string encoding issues with non-ASCII bytes
dict: copy #[]
for i 0 255 1 [ dict/(join #{} i): i ]
;; w is the current match buffer as a binary! series
;; clear #{} gives us a reusable empty binary! to build patterns into
w: clear #{}
result: copy []
foreach c to binary! str [
;; Extend current pattern by appending the new byte c
;; join creates a new binary! series each time (w is not mutated here)
wc: join w c
either dict/:wc [
;; Extended pattern wc exists in dictionary — keep growing the match
;; w now points to the new longer series wc
w: wc
][
;; Extended pattern wc is new — emit code for longest known match w
append result dict/:w
;; Register the new pattern wc in the dictionary with the next code
dict/:wc: length? dict
;; Reuse w's storage by clearing it and appending just the current byte
;; This avoids allocating a new binary! series for the reset
append clear w c
]
]
;; Flush the last buffered pattern if anything remains in w
if (length? w) > 0 [ append result select dict w ]
result
]
lzw-decompress: function [codes [block!]] [
;; Initialize the reverse dictionary (code -> binary) for ASCII 0-255
;; This is the inverse of the compress dictionary
dict: copy []
for i 0 255 1 [append dict join #{} i]
;; Read the first code and convert it to a binary to start the output
w: join #{} codes/1
result: copy w
foreach code next codes [
unless entry: pickz dict code [
;; Code not yet in dict (pattern references itself)
;; This happens when the encoder emits a code it just added
assert [code = length? dict]
;; The new entry is the previous pattern + its own first byte
entry: join w w/1
]
;; Emit the decoded entry to output
append result entry
;; Add new dictionary entry: previous pattern + first byte of current entry
append dict join w entry/1
;; Current entry becomes the new previous pattern
w: entry
]
to string! result
]
foreach text [
"TOBEORNOTTOBEORTOBEORNOT"
"štěstí v neštěstí"
][
print ["Original: " text]
print ["Compresed: " blk: lzw-compress text]
print ["Decompressed:" lzw-decompress blk]
prin LF
]

View file

@ -0,0 +1,47 @@
fn compress(uncompressed string) []int {
mut wsg := ""
mut result := []int{}
mut dict_size := 256
mut dict := map[string]int{}
for ial in 0 .. 256 { dict[rune(ial).str()] = ial }
for cal in uncompressed.runes() {
wc := wsg + rune(cal).str()
if wc in dict { wsg = wc }
else {
result << dict[wsg]
dict[wc] = dict_size
dict_size++
wsg = rune(cal).str()
}
}
if wsg != "" { result << dict[wsg] }
return result
}
fn decompress(compressed []int) ?string {
mut dict_size := 256
mut dict := map[int]string{}
for ial in 0 .. 256 { dict[ial] = rune(ial).str() }
mut wsg := dict[compressed[0]]
mut result := wsg
for kal in compressed[1..] {
entry := if kal in dict { dict[kal] }
else if kal == dict_size { wsg + wsg[0].ascii_str() }
else { return none }
result += entry
dict[dict_size] = wsg + entry[0].ascii_str()
dict_size++
wsg = entry
}
return result
}
fn main() {
comp := compress("TOBEORNOTTOBEORTOBEORNOT")
println(comp)
decomp := decompress(comp) or {
println("Failed to decompress")
return
}
println(decomp)
}

View file

@ -0,0 +1,74 @@
Option Explicit
Const numchars=127 'plain ASCII
Function LZWCompress(si)
Dim oDict, intMaxCode, i,z,ii,ss,strCurrent,strNext,j
Set oDict = CreateObject("Scripting.Dictionary")
ReDim a(Len(si))
intMaxCode = numchars
For i = 0 To numchars
oDict.Add Chr(i), i
Next
'strCurrent = ofread.ReadText(1)
strCurrent = Left(si,1)
j=0
For ii=2 To Len(si)
strNext = Mid(si,ii,1)
ss=strCurrent & strNext
If oDict.Exists(ss) Then
strCurrent = ss
Else
a(j)=oDict.Item(strCurrent) :j=j+1
intMaxCode = intMaxCode + 1
oDict.Add ss, intMaxCode
strCurrent = strNext
End If
Next
a(j)=oDict.Item(strCurrent)
ReDim preserve a(j)
LZWCompress=a
Set oDict = Nothing
End Function
Function lzwUncompress(sc)
Dim intNext, intCurrent, intMaxCode, i,ss,istr,s,j
s=""
reDim dict(1000)
intMaxCode = numchars
For i = 0 To numchars : dict(i)= Chr(i) : Next
intCurrent=sc(0)
For j=1 To UBound(sc)
ss=dict(intCurrent)
s= s & ss
intMaxCode = intMaxCode + 1
intnext=sc(j)
If intNext<intMaxCode Then
dict(intMaxCode)=ss & Left(dict(intNext), 1)
Else
dict(intMaxCode)=ss & Left(ss, 1)
End If
intCurrent = intNext
Next
s= s & dict(intCurrent)
lzwUncompress=s
End function
Sub printvec(a)
Dim s,i,x
s="("
For i=0 To UBound (a)
s=s & x & a(i)
x=", "
Next
WScript.echo s &")"
End sub
Dim a,b
b="TOBEORNOTTOBEORTOBEORNOT"
WScript.Echo b
a=LZWCompress (b)
printvec(a)
WScript.echo lzwUncompress (a )
wscript.quit 1

View file

@ -0,0 +1,186 @@
const std = @import("std");
const ArrayList = std.ArrayList;
const HashMap = std.HashMap;
const Allocator = std.mem.Allocator;
// Custom hash function for byte slices
fn hashBytes(bytes: []const u8) u64 {
var hash: u64 = 0;
for (bytes) |byte| {
hash = hash *% 31 +% byte;
}
return hash;
}
// Context for HashMap with byte slice keys
const ByteSliceContext = struct {
pub fn hash(self: @This(), key: []const u8) u64 {
_ = self;
return hashBytes(key);
}
pub fn eql(self: @This(), a: []const u8, b: []const u8) bool {
_ = self;
return std.mem.eql(u8, a, b);
}
};
const DictMap = HashMap([]const u8, u32, ByteSliceContext, std.hash_map.default_max_load_percentage);
const ReverseDictMap = HashMap(u32, []const u8, std.hash_map.AutoContext(u32), std.hash_map.default_max_load_percentage);
fn compress(allocator: Allocator, data: []const u8) !ArrayList(u32) {
// Build initial dictionary
var dictionary = DictMap.init(allocator);
defer {
// Clean up allocated dictionary keys
var iterator = dictionary.iterator();
while (iterator.next()) |entry| {
allocator.free(entry.key_ptr.*);
}
dictionary.deinit();
}
// Initialize dictionary with single bytes (0-255)
for (0..256) |i| {
const key = try allocator.alloc(u8, 1);
key[0] = @intCast(i);
try dictionary.put(key, @intCast(i));
}
var w = ArrayList(u8){};
defer w.deinit(allocator);
var compressed = ArrayList(u32){};
for (data) |b| {
// Create wc = w + b
var wc = try w.clone(allocator);
defer wc.deinit(allocator);
try wc.append(allocator, b);
if (dictionary.contains(wc.items)) {
// Update w to wc
w.deinit(allocator);
w = try wc.clone(allocator);
} else {
// Write w to output
if (w.items.len > 0) {
const code = dictionary.get(w.items).?;
try compressed.append(allocator, code);
}
// wc is a new sequence; add it to the dictionary
const new_key = try allocator.dupe(u8, wc.items);
try dictionary.put(new_key, @intCast(dictionary.count()));
// Reset w to single byte b
w.deinit(allocator);
w = ArrayList(u8){};
try w.append(allocator, b);
}
}
// Write remaining output if necessary
if (w.items.len > 0) {
const code = dictionary.get(w.items).?;
try compressed.append(allocator, code);
}
return compressed;
}
fn decompress(allocator: Allocator, data: []const u32) !ArrayList(u8) {
if (data.len == 0) {
return ArrayList(u8){};
}
// Build the dictionary
var dictionary = ReverseDictMap.init(allocator);
defer {
// Clean up allocated dictionary values
var iterator = dictionary.iterator();
while (iterator.next()) |entry| {
allocator.free(entry.value_ptr.*);
}
dictionary.deinit();
}
// Initialize dictionary with single bytes (0-255)
for (0..256) |i| {
const value = try allocator.alloc(u8, 1);
value[0] = @intCast(i);
try dictionary.put(@intCast(i), value);
}
// Get first sequence
const first_entry = dictionary.get(data[0]).?;
var w = try allocator.dupe(u8, first_entry);
defer allocator.free(w);
var decompressed = ArrayList(u8){};
try decompressed.appendSlice(allocator, w);
for (data[1..]) |k| {
var entry: []const u8 = undefined;
var should_free_entry = false;
if (dictionary.contains(k)) {
entry = dictionary.get(k).?;
} else if (k == dictionary.count()) {
// Special case: k is not in dictionary yet
var temp_entry = try allocator.alloc(u8, w.len + 1);
@memcpy(temp_entry[0..w.len], w);
temp_entry[w.len] = w[0];
entry = temp_entry;
should_free_entry = true;
} else {
std.debug.panic("Invalid dictionary key: {}\n", .{k});
}
try decompressed.appendSlice(allocator, entry);
// New sequence; add it to the dictionary
var new_sequence = try allocator.alloc(u8, w.len + 1);
@memcpy(new_sequence[0..w.len], w);
new_sequence[w.len] = entry[0];
try dictionary.put(@intCast(dictionary.count()), new_sequence);
// Update w
allocator.free(w);
w = try allocator.dupe(u8, entry);
if (should_free_entry) {
allocator.free(entry);
}
}
return decompressed;
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const input = "TOBEORNOTTOBEORTOBEORNOT";
var compressed = try compress(allocator, input);
defer compressed.deinit(allocator);
std.debug.print("Compressed: " , .{} );
for (compressed.items) |code| {
std.debug.print("{} ", .{code});
}
std.debug.print("\n" , .{});
var decompressed = try decompress(allocator, compressed.items);
defer decompressed.deinit(allocator);
std.debug.print("Decompressed bytes: " , .{});
for (decompressed.items) |byte| {
std.debug.print("{} ", .{byte});
}
std.debug.print("\n" , .{});
std.debug.print("Decompressed: {s}\n", .{decompressed.items});
}