Burrows–Wheeler transform: Difference between revisions

Content added Content deleted
No edit summary
m (→‎{{header|Phix}}: added syntax colouring, marked p2js compatible)
Line 1,942: Line 1,942:
An efficient implementation, based mainly on http://spencer-carroll.com/an-easy-to-understand-explanation-of-the-burrows-wheeler-transform/ <br>
An efficient implementation, based mainly on http://spencer-carroll.com/an-easy-to-understand-explanation-of-the-burrows-wheeler-transform/ <br>
Takes around about ten seconds to transform and invert a 100K string. Note: requires 0.8.0+
Takes around about ten seconds to transform and invert a 100K string. Note: requires 0.8.0+
<lang Phix>--demo\rosetta\burrows_wheeler.exw
<!--<lang Phix>(phixonline)-->
<span style="color: #000080;font-style:italic;">-- demo\rosetta\burrows_wheeler.exw
--/*
--/*
The traditional method:
The traditional method:

7 banana$ $banana 6
6 $banana ===> a$banan 5
7 banana$ $banana 6
5 a$banan ana$ban 3
6 $banana ===&gt; a$banan 5
4 na$bana sort anana$b 1
5 a$banan ana$ban 3
3 ana$ban banana$ 7
4 na$bana sort anana$b 1
2 nana$ba ===> na$bana 4
3 ana$ban banana$ 7
1 anana$b nana$ba 2
2 nana$ba ===&gt; na$bana 4
^ desired answer == "annb$aa"
1 anana$b nana$ba 2
^ desired answer == "annb$aa"

First ignore the numbers: the desired answer is found by creating a table of all
First ignore the numbers: the desired answer is found by creating a table of all
rotations of "banana$", sorting it, and then extracting the right-hand column.
rotations of "banana$", sorting it, and then extracting the right-hand column.

However, there is no need to actually create such a table, which could be very
However, there is no need to actually create such a table, which could be very
expensive for long strings, instead just number them logically (admittedly that
expensive for long strings, instead just number them logically (admittedly that
was somewhat arbitrarily chosen to get the indexes to work out nicely, I picked
was somewhat arbitrarily chosen to get the indexes to work out nicely, I picked
the original index of the last character), and perform a custom sort on those.
the original index of the last character), and perform a custom sort on those.

The latter effectively just recreates the rotations one character at a time until
The latter effectively just recreates the rotations one character at a time until
there is a mismatch (which there always will be since there is only one $).
there is a mismatch (which there always will be since there is only one $).
The left hand column is my arbitrary numbering scheme and the right hand column
The left hand column is my arbitrary numbering scheme and the right hand column
is those sorted into order, which is also the indexes to the original string of
is those sorted into order, which is also the indexes to the original string of
the characters that we want.
the characters that we want.

The code below uses $ as the terminator, but eg 1 (== '\#01') should be fine,
The code below uses $ as the terminator, but eg 1 (== '\#01') should be fine,
except of course for the display of that on a console.
except of course for the display of that on a console.
--*/
--*/</span>
constant terminator = '$'
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>

<span style="color: #008080;">constant</span> <span style="color: #000000;">terminator</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">'$'</span>
function rot_sort(integer i,j, sequence s)
-- i,j are indexes of the last character, so bump before first compare.
<span style="color: #008080;">function</span> <span style="color: #000000;">rot_sort</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">,</span><span style="color: #000000;">j</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">sequence</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">)</span>
-- eg/ie rot_sort(i,j,s) should yield compare(rotate(s,i),rotate(s,j)),
<span style="color: #000080;font-style:italic;">-- i,j are indexes of the last character, so bump before first compare.
-- as in rot_sort(7,6,"banana$") == compare("banana$","$banana")
-- eg/ie rot_sort(i,j,s) should yield compare(rotate(s,i),rotate(s,j)),
-- - but one character at a time rather than constructing both.
-- as in rot_sort(7,6,"banana$") == compare("banana$","$banana")
integer l = length(s)
-- - but one character at a time rather than constructing both.</span>
while true do
<span style="color: #004080;">integer</span> <span style="color: #000000;">l</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span>
i = mod(i,l)+1
<span style="color: #008080;">while</span> <span style="color: #004600;">true</span> <span style="color: #008080;">do</span>
j = mod(j,l)+1
<span style="color: #000000;">i</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">mod</span><span style="color: #0000FF;">(</span><span style="color: #000000;">i</span><span style="color: #0000FF;">,</span><span style="color: #000000;">l</span><span style="color: #0000FF;">)+</span><span style="color: #000000;">1</span>
integer c = compare(s[i],s[j])
<span style="color: #000000;">j</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">mod</span><span style="color: #0000FF;">(</span><span style="color: #000000;">j</span><span style="color: #0000FF;">,</span><span style="color: #000000;">l</span><span style="color: #0000FF;">)+</span><span style="color: #000000;">1</span>
if c!=0 then return c end if
<span style="color: #004080;">integer</span> <span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">compare</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">j</span><span style="color: #0000FF;">])</span>
end while
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">c</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end function
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>

<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
function burrows_wheeler_transform(string s)
if find(terminator,s) then ?9/0 end if
<span style="color: #008080;">function</span> <span style="color: #000000;">burrows_wheeler_transform</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">)</span>
s &= terminator
<span style="color: #008080;">if</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">terminator</span><span style="color: #0000FF;">,</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #008000;">"error"</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
integer l = length(s)
<span style="color: #000000;">s</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">terminator</span>
sequence t = custom_sort(routine_id("rot_sort"),tagset(l),{s})
<span style="color: #004080;">integer</span> <span style="color: #000000;">l</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span>
string res = repeat(' ',l)
<span style="color: #004080;">sequence</span> <span style="color: #000000;">t</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">custom_sort</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">routine_id</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"rot_sort"</span><span style="color: #0000FF;">),</span><span style="color: #7060A8;">tagset</span><span style="color: #0000FF;">(</span><span style="color: #000000;">l</span><span style="color: #0000FF;">),{</span><span style="color: #000000;">s</span><span style="color: #0000FF;">})</span>
for i=1 to l do
<span style="color: #004080;">string</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">' '</span><span style="color: #0000FF;">,</span><span style="color: #000000;">l</span><span style="color: #0000FF;">)</span>
res[i] = s[t[i]]
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">l</span> <span style="color: #008080;">do</span>
end for
<span style="color: #000000;">res</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">t</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]]</span>
return res
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
end function
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span>

<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
--/*
Inversion. The traditional method is add column and sort, seven times,
<span style="color: #000080;font-style:italic;">--/*
to reconstruct the table above, then pick the entry that ends with the
Inversion. The traditional method is add column and sort, seven times,
marker. Showing that technique in full detail here is not helpful, and
to reconstruct the table above, then pick the entry that ends with the
like above that would be hideously inefficient for large strings.
marker. Showing that technique in full detail here is not helpful, and

like above that would be hideously inefficient for large strings.
$banana 1 $ (1 ) a 2
a$banan 2 a ( 1) n 6
ana$ban 3 a ( 2) n 7
$banana 1 $ (1 ) a 2
anana$b 4 a ( 3) b 5
a$banan 2 a ( 1) n 6
banana$ 5 b $ 1
ana$ban 3 a ( 2) n 7
na$bana 6 n (2 ) a 3
anana$b 4 a ( 3) b 5
nana$ba 7 n (3 ) a 4
banana$ 5 b $ 1
^ ^ ^ ^ ^
na$bana 6 n (2 ) a 3
f l f l t
nana$ba 7 n (3 ) a 4
^ ^ ^ ^ ^

f l f l t
However, we already have the last column, and the first is just that
sorted alphabetically, and with just those two, we have all possible
However, we already have the last column, and the first is just that
character pairings of the original message. The trick is in figuring
sorted alphabetically, and with just those two, we have all possible
out how to stitch them together in the right order. If you carefully
character pairings of the original message. The trick is in figuring
study the three that end in a, and the three that start in a, notice
the $banan,na$ban,nana$b parts are sorted in the same order, whether
out how to stitch them together in the right order. If you carefully
study the three that end in a, and the three that start in a, notice
they are prefixed with a or not. That is, the middle (parenthesised)
the $banan,na$ban,nana$b parts are sorted in the same order, whether
matching numbers are both 123, not 123 and say 231. It is quite hard
they are prefixed with a or not. That is, the middle (parenthesised)
to see that being useful, but eventually the penny should drop. The
matching numbers are both 123, not 123 and say 231. It is quite hard
right-hand 1 with an a rotated right gives the left-hand 1, and the
to see that being useful, but eventually the penny should drop. The
same goes for 2 and 3: they are in fact links to the prior pairing.
right-hand 1 with an a rotated right gives the left-hand 1, and the

In other words the first a in l always corresponds to the first in f,
same goes for 2 and 3: they are in fact links to the prior pairing.
the second to the second, and so on, and that (amazingly) forms the
In other words the first a in l always corresponds to the first in f,
order in which the pairings need to be daisy-chained together.
the second to the second, and so on, and that (amazingly) forms the

order in which the pairings need to be daisy-chained together.
Try following (1->)2a->6n->3a->7n->4a->5b->$, == reverse("banana"),
in the above f and t tables.
Try following (1-&gt;)2a-&gt;6n-&gt;3a-&gt;7n-&gt;4a-&gt;5b-&gt;$, == reverse("banana"),

in the above f and t tables.
The code below builds a queue of 'a' ({1,6,7}, built backwards) from
l (aka s), into which we pop into t the {2,3,4} of the 'a' in f, and
The code below builds a queue of 'a' ({1,6,7}, built backwards) then
likewise for all other letters, forming the links for each pairing.
we pop {2,3,4} into those slots in t as we find 'a' in f, likewise
See the trivial step 3 scan below, then go back and stare at f and
for all other letters, forming the links for each pairing as shown.
t as shown above, and once again, eventually the penny should drop.
See the trivial step 3 scan below, then go back and stare at f and
I will admit I had to read ten or so explanations before I got it.
t as shown above, and once again, eventually the penny should drop.

I will admit I had to read ten or so explanations before I got it.
--*/
--*/</span>

function inverse_burrows_wheeler(string s)
<span style="color: #008080;">function</span> <span style="color: #000000;">inverse_burrows_wheeler</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">)</span>
if find('\0',s) then ?9/0 end if -- (doable, but needs some +1s)
<span style="color: #008080;">if</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'\0'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> <span style="color: #000080;font-style:italic;">-- (doable, but needs some +1s)</span>
integer l = length(s), c
<span style="color: #004080;">integer</span> <span style="color: #000000;">l</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">),</span> <span style="color: #000000;">c</span>
string f = sort(s)
<span style="color: #004080;">string</span> <span style="color: #000000;">f</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sort</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span>
sequence q = repeat(0,256), -- queue heads (per char)
<span style="color: #004080;">sequence</span> <span style="color: #000000;">q</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">256</span><span style="color: #0000FF;">),</span> <span style="color: #000080;font-style:italic;">-- queue heads (per char)</span>
x = repeat(0,l), -- queue links
<span style="color: #000000;">x</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">l</span><span style="color: #0000FF;">),</span> <span style="color: #000080;font-style:italic;">-- queue links</span>
t = repeat(0,l) -- reformed/pairing links
<span style="color: #000000;">t</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">l</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- reformed/pairing links
-- Step 1. discover/build queues (backwards)
-- Step 1. discover/build queues (backwards)</span>
for i=l to 1 by -1 do
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">l</span> <span style="color: #008080;">to</span> <span style="color: #000000;">1</span> <span style="color: #008080;">by</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
c = s[i]
<span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
x[i] = q[c]
<span style="color: #000000;">x</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">q</span><span style="color: #0000FF;">[</span><span style="color: #000000;">c</span><span style="color: #0000FF;">]</span>
q[c] = i
<span style="color: #000000;">q</span><span style="color: #0000FF;">[</span><span style="color: #000000;">c</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">i</span>
end for
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
-- Step 2. reform/pop char queues into pairing links
<span style="color: #000080;font-style:italic;">-- Step 2. reform/pop char queues into pairing links</span>
for i=1 to l do
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">l</span> <span style="color: #008080;">do</span>
c = f[i]
<span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">f</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
t[q[c]] = i
<span style="color: #000000;">t</span><span style="color: #0000FF;">[</span><span style="color: #000000;">q</span><span style="color: #0000FF;">[</span><span style="color: #000000;">c</span><span style="color: #0000FF;">]]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">i</span>
q[c] = x[q[c]]
<span style="color: #000000;">q</span><span style="color: #0000FF;">[</span><span style="color: #000000;">c</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">[</span><span style="color: #000000;">q</span><span style="color: #0000FF;">[</span><span style="color: #000000;">c</span><span style="color: #0000FF;">]]</span>
end for
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
-- Step 3. rebuild (backwards)
<span style="color: #000080;font-style:italic;">-- Step 3. rebuild (backwards)</span>
c = find(terminator,f)
<span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">terminator</span><span style="color: #0000FF;">,</span><span style="color: #000000;">f</span><span style="color: #0000FF;">)</span>
string res = repeat(' ',l-1)
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #008000;">"error"</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
for i=l-1 to 1 by -1 do
<span style="color: #004080;">string</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">' '</span><span style="color: #0000FF;">,</span><span style="color: #000000;">l</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
c = t[c] -- (first time in, skip the end marker)
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">l</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">1</span> <span style="color: #008080;">by</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
res[i] = f[c]
<span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">t</span><span style="color: #0000FF;">[</span><span style="color: #000000;">c</span><span style="color: #0000FF;">]</span> <span style="color: #000080;font-style:italic;">-- (first time in, skip the end marker)</span>
end for
<span style="color: #000000;">res</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">f</span><span style="color: #0000FF;">[</span><span style="color: #000000;">c</span><span style="color: #0000FF;">]</span>
return res
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
end function
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span>

<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
procedure test(string src)
string enc = burrows_wheeler_transform(src),
<span style="color: #008080;">procedure</span> <span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">src</span><span style="color: #0000FF;">)</span>
dec = inverse_burrows_wheeler(enc)
<span style="color: #004080;">string</span> <span style="color: #000000;">enc</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">burrows_wheeler_transform</span><span style="color: #0000FF;">(</span><span style="color: #000000;">src</span><span style="color: #0000FF;">),</span>
printf(1,"original: %s --> %s\n inverse: %s\n",{src,enc,dec})
<span style="color: #000000;">dec</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">inverse_burrows_wheeler</span><span style="color: #0000FF;">(</span><span style="color: #000000;">enc</span><span style="color: #0000FF;">)</span>
end procedure
<span style="color: #000000;">src</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">shorten</span><span style="color: #0000FF;">(</span><span style="color: #000000;">src</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"characters"</span><span style="color: #0000FF;">)</span>

<span style="color: #000000;">enc</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">shorten</span><span style="color: #0000FF;">(</span><span style="color: #000000;">enc</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"characters"</span><span style="color: #0000FF;">)</span>
test("banana")
<span style="color: #000000;">dec</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">shorten</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dec</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"characters"</span><span style="color: #0000FF;">)</span>
test("dogwood")
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"original: %s --&gt; %s\n inverse: %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">src</span><span style="color: #0000FF;">,</span><span style="color: #000000;">enc</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dec</span><span style="color: #0000FF;">})</span>
test("TO BE OR NOT TO BE OR WANT TO BE OR NOT?")
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
test("SIX.MIXED.PIXIES.SIFT.SIXTY.PIXIE.DUST.BOXES")</lang>
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"banana"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"dogwood"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"TO BE OR NOT TO BE OR WANT TO BE OR NOT?"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"SIX.MIXED.PIXIES.SIFT.SIXTY.PIXIE.DUST.BOXES"</span><span style="color: #0000FF;">)</span>
<!--</lang>-->
{{out}}
{{out}}
<pre>
<pre>