функция tolower для строк C++

Есть ли встроенная функция для преобразования строки C++ из прописных букв в строчные? Если не преобразовать его в cstring и использовать tolower для каждого символа, это единственный вариант?

Заранее большое спасибо.


person brett    schedule 04.08.2010    source источник
comment
В Германии tolower(STRASSE) должно привести к straße. В Швейцарии это должно быть strasse. И таких случаев в мире гораздо больше. Встроенная функция должна правильно обрабатывать такие случаи. Если вам все равно, просто используйте tolower() для каждого символа, как показывают большинство ответов.   -  person Sjoerd    schedule 04.08.2010
comment
@Sjoerd: Хороший пример. Слышали ли вы о какой-нибудь библиотеке, которая изящно справляется с такими случаями? Я мог бы заинтересоваться этим.   -  person ereOn    schedule 04.08.2010
comment
@ereOn: Нет, он мне никогда не был нужен. Я знаю, что с tolower() есть проблемы, но там, где я живу и в приложениях, которые я пишу, tolower() обычно достаточно хорош.   -  person Sjoerd    schedule 04.08.2010
comment
Я полагаю, что ICU может справиться с этим правильно (icu-project.org), но это может быть излишним для цели ОП.   -  person jalf    schedule 04.08.2010
comment
@ereOn: на самом деле это практически невозможно без словаря, содержащего все неоднозначные слова. В немецком языке SS будет ß только в том случае, если говорить медленно, в противном случае оно должно стать ss.   -  person Sebastian Mach    schedule 16.06.2011
comment
@Jalf: Есть ли в ICU словари? Например, в немецком языке нет однозначного отображения SS -> lowercase; например STRASSE -> straße, но TRASSE -> trasse. Некоторые слова даже не однозначны: MASSE -> maße (= меры, размеры) и MASSE -> masse (= ​​масса). (редактировать: только сейчас я понимаю, что уже посещал этот вопрос в прошлом, xd)   -  person Sebastian Mach    schedule 25.04.2012
comment
@phresnel: честно? Я не знаю, как (и если) это дело обрабатывается. ICU просто следует правилам Unicode, и я не знаю, что стандарт Unicode говорит об этом случае.   -  person jalf    schedule 25.04.2012
comment
@jalf: Хорошо, спасибо за информацию :)   -  person Sebastian Mach    schedule 25.04.2012


Ответы (6)


Если boost является вариантом:

#include <boost/algorithm/string.hpp>    

std::string str = "wHatEver";
boost::to_lower(str);

В противном случае вы можете использовать std::transform:

std::string str = "wHatEver";
std::transform(str.begin(), str.end(), str.begin(), ::tolower);

Вы также можете использовать другую функцию, если у вас есть какой-то пользовательский tolower с учетом локали.

person ereOn    schedule 04.08.2010

Как говорит ereOn: std::transform(str.begin(), str.end(), str.begin(), std::tolower );

Или через for_each: std::for_each(str.begin(), str.end(), std::tolower );

Преобразование, вероятно, лучше из двух.

person graham.reeds    schedule 04.08.2010
comment
Бьюсь об заклад. for_each не меняет str. - person Nordic Mainframe; 04.08.2010
comment
Это было написано наобум. Вы можете использовать лямду для вызова tolower для каждого символа. - person graham.reeds; 04.08.2010

Для этого нет встроенной функции, и сделать это на удивление сложно из-за локалей и др. Если tolower делает то, что вам нужно, это может быть вашим лучшим выбором.

person Community    schedule 04.08.2010

Для этой проблемы вы можете использовать метод преобразования STL для ее решения:

std::string str = "simple";
std::transform(str.begin(), str.end(), str.begin(), std::tolower);
person Nanne    schedule 04.08.2010

У меня есть реализация, которую я нашел быстрее, чем std::transform , скомпилированная в g++ -03 Fedora 18. мой пример преобразует std::string

performance time in seconds :
transform took         : 11 s
my implementation took : 2 s
Test data size = 26*15*9999999 chars
inline void tolowerPtr(char *p) ;

inline void tolowerStr(std::string& s)
{char* c=const_cast<char*>(s.c_str());
size_t l = s.size();
  for(char* c2=c;c2<c+l;c2++)tolowerPtr(c2); 
};

inline void tolowerPtr(char *p) 
{
switch(*p)
{
  case 'A':*p='a'; return;
  case 'B':*p='b'; return;
  case 'C':*p='c'; return;
  case 'D':*p='d'; return;
  case 'E':*p='e'; return;
  case 'F':*p='f'; return;
  case 'G':*p='g'; return;
  case 'H':*p='h'; return;
  case 'I':*p='i'; return;
  case 'J':*p='j'; return;
  case 'K':*p='k'; return;
  case 'L':*p='l'; return;
  case 'M':*p='m'; return;
  case 'N':*p='n'; return;
  case 'O':*p='o'; return;
  case 'P':*p='p'; return;
  case 'Q':*p='q'; return;
  case 'R':*p='r'; return;
  case 'S':*p='s'; return;
  case 'T':*p='t'; return;
  case 'U':*p='u'; return;
  case 'V':*p='v'; return;
  case 'W':*p='w'; return;
  case 'X':*p='x'; return;
  case 'Y':*p='y'; return;
  case 'Z':*p='z'; return;
};
return ;
}

void testtransform( std::string& word )
{
std::string word2=word; 
time_t t;
time_t t2;
time(&t);
std::cout << "testtransform: start " << "\n";
int i=0;
for(;i<9999999;i++) 
{    word2=word;
    std::transform(word2.begin(), word2.end(), word2.begin(), ::tolower);
}
time(&t2);
std::cout << word2 << "\n";
std::cout << "testtransform: end " << i << ":"<< t2-t << "\n";
}

void testmytolower( std::string& word )
{
std::string word2=word; 
time_t t;
time_t t2;
time(&t);
std::cout << "testmytolower: start " << "\n";
int i=0;
for(;i<9999999;i++)
{   word2=word;
    cstralgo::tolowerStr(word2);
}
time(&t2);
std::cout << word2 << "\n";
std::cout << "testmytolower: end " << i << ":"<< t2-t << "\n";
}

int main(int argc, char* argv[])
{
   std::string word ="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
   word =word+word+word+word+word+word+word+word+word+word+word+word+word+word+word;
   testtransform( word);
   testmytolower( word);
   return 0;
}

Я буду рад узнать, можно ли еще улучшить производительность.

person Anand Rathi    schedule 10.04.2013
comment
Вы просто освещаете здесь алфавит ASCII, и довольно ужасным образом. То же самое может быть достигнуто: if (*p >= 'A' && *p <=Z) *p += 'a' - 'A'. И вы по-прежнему потенциально пропускаете многие другие буквы, например. 'А'. - person gatopeich; 13.04.2018

person    schedule
comment
Этот и другие ответы transform + tolower должны учитывать, что это не обязательно будет компилироваться, в зависимости от того, какие стандартные заголовки включены в этот файл. Есть один tolower в <cctype> и перегрузка в <locale>. Если оба будут включены, вы получите ошибку компилятора. См., например: stackoverflow.com /вопросы/1350380/ - person UncleBens; 04.08.2010
comment
Обратите внимание, что этот ответ (и все остальные ответы transform) потенциально могут вызвать неопределенное поведение, поскольку std::tolower cstdlib требует неотрицательного аргумента. - person M.M; 16.08.2015