HOME - - - - - Delphi Tutorials TOC - - - - - - Other material for programmers

Delphi tutorial: A complete example- manipulating character strings.

This has good information, and a search button at the bottom of the page

Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

Click here if you want to know more about the source and format of these pages. It may be easier to read this if you re-size the window, so that it does not use the full width of your screen.


Many of my Level Two tutorials address bits and pieces of the whole picture, looking at them quite carefully, although I do try to spare you details which can wait until you need them.

This tutorial, on the other hand, covers a lot of ground, perhaps a little quickly, in order to produce an application which could be an important part of something more than an academic exercise.

It is my hope that you will get a feeling for how applications get built as you follow through this tutorial


This tutorial was written in May 2007, after I had written many of the other tutorials on this site. It was tested with Delphi 2, and should work with little or no modification in any later Delphi. It stays focussed better than some of my tutorials do!

Please take the trouble to struggle through these introductory remarks? They are the worst part of this tutorial. I've tried to edit them, but not, I fear, with much success yet. Once you get past them, you really do get into some Good and Useful Stuff.....

Very rarely do good things come of rushing into something. Before I start writing the software, I think carefully about specifics of what I want it to do. I often write up an explicit description, and that text, as an extended comment, becomes part of the application's sourcecode. I'll show the description of what this application does in a moment.

While I am planning the details of what an application will do, I also think about what users will see. Once you've done a good job of planning what an application will do, creating the finished product is easier: You "only" have to build the interface (what the users see- form, buttons, edit boxes, memos, etc), and "fill in" the software behind the (virtual) objects of the interface. Programming, actually, ought to be dull. The fun bit is choosing what programming is going to be needed.

The brief description of what the application does, which follows, will, I hope, allow you to infer what the interface looks like.....

The application is a "testbed" for a system that allows a programmer to use as a password or access code any string of characters he or she wishes inside a program even though when humans deal with the password, they will only see strings of characters made up entirely of unambiguous characters. Ever seen something written down and been unsure as to whether a character was an o ("oh") or a 0 ("zero")? And then there's 1s (ones) and l's ("ells"). And so on.

Now! I know what you're thinking: "No, I haven't lost a lot of sleep over these things." Well, maybe not. But pretend you have! Many general techniques are explored in the program developed during this tutorial. There's some nifty work done with characters, strings of characters, conversions back and forth to and from numeric representation of characters, and some work in the area of hex numbers. At the very end, there are two instances of really neat nested loops. The programming of the following application still has things to teach you, even if you don't need the application. Speaking of which, I am finally going to describe the application in action:

Users will see a column of components, which I will describe from top to bottom.

The top component will be an edit box. Users type a string, complete, maybe, with ambiguous characters, into the edit box. (The users are pretending to be a computer, defining a "troublesome" string, so that we can see what the application's answer to that string would be.)

The next component is a button. Click it, and an alternative rendition of the string appears in the fourth component. (The third component is merely a label holding a fixed caption.) The alternative rendition is equivalent to the original... but it doesn't have "oh"s or zeros, or any other characters programmers want to rule out because they think those characters are ambiguous.

Under the translated- to- human- friendly version of the string is another button. When users click it, the application shows that it can convert the human- friendly version back into the original string. It does this by displaying the original version in the application's last component: another label.


Definition: "String": A string of characters, e.g. "Hello World", or "fe23w+r9".

If this software were going to be used as part of some bigger application, typically the human- unfriendly strings would be arising within the application, but a human would sometimes need to deal with at least an equivalent of those strings. Take for instance a system for exchanging encrypted emails. You don't always want to give people complete freedom to choose whatever key comes into their head. Let the computer generate a key, and then tell the human what to pass on to the email's recipient so that the recipient can gain access to the email. Take out the zeros and "oh"s, and you've taken out one way for users to go wrong.

That should give you an idea of what the users are going to see, and that is a very important part of planning any application.

But you also have to plan what is going to go on inside the program. I generally write that up early on, and include the description as comments, or "rems" (remarks) in the sourcecode. You will find that description invaluable if you come back to the sourcecode sometime in the future. And if it is in the sourcecode, it won't be hard to find! Having it there also spares you excuses for failing to keep the description consistent with what is actually going on in the application.

What follows is extracted from the sourcecode of the application this tutorial analyses. It isn't light reading, but do please take a few minutes and get a good grasp of it.

(*Why this application was written. How it works.

Ever been asked to type something like "ABC01ol" into a computer,
to gain access to something? Is that "ABC zero one oh ell"? Or
some other mix of ohs and zeros, ones and ells?

This application will take a string of any printable characters,
and even some characters that aren't "printable" (e.g. a space, or a TAB)
and convert them into a second string... one that does not contain
any troublemakers! You can quite easily modify the code to re-define
"troublemaker".

The resulting string will sometimes be longer than the original... but often it
will not be much longer.

The "code" is not very complex. Don't use it to hide text. But you can use
it to make something that has already been scrambled by another application
harder to mistype.

The application includes a de-coding routine, so that you can get back the
original string, should you need it, say within the application the string
has been typed into.

The method is an extended version of the following. To follow the example,
remember that the ascii for "0" (zero), in hex, is 30, and the ascii for
"o" (lower case oh), in hex, is  6F, and the ascii for "+", in hex is 2B.

Something you don't have to understand, but may help some readers:
We're simple going to use an escape character. (Don't worry if
that doesn't mean anything to you.)

The string ABCo0567+XYZ, when run through my system, becomes...

ABC+gw+da567+2bXYZ

... if the encoding string (more on this in a moment) is...

These letters:           abcdefghjkmnprtw  :-- note that not every letter has been used
    are used to stand...
for these hex digits:    0123456789abcdef

There's only one little bit of "cleverness" in this program.

The UNclever bit is as follows: To make the output, just transcribe the input,
one character at a time. If you get to one of the "unacceptable" characters,
replace it with a plus sign, and two characters which stand for the replaced
character's ascii code in hex.

The clever bit is to remember that the plus sign itself must be shown the way
the unacceptable characters are shown. (Otherwise you don't know if a plus sign
means "a plus sign", or means "make a character out of the next two characters,
using the ascii table."

Encoding string:

This is just 16 characters which are going to stand for the sixteen hex digits,
0-9, a-f. They can be any characters you like... as long as none of the
unacceptable characters (like 0 and O), and the escape character ("+", as this
has been presented) are included in the set.

*)



Let's do it!

Start a new application.

Stack vertically....

Leave their names as they are set by the system.

Make the text of Label1 say "That can be interpreted as...".

Name the form CD83f1.

Save everything in a folder called anything you like... mine was "CD83".

Save the code for the application as CD83u1.pas, and the project as CD83.dpr. Just to get things rolling, make the Button1Click handler be....

label2.caption:=edit1.text;

(If you've typed everything correctly, when you run the program, and click the button, whatever is in the edit box is copied to the second label.)

Next, move a little closer to our destination by making it....

procedure TCD83f1.Button1Click(Sender: TObject);
begin
label2.caption:=sNoBadChars(edit1.text);
end;

function TCD83f1.sNoBadChars(sSource:string):string;
var c1,iHowMany:integer;
    sResult:string;
begin
sResult:='';
sSource:=edit1.text;
iHowMany:=length(sSource);
for c1 := 1 to iHowMany do begin
   sResult:=sResult+sSource[c1];
   end;//for
result:=sResult;
end;//sNoBadChars

To make the code "work" you'll also have to add...

function sNoBadChars(sSource:string):string;

... to the source code just after the....

public
    { Public declarations }

... near its top.

Now set some constants, by adding the following on a line just before the word "type" near the top of the sourcecode....

cEsc='+';
cHexSubs='abcdefghjkmnprtw';
sNotAllowed='oO01l5Ss';

Revise the code for sNoBadCharacters as follows. For the moment all Bad Characters are merely being replaced with the escape character. Fear not... we'll be fixing that in a second... but you get applications done faster by building them stages by stage. Be sure to note the extra variable's declaration. (ch1)...

function TCD83f1.sNoBadChars(sSource:string):string;
var c1,iHowMany:integer;
    sResult:string;
    ch1:char;
begin
sResult:='';
sSource:=edit1.text;
iHowMany:=length(sSource);
for c1 := 1 to iHowMany do begin
   ch1:=sSource[c1];
   if pos(ch1,sNotAllowed)=0 then {do nothing} else begin
      ch1:=cEsc;
      end;//else
   sResult:=sResult+ch1;
   end;//for
result:=sResult;
end;//sNoBadChars

Get that running. I.e. get rid of any typos that have crept in!

Now replace the code with the following. Note that the things previously done by ch1 are now being done by s1.... sorry, my mistake. Sign of imperfect planning!

function TCD83f1.sNoBadChars(sSource:string):string;
var c1,iHowMany:integer;
    sResult,s1:string;
    b1,b2,bWhole:byte;
begin
sResult:='';
sSource:=edit1.text;
iHowMany:=length(sSource);
for c1 := 1 to iHowMany do begin
   s1:=sSource[c1];
   if pos(s1,sNotAllowed)=0 then {do nothing} else begin
      bWhole:=ord(s1[1]);
      b1:=bWhole div 16+1;(*"+1" so that zero is translated to the
             first (1th) character in cHexSubs, "1" is translated to
             the 2nd character, etc.*)
      b2:=bWhole and $0F+1;
      s1:=cEsc+copy(cHexSubs,b1,1)+copy(cHexSubs,b2,1);
      end;//else
   sResult:=sResult+s1;
   end;//for
result:=sResult;
end;//sNoBadChars

That's it! We're done with the "encode in non-ambiguous characters" part of the source code.


Now to write the decoding routine....

Add a further button and label to the form, beneath the existing components.

Make Button2's Click handler be...

label3.caption:=sBackToAmbig(label2.caption);

Add a line to the forward declarations at the top of the source code....

  public
    { Public declarations }
    function sNoBadChars(sSource:string):string;
    function sBackToAmbig(sSource:string):string;

And add the following just before the sourcecode's final "end."....

function TCD83f1.sBackToAmbig(sSource:string):string;
var c1,iHowMany:integer;
    sResult,s1:string;
    b1,b2:byte;
begin
sResult:='';
sSource:=label2.caption;
iHowMany:=length(sSource);
c1:=1;
repeat //for loop replaced by near equivalent so index can be manipulated within loop
   s1:=sSource[c1];
  if s1=cEsc then begin
      b1:=pos(sSource[c1+1],cHexSubs)-1;
      b2:=pos(sSource[c1+2],cHexSubs)-1;
      c1:=c1+2;//This is the line that meant the "for" loop had to be replaced
      //This line was useful while I was getting everything right! --> showmessage(inttostr(b1)+' '+inttostr(b2));
      s1:=chr(b1*16+b2);
      end;//then...
   sResult:=sResult+s1;
   inc(c1);
   until c1> iHowMany;
result:=sResult;
end;//sNoBadChars

Study that. When you think you really understand it, rem all of sBackToAmbig out, and try to recreate it without peeking! Seriously: Part of becoming a good programmer is learning to build code logically. You were shown exactly how I built sNoBadChars. sBackToAmbig was also build in stages. You become a better programmer by... you guessed it... programming! If you can do... and properly test... sBackToAmbig in 5 minutes: Congratulations! You won't have wasted much time. I bet you can't, and whatever time you spend will be invested in strengthening your skills.


That takes care of the two core jobs required in the application.

Because you may choose to change the list of unacceptable characters, and because the whole system breaks down if cEsc is one of the characters you have excluded, or if you use a character twice in cHexSubs, we're going to write one more function.

Start with a shell....

function TCD83f1.boAreNoBadConstantsOkay:boolean;
begin
result:=true;
end;

... and of course put the forward declaration into the source code up at the top, just after the line shown below....

function sBackToAmbig(sSource:string):string;
function boAreNoBadConstantsOkay:boolean;

Add a button to the form. Make its Click handler...

if boAreNoBadConstantsOkay then showmessage('Constants are okay.')//no ; here
  else showmessage('Constants are NOT okay.');

Once that's working, expand the shell, making it....

function TCD83f1.boAreNoBadConstantsOkay:boolean;
(*Yes- this could be written to run faster, but....
 a) It wouldn't be as clear.
 b) It won't be run often, and then not inside a loop.
*)

var c1,c2:byte;
begin
result:=true;//Work from an assumption that all is well.
(*Start by checking that the escape character is not one of the "illegal"
    ambiguous characters which are not allowed in the output.*)
if pos(cEsc,sNotAllowed)<>0 then result:=false;
(*Next make sure that cHexSubs has exactly the right number of characters...
     there must be a substitute for 0-9 and a-f...*)
if length(cHexSubs)<>16 then result:=false;
//Next check that the escape character isn't used in the substitution table...
if pos(cEsc,cHexSubs)<>0 then result:=false;
(*Next check that no "illegal", ambiguous character is used in the substitution table.*)
for c1:=1 to length(cHexSubs) do
  for c2:=1 to length(sNotAllowed) do
    if cHexSubs[c1]=sNotAllowed[c2] then result:=false;
//Finally, check to see that no character is used twice in the substitution table...
for c1:=1 to length(cHexSubs)-1 do
  for c2:=c1+1 to length(cHexSubs) do
    if cHexSubs[c1]=cHexSubs[c2] then result:=false;
end;//boAreNoBadConstantsOkay

If you look through that, I hope you'll quickly see that we provisionally assume that all is well ("result:=true;"), but then check various things that could be wrong, setting the result to "false" if need be.

An alternative way to write this would have been to have it return a number: 0 if all was well, and something else if a fault were found. With the zero/ not zero scheme, we can "say" what the fault was by the number returned. That is certainly a common, and workable, practice. In its simple form, as just described, it can only report one fault. there are other ways of doing something like this which allow a single "there was a/ were fault(s)" message to report more than one fault.... but that's a story for another time!

Concluding remarks

Well! That was a somewhat unusual tutorial for Level Two. Not everything was fully explained. Some of the things I didn't explain aren't too critical, and others were, I hope, clear from what you saw the application doing?

While what the application did isn't likely to be something you need, the converting of strings from one "alphabet" to another, restricted "alphabet", there are many things in the application which crop up in application after application. You also, I hope, saw how a application can be written in stages. Looking at a finished statue carved in marble doesn't tell you a lot about how the sculptor turned a lump of stone into the finished product. I hope that by following this tutorial through its stages you have become a little wiser in the ways of software "sculptors"?


            powered by FreeFind
  Site search Web search
Site Map    What's New    Search This search merely looks for the words you enter. It won't answer "Where can I download InpOut32?"


Click here if you're feeling kind! (Promotes my site via "Top100Borland")

Looking for email, domain registration, or web site hosting? If you visit 1&1's site from here, it helps me. They host my website, and I wouldn't put this link up for them if I wasn't happy with their service. They offer things for the beginner and the corporation.


Ad from page's editor: Yes.. I do enjoy compiling these things for you. I hope they are helpful. However... this doesn't pay my bills!!! Sheepdog Software (tm) is supposed to help do that, so if you found this stuff useful, (and you run a Windows or MS-DOS PC) please visit my freeware and shareware page, download something, and circulate it for me? Links on your page to this page would also be appreciated!
Click here to visit editor's freeware, shareware page.

Link to Tutorials main page
How to email or write this page's editor, Tom Boyd


Valid HTML 4.01 Transitional Page WILL BE tested for compliance with INDUSTRY (not MS-only) standards, using the free, publicly accessible validator at validator.w3.org


If this page causes a script to run, why? Because of things like Google panels, and the code for the search button. Why do I mention scripts? Be sure you know all you need to about spyware.

....... P a g e . . . E n d s .....