:TITLE: String comparisons - compare match first last wordend
;#
;# RCSID: $Header: /home/cvs/TclTutor3/lesson/Tcl_English/Tcl_English18.lsn,v 1.1 2008/08/02 12:37:17 clif Exp $
;# Copyright (c) 1995 Clif Flynt
;# 9300 Fleming Rd.
;# Dexter, MI  48130
;# clif@cflynt.com
;# See file "NOTICE" for licensing terms.
;#
:LESSON_TEXT_START_LEVEL 0:
There are 6 string subcommands that do pattern and string matching.
<DL>
<B><DT>string compare</B> <I>string1 string2</I>
<DD>Compares <I>string1</I> to <I>string2</I> and returns
  <UL>
  <LI>-1 ..... If <I>string1</I> is less than <I>string2</I>
  <LI> 0 ........ If <I>string1</I> is equal to <I>string2</I>
  <LI> 1 ........ If <I>string1</I> is greater than <I>string2</I>
  </UL>
  These comparisons are done lexicographically, not numerically.
<B><DT>string first</B> <I>string1 string2</I>
<DD> Returns the index of the character in <I>string1</I>
that starts the first match to <I>string2</I>, or -1 if there is no
match to <I>string2</I> in <I>string1</I>
<B><DT>string last</B> <I>string1 string2</I>
<DD> Returns the index of the character in <I>string1</I>
that starts the last match to <I>string2</I>, or -1 if there is no
match to <I>string2</I> in <I>string1</I>
<B><DT>string wordend</B> <I>string index</I>
<DD>Returns the index of the character just after the last one in the
word which contains the <I>index'th</I> character of <I>string</I>.  A word is
any contiguous set of letters, numbers or underscore characters, or a 
single other character.
<B><DT>string wordstart</B> <I>string index</I>
<DD>Returns the index of the character just before the first one in the
word which contains the <I>index'th</I> character of <I>string</I>.  A word is
any contiguous set of letters, numbers or underscore characters, or a 
single other character.
<B><DT>string match</B> <I>pattern string</I>
<DD> Returns 1 if the <I>pattern</I> matches <I>string</I>.  <I>Pattern</I>
is a glob style pattern.
<P>
<B>Globbing</B> is the wildcarding technique that the shell uses.  
<P>
<B>globbing</B> wildcards are:
<DL>
<B><DT>*</B><DD> Matches any quantity of any character
<B><DT>?</B><DD> Matches one occurrence of any character
<B><DT>\X</B><DD> The backslash escapes a special character in globbing
just the way it does in Tcl substitutions.  Using the backslash lets you use 
glob to match a <B>*</B> or <B>?</B>.  
<B><DT>[...]</B><DD> Matches one occurrence of any character within the brackets.
A range of characters can be matched by using a range between the brackets.
For example, [a-z] will match any lower case letter.
</DL>
</DL>

:TEXT_END:

:LESSON_TEXT_START_LEVEL 1:
There are 6 string subcommands that do pattern and string matching.
<DL>
<B><DT>string compare</B> <I>string1 string2</I>
<DD>Compares <I>string1</I> to <I>string2</I> and returns
  <UL>
  <LI>-1 ..... If <I>string1</I> is less than <I>string2</I>
  <LI> 0 ........ If <I>string1</I> is equal to <I>string2</I>
  <LI> 1 ........ If <I>string1</I> is greater than <I>string2</I>
		  </UL>
  These comparisons are done lexicographically, not numerically.
<B><DT>string first</B> <I>string1 string2</I>
<DD> Returns the index of the character in <I>string1</I>
that starts the first match to <I>string2</I>, or -1 if there is no
match to <I>string2</I> in <I>string1</I>
<B><DT>string last</B> <I>string1 string2</I>
<DD> Returns the index of the character in <I>string1</I>
that starts the last match to <I>string2</I>, or -1 if there is no
match to <I>string2</I> in <I>string1</I>
<B><DT>string wordend</B> <I>string index</I>
<DD>Returns the index of the character just after the last one in the
word which contains the <I>index'th</I> character of <I>string</I>.  A word is
any contiguous set of letters, numbers or underscore characters, or a 
single other character.
<B><DT>string wordstart</B> <I>string index</I>
<DD>Returns the index of the character just before the first one in the
word which contains the <I>index'th</I> character of <I>string</I>.  A word is
any contiguous set of letters, numbers or underscore characters, or a 
single other character.
<B><DT>string match</B> <I>pattern string</I>
<DD> Returns 1 if the <I>pattern</I> matches <I>string</I>.  <I>Pattern</I>
is a glob style pattern.
<P>
<B>Globbing</B> is the wildcarding technique that the shell uses.  
<P>
<B>globbing</B> wildcards are:
<DL>
<B><DT>*</B><DD> Matches any quantity of any character
<B><DT>?</B><DD> Matches one occurrence of any character
<B><DT>\X</B><DD> The backslash escapes a special character in globbing
just the way it does in Tcl substitutions.  Using the backslash lets you use 
glob to match a <B>*</B> or <B>?</B>.  
<B><DT>[...]</B><DD> Matches one occurrence of any character within the brackets.
A range of characters can be matched by using a range between the brackets.
For example, [a-z] will match any lower case letter.
</DL>
</DL>
:TEXT_END:

:LESSON_TEXT_START_LEVEL 2:
Operations that are often performed on strings include searching for a
pattern, or comparing one string to another.  In this lesson the 
string commands for searching and comparing are discussed.
<P>
Tcl has several methods of searching for one string within another 
string.  First and last are the string subcommands that will return
the first and last occurrence of one string within another.  You
might use these commands to search a text file for a particular word.
<P>
The match command will tell you if a pattern occurs within a string.
It uses the same <B>globbing</B> rules as the <B>lsearch</B> command.
<P>
The string compare will tell you if one string comes before the other
alphabetically.  This is useful to sort a set of strings into alphabetic
order.
<P>
The descriptions of these commands is:
<DL>
<B><DT>string compare</B> <I>string1 string2</I>
<DD>Compares <I>string1</I> to <I>string2</I> and returns
  <UL>
  <LI>-1 ..... If <I>string1</I> is less than <I>string2</I>
  <LI> 0 ........ If <I>string1</I> is equal to <I>string2</I>
  <LI> 1 ........ If <I>string1</I> is greater than <I>string2</I>
  </UL>
  These comparisons are done lexicographically, not numerically.
<B><DT>string first</B> <I>string1 string2</I>
<DD> Returns the index of the character in <I>string1</I>
that starts the first match to <I>string2</I>, or -1 if there is no
match to <I>string2</I> in <I>string1</I>
<B><DT>string last</B> <I>string1 string2</I>
<DD> Returns the index of the character in <I>string1</I>
that starts the last match to <I>string2</I>, or -1 if there is no
match to <I>string2</I> in <I>string1</I>
<B><DT>string wordend</B> <I>string index</I>
<DD>Returns the index of the character just after the last one in the
word which contains the <I>index'th</I> character of <I>string</I>.  A word is
any contiguous set of letters, numbers or underscore characters, or a 
single other character.
<B><DT>string wordstart</B> <I>string index</I>
<DD>Returns the index of the character just before the first one in the
word which contains the <I>index'th</I> character of <I>string</I>.  A word is
any contiguous set of letters, numbers or underscore characters, or a 
single other character.
<B><DT>string match</B> <I>pattern string</I>
<DD> Returns 1 if the <I>pattern</I> matches <I>string</I>.  <I>Pattern</I>
is a glob style pattern.
<P>
<B>Globbing</B> is the wildcarding technique that the shell uses.  
<P>
<B>globbing</B> wildcards are:
<DL>
<B><DT>*</B><DD> Matches any quantity of any character
<B><DT>?</B><DD> Matches one occurrence of any character
<B><DT>\X</B><DD> The backslash escapes a special character in globbing
just the way it does in Tcl substitutions.  Using the backslash lets you use 
glob to match a <B>*</B> or <B>?</B>.  
<B><DT>[...]</B><DD> Matches one occurrence of any character within the brackets.
A range of characters can be matched by using a range between the brackets.
For example, [a-z] will match any lower case letter.
</DL>
</DL>
<P>
In the example, <CODE>first</CODE> and <CODE>last</CODE> are used to
find the first and last slash in a path.  By knowing if the first character
is a "/", we can tell if a path is absolute or relative.
<P>
The value of
<CODE>last</CODE> is incremented before we test to see if the "/" is
the last character in  the string because Tcl numbers characters in a
string from 0.  If there were two characters in a string, <CODE> string length </CODE>
would return a 2, obviously, and <CODE>string last</CODE> would report the
last character at position 1.  If the "/" is the last character, then 
<CODE>last</CODE> is moved back 2 spaces, since <CODE>string range</CODE>
returns the all the characters from start to end, including the start and 
end positions.
<P>
In the final section of code, the comparison to "a", we determine
whether the first character of the string is upper or lower case.  The
order of the characters that a computer uses go from 0 to 9, then A 
Z, and finally a to z.  Any letter less than 'a' is an upper case
letter.  This is a very simple minded test that will report numbers as
being uppercase.  
<P>
Try rewriting this example using the <CODE>split</CODE> command to separate
the parts of the path into separate list elements.
<P>
:TEXT_END:

:CODE_START:
set fullpath "/usr/home/clif/TCL_STUFF/TclTutor/Lsn.17"
set relativepath "CVS/Entries"
set directorypath "/usr/bin/"

set paths [list $fullpath $relativepath $directorypath]

foreach path $paths  {
  set first [string first "/" $path];
  set last [string last "/" $path];

  ;# Report whether path is absolute or relative

  if {$first != 0} {
    puts "$path is a relative path"
    } else {
    puts "$path is an absolute path"
    }

  ;# If "/" is not the last character in $path, report the last word.
  ;# else, remove the last "/", and find the next to last "/", and
  ;#   report the last word.

  incr last;
  if {$last != [string length $path]} {
    set name [string range $path $last end];
    puts "The file referenced in $path is $name"
    } else {
    incr last -2;
    set tmp [string range $path 0 $last];
    set last [string last "/" $tmp];
    incr last;
    set name [string range $tmp $last end]
    puts "The final directory in $path is $name"
    }

  ;# CVS is a directory created by the CVS source code control system.
  ;#

  if {[string match "*CVS*" $path]} {
    puts "$path is part of the source code control tree"
    }

  ;# Compare to "a" to determine whether the first char is upper or lower case
  set comparison [string  compare $name "a"]
  if {$comparison >= 0} {
    puts "$name starts with a lowercase letter\n"
    } else {
    puts "$name starts with an uppercase letter\n"
    }
  }
:TEXT_END:

