I would like to first thank feherke for a very concise and timely response. Thank You! And, no, this is not MY homework.
Now, I would like to understand better, exactly what you have done. Like I said, I am new to Tcl/Tk and I've spent over an hour trying to figure out exactly what is going on in your code. I have added my own code to it to make it interactive. I will copy the code and comment it line by line as I interpret it.
I also want to make a few slight changes:
1. Instead of counting each upper and lowercase letter individually, I want to convert them all to lowercase (or uppercase) and just count them once as a single a or b or c.... Instead of displaying only letters that appear in the file, I would like to display all 26 letters and show how often each letter occured in the file, and I would like to lump all non-letter characters together and display their presence as "other characters".
i.e. There were 11 A's in the file.
There were 2 B's in the file...
There were 0 Z's in the file.
There were 13 other charaters in the file.
There were 6 lines in the file.
2. As you can see from above, I would also like to count the number of lines read in from the file, and display that information on a separate line formatted as above. I noticed that from the code that you gave me, it counted the carriage returns, however, it also "used" them as carriage returns, splitting the output into two separate lines.
"There were 7
's in the file"
3. I have done lots of research on this, and have come to the conclusion that it might not be possible, however, if it is possible, I would like to clear the screen upon executing the program and again after the file name is input from the user. This will give a nice full page for the summary output to display.
Well, here goes nothing:
puts "This program counts the occurances letters and symbols in a given file.\n"
#displays the quoted text to the screen
puts "\n"
#displays a blank line to the screen
puts "example: c:\\data\\data.dat\n"
#displays the quoted text to the screen, note the double backslashes, I don't know why, but unless you double the backslashes, they won't display
puts -nonewline stdout "Enter the file name: "
#displays the quoted text to the screen, I am not real sure what the "-nonewline stdout" is for you can get the same results by using a simple puts
flush stdout
#I don't know what this does, but a shot in the dark is, it clears the memory buffer allocated for "stdout". As I said previously, it is probably not necessary to use
set filename [gets stdin]
#assigns the variable named "filename" whatever the user types in. There should probably be some error checking here but, I am new to this and don't know how to do that
set f [open $filename r]
#opens the file and assigns it to the variable named "f"
puts "\n"
#displays a blank line to the screen
while {! [eof $f]} {
#starts a while loop to process the file until the 'end-of-file' is reached
set t [read $f 10240]
#assigns the variable named "t" one 'byte' of data at a time. Very nice, I like that.
set s [split $t {}]
#I am guessing this assigns the variable named "s" one character at a time from the "byte" using the 'split' command
for {set i 0} {$i<[llength $s]} {incr i}
#initiates a for loop with initialize, condition, and increment or decrement. In this case, you initialize the variable "i" to zero. Your condition is while "i" is less than "s". I am guessing that as long as there is an "s" s's length will return a value of 1, when there is no "s", the value of s will be 0 making the condition false and terminating the loop. However the i is being incremented by 1 through each iteration of the loop and by my definition would cause the loop to end after just one pass. So obviously I don't know what the split command does in the previos line of code
{
#the open braces is used to group all of the actions which will take place if the conditions are met in the for loop
set c [lindex $s $i]
#now this is where things get muddy. I know c is a variable being assigned something, but that's about it
if {[array names cc -exact $c]!=""}
#I recognise an if statement, however, the condition is unclear. I believe an array is being set up. I am guessing that names is a reserved word, the rest, I don't have a clue
{
#the open braces is used to group all of the actions which will take place if the conditions are met making the 'if' statement "true"
set cc($c) [expr $cc($c)+1]
#again, nothing
}
#this close braces marks the end of the true if-condition group
else
#the "else" condition if not this, then this
{
#the open braces is used to group all of the actions which will take place if the conditions are false in the if statement
set cc($c) 1
#I got nothing
}
#this close braces marks the end of the else-condition group
}
#this close braces marks the end of the for loop
}
#this close braces marks the end of the while loop
close $f
#closes the open file
foreach c [array names cc]
#this is a new loop structure for me. It appears to be very useful because you don't have to know how many elements are in the array, you simply "do" 'for each element within the array', cool!
{
#the open braces is used to group all of the actions which will take place "for each" element of the array
puts "There were $cc($c) $c's in the file"
#I know that this is formatted output, however, I am not quite sure what is going on with the $cc. I am guessing that that is the name of the array, and that the '($c)' is the current element of the array. The '$c' is the current character
}
#this close braces marks the end of the foreach loop
puts "This program counts the occurances letters and symbols in a given file.\n"
puts "\n"
puts "example: c:\\data\\data.dat\n"
puts -nonewline stdout "Enter the file name: "
flush stdout
set filename [gets stdin]
set f [open $filename r]
puts "\n"
while {! [eof $f]} {
set t [read $f 10240]
set s [split $t {}]
for {set i 0} {$i<[llength $s]} {incr i} {
set c [lindex $s $i]
if {[array names cc -exact $c]!=""} {
set cc($c) [expr $cc($c)+1]
} else {
set cc($c) 1
}
}
}
close $f
foreach c [array names cc] {
puts "There were $cc($c) $c's in the file"
}