Pascal

Moderators: None (Apply to moderate this forum)
Number of threads: 4106
Number of posts: 14016

This Forum Only
Post New Thread
Single Post View       Linear View       Threaded View      f

Report
error checking on strings Posted by lazerspewpew on 23 Feb 2009 at 2:13 PM
Hi

when a user is entering in a string to my program I want to be able to do error checking to allow them to only enter in specific characters in the string.

Is there any easy way to do this in a while loop?

I know with an integer or a char it would be easy, i.e....

readln (mynumber);
   while (mynumber <1) or (mynumber >10) do
      begin
         writeln('im sorry the number you entered must be between 0 and 10);
      end;


any takers?
Report
Re: error checking on strings Posted by Atex on 23 Feb 2009 at 2:30 PM
This is done with repeat..until loop, but it would be possible with a while also:
const ch=['A'..'Z','a'..'z']; {<-- Modify this to your needs}

var s:string;
    t:boolean;          {Trigger}
    sl:byte absolute s; {length of s}
    i:byte;

begin
 repeat
  t:=true;   {Init trigger}
  write(#13#10,'Enter string: ');readln(s);
  for i:=1 to sl do
   if not(s[i] in ch) then t:=false; {check if the string's characters are in the accepted range}
  if not(t) then writeln('<error message goes here>');
 until (t and (sl>0)); {If trigger was changed or length=0 then repeat}
 writeln(#13#10,'Accepted: ',s);
 readln;
end.


Report
Re: error checking on strings Posted by lazerspewpew on 23 Feb 2009 at 2:47 PM
Hi

Thanks for the reply Atex.

Again, I really do appreciate the help you offer not just to me but around the forum. However, I managed to change the program I posted yesterday (levenshtein distance) just by adding in the begin and ends for the for loops and I had also forgotten the readln statement at the end.

I havn't used absolute addressing before and I dont understand how the 'write#32' statements work. what is the benefit of using these?
is there a 'simpler' way of doing it without using it?

Regards,
Alex
Report
Re: error checking on strings Posted by Atex on 23 Feb 2009 at 8:23 PM
: I havn't used absolute addressing before and I dont understand how

Absolute addressing has certain advantages, one is meant to overcome pascal's strong typing by being able to convert between different data types. Is basically multiple variables denoting the same memory location.
var w:word;
    b:array[0..1] of byte absolute w;
What it means is that w and b are the same but of different type. So if you modify w then b will change accordingly and vice versa. Is useful when quick access is needed to w's high or low byte, instead of calling a function ( hi(w) or lo(w) ) can be simply referring to b[0] or b[1]. Another thing is that can be used for string manipulations (would speed up and simplify certain operations, since string ops. are quite slow)
var s:string;
    l:byte absolute s;
Is this example l denotes the length of s. Why, because how strings are stored in memory, for example
The string: "absolute" is stored as:
Offset: 0  1  2  3  4  5  6  7....
        8  a  b  s  o  l  u.... 
The first byte at offset 0 indicates the length of the string ( that's why a string's length can only be 255 at most since a byte cannot store a higher value than 255 ). Also, declaring a string variable will eat up 256 bytes of memory (length_marker + 255 reserved bytes ), so for large structures is always good to declare the strings at their biggest expected length (e.g. string[15] <-- will limit the length to 15, takes 16 bytes of memory), however this is not an issue with 32 bit protected-mode programs only for dos real-mode. Back to the example, declaring a byte absolute to the string will refer to offset 0 which is the length marker. Now instead of calling length(s); we can directly work with l, same thing, only faster because is no calls are involved. Also is a quick way to truncate or concatenate s
s:=copy(s,1,5);
 -OR-
l:=5;

s:='';
for i:=1 to 15 do {<-- slow string operation}
 s:=s+'X';
 -OR-
l:=15;            {set length        }
for i:=1 to l do  {<-- fast indexing }
 s[i]:='X';
Note, that care with the coding must be considered, since the speed comes with a trade off, the possibility of creating bugs. But when you'll get the hang of it this won't be an issue anymore. Another use of "absolute" would be mapping directly the memory, I'm not getting into this because it can be used only for real-mode dos applications, tinkering with memory in protected-mode could easily lead to an app. killer: "general protection fault".

: the 'write#32' statements work. what is the benefit of using these?
: is there a 'simpler' way of doing it without using it?

This is my "bad" habit of coding , it comes from my tendency to optimize for no good reason and the laziness of typing...
Is just inserting ASCII codes to create certain effects, is comes from the way the video interrupt handles the data passed to it by the write routine, so:
write(#13#10,'blah..blah..blah...');
-Is equivalent to:
writeln;
write('blah..blah..blah...'); {Saved a few keystrokes and a function call }

Here are a few ASCII codes you could insert:
#7 - Will produce a beep sound
#8 - Back space {  equivalent to: gotoxy(wherex-1,wherey);  }
#13#10 - Carriage return + Line feed
#32 - Sapce -OR- ' '
Also can be used to display some nonprinting chars. like: #9, #11 etc.

Report
Re: error checking on strings Posted by lazerspewpew on 25 Feb 2009 at 6:25 AM
Your an absolute legend

Ive put it into my program and everything is working great.

Thanks again
Report
Re: error checking on strings Posted by Actor on 25 Feb 2009 at 1:34 PM
This program inputs a string and filters it on the fly. Characters not in the LEGAL set are ignored.
Program MyString ;

Uses
   Crt ;

CONST
   CR    = Chr(13) ;
   BLANK = ' ' ;
   LEGAL = ['A' .. 'Z', 'a' .. 'z', BLANK] ; { allowed characters }

Var
   Str   :  String ;
   Ch    :  Char ;

begin
   Str := '' ;  { nul string }
   repeat
      Ch := ReadKey ;
      if Ch = CR then
         break ;
      if Ch IN LEGAL then begin
         Str := Str + Ch ;
         Write (Ch)     { echo }
      end ;
   until Length(Str) = 255 ;

   WriteLn ;
   WriteLn (Str)
end.


Report
Re: error checking on strings Posted by Actor on 25 Feb 2009 at 1:39 PM
This program inputs a string and filters it on the fly. Characters not in the LEGAL set are ignored.
Program MyString ;

Uses
   Crt ;

CONST
   CR    = Chr(13) ;
   BLANK = ' ' ;
   LEGAL = ['A' .. 'Z', 'a' .. 'z', BLANK] ; { allowed characters }

Var
   Str   :  String ;
   Ch    :  Char ;

begin
   Str := '' ;  { nul string }
   repeat
      Ch := ReadKey ;
      if Ch = CR then
         break ;
      if Ch IN LEGAL then begin
         Str := Str + Ch ;
         Write (Ch)     { echo }
      end ;
   until Length(Str) = 255 ;

   WriteLn ;
   WriteLn (Str)
end.


Report
Re: error checking on strings Posted by obiWan on 25 Feb 2009 at 1:59 PM
This might help indirectly... it's the first program in "Software Tools in Pascal" (Kernighan(!), Plauger):

program copyprog (input, output); {copyprog.pas}
const
	ENDFILE=	-1;
	NEWLINE=	10;
type
	character=	-1..127;

{ get -- get one character from standard input }
function getc(var c: character): character;
var
	ch:	char;
begin
	if (eof) then
		c:= ENDFILE
	else if (eoln) then begin
		readln;
		c:= NEWLINE
	end
	else begin
		read(ch);
		c:= ord(ch)
	end;
	getc := c
end;

{ putc -- put one character on standard output }
procedure putc(c: character);
begin
	if (c = NEWLINE) then
		writeln
	else
		write(chr(c))
end;

{ copy -- copy input to output }
procedure copy;
var
	c:	character;
begin
	while (getc(c) <> ENDFILE) do
		putc(c)
end;

{ main program }
begin
	copy
end.

Report
Re: error checking on strings Posted by Actor on 25 Feb 2009 at 4:32 PM
Although Software Tools in Pascal is generally a good read, I don't recommend it for beginners. It simply has too much bad advice. The program you cite is an exercise in obfuscation. The following accomplishes the same thing without re-inventing Pascal's I/O methodology.
Program Kopy ; {   copy input to output  }
Var
   Ch : Char ;
begin { Kopy }
   while NOT eof do begin
      Read (Ch) ;
      Write (Ch)
   end
end.  { Kopy }

The book is basically an attempt to write a set of Pascal programs in a style that makes them look like C programs. Pursuant to that they invent getc and putc as their I/O "primitives", promising on page 8 to "explain why we didn't just use read and write," but no satisfactory explanation is ever given.

The same year that Software Tools in Pascal was published, Kernighan also published his rant "Why Pascal is Not My Favorite Programming Language," directed at a language which, at the time, had no standard. As Pascal existed in 1981, each of Kernighan's nine points condemning the language are valid.

Today it's a different story. Kernighan's rant simply does not apply to Turbo Pascal, Free Pascal or to any implementation of Pascal that is based on ANSI/IEEE770X3.97-1983. Unfortunately Kernighan's rant, is still widely distributed today (google it) and applied by the unknowing to all implementations of Pascal.

Report
Re: error checking on strings Posted by obiWan on 26 Feb 2009 at 12:20 AM
Well, I thought the program might have been helpful in a couple of ways- it seems like a good way to restrict or make rules which dis/allow certain characters to get copied to standard output. And the other thing is that it kind of gave me an insight into what the 'read' and 'write' commands might look like-- talking of which, what do they look like?

I also picked up on the c-likeness of the book.

But I like the first chapter. One of the book's strong points, and I've only just started it, is that it shows you how to go about thinking about a larger program and break it down into a bunch of smaller procedures. Well, you read that everywhere, but this is a helpful walkthrough. And I bought it for 85c! (Does that mean you're right about its value?- It is very dog-eared though...)
Report
Re: error checking on strings Posted by obiWan on 26 Feb 2009 at 3:48 AM
I hope this isn't annoying, but there's this really cool little procedure in the first chapter, which I thought someone might be interested in:
{ wordcount -- count words in standard input }
procedure wordcount;
var
	nw:	integer;
	c:	character;
	inword:	boolean;
begin
	nw:= 0;
	inword:= false;
	while (get(c) <> ENDFILE) do
		if (c = BLANK) or (c = NEWLINE) or (c = TAB) then
			inword := false
		else if (not inword) then begin
			inword:= true;
			nw:= succ(nw)
		end;
	putdec(nw, 1);
	putc(NEWLINE)
end;


What a cool way to use booleans! I guess, this is a good example of 'program state'?
Report
Re: error checking on strings Posted by Actor on 27 Feb 2009 at 1:11 AM
I hate to say this, but of all the programs in chapter one, this one is the worst. The algorithm takes a relatively simple problem (count number of transitions from white space to non-white space) and complicates it. The if statement that makes up the body of the while is about as obfuscated as code can get. Later in the book, K&P apologize for the use of the boolean flag (inword).

My solution.
Program WordCount ;   { count words in input -- first draft }
CONST
   NUL        = Chr(0) ;
   BLANK      = ‘ ‘ ;
   WHITESPACE : Set of Char = [NUL .. BLANK] ;

      Function Start (Prev, Current : Char) : Boolean
      {
         return TRUE at the beginning of a word 
      }
      begin
         Start :=
            NOT(Current IN WHITESPACE)
         AND
            (Prev IN WHITESPACE)
      end ;

Var
   Ch,
   Prev  : Char ;
   Count : LongInt ;

begin { WordCount }
   Prev  := NUL ;   { must initially be white space }
   Count := 0 ;
   while NOT eof do begin
      Read(Ch) ;
      if Start (Prev, Ch) then
          Count := Count + 1 ;
      Prev := Ch
   end ;
   WriteLn(Count:0)
end.  { WordCount }

Report
Re: error checking on strings Posted by Actor on 27 Feb 2009 at 1:00 AM
: Well, I thought the program might have been helpful in a couple of
: ways- it seems like a good way to restrict or make rules which
: dis/allow certain characters to get copied to standard output.

The problem with that, and the reason I used ReadKey instead of Read, is that Read is buffered input, i.e., as you type the characters are stored in a buffer (and echoed) until you hit ENTER. Only then does the program "read" the input from the buffer. ReadKey sends characters to the program immediately and does not echo. You have to echo the input. To be fair, keys such as BACKSPACE and DELETE need special handling, which I did not do.

: And
: the other thing is that it kind of gave me an insight into what the
: 'read' and 'write' commands might look like-- talking of which, what
: do they look like?

What do mean by "look like?"

: I also picked up on the c-likeness of the book.

There's a reason for that, I mean a reason apart from the fact that Kernighan was thick with Ritchie, the inventor or C. You are probably aware that the original Software Tools had programs in RatFor (Rational Fortran), a version of Fortran that had a C-like syntax. K&P were essentially just trying to translate the RatFor programs of the first book into Pascal with a minimum of effort.

: But I like the first chapter. One of the book's strong points, and
: I've only just started it, is that it shows you how to go about
: thinking about a larger program and break it down into a bunch of
: smaller procedures. Well, you read that everywhere, but this is a
: helpful walkthrough. And I bought it for 85c! (Does that mean you're
: right about its value?- It is very dog-eared though...)

I don't want to throw the baby out with the bath water. On balance, the book is a good one, but I take exception to the claim on the cover that it is "ideal ... for a second course in programming." Until a student has a solid foundation in Pascal he should avoid this exercise in pseudo Pascal.

As for the 85c cost, there are a lot of excellent books dating from that period that can be had for less than $1 in today's market.

Report
Re: error checking on strings Posted by obiWan on 4 Mar 2009 at 1:18 PM
Hello Actor, I just found your block on programer's heaven- it's a very nice collection of ideas about the start of the Software Tools book.
For anyone else, who might be interested:
http://www.programmersheaven.com/user/Actor/blog/
Report
Re: error checking on strings Posted by obiWan on 4 Mar 2009 at 1:57 PM
Just thinking about the way the procedure wordcount can be integrated into the copy- or in your case, Actor, kopy program (this does seem like the better way to go with pascal)- it's hard to call as a simple procedure, because you're reading a stream of characters in a while loop and if you call the countword procedure from within the while loop, you can only ever send a single character- which is pointless for counting words- so the countword procedure has to have the same scope as the kopy program.
{ textEd.pas -- text editor }
program textEd;
const
        BLANK=          32;
        TAB=            9;
        NEWLINE=        10;
        ENDFILE=        -1;
var
        ch:             char;
        wordcount:      integer;
        inword:         boolean;
begin
        wordcount:= 0;
        inword:= false;
        while not eof do
                begin
                     read(ch);
                     if (ord(ch) = BLANK) 
                        or (ord(ch) = TAB) 
                        or (ord(ch) = NEWLINE) then                             
                                inword:= false
                     else if (not inword) then begin
                                inword:= true;
                                wordcount:= succ(wordcount)
                     end;
                        { linenumber(ch); }
                     write(ch);
                end;
        writeln(wordcount);
end.    


(sorry about the tab settings)
The intuitive solution would be to write stdin to some kind of file (or a buffer) and then call the procedure to count the words by using the buffer as stdin... If that makes sense. Do you have to actually write to a file in this case or is it possible to save the text from stdin in memory some how. If this makes sense, what would be the best way to go about doing it? Or, to be more exact, how do you make a buffer (of char) lol.
Report
Re: error checking on strings Posted by Actor on 4 Mar 2009 at 11:25 PM
: Just thinking about the way the procedure wordcount can be
: integrated into the copy- or in your case, Actor, kopy program

I called it Kopy because copy is an existing DOS command. It's not a .com, .exe or even a .bat file but part of command.com, meaning that you cannot overload that name with any other program.

: (this
: does seem like the better way to go with pascal)- it's hard to call
: as a simple procedure, because you're reading a stream of characters
: in a while loop and if you call the countword procedure from within
: the while loop, you can only ever send a single character- which is
: pointless for counting words- so the countword procedure has to have
: the same scope as the kopy program.
:
: 
: { textEd.pas -- text editor }
: program textEd;
: const
:         BLANK=          32;
:         TAB=            9;
:         NEWLINE=        10;
:         ENDFILE=        -1;
: var
:         ch:             char;
:         wordcount:      integer;
:         inword:         boolean;
: begin
:         wordcount:= 0;
:         inword:= false;
:         while not eof do
:                 begin
:                      read(ch);
:                      if (ord(ch) = BLANK) 
:                         or (ord(ch) = TAB) 
:                         or (ord(ch) = NEWLINE) then                             
:                                 inword:= false
:                      else if (not inword) then begin
:                                 inword:= true;
:                                 wordcount:= succ(wordcount)
:                      end;
:                         { linenumber(ch); }
:                      write(ch);
:                 end;
:         writeln(wordcount);
: end.    
: 
: 
:
: (sorry about the tab settings)
: The intuitive solution would be to write stdin to some kind of file
: (or a buffer) and then call the procedure to count the words by
: using the buffer as stdin... If that makes sense. Do you have to
: actually write to a file in this case or is it possible to save the
: text from stdin in memory some how. If this makes sense, what would
: be the best way to go about doing it? Or, to be more exact, how do
: you make a buffer (of char) lol.
:
My first question is why do you want to combine the functions of copy and wordcount? Whatever. It looks to me like your code works fine except that it adds the count to the end of the copied file. I suggest the following..
: 
{ textEd.pas -- text editor }
program textEd;
const
    BLANK=          32;
    TAB=            9;
    NEWLINE=        10;
    ENDFILE=        -1;
    CON             'CON'; 
var
    ch:             char;
    wordcount:      integer;
    inword:         boolean;
    countfile:      text;
begin
    assign(countfile,CON);
    rewrite(countfile);
    wordcount:= 0;
    inword:= false;
    while not eof do
    begin
        read(ch);
        if (ord(ch) = BLANK) 
            or (ord(ch) = TAB) 
            or (ord(ch) = NEWLINE) then                             
                inword:= false
        else if (not inword) then begin
            inword:= true;
            wordcount:= succ(wordcount)
        end;
        { linenumber(ch); }
        write(ch);
    end;
    writeln(countfile,wordcount);
    close(countfile)
end.    

This may be closer to what you want. wordcount will always be written to the screen, but you can redirect the copy.

Report
Re: error checking on strings Posted by obiWan on 4 Mar 2009 at 11:55 PM
Well, what I'd like to do would be able to countwords from a procedure- to send the input from the read() command to a procedure which then counts the words- but because read() is in a while loop, the procedure countword is called for each input-ed character and doesn't work. Something like:
program ...

procedure (countword) ...

begin
   while not eof do begin
      read(ch);
      countword;
      write(ch);
   end;
end.


But the problem is that the variable that counts the words needs to have at least the scope of the while loop. I'd like to use a procedure, because that makes the program easier to read and more structred.
Report
Re: error checking on strings Posted by Actor on 5 Mar 2009 at 12:50 AM
: But the problem is that the variable that counts the words needs to
: have at least the scope of the while loop.

If you were programming in C you's use a static variable which retains its value between calls. Unfortunately, Pascal does not have static variables. However, in another post, Atex says that you can use a typed constant as a static variable. (Typed constants are not really constants.) I have not tried this. Good luck.

If it doesn't work then you are right, the counter variable has to have the same scope as the procedure that calls the count procedure. I'd declare and initialize the counter variable in the calling procedure and pass it as a var parameter.

Report
Re: error checking on strings Posted by Atex on 5 Mar 2009 at 9:01 PM
"Static" variable demo:
program static_var_test;
uses crt;

function _xyz_:byte; {Dummy function, increments "b" by one and returns it}
 const b:byte=0;     {<- "static" variable, its value is stored between calls}
 begin
  inc(b);
  _xyz_:=b;
 end;


begin
 while not keypressed do begin
  writeln(_xyz_);               {Output "b"-s current value}
  delay(50);
 end;
 readkey;
end.




 

Recent Jobs

Official Programmer's Heaven Blogs
Web Hosting | Browser and Social Games | Gadgets

Popular resources on Programmersheaven.com
Assembly | Basic | C | C# | C++ | Delphi | Flash | Java | JavaScript | Pascal | Perl | PHP | Python | Ruby | Visual Basic
© Copyright 2011 Programmersheaven.com - All rights reserved.
Reproduction in whole or in part, in any form or medium without express written permission is prohibited.
Violators of this policy may be subject to legal action. Please read our Terms Of Use and Privacy Statement for more information.
Operated by CommunityHeaven, a BootstrapLabs company.