home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 2000 March / pcp161b.iso / handson / archive / Issue158 / delphi / RichEditTest / Strutils.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1999-08-13  |  9.5 KB  |  325 lines

  1. unit Strutils;
  2. { string handling procedures for Pascal-style strings }
  3.  
  4. interface
  5. uses Classes;   { this unit defines TStringList }
  6.  
  7. const
  8.    TAB = #09;
  9.    CR  = #13;
  10.    LF  = #10;
  11.    CRLF = CR + LF;
  12.    SEPARATORS = [' ', '.', ',', '!', '?',';',':', '''', '"', '(', ')',
  13.                  '[', ']', '{', '}', TAB ];
  14.    LOWCHARS = ['a'..'z'];
  15.    UPCHARS = ['A'..'Z'];
  16.  
  17. type
  18.    charSet = set of char;
  19.  
  20.  
  21.    tokenindex = record
  22.       tstart, tend : integer;
  23.    end;
  24.  
  25.    tokenindexes = array[1..255] of tokenindex;
  26.  
  27.  
  28.  
  29. function LowCase( c : char ) : char;
  30.     { return lowercase version of char c                }
  31. function ChangeCase( const s : string ) : string;
  32.     { return toggled-case version of string s           }
  33. function removeLeadChars( const s : string;  chars : charSet  ) : string;
  34.     { trim chars from Left of String s                  }
  35. function removeTrailingChars( const s : string; chars : charSet ) : string;
  36.     { trim chars from Right of String s                 }
  37. function trimLeftStr( const s : string ) : string;
  38.    { remove leading SEPARATORS from string 's'          }
  39. function trimRightStr( const s : string ) : string;
  40.    { remove trailing SEPARATORS from string 's'         }
  41. function trimEndsStr( const s : string ) : string;
  42.    { trim SEPARATORS from both left and right of string }
  43. procedure firstrestStr( const s : string; var first, rest : string );
  44.    { parse s into 1st word first and remainder rest     }
  45. function encrypt( const s : string; cryptint : integer ) : string;
  46.    { encrypt a string by doing maths using cryptint     }
  47. function decrypt( const s : string; cryptint : integer ) : string;
  48.    { decrypt a string by doing maths using cryptint     }
  49. procedure parse( const s : string; slist : TStringList );
  50.    { parse string, s, into individual words in slist    }
  51.  
  52.  
  53. {===NEW ROUTINES===}
  54. function TokenStart( const s : string; chars : charSet  ) : integer;
  55. procedure firstTokenAt(  s : string;
  56.                         var tokstart, tokend : integer;
  57.                         var first, rest : string );
  58. procedure tokensFoundAt( s : string;
  59.                          var num: integer;
  60.                          var tindexes: tokenindexes );
  61. (* // the following procedure is not public
  62. procedure firstTokenAtSIndex(   s : string;
  63.                          var startindex, prevend : integer;
  64.                          var first, rest : string ); *)
  65. {===============}
  66.  
  67. implementation
  68.  
  69. function LowCase( c : char ) : char;
  70. begin
  71.   if (c in UPCHARS) then
  72.      Result := Chr(Ord(c) + 32)
  73.   else Result := c;
  74. end;
  75.  
  76. function ChangeCase( const s : string ) : string;
  77. { changes all lowercase chars to uppercase and vice versa }
  78. var
  79.    i : integer;
  80.    s2 : string;
  81. begin
  82.    s2 := '';
  83.    for i := 1 to Length( s ) do
  84.       if (s[i] in LOWCHARS) then
  85.          s2 := s2 + UpCase( s[i] )
  86.       else s2 := s2 + LowCase( s[i] );
  87.    Result := s2;
  88. end;
  89.  
  90. function TokenStart( const s : string; chars : charSet  ) : integer;
  91. { Find index (1 based) of first token in s. Return 0 if this is an empty string
  92.   chars is a set of chars that separate tokens (e.g. whitespace, punctuation)
  93.    TokenStart('.Hello', SEPARATORS );
  94.  returns:
  95.    2 // the index of the letter 'H'
  96.  NOTE:
  97.    returns 0 if no token is found    
  98.   }
  99. var
  100.    i : integer;
  101. begin
  102.    i := 1;
  103.    if not (Length(s) = 0) then
  104.    while (s[i] in chars) do
  105.        inc(i);
  106.    if i > Length(s) then { return 0 if s nothing but characters in chars set }
  107.       Result := 0
  108.    else
  109.       Result := i;
  110. end;
  111.  
  112. procedure firstTokenAtSIndex(   s : string;
  113.                          var startindex, prevend : integer;
  114.                          var first, rest : string );
  115. {
  116.   This is really just a wrapper around the firstTokenAt() function.
  117.   The differencs is that it keeps track of the index of each
  118.   token relative to the original input string.
  119.   This procedure is PRIVATE!
  120. }
  121. var
  122.   tokstart,tokend : integer;
  123. begin
  124.   tokstart := 0; tokend := 0;
  125.   firstTokenAt( s, tokstart, tokend, first, rest);
  126.   startindex := (prevend+tokstart)-1; // 0-index
  127.   prevend := (prevend+tokend)-1;
  128. end;
  129.  
  130. procedure tokensFoundAt( s : string;
  131.                          var num: integer;
  132.                          var tindexes: tokenindexes );    //!! NEW
  133. var
  134.    first : string;
  135.    te, ts : integer;
  136. begin
  137.    first := '';
  138.    ts := 0;
  139.    te := 1;
  140.    num := 0;
  141.    while (s <> '') do  // loop while there is more to process
  142.    begin
  143.      firstTokenAtSIndex( s, ts, te, first, s) ;
  144.      if (te > ts) then   // only if a token has been parsed (end index, te
  145.      begin               // is greater than start index, ts), inc num
  146.           num := num + 1; // and fill a record with a pair of indexes
  147.           tindexes[num].tstart := ts-1; // 0-indexed
  148.           tindexes[num].tend := te-ts;
  149.      end;
  150.    end;
  151. end;
  152.  
  153. procedure firstTokenAt(   s : string;
  154.                          var tokstart, tokend : integer;
  155.                          var first, rest : string );
  156. { Return first token in string s and its start and end indices.
  157.   Also return rest of string.
  158.  
  159.   arguments
  160.              INPUT                       OUTPUT
  161.   s          a string
  162.   tokstart                               index of 1st char of 1st token in s
  163.   tokend                                 index of end of 1st token + 1 in s
  164.   first                                  first token in s
  165.   rest                                   remainder of s after 1st token
  166.  
  167.   NOTE: indexed from 1, not 0
  168.         when no more tokens in s, sets first and rest to '', sets
  169.         tokstart and tokend to 0.
  170.  
  171.   examples:
  172.   //i
  173.  
  174.      s:= '!Hello, world!'
  175.      firstTokenAt( s,tokstart,tokend,first,rest);
  176.  
  177.     returns:
  178.      tokstart=2, tokend = 7, first='Hello' rest=', world!'
  179.  
  180.   //ii
  181.    rest := !Hello, world!;
  182.    first := '';
  183.    tokstart := 1;
  184.    tokend := 0;
  185.    while (tokstart <> 0) do
  186.      firstTokenAt( rest, tokstart, tokend, first, rest);
  187.  
  188.    returns (in succession):
  189.     tokstart=2, tokend = 7, first=Hello, rest=, world!
  190.     tokstart=3, tokend = 8, first=world, rest=!
  191.   }
  192. begin
  193.   first := '';
  194.   rest := '';
  195.    tokstart := TokenStart( s, SEPARATORS );
  196.    if tokstart = 0 then
  197.       tokend := 0
  198.    else
  199.    begin
  200.       tokend := tokstart;
  201.        while not (s[tokend] in SEPARATORS) and not (tokend > Length( s ) ) do
  202.           inc(tokend);
  203.       first := copy( s, tokstart, tokend-tokstart );
  204.       rest := copy(s, tokend, MAXINT );
  205.    end;
  206. end;
  207.  
  208.  
  209. function removeLeadChars( const s : string;  chars : charSet  ) : string;
  210.    { trims string 's' by removing chars in charSet 'chars'
  211.    e.g. charSet might be [' ', '.' ]. So if s = ' .hello'
  212.    this function would return: 'hello'.
  213.  
  214.    N.B. The Constant MAXINT is used to define the string
  215.    length to the Copy function since, as Delphi Help states:
  216.      "If Count specifies more characters than are available,
  217.      the only the characters from S[Index] to the end of S are returned."
  218.    MAXINT contains the largest possible Integer}
  219. var
  220.    i : integer;
  221. begin
  222.    i := 1;
  223.    if not (Length(s) = 0) then
  224.    while (s[i] in chars) do
  225.        inc(i);
  226.    Result := Copy( s, i, MAXINT );
  227. end;
  228.  
  229. function removeTrailingChars( const s : string; chars : charSet ) : string;
  230. var
  231.    i : integer;
  232. begin
  233.    i := length(s);
  234.        { count backward from end of characters found in charSet }
  235.    if not (Length(s) = 0) then
  236.    while (s[i] in chars) and (i <> 0 ) do
  237.        dec(i);
  238.        { then return a copy of the string minus the unwanted trailing chars }
  239.    Result := copy(s, 1, i);
  240. end;
  241.  
  242.  
  243. function trimLeftStr( const s : string ) : string;
  244. { remove leading separators from string 's' }
  245. begin
  246.    trimLeftStr := removeLeadChars( s, SEPARATORS );
  247. end;
  248.  
  249. function trimRightStr( const s : string ) : string;
  250. { remove trailing separators from string 's' }
  251. begin
  252.    trimRightStr := removeTrailingChars( s, SEPARATORS );
  253. end;
  254.  
  255. function trimEndsStr( const s : string ) : string;
  256. { trim separators from both left and right of string }
  257. begin
  258.    trimEndsStr := trimLeftStr(trimRightStr(s));
  259. end;
  260.  
  261. procedure firstrestStr( const s : string; var first, rest : string );
  262. { Given a string, 's', parse out the first word as 'first' and
  263.   leave the remainder of the string untouched as 'rest' }
  264. var
  265.    i : integer;
  266.    s2 : string;
  267. begin
  268.    i := 1;
  269.    first := '';
  270.    rest := '';
  271.    s2 := trimLeftStr( s );
  272.    if not (Length(s2) = 0) then
  273.    while not (s2[i] in SEPARATORS) and not (i > Length( s2 ) ) do
  274.        inc(i);
  275.    first := copy( s2, 1, i-1 );
  276.    rest := copy(s2, i, MAXINT );
  277. end;
  278.  
  279. function encrypt( const s : string; cryptint : integer ) : string;
  280. var
  281.    i : integer;
  282.    s2 : string;
  283. begin
  284.   s2 := '';
  285.   if not ( Length(s) = 0 ) then
  286.   for i := 1 to Length( s ) do
  287.     s2 := s2 + Chr(Ord( s[i] ) + cryptint );
  288.   Result := s2;
  289. end;
  290.  
  291. function decrypt( const s : string; cryptint : integer ) : string;
  292. var
  293.    i : integer;
  294.    s2 : string;
  295. begin
  296.   s2 := '';
  297.   if not ( Length(s) = 0 ) then
  298.   for i := 1 to Length( s ) do
  299.      s2 := s2 + Chr(Ord( s[i] ) - cryptint );
  300.   Result := s2;
  301. end;
  302.  
  303. procedure parse( const s : string; slist : TStringList );
  304. { parse s into a series of tokens (e.g. individual words) and
  305.   return these in slist.
  306.  
  307.   IMPORTANT: It is the responsibility of the calling
  308.   code to create a valid TStringList object and to free
  309.   it upon completion! }
  310. var
  311.    s2, f, r : string;
  312. begin
  313.    s2 := TrimEndsStr(s);
  314.      { loop through string, until there are no more words to be parsed }
  315.    while s2 <> '' do
  316.    begin
  317.      firstrestStr(s2, f, r );   { parse 1st word, f, from string }
  318.      slist.Add(f);
  319.      s2 := r;
  320.    end;
  321. end;
  322.  
  323.  
  324. end.
  325.