Burrows, Wheeler and Back
Pyth, 29 bytes
?tthu+VzSGzz}dzseMS.>L+z\ hlz
Demonstration. Test harness.
This straightforwardly divides into an encoding and decoding segment, with the code deciding which one to use with a ternary.
?tthu+VzSGzz}dzseMS.>L+z\ hlz
Implicit:
z = input()
d = ' '
? }dz If there is a space in the input,
u zz Update G to the result of the following,
with G starting as z and repeating len(z) times:
+V The vectorized sum of
zSG z and sorted(G)
h Take the first such result, which will consist of
the first character of z followed by the
first cyclic permuation of the pre-BWT string,
which must start with ' '.
tt Remove the first two characters and return.
L Otherwise, left-map (map with the variable as the
left parameter and a constant as the right)
.> cyclic right shift
+z\ of z + ' '
hlz over range(len(z)+1)
S Sort the shifted strings,
eM take their last charactes,
s combine into one string and return.
CJam, 41 36 35 bytes
q:XS&LX,{X\.+$}*0=1>XS+_,,\fm<$zW>?
Test it here.
Explanation
q:X e# Read STDIN and store it in X.
S& e# Take the set intersection with " ". We'll use this as a truthy/falsy value to
e# select the correct output later.
# Compute the iBWT:
LX, e# Push an empty array, compute the length of X.
{ e# Run the following block that many times:
X\ e# Push X and pull the other array on top.
.+ e# Add the characters of X to the corresponding line of the other array,
e# i.e. prepend X as a new column.
$ e# Sort the rows.
}*
0= e# Since we just sorted the rows, the first permutation of the output will be
e# one starting with a space, followed by the string we actually want. So just
e# pick the first permutation.
1> e# Remove the leading space.
# Compute the BWT:
XS+ e# Push X and append a space.
_, e# Get that string's length N.
,\ e# Turn it into a range [0 .. N-1], swap it with the string.
fm< e# Map each value in the range to the string shifted left by that many characters.
$ e# Sort the permutations.
zW> e# Transpose the grid and discard all lines but the last.
? e# Choose between the iBWT and the BWT based on whether the input had a space.
Perl 5, 179
Another not-so-good one from me. There are probably some gains to be had in this one, but it's not going to compete with the purpose-built golf languages.
$_=<>;@y=/./g;if(/ /){@x=sort@y;for(1..$#y){@x=sort map$y[$_].$x[$_],0..$#x}
say$x[0]=~/^ (.*)/}else{push@y," ";say map/(.)$/,sort map{$i=$_;join"",
map$y[($_+$i)%@y],0..$#y}0..$#y}
Un-golfed:
# Read input
$_ = <>;
# Get all the chars of the input
my @chars = /./g;
if (/ /) {
# If there's a space, run the IBWT:
# Make the first column of the table
my @working = sort @chars;
# For each remaining character
for (1 .. $#chars) {
# Add the input as a new column to the left of @working,
# then sort @working again
@working = sort map {
$chars[$_] . $working[$_]
} 0 .. $#working;
}
# Print the first element of @working (the one beginning with space), sans space
say $working[0] =~ /^ (.*)/;
} else {
# BWT
# Add a space to the end of the string
push @chars, " ";
# Get all the rotations of the string and sort them
@rows = sort map {
my $offset = $_;
join "", map {
$chars[($_ + $offset) % @chars]
} 0 .. $#chars
} 0 .. $#chars;
# Print all the last characters
say map /(.)$/, @rows;
}