Шаг 386.
Библиотека STL.
Строки. Интернационализация

    На этом шаге мы рассмотрим более подробно понятие интернационализации.

    Как уже упоминалось во вводном описании строковых классов, шаблон строкового класса basic_string<> параметризуется по типу символов, трактовкам типа символов и модели памяти. Тип string представляет собой специализированную версию шаблона для символов типа char, а тип wstring предназначен для символов типа wchar_t.

    Трактовки типа символов представляют собой информацию о том, как следует поступать в зависимости от представления типа символов. Необходимость в дополнительном классе объясняется тем, что интерфейс встроенных типов (таких, как char и wchar_t) изменять нельзя, но один символьный тип может трактоваться по-разному.

    В следующем фрагменте определяется специальный класс трактовок для строк, благодаря которому операции со строками выполняются без учета регистра символов:

#ifndef ICSTRING_HPP
#define ICSTRING_HPP

#include <string>
#include <iostream>
#include <cctype>

// Замена функций стандартного класса char_traits<char>
//  для того, чтобы операции со строками
//  выполнялись без учета регистра символов
struct ignorecase_traits : public std::char_traits<char> {
    // Проверка равенства c1 и c2
    static bool eq(const char& c1, const char& c2) {
        return std::toupper(c1)==std::toupper(c2);
    }
    // Проверка условия "с1 меньше c2"
    static bool lt(const char& c1, const char& c2) {
        return std::toupper(c1)<std::toupper(c2);
    }
    // Сравнение до n символов s1 и s2
    static int compare(const char* s1, const char* s2,
                       std::size_t n) {
        for (std::size_t i=0; i<n; ++i) {
            if (!eq(s1[i],s2[i])) {
                return lt(s1[i],s2[i])?-1:1;
            }
        }
        return 0;
    }
    // Поиск c в s
    static const char* find(const char* s, std::size_t n,
                            const char& c) {
        for (std::size_t i=0; i<n; ++i) {
            if (eq(s[i],c)) {
                return &(s[i]);
            }
        }
        return 0;
    }
};

// Определение специального типа для таких строк
typedef std::basic_string<char,ignorecase_traits> icstring;

/* Определение оператора вывода,
 * так как тип трактовок отличен от типа,
 * заданного для std::ostream
 */
inline
std::ostream& operator << (std::ostream& strm, const icstring& s)
{
    // Простое преобразование icstring в обычную строку
    return strm << std::string(s.data(),s.length());
}

#endif    // ICSTRING_HPP

    Определение оператора вывода необходимо из-за того, что стандарт описывает операторы ввода-вывода только для потоков данных, у которых тип символов соответствует типу трактовок. В данном случае мы используем другой тип трактовок, поэтому для него приходится определять собственный оператор вывода. Аналогичная проблема существует и для операторов ввода.

    В следующей программе показано, как использовать специализированный вид строк:

//---------------------------------------------------------------------------

#include <vcl.h>
#include "icstring.hpp"

#include <conio.h>   //необходимо для getch()

#pragma hdrstop

//---------------------------------------------------------------------------

#pragma argsused
using namespace std;

std::string ToRus(const std::string &in)
{
  char *buff = new char [in.length()+1];
  CharToOem(in.c_str(),buff);
  std::string out(buff);
  delete [] buff;
  return out;
}

int main (int argc, char* argv[])
{
  using std::cout;
  using std::endl;

  icstring s1("hallo");
  icstring s2("otto");
  icstring s3("hALLo");
    
  cout << std::boolalpha;
  cout << s1 << " == " << s2 << " : " << (s1==s2) << endl;
  cout << s1 << " == " << s3 << " : " << (s1==s3) << endl;

  icstring::size_type idx = s1.find("All");
  if (idx != icstring::npos) {
      cout << ToRus("Номер вхождения строки \"All\" в строку \"") << s1 << "\": "
             << idx << endl;
  }
  else {
      cout << ToRus("Строка \"All\" отсутствует в строке \"") << s1 << endl;
  }


  getch();
  return 0;
}

//---------------------------------------------------------------------------
Текст этого примера можно взять здесь.

    Результат выполнения программы выглядит так:


Рис.1. Результат работы приложения

    На следующем шаге мы остановимся более подробно на эффективности.




Предыдущий шаг Содержание Следующий шаг