Click here to monitor SSC

Phil Factor's Phrenetic Phoughts

Simple-Talk columnist
The wilder shores of Transact SQL    Phil on Twitter   Phil on SQL Server Central  Phil on BOS

If you go down to the woods today...

Published Sunday, January 29, 2006 8:59 PM

--On the drawing of  teddy-bears
/*
I have been gently reproached for making my blog too developer-oriented, and geeky; thereby making managers feel neglected. We therefore introduce Teddy, our foray into unashamed  nostalgia in the days of 80x25 character terminals. In those days, immense effort was expended in drawing pictures in this unpromising medium
*/

Create   procedure spTeddy
@teddy varchar(8000)=null output as

Select @teddy='

       (.)_(.)      
       { . . }      
        \_*_/       
      / .   . \     
     {_}     {_}    
       |     |      
      (_}- -{_}     
'

go

--which we can then display with....
Declare @teddy varchar(8000)
Execute spTeddy @teddy=@Teddy output
Select @Teddy


/* at this point I was going to introduce a competition to turn teddy upside down, but in experimenting with the concept I decided it was far too simple for our razor-sharp audience.
You may think... */
Declare @teddy varchar(8000)
Execute spTeddy @teddy=@Teddy output
Select reverse(@Teddy)

/* will do the trick. Well almost, but the results need tidying up
So we introduce a helping function that reverses some of the characters*/
Create function dbo.ufsReplaceChars
(
@String varchar(8000),--the string within which you want the characters substituted
@change varchar(200), --the characters
@ReplaceWith Varchar(200)--the substitutes
)
RETURNS varchar(8000) AS

BEGIN
Declare @ModifiedString Varchar(8000)
if len(@replaceWith)<Len(@Change)
 Select @Change=@Change+space(Len(@Change)-len(@replaceWith))
IF (coalesce(@String,'') ='' )
 select @ModifiedString=@String
else
 WHILE len(@string)>0

  IF CHARINDEX (substring (@String,1,1), @change) = 0
   BEGIN
   SELECT @ModifiedString = coalesce(@ModifiedString,'')
     +substring (@String,1,1)
   select @String=substring (@String,2,len(@String)-1)
   END
  else
   begin
   SELECT @ModifiedString = coalesce(@ModifiedString,'')
    +substring (@ReplaceWith,CHARINDEX (substring (@String,1,1), @change),1)
   select @String=substring (@String,2,len(@String)-1)
   end
RETURN (@ModifiedString)
END


Declare @teddy varchar(8000)
Execute spTeddy @teddy=@Teddy output
Select replace(dbo.ufsReplaceChars(reverse(@Teddy),'_)({}.','¯()}{''')
,char(10)+char(13),'
')

/*
      {¯}- -{¯)     
       |     |      
     {¯}     {¯}    
      \ '   ' /     
        /¯*¯\       
       { ' ' }      
       (')¯(')
      

All very satisfying.

ASCII art is one of the more esoteric parts of Computer science. Since Wikipedia has covered the subject in excellent detail, I need only refer you there http://en.wikipedia.org/wiki/ASCII_art. Someone has even recoded the entire Matrix movie as ASCII.

You'll wonder, as I did, whether one could introduce some compression into the storage of ASCII art. Some ASCII art can get pretty big in size.
Then I got to thinking that I hadn't actually seen a good string compression function around for SQL server

ASCII art generally uses a tiny subset of the ASCII range so storing it in standard ASCII is very uneconomic. . In fact the Teddy is only 14 characters
*/
character  freq.      
---------- -----------
' '        111
char(10)   9
char(13)   9
'_'        7
'.'        6
'}'        5
'{'        4
'('        3
')'        2
'/'        2
'\'        2
'|'        2
'-'        2
'*'        1

/* we can determine this using another helper function that looks at the character count */

create  FUNCTION dbo.uftvCharacterFrequency
/* produces a character count of all the characters in a string
as a frequency table*/
(
 @String varchar(8000)
)
RETURNS
@Results TABLE
(
 [character] varchar(10),
 [freq.] int
)
AS
begin
declare @ii int
Declare @iiMax int
Declare @temp table (Thechar char(1))
Select @ii=1, @iiMax=len( @String)
while @ii<
=@iiMax
 Begin
 insert into @temp select substring( @String,@ii,1)
 Select @ii=@ii+1
 end
insert into @Results
select [character]=
 case
     when ascii(TheChar)>=32 then ''''+TheChar+''''
 else 'char('+convert(Varchar(3),ascii(TheChar))+')' end,
[freq.]= count(*) from @temp group by theChar order by count(*) desc
return
end

/* we can then see what the character frequency of Teddy is with the following code */
Declare @teddy varchar(8000)
Execute spTeddy @teddy=@Teddy output
Select * from dbo.uftvCharacterFrequency(@Teddy)

/* So The competition here is to provide the best compression/Decompression algorithm for reducing the storage requirements for typical ASCII art such as teddy.
This doesn't have to be complex. Even replacing every group of five spaces with a special character reduces Teddy's storage by 38.8%

*/

Comments

 

Marketing said:

Hmm... SQL Bear Compare ...excellent new product idea Phil.
January 30, 2006 7:51 AM
 

Phil Factor said:

I was thinking more of SQL ComBear and SQL Data ComBear
January 30, 2006 1:11 PM
 

Arthur 'Geek' M said:

/* The following procedure stores teddy in 63 bytes, down from 165; but I reckon one could do a lot better. All I have done is to squeeze two characters into one byte. This is because each nibble can contain an integer between 0 and 15. As there are only fourteen characters one can just do a lookup into a string containing all the characters.

n.b. the packed strings are difficult to represent as strings, especially in a web-page, so the stored procedure etc may show a corruption. To mend this, you may need to recompile Teddy2 using the output of @evenShorter below
*/

create procedure spTeddy2
@teddy varchar(8000)=null output
as
Select @Teddy= dbo.ufsUnPacked(replace('##|•„•|1||#|KN|1¡QQ±|#qdqd1||#|HÖÑG1','|',''))
go

Declare @teddy varchar(8000)
Execute spTeddy2 @teddy=@Teddy output
select @Teddy

/* The two routines that do the packing and unpacking are as follows, using Phil's as a basis.*/

Create function dbo.ufsPacked
(
@String varchar(8000)--the raw string
)
RETURNS varchar(8000) AS

BEGIN
Declare @packedString Varchar(8000)
Declare @Range char(16)
Select @range=' '+char(10)+char(13)+'_' +'.'+'}'+'{'+'('+')'+'/'+'\'+'|'+'-'+'*'

IF (coalesce(@String,'') ='')
select @packedString=@String
else
WHILE len(@string)>0
begin
select @packedString=coalesce(@packedString,'')+char(charindex(substring(@string,1,1),@range)+
(charindex(substring(@string,2,1),@range)*16))
select @String=substring(@string,3,len(@string))
end
RETURN (@packedString)
END

create function dbo.ufsUnPacked
(
@packedString varchar(8000)--the raw string
)
RETURNS varchar(8000) AS

BEGIN
Declare @UnPackedString Varchar(8000)
Declare @PackedChar char(1)
Declare @Range char(16)
Select @range=' '+char(10)+char(13)+'_' +'.'+'}'+'{'+'('+')'+'/'+'\'+'|'+'-'+'*'

IF (coalesce(@PackedString,'') ='')
select @UnpackedString=@packedString
else
WHILE len(@packedstring)>0
begin
select @packedChar=substring(@packedString,1,1)
select @unpackedString=coalesce(@unpackedString,'')+substring(@range,ascii(@packedChar) % 16,1)+
substring(@range,ascii(@packedChar) / 16,1)
select @packedString=substring(@packedString,2,len(@packedString))
end
RETURN (@unpackedString)
END
/*
And now to test everything out......
*/

Declare @teddy varchar(8000)
Declare @evenShorter varchar(8000)

Execute spTeddy @teddy=@Teddy output
select [packed length]=len(dbo.ufsPacked(@teddy))
select @evenShorter= replace(dbo.ufsPacked(@teddy),'','|')
Select [packed length, replacing adjacent packed spaces]=len(@EvenShorter)
select dbo.ufsUnPacked(replace(@evenShorter,'|',''))
select dbo.ufsUnPacked(dbo.ufsPacked(@teddy))

January 30, 2006 7:56 PM
 

Phil Factor said:

I wonder if one can huffmanise it?
February 1, 2006 9:06 AM
 

Robert Sterbal said:

There are only a few characters that work with ascii art in non fixed width fonts:

32 ' '
44 ','
46 '.'
58 ':'
59 ';'
105 'i'
108 'l'

so my challenge is to see if anyone can create a generator for ascii art that takes a given ascii art project and creates several variations of these character.

I'm thinking about this for mail signatures, so a mazimum width check would be nice to have too.

March 2, 2006 2:07 PM
 

Phil Factor said:

Robert,
This sounds interesting. Can you give us an example?
March 2, 2006 7:40 PM
 

rsterbal said:

This is not a great example, but I tried an R

Original -

*******
/**////**
/** /**
/*******
/**///**
/** //**
/** //**
// //


* = : and / = l -

:::::::
l::llll::
l:: l::
l:::::::
l::lll::
l:: ll::
l:: ll::
ll ll


* = , and / = :

,,,,,,,
:,,::::,,
:,, :,,
:,,,,,,,
:,,:::,,
:,, ::,,
:,, ::,,
:: ::


* = : and / = :

:::::::
:::::::::
::: :::
::::::::
::::::::
::: ::::
::: ::::
:: ::

* = . and / = .

.......
.........
... ...
........
........
... ....
... ....
.. ..



= l and / = : and * = . -

l.......
:..::::..
:..lll:..
:.......
:..:::..
:..ll::..
:..lll::..
::lllll::


Another eventual goal is create text documentation that opens in the default font in Word that as legible in Arial as it is in Courer, at least for the ascii art figlets (fonts composed from ascii character)

-Robert
March 3, 2006 7:18 PM
 

Phil Factor said:

Yes, I can see that this would be the only way to get ASCII art into comment sections, like this one, that force a proportional font on you.

You'd have to design it in an editor that allowed you to use Arial (Wordpad upwards)

Ah, nostalgia for the old days when one drew graphs in ASCII letters.

I asked the supplier of this BLOG, (currently Communuty Server) if there was a way of specifying a non-proportional font in a comment, but they pretended not to understand the question
March 9, 2006 9:16 AM
 

Cirruzhanxo said:

I am new here,
you shared the nice done place =)
There were a post and author was want to check Assume that I searched not good :-(                       [spam deleted]
(Phil Factor says f******* off and spam somewhere else )
April 16, 2007 11:41 PM
You need to sign in to comment on this blog
<January 2006>
SuMoTuWeThFrSa
25262728293031
1234567
891011121314
15161718192021
22232425262728
2930311234
Automated Script-generation with Powershell and SMO
 In the first of a series of articles on automating the process of building, modifying and copying SQL... Read more...

Converting String Data to XML and XML to String Data
 We all appreciate that, in general, XML documents or fragments are held in strings as text markup. In... Read more...

Geek of the Week: Don Syme
 With the arrival of F# 3.0 Microsoft announced a wide range of improvements such as type providers that... Read more...

How to Document and Configure SQL Server Instance Settings
 Occasionally, when you install identical databases on two different SQL Server instances, they will... Read more...

What's the Point of Using VARCHAR(n) Anymore?
 The arrival of the (MAX) data types in SQL Server 2005 were one of the most popular feature for the... Read more...