Сравнение std::string без учета регистра
От: Павел Кузнецов  
Дата: 18.08.03 10:54
Оценка: 22 (5)
#Имя: FAQ.cpp.string.compare
Y> Мне надо сравнить два std::string без учета регистра. Я написал свою
Y> функцию сравнения, все вроде Ok, но меня мучает такой вопрос: есть ли
Y> стандартные средства (библиотечные) для такого сравнения?

Если подробно и "правильно", там все очень долго и сложно, т.к. преобразование символов
в разный регистр зависит от того, какой объект std::locale использовать и может приводить
к разным сюрпризам вроде преобразования одного заглавного символа в несколько строчных
и наоборот. Вкратце, более-менее "стандартным", (в смысле, что в нем используются только
стандартные возможности) можно считать примерно такой вариант:

#include <string>
#include <locale>
#include <algorithm>

class ToUpper
{
public:
  ToUpper(const std::locale&);

  char operator()(char c) const
  {
    return m_ct.toupper(c);
  }

private:
  const std::ctype<char>& m_ct;
};

class ToLower
{
public:
  ToLower(const std::locale&);

  char operator()(char c) const
  {
    return m_ct.tolower(c);
  }

private:
  const std::ctype<char>& m_ct;
};

void to_upper(const std::string& in, std::string& out, const std::locale& lc)
{
  if (out.length() < in.length())
    out.resize(in.length());
  std::transform(in.begin(), in.end(), out.begin(), ToUpper(lc));
}

void to_lower(const std::string& in, std::string& out, const std::locale& lc)
{
  if (out.length() < in.length())
    out.resize(in.length());
  std::transform(in.begin(), in.end(), out.begin(), ToLower(lc));
}

int compare_no_case(const std::string& l, const std::string& r, const std::locale& lc)
{
  ToUpper transformer (lc);

  std::string l_nc;
  l_nc.resize(l.length());
  std::transform(l.begin(), l.end(), l_nc.begin(), transformer);

  std::string r_nc;
  r_nc.resize(l.length());
  std::transform(l.begin(), l.end(), r_nc.begin(), transformer);

  return l_nc.compare(r_nc);
}


Приведенный код можно оптимизировать и оптимизировать, но наглядность его от этого не увеличится
Существенным недостатком приведенного варианта является отсутствие поддержки преобразований,
приводящих к преобразованию одного символа в несколько или наоборот, но основная идея использования
std::locale для преобразования между регистрами должна быть ясна

P.S. также можно воспользоваться какими-нибудь нестандартными расширениями,
предоставленными поставщиком компилятора; например, _strcmpi.
Posted via RSDN NNTP Server 1.6 RC1
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re: Сравнение std::string без учета регистра
От: vadimus  
Дата: 18.08.03 10:19
Оценка: 6 (2)
Здравствуйте, Yuri, Вы писали:

Y>Привет всем.

Y>Мне надо сравнить два std::string без учета регистра. Я написал свою функию сравнения, все вроде Ok, но меня мучает такой вопрос: есть ли стандартные средства (библиотечные) для такого сравнения?

int strcmpi(char*,char*);
Re: Сравнение std::string без учета регистра
От: LaptevVV Россия  
Дата: 18.08.03 10:23
Оценка: 4 (1)
Здравствуйте, Yuri, Вы писали:

Y>Привет всем.

Y>Мне надо сравнить два std::string без учета регистра. Я написал свою функию сравнения, все вроде Ok, но меня мучает такой вопрос: есть ли стандартные средства (библиотечные) для такого сравнения?
Не, в STL точно таких средств нет. У Герба Саттера ОЧЕНЬ много на эту тему написано. А потом, у тебя ведь и русские буквы сравниваются, да? Тем более нету.
А ты локали применял?
Напиши текст, дай посмотреть, а то я влокалях пока полный профан!
В string.h есть strcmpi, но она ведь тоже английские кушает.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Сравнение std::string без учета регистра
От: Yuri Россия http://spbdetails.ru
Дата: 18.08.03 10:03
Оценка:
Привет всем.
Мне надо сравнить два std::string без учета регистра. Я написал свою функию сравнения, все вроде Ok, но меня мучает такой вопрос: есть ли стандартные средства (библиотечные) для такого сравнения?
Take it easy.
Re[2]: Сравнение std::string без учета регистра
От: Anton V. Kolotaev  
Дата: 18.08.03 10:23
Оценка:
Здравствуйте, vadimus, Вы писали:

Y>>Мне надо сравнить два std::string без учета регистра. Я написал свою функию сравнения, все вроде Ok, но меня мучает такой вопрос: есть ли стандартные средства (библиотечные) для такого сравнения?


V>int strcmpi(char*,char*);


А он умеет сравнивать, если алфавит не латинский???
Re[3]: Сравнение std::string без учета регистра
От: vadimus  
Дата: 18.08.03 10:29
Оценка:
Здравствуйте, Anton V. Kolotaev, Вы писали:

AVK>Здравствуйте, vadimus, Вы писали:


V>>int strcmpi(char*,char*);


AVK>А он умеет сравнивать, если алфавит не латинский???


По-моему нет
Re[2]: Сравнение std::string без учета регистра
От: Yuri Россия http://spbdetails.ru
Дата: 18.08.03 10:29
Оценка:
Здравствуйте, LaptevVV, Вы писали:

LVV>Здравствуйте, Yuri, Вы писали:


Y>>Привет всем.

Y>>Мне надо сравнить два std::string без учета регистра. Я написал свою функию сравнения, все вроде Ok, но меня мучает такой вопрос: есть ли стандартные средства (библиотечные) для такого сравнения?
LVV>Не, в STL точно таких средств нет. У Герба Саттера ОЧЕНЬ много на эту тему написано. А потом, у тебя ведь и русские буквы сравниваются, да? Тем более нету.
LVV>А ты локали применял?
LVV>Напиши текст, дай посмотреть, а то я влокалях пока полный профан!
LVV>В string.h есть strcmpi, но она ведь тоже английские кушает.

Не, русские строки она сравнивать не умеет, в моей задаче этого не нужно.
Take it easy.
Re[3]: Сравнение std::string без учета регистра
От: Аноним  
Дата: 18.08.03 10:37
Оценка:
Здравствуйте, Anton V. Kolotaev, Вы писали:

AVK>А он умеет сравнивать, если алфавит не латинский???


Да. См. setlocale().
Re[2]: Сравнение std::string без учета регистра
От: alexkro  
Дата: 19.08.03 03:26
Оценка:
Здравствуйте, LaptevVV, Вы писали:

LVV>Не, в STL точно таких средств нет. У Герба Саттера ОЧЕНЬ много на эту тему написано.


http://www.gotw.ca/gotw/029.htm

Какая-то поддержка, все-таки, в STL есть.
Re[4]: Сравнение std::string без учета регистра
От: Alexey Shirshov Россия http://wise-orm.com
Дата: 19.08.03 05:00
Оценка:
Hello, !
You wrote on Mon, 18 Aug 2003 10:37:13 GMT:

хъ
MSDN

_stricmp differs from _stricoll in that the _stricmp comparison is not
affected by locale, whereas the _stricoll comparison is according to the
LC_COLLATE category of the current locale.


With best regards, Alex Shirshov.
Posted via RSDN NNTP Server 1.7 beta
Re: Сравнение std::string без учета регистра
От: Аноним  
Дата: 13.01.05 08:55
Оценка:
Здравствуйте, Павел, Вы писали:

[skip]...[/skip]
class ToUpper
{
public:
  ToUpper(const std::locale&);

  char operator()(char c) const
  {
    return m_ct.toupper(c);
  }

[skip]...[/skip]

Что-то я торможу.
Не понятно где и какую роль играет std::locale? Приведите пожалуйста реализацию конструктора ToUpper(const std::locale&).
Re[2]: Сравнение std::string без учета регистра
От: Павел Кузнецов  
Дата: 14.01.05 16:51
Оценка:
> Не понятно где и какую роль играет std::locale? Приведите пожалуйста реализацию конструктора ToUpper(const std::locale&).

std::locale используется для получения std::ctype:
class ToUpper
{
public:
   ToUpper(const std::locale& l)
   : m_ct (std::use_facet<std::ctype<char> >(l))
   {
   }

   char operator()(char c) const
   {
     return m_ct.toupper(c);
   }

private:
   const std::ctype<char>& m_ct;
};

Но здесь есть тонкий момент: facet m_ct будет жить только пока жива locale, из которой он получен. Т.к. периодически могут использоваться временные объекты std::locale и ToUpper может использоваться не в точке создания, то более надежным вариантом будет продление жизни полученной std::locale:
class ToUpper
{
public:
   ToUpper(const std::locale& l)
   : m_l  (l)
   , m_ct (std::use_facet<std::ctype<char> >(m_l))
   {
   }

   char operator()(char c) const
   {
     return m_ct.toupper(c);
   }

private:
   std::locale m_l;
   const std::ctype<char>& m_ct;
};
Posted via RSDN NNTP Server 1.9
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.