PDA

View Full Version : Ascii help / column width - new to this.



stevengreen22
20-02-2011, 06:15 PM
Hi guys,

Before I begin, Uber thanks for any help!!!

So the scenario is that I'm studying for a degree and we've been asked to look into Pascal due to the rigidity of the language.
this is my first taste of programming at this level./

Our current assignment is to reproduce the ASCII table.

This is low level stuff and I'm very new so bear with me.

So fair I have this:


program ASCIITABLE(output);

var i: Integer;
ch: Char;

begin {main program}

writeln ('A to Z in ASCII');

for i := 01 to 127 do
begin
write ( chr(i ));
writeln (' ', i);

end;

writeln ('Press any key to continue' ,ch);
read (ch);

end.

as you can see, fairly basic.
What I'd like is to set the column width and blank fill with spaces so they are all aligned nicely adn to also set up 6 colums for tyhe code to be displayed in.

cna anyone help at all?

huge thanks

WILL
20-02-2011, 07:41 PM
Hi Steven and welcome to PGD. :)

Not too bad on your first run through. I'm guessing that you have gotten yourself familiar with C already? I have a few small tips that might help clean up your code a little.

...but first, have you tried to compile your program yet?

You can remove "(output)" from the first line. Pascal does not return values this way, I don't think, and you don't need to return anything anyhow, not for this program at least.

Also the way your program will write each ascii character, you'll have one character per line, is this intended? If not the remove the line in your for loop with "writeln" in it. Instead you might want to try this...


for (i := 1 to 127) do
write (chr(i) + '');

I've saved you a few lines by using proper string manipulation and eliminated a reason to code block your for loop. Now the down side to this is that your next writeln call will print the text right after your last ascii character instead of on the next line or so.

To fix this you could call a couple of writeln(''); procedures right after the for loop OR instead you can simply add in "\n" inside your string at the beginning. What this little guy will do is simply carry your text onto the next line. Put in a couple like this...


writeln('\n\nPress any key to continue');

...and you'll have your cursor skip down to lines before printing the desired text.

One last thing, you can do away with those extra parameters hanging off the end of your write and writeln procedures, they don't really do anything for you in this case and it's more of a C-type construct anyhow.

Hope that helps. :)

User137
20-02-2011, 09:39 PM
One last thing, you can do away with those extra parameters hanging off the end of your write and writeln procedures, they don't really do anything for you in this case and it's more of a C-type construct anyhow.
Actually...
I prefer this:

writeln (' ', i);
...rather than:

writeln (' '+inttostr(i));
They do the same thing. Writeln lets you do things like

writeln (3, ' divided by ', 2); // Will print "3 divided by 2"

you can use word "mod" to do the line change every 6 columns. For example "i mod 6=0" will return true on 0, 6, 12, 18...

JSoftware
20-02-2011, 10:12 PM
Here's how I would do it:


program ASCIITABLE;

const
ColumnCount = 6;
ColumnWidth = 8;

var i: longint;
ch: Char;

begin
writeln ('A to Z in ASCII');

for i := 0 to 127 do
begin
write(chr(i):ColumnWidth);

// Each column start at index 0, and ends at ColumnCount-1
if (((i+1) mod ColumnCount) = 0) then
Writeln;
end;

Writeln;
writeln('Press any key to continue' ,ch);
read(ch);
end.


The magic happens in a special syntax for the write/writeln function

If you call Write('a':4); then it'll write " a". Write(1:5); will produce " 1". This is some bad syntactic sugar that's always existed in Pascal

Murmandamus
20-02-2011, 10:22 PM
The Program statement parameters are optional in most modern Pascal compilers. They are vestigial holdovers from the mainframe days where you specified the input/output "files" that were used for read/readln and write/writeln. You can include them, but modern compilers just ignore them. If your professor grades you for strict adherence to syntax, you might want to keep them. In that case, the proper way is like so:


program ASCIITABLE(input,output);

As for the formatting of your output, you can space it a number of ways. The easiest and quickest is to use the field options for each data parameter you pass to write/writeln. Just put a colon and a number after it specifying the field size, like so:


writeln(i:3,chr(i):2);

That will right-justify the character index number (ordinal) in a 3-space field, and the actual character right-justified in a 2-space field.

As for doing them in more than one column, you have to do a little math in the loop, depending on whether you want the numbers incrementing horizontally (row ordering) or vertically (column ordering). Most ASCII tables are done in column ordering, so you'll probably want to do that. Since you can't "go back up" and write them out on the same lines (well, not with basic text streams, anyway), you have to write out several characters at once, which means you'll have to alter your loop a little bit. The first thing you'll have to do is figure out how many rows you will need. Since you said you wanted six columns, you take the number of characters you are writing out and divide it by 6. 127 / 6 = 21.166667. Thus, to keep all the characters in six columns, you will need 22 rows (have to round any fraction up to the next whole). So your ASCII chart will look something like this:



1 . 23 . 45 - 67 C 89 Y 111 o
2 . 24 . 46 . 68 D 90 Z 112 p
3 . 25 . 47 / 69 E 91 [ 113 q
... (13 more rows here)
17 . 39 ' 60 < 83 S 105 i 127 .
18 . 40 ( 61 = 84 T 106 j
19 . 41 ) 62 > 85 U 107 k
20 . 42 * 64 @ 86 V 108 l
21 . 43 + 65 A 87 W 109 m
22 . 44 , 66 B 88 X 110 n


Now, the trick is to figure out the right loop structures and calculations to generate the table this way. There are actually several ways you can do it. The most obvious and straightforward is to use two loops (the outer one from 1 to 22, the inner one 1 to 6), but it is possible to still just use one loop. Do note that there are a couple issues you will have to deal with:

1) due to the fact that there are not 6 full columns (since 6 does not divide into 127 equally), you will have to use some kind of condition to suppress output for the sixth column after you get past 127 in it.
2) Many of the characters below 32 are "unprintable" control characters. Some may print, depending on how you view the output, but some will break the formatting of your table. You may need to detect these and place an "unprintable placeholder" character instead. In the example above, I used the period "." character to represent the unprintables. What character you choose and how you do it is entirely up to you.

Since this is a class project, I'll leave it to you to decide the logic you want to use, and then we can talk about how to implement it in Pascal. :)

stevengreen22
21-02-2011, 05:36 PM
Not sure what to say!

Theres so much useful information in there its unreal.

This is my first attempt at programmingin so no prior knowledge of C etc, I think the last time I tried anythignw as when BASIC was about and then I was a bit too young to knwo what I was doing.

The best thing to come out of what you guys have said is the explanations that go with it. It helps me understand so much more.

Thanks!

I'm going to take a little bit of everything and see what happens :d

Many thanks!

stevengreen22
21-02-2011, 08:01 PM
Here's how I would do it:


program ASCIITABLE;

const
ColumnCount = 6;
ColumnWidth = 8;

var i: longint;
ch: Char;

begin
writeln ('A to Z in ASCII');

for i := 0 to 127 do
begin
write(chr(i):ColumnWidth);

// Each column start at index 0, and ends at ColumnCount-1
if (((i+1) mod ColumnCount) = 0) then
Writeln;
end;

Writeln;
writeln('Press any key to continue' ,ch);
read(ch);
end.
The magic happens in a special syntax for the write/writeln function

If you call Write('a':4); then it'll write " a". Write(1:5); will produce " 1". This is some bad syntactic sugar that's always existed in Pascal




-----------
// Each column start at index 0, and ends at ColumnCount-1
if (((i+1) mod ColumnCount) = 0) then
Writeln;

Can you explain how this creates a new column? we're div the ascci numeral by 6 and if no remainder then a new line is created?

Sorry if this sounds retarded, I can "see" how it works, I just can't explain it to myself....

(not the best sentence I've ever written....)

stevengreen22
22-02-2011, 10:54 AM
Hi guys,

Firstly, huge thankyou to you all who helped or had suggestions. Gained a lot of info from it, some stuff I didn't understand but that was great as it meant I had to dig a little deeper :)

I've amended the code a bit, seemed easier to have columnwidths etc and to use the (((i+1) mod 8)=0) then writeln as a way to get the characters to display ok.

As mentioned, the first 32 characters throw the table out of sync, instead of these I was going to use the 2/3 char's for them.

This is where I tried to get clever....

On the script you can see I've tried to use an array and I can see this is faulty - Am trying to work around this and see how it implements into the script and so on...is completely new ground to me.

But, the issue i'm having is now it won't compile (even without the array inc.) where it was before.

I get an unexpected end error?


program ASCIITABLE(output);

uses crt;

const columncount = 8; {8 columns as 128 is div perfectly by 8}
columnwidth = 3; {unprintables need 3 spaces, neater output}
Title:string = (' ASCII TABLE ');

var unprint: array [0..32] of string =(
{string as below are 'string' variable}
'NUL','SOH','STX','ETX','EOT','ENQ',
'ACK','BEL','BS ','HT ','LF ','VT ',
'FF ','CR ','SO ','SI ','DLE','DC1',
'DC2','DC3','DC4','NAK','SYN','ETB',
'CAN','EM ','SUB','ESC','FS ','GS ',
'RS ','US ','SP ');

index :integer;
i: integer;
ch: Char;



begin {main program}
ClrScr;
writeln (Title);
writeln;


{ for i := 0 to 32 do
begin
read(unprint[i]);
write (chr(i):columnwidth);
{ write ('',unprint[0..32]); }
{ if (((index+1) mod columncount) = 0 then }
{ writeln;
end; }

for i:= 33 to 127 do
begin
write (chr(i):columnwidth);
write (' ',i:4);
if (((i+1) mod Columncount) = 0) then
writeln;
end;

{ writeln (' '); }
writeln;
writeln;
writeln ('Press any key to continue' ,ch);

read (ch);
end.


Please ignore the improper way in which I've typed the program, still picking it up as I go.

Thanks again for all your help and apologies for not being able to reply to the thread, I think I'm waiting on the account to be verified?

stevengreen22
22-02-2011, 05:04 PM
Hi all,

Seems all my replies got posted at once :)

I figured out what I did wrong, removed the read line and amended the write line.

Finally it works!!!

Although...Does nayone knwo how its possible to display the characters in a neat format instead or would i need to set several loops instead?

Murmandamus
22-02-2011, 05:10 PM
Well, let's see.. first thing is this:


Title:string = (' ASCII TABLE ');

String constants only need to be delimited with apostrophes ('). You don't need the parentheses.

Next..


var unprint: array [0..32] of string =(
{string as below are 'string' variable}
'NUL','SOH','STX','ETX','EOT','ENQ',
'ACK','BEL','BS ','HT ','LF ','VT ',
'FF ','CR ','SO ','SI ','DLE','DC1',
'DC2','DC3','DC4','NAK','SYN','ETB',
'CAN','EM ','SUB','ESC','FS ','GS ',
'RS ','US ','SP ');

Since you are creating a constant array, this needs to be "const unprint" instead of "var unprint". Note that, if you change this, the var declarations below (index, i, and ch) will need their own "var" preceding them.

Next..


read(unprint[i]);

What you are telling the computer to do is to read input from the user and put it into your unprintables array. I don't think that is what you are intending, you just want to use the array, so I would recommend deleting that line entirely, as it is unnecessary.

You will also need to put in a write for your character index value for the unprintables. (like "write(' ',i:4);" in the printables section)

Next..


if (((index+1) mod columncount) = 0 then

You declared another index variable which you only used in this line, but I think you just need the one "i" index variable and to use it here. Also, you have unbalanced parentheses in your conditional expression (too many lefts/opens, not enough rights/closes).

Next..


writeln ('Press any key to continue' ,ch);

The ",ch" part is unnecessary, especially because at this point, ch is undefined. You don't need to write out the contents of the variable you are going to use as a "dummy" (ie, you're not really going to use the value it returns) in the read statement afterwards.

Next..

Block comments are not nest-able, unless you use a different set. Block comments in Pascal start with "{" or "(*" and end with the FIRST matching "}" or "*)" encountered in the code. For example, if have some block comments in a block of code, then decide you want to comment out the entire block for whatever reason, use the "other" set to do it.

If you have this:


for i := 0 to 32 do { do the unprintables first }
begin
write (chr(i):columnwidth,' ',i:4);
if (((index+1) mod columncount) = 0 then
writeln;
end;

and you want to comment it out, then do it like this:


(*
for i := 0 to 32 do { do the unprintables first }
begin
write (chr(i):columnwidth,' ',i:4);
if (((index+1) mod columncount) = 0 then
writeln;
end;
*)

Lastly, just so you know, you can use the
{put your code here} tags around your code to preserve formatting here in the forum.

stevengreen22
22-02-2011, 05:21 PM
program ASCIITABLE(output);

uses crt;

const columncount = 8; {8 columns as 128 is div perfectly by 8}
columnwidth = 3; {unprintables need 3 spaces, neater output}
Title:string = (' ASCII TABLE ');
By:string = (' By Steve Green ');

unprint: array [0..32] of string =(
{string as below are 'string' variable}
'NUL','SOH','STX','ETX','EOT','ENQ',
'ACK','BEL','BS ','HT ','LF ','VT ',
'FF ','CR ','SO ','SI ','DLE','DC1',
'DC2','DC3','DC4','NAK','SYN','ETB',
'CAN','EM ','SUB','ESC','FS ','GS ',
'RS ','US ','SP ');


var i: integer;
ch: Char;
idx: byte;

begin {main program}
ClrScr;
writeln (Title);
writeln;
writeln (by);
writeln;
for i := 0 to 32 do
begin
write (' ',unprint[i]:columnwidth);
write (' ',i:3);
if (((i+1) mod columncount) = 0) then
writeln;
end;

for i:= 33 to 127 do
begin
write (' ',chr(i):columnwidth);
write (' ',i:3);
if (((i+1) mod Columncount) = 0) then
writeln;
end;


{ writeln (' '); }
writeln;
writeln;
writeln ('Press Return to continue' ,ch);

read (ch);
end.



So after playing around a bit, this is what I've got.
It displays Ok, Not as perfect as I'd like it but this is within my scope.

I'd like to be able to use the characters instead...
I can do chr 1 to 7 (these display ok) and 16 - to 127 but it's 8 that causes the problem :) throws the whole table out.

User137
22-02-2011, 09:39 PM
I like // comments for single line as they work in most programming languages, for ex:

DoSomething; // comment...