Table of Contents ChiLib Library Documentation

3. Strings

3.1. Introduction

ChiLib provides a convenient String class that implements strings with complete memory management and value copy semantics, replacing the need for char* C strings. The string class has essentially the same interface as the proposed ANSI string class, and you may want to use the latter if your compiler supports it. The major addition is support for fields or tokens.

3.2. Construction

      String(); 
      String(const char s[]); 
      String(char ch); 

The default constructor creates an empty string (of length zero). The second variant accepts a C string--usually a literal "...". The third variant accepts a single character--variable or literal.

Most string operations are similarly overloaded to take C strings and characters. For simplicity, these overloaded versions are not listed in this documentation.

      char h[] = "Hell"; 
      char w = ' '; 
      String a(h); 
      String b('o'); 

      String c(w); 
      String d("World"); 
      String e; 
      String f('!'); 
 
      cout << a << b << c << d << e << f << endl; 
         // prints Hello World! 

3.3. Element access

      char get(int i) const; 
      void set(int i, char ch); 
      char String::operator[](int i) const; 
      char& String::operator[](int i); 

The get and set operations return and change, respectively, a particular character in a string. To prevent C programmers from going mad, the first character is at index 0. If the index i is out of the string's current range, set will grow the string to include the character within the string (padding with spaces) if necessary.

The bracket operator behaves as one would expect, except that it does not grow the string. Attempting to access an element of the string outside the string's current range with brackets results in a run-time error.

      String s("Brisco"); 
      char c1 = s.get(5); // c1 is o 
      char c2 = s[5]; // ditto for c2 
      s.set(0, 'F'); // Frisco 
      s[2] = 'e'; // Fresco 
      s[10] = 'L'; // error caught 
      s.set(11, 'B'); // string is grown 

3.4. Length

      int length() const; 
      Bool is_empty() const; 

The length function returns the number of characters in the string. The is_empty returns true if and only if the the string has zero length.

s[s.length()] is legal and returns a zero. Any attempt to modify that value has no effect. Strings may contain zero bytes, so length() is not necessarily the offset of the first 0 in the string.

      String a("Foo"); 
      int i = a.length(); // i equals 3 
      if (!a.is_empty()) cout << a << endl; 

3.5. Comparison

      int compare(const String& b) const; 
      int compare(const String& b, int n) const; 
      int compare_insens(const String& b) const; 

      static int compare(const String& a, const String& b); 
      static int compare_insens(const String& a, const String& b); 
      static int hash(const String& a); 

The single-argument compare functions perform a lexicographic comparison between the instance's string and the argument's. If the strings are equal, the functions return 0. If the instance's string is lexicographically less than the argument's, the function returns an integer less than 0. Otherwise, the function returns an integer greater than 0. The dual-argument versions behave the same way, except that only a maximum of n characters are compared.

The compare_insens operation performs case-insensitive comparisons.

      String s("abcdexg"); 
      int i = s.compare_insens("XYZ"); // a negative number 
      int j = s.compare("XYZ"); // a positive number 

The operators == != < <= > >= are overloaded to call compare.

      String s("abcdexg"); 
      if (s < "XYZ") ... // the condition is FALSE 

The shared (static) functions are used as comparison functions for sorting. They are functions, not class operations, because several templates require function pointers as arguments.

      Map<String, double> m(String::hash, String::compare); 

3.6. Concatenation

      void append(const String& s); 

The overloaded + operator concatenates two strings, returning a new string holding the result. The append operation modifies a string by appending another. The += operator is a synonym for append.

      String s = "What"; 
      String t = s + "'s"; 
      t.append(" up, "); 
      t += "Doc?"; 
      cout << t; // prints What's up, Doc? 

3.7. Inserting and removing characters

      void insert(int at, char ch); 
      char remove_char(int at); 

The insert operation inserts a character at position at, shifting all other characters up by 1. If at is beyond the end of the string, the string is padded with spaces up to position at - 1.

The remove operation removes and returns the character at position at. If at is beyond the end of the string, remove returns 0 and does not change the string.

3.8. Substrings

      String substr(int from, int n) const; 
      void insert(int at, const String& s); 
      String remove(int from, int n); 
      void replace(int from, int n, const String& s); 
      void replace(int from, int n, char ch); 

The substr operation returns a copy of the substring starting at from and containing up to n characters (fewer if the end of the string is reached first); remove returns that substring and removes it from the original. If n is not specified, the substring extends to the end of the string. The insert operation inserts a substring at position at, padding with spaces if at is beyond the end of the string.

The replace functions replace the instance's substring that starts at from and is n characters long with s or ch.

3.9. Fields

      String field(int n) const; 
      String insert_field(int n, String s); 
      String remove_field(int n); 
      String replace_field(int n, String s); 

These operations consider a string as a sequence of fields, or tokens, delimited by white space. The field operation returns a copy of the nth token, whereas remove_field returns the token and removes it from the string. The insert_field operation inserts another field s before the nth field. The replace_field operation replaces one field with another. The first field of a string has index zero.

      String t = "What's up, Doc?" 
      cout << t.field(1); // prints up, 
      t.remove_field(0); // t is "up, Doc?" 
      t.insert_field(0, "Hands"); // t is "Hands up, Doc?" 
      t.replace_field(2, "Doc!"); // t is "Hands up, Doc!" 

3.10. Input and output

      int read_line(istream& is); 
      int read_delimited(istream& is); 
      void write_delimited(ostream& os); 

The read_line function reads characters from the input stream until it reaches a newline character or the end of file. The newline character is not placed into the string. The function returns the number of characters placed into the string or -1 at the end of the file.

      String s; 
      cout << s.read_line(cin); // entering "FORTRAN" causes "7" to be  
      printed 
      cout << s; // prints "FORTRAN" and no newline 

The read_delimited and write_delimited operations read and write strings enclosed in "...". Use these operations for strings containing white space.

3.11. Finding

      int find(char c, int from = 0) const; 
      int find(const String& s, int from = 0) const; 
      int rfind(char c, int from = NPOS) const; 

The find functions return the index of a character or string found within the instance's string. The default starting index is from the string's beginning. The rfind operation performs a search backwards from from toward the string's beginning. The functions return NPOS if they do not find the substring or character.

      int find_first_of(const String& s, int from = 0) const; 
      int find_first_not_of(const String& s, int from = 0) const; 

These functions treat s as a set of characters. Starting from from (or the string's beginning if nothing is specified), find_first_of returns the index to the first character that matches any character in s. The find_first_not_of operation returns the index to the first character that does not match any character in s.

      String s("abcdexg"); 
      cout << s.find_first_not_of("xyzb"); // prints 0 
      cout << s.find_first_of("xyzb"); // prints 1 

3.12. Case conversion

      String& to_lower(); 
      String& to_upper(); 

These change all characters in the instance to lowercase or uppercase, respectively.

      String s("Harry"); 
      s.to_upper(); 
      cout << s; // prints HARRY 
      s.to_lower(); 
      cout << s; // prints harry 

3.13. Numeric conversion

      long to_long() const; 
      double to_double() const; 
      void from_long(long n); 
      void from_double(double d); 

These functions convert longs or doubles to strings, or strings to longs or doubles.

3.14. Conversion to C strings

      char* c_array(char buf[], size_t buflen,  
                    int from = 0, int n = NPOS) const; 
      const char* c_str() const; 
      char* new_c_array() const; 

Occasionally, you need a C-style string, usually as an argument to a library function. These functions provide this to you.

The c_array operation copies n bytes of the instance's string, beginning at index from. You must specify the size of the buffer pointed to by buf. If you specify no from or n, the the entire string is copied.

The c_str returns a pointer to the string's internal data representation. Because the string's storage may not be in a permanent memory location, c_str's pointer should be understood as having an extremely short lifetime. You should never store the pointer, or write to its contents.

The new_c_array operation creates a copy of the string's internal data representation and returns a pointer to the newly allocated block. After using the block, you must call delete[] on the block.