una que programa pasar muestre minusculas mayusculas mayuscula letra hasta escribir dev convertir como caracteres cambiar cadena abecedario c++ string c++-standard-library tolower

que - programa de mayusculas a minusculas c++



¿Cómo convertir std:: string a minúsculas? (21)

Quiero convertir un std::string a minúsculas. Soy consciente de la función tolower() , sin embargo, en el pasado he tenido problemas con esta función y casi no es ideal, ya que su uso con una std::string requeriría iterar sobre cada carácter.

¿Existe alguna alternativa que funcione el 100% del tiempo?


Fragmento de código

#include<bits/stdc++.h> using namespace std; int main () { ios::sync_with_stdio(false); string str="String Convert/n"; for(int i=0; i<str.size(); i++) { str[i] = tolower(str[i]); } cout<<str<<endl; return 0; }


Aquí hay una técnica macro si quieres algo simple:

#define STRTOLOWER(x) std::transform (x.begin(), x.end(), x.begin(), ::tolower) #define STRTOUPPER(x) std::transform (x.begin(), x.end(), x.begin(), ::toupper) #define STRTOUCFIRST(x) std::transform (x.begin(), x.begin()+1, x.begin(), ::toupper); std::transform (x.begin()+1, x.end(), x.begin()+1,::tolower)

Sin embargo, tenga en cuenta que el comentario de @ AndreasSpindler sobre esta respuesta aún es una consideración importante, sin embargo, si está trabajando en algo que no son solo caracteres ASCII.


De this :

#include <algorithm> #include <string> std::string data = "Abc"; std::transform(data.begin(), data.end(), data.begin(), ::tolower);

Realmente no vas a salir con la iteración a través de cada personaje. No hay forma de saber si el carácter es minúscula o mayúscula de lo contrario.

Si realmente odias tolower() , aquí hay una alternativa no portátil que no te recomiendo que uses:

char easytolower(char in) { if(in <= ''Z'' && in >= ''A'') return in - (''Z'' - ''z''); return in; } std::transform(data.begin(), data.end(), data.begin(), easytolower);

Tenga en cuenta que ::tolower() solo puede realizar una sustitución de un byte por carácter, lo que no es adecuado para muchos scripts, especialmente si se utiliza una codificación de múltiples bytes como UTF-8.


En las plataformas Microsoft, puede usar la familia de funciones strlwr : http://msdn.microsoft.com/en-us/library/hkxwh33z.aspx

// crt_strlwr.c // compile with: /W3 // This program uses _strlwr and _strupr to create // uppercase and lowercase copies of a mixed-case string. #include <string.h> #include <stdio.h> int main( void ) { char string[100] = "The String to End All Strings!"; char * copy1 = _strdup( string ); // make two copies char * copy2 = _strdup( string ); _strlwr( copy1 ); // C4996 _strupr( copy2 ); // C4996 printf( "Mixed: %s/n", string ); printf( "Lower: %s/n", copy1 ); printf( "Upper: %s/n", copy2 ); free( copy1 ); free( copy2 ); }


Esta podría ser otra versión simple para convertir mayúsculas a minúsculas y viceversa. Usé la versión de la comunidad VS2017 para compilar este código fuente.

#include <iostream> #include <string> using namespace std; int main() { std::string _input = "lowercasetouppercase"; #if 0 // My idea is to use the ascii value to convert char upperA = ''A''; char lowerA = ''a''; cout << (int)upperA << endl; // ASCII value of ''A'' -> 65 cout << (int)lowerA << endl; // ASCII value of ''a'' -> 97 // 97-65 = 32; // Difference of ASCII value of upper and lower a #endif // 0 cout << "Input String = " << _input.c_str() << endl; for (int i = 0; i < _input.length(); ++i) { _input[i] -= 32; // To convert lower to upper #if 0 _input[i] += 32; // To convert upper to lower #endif // 0 } cout << "Output String = " << _input.c_str() << endl; return 0; }

Nota: si hay caracteres especiales, debe manejarse utilizando la verificación de condición.


Este es un seguimiento de la respuesta de Stefan Mai: si desea colocar el resultado de la conversión en otra cadena, debe asignar previamente su espacio de almacenamiento antes de llamar a std::transform . Como STL almacena los caracteres transformados en el iterador de destino (incrementándolo en cada iteración del bucle), la cadena de destino no se redimensionará automáticamente y corre el riesgo de que la memoria se detenga.

#include <string> #include <algorithm> #include <iostream> int main (int argc, char* argv[]) { std::string sourceString = "Abc"; std::string destinationString; // Allocate the destination space destinationString.resize(sourceString.size()); // Convert the source string to lower case // storing the result in destination string std::transform(sourceString.begin(), sourceString.end(), destinationString.begin(), ::tolower); // Output the result of the conversion std::cout << sourceString << " -> " << destinationString << std::endl; }


Hay un algoritmo de cadena Boost para esto:

#include <boost/algorithm/string.hpp> std::string str = "HELLO, WORLD!"; boost::algorithm::to_lower(str); // modifies str

O, para no en el lugar:

#include <boost/algorithm/string.hpp> const std::string str = "HELLO, WORLD!"; const std::string lower_str = boost::algorithm::to_lower_copy(str);


Hay una manera de convertir mayúsculas a inferiores sin hacer si las pruebas , y es bastante sencillo. El uso de la función / macro isupper () de clocale.h debería ocuparse de los problemas relacionados con su ubicación, pero si no, siempre puede ajustar la UtoL [] al contenido de su corazón.

Dado que los caracteres de C son en realidad solo ints de 8 bits (ignorando los conjuntos de caracteres anchos por el momento), puede crear una matriz de 256 bytes que contiene un conjunto alternativo de caracteres, y en la función de conversión use los caracteres de su cadena como subíndices en el matriz de conversión.

Sin embargo, en lugar de una asignación 1-por-1, dé a los miembros de la matriz en mayúsculas los valores BYTE int para los caracteres en minúsculas. Puede encontrar isower () y isupper () útiles aquí.

El código se ve así ...

#include <clocale> static char UtoL[256]; // ---------------------------------------------------------------------------- void InitUtoLMap() { for (int i = 0; i < sizeof(UtoL); i++) { if (isupper(i)) { UtoL[i] = (char)(i + 32); } else { UtoL[i] = i; } } } // ---------------------------------------------------------------------------- char *LowerStr(char *szMyStr) { char *p = szMyStr; // do conversion in-place so as not to require a destination buffer while (*p) { // szMyStr must be null-terminated *p = UtoL[*p]; p++; } return szMyStr; } // ---------------------------------------------------------------------------- int main() { time_t start; char *Lowered, Upper[128]; InitUtoLMap(); strcpy(Upper, "Every GOOD boy does FINE!"); Lowered = LowerStr(Upper); return 0; }

Este enfoque le permitirá, al mismo tiempo, reasignar cualquier otro personaje que desee cambiar.

Este enfoque tiene una gran ventaja cuando se ejecuta en procesadores modernos, no hay necesidad de hacer predicciones de bifurcaciones ya que no hay pruebas de si las bifurcaciones. Esto guarda la lógica de predicción de ramificación de la CPU para otros bucles, y tiende a evitar las paradas de la tubería.

Algunos aquí pueden reconocer este enfoque como el mismo utilizado para convertir EBCDIC a ASCII.


Intenté std :: transform, todo lo que recibo es un error de compilación críptica stl abominable que solo los druidas de hace 200 años pueden entender (no se puede convertir a la gripe flibidi flabidi)

esto funciona bien y se puede modificar fácilmente

string LowerCase(string s) { int dif=''a''-''A''; for(int i=0;i<s.length();i++) { if((s[i]>=''A'')&&(s[i]<=''Z'')) s[i]+=dif; } return s; } string UpperCase(string s) { int dif=''a''-''A''; for(int i=0;i<s.length();i++) { if((s[i]>=''a'')&&(s[i]<=''z'')) s[i]-=dif; } return s; }


La forma más sencilla de convertir cadenas en minúsculas sin preocuparse por el espacio de nombres estándar es la siguiente

1: cadena con / sin espacios

#include <algorithm> #include <iostream> #include <string> using namespace std; int main(){ string str; getline(cin,str); //------------function to convert string into lowercase--------------- transform(str.begin(), str.end(), str.begin(), ::tolower); //-------------------------------------------------------------------- cout<<str; return 0; }

2: cadena sin espacios

#include <algorithm> #include <iostream> #include <string> using namespace std; int main(){ string str; cin>>str; //------------function to convert string into lowercase--------------- transform(str.begin(), str.end(), str.begin(), ::tolower); //-------------------------------------------------------------------- cout<<str; return 0; }


Otro enfoque utilizando rango basado en bucle con variable de referencia

string test = "Hello World"; for(auto& c : test) { c = tolower(c); } cout<<test<<endl;


Por lo que veo, las bibliotecas Boost son realmente malas en cuanto a rendimiento. He probado su mapa desordenado a STL y fue 3 veces más lento en promedio (mejor caso 2, peor fue 10 veces). También este algoritmo parece demasiado bajo.

La diferencia es tan grande que estoy seguro de que cualquier adición que tenga que hacer para tolower para que sea igual para impulsar "para sus necesidades" será mucho más rápida que el impulso.

He realizado estas pruebas en un Amazon EC2, por lo tanto, el rendimiento varió durante la prueba, pero aún se entiende la idea.

./test Elapsed time: 12365milliseconds Elapsed time: 1640milliseconds ./test Elapsed time: 26978milliseconds Elapsed time: 1646milliseconds ./test Elapsed time: 6957milliseconds Elapsed time: 1634milliseconds ./test Elapsed time: 23177milliseconds Elapsed time: 2421milliseconds ./test Elapsed time: 17342milliseconds Elapsed time: 14132milliseconds ./test Elapsed time: 7355milliseconds Elapsed time: 1645milliseconds

-O2 hizo así:

./test Elapsed time: 3769milliseconds Elapsed time: 565milliseconds ./test Elapsed time: 3815milliseconds Elapsed time: 565milliseconds ./test Elapsed time: 3643milliseconds Elapsed time: 566milliseconds ./test Elapsed time: 22018milliseconds Elapsed time: 566milliseconds ./test Elapsed time: 3845milliseconds Elapsed time: 569milliseconds

Fuente:

string str; bench.start(); for(long long i=0;i<1000000;i++) { str="DSFZKMdskfdsjfsdfJDASFNSDJFXCKVdnjsafnjsdfjdnjasnJDNASFDJDSFSDNJjdsanjfsdnfjJNFSDJFSD"; boost::algorithm::to_lower(str); } bench.end(); bench.start(); for(long long i=0;i<1000000;i++) { str="DSFZKMdskfdsjfsdfJDASFNSDJFXCKVdnjsafnjsdfjdnjasnJDNASFDJDSFSDNJjdsanjfsdnfjJNFSDJFSD"; for(unsigned short loop=0;loop < str.size();loop++) { str[loop]=tolower(str[loop]); } } bench.end();

Supongo que debería hacer las pruebas en una máquina dedicada, pero usaré este EC2, así que no necesito probarlo en mi máquina.



Usando rango basado en bucle de C ++ 11, un código más simple sería:

#include <iostream> // std::cout #include <string> // std::string #include <locale> // std::locale, std::tolower int main () { std::locale loc; std::string str="Test String./n"; for(auto elem : str) std::cout << std::tolower(elem,loc); }



Una alternativa a Boost es POCO (pocoproject.org).

POCO ofrece dos variantes:

  1. La primera variante hace una copia sin alterar la cadena original.
  2. La segunda variante cambia la cadena original en su lugar.
    Las versiones "en el lugar" siempre tienen "InPlace" en el nombre.

Ambas versiones se muestran a continuación:

#include "Poco/String.h" using namespace Poco; std::string hello("!"); // Copies "!" into ''newString'' without altering ''hello.'' std::string newString(toUpper(hello)); // Changes newString in-place to read "!" toLowerInPlace(newString);


std::ctype::tolower() de la biblioteca de localización estándar de C ++ hará esto correctamente por usted. Aquí hay un ejemplo extraído de la página de referencia de tolower

#include <locale> #include <iostream> int main () { std::locale::global(std::locale("en_US.utf8")); std::wcout.imbue(std::locale()); std::wcout << "In US English UTF-8 locale:/n"; auto& f = std::use_facet<std::ctype<wchar_t>>(std::locale()); std::wstring str = L"HELLo, wORLD!"; std::wcout << "Lowercase form of the string ''" << str << "'' is "; f.tolower(&str[0], &str[0] + str.size()); std::wcout << "''" << str << "''/n"; }


Copia porque no estaba permitido mejorar la respuesta. Gracias

string test = "Hello World"; for(auto& c : test) { c = tolower(c); }

Explicación:

for(auto& c : test) es un bucle para el tipo de rango
for ( range_declaration : range_expression ) loop_statement :

  1. range_declaration : auto& c
    Aquí el especificador automático se utiliza para la deducción automática de tipos. Entonces el tipo se deduce del inicializador de variables.

  2. range_expression : test
    El rango en este caso son los caracteres de test de cadena.

Los caracteres de la test cadena están disponibles como una referencia dentro del bucle for a través del identificador c .


tl; dr

Utilice la biblioteca de la UCI .

Primero tienes que responder una pregunta: ¿Cuál es la codificación de tu std::string ? ¿Es ISO-8859-1? ¿O tal vez la norma ISO-8859-8? ¿O la página de códigos de Windows 1252? ¿Lo que estás usando para convertir mayúsculas a minúsculas lo sabe? (¿O falla miserablemente para los personajes de más de 0x7f ?)

Si está utilizando UTF-8 (la única opción sensata entre las codificaciones de 8 bits) con std::string como contenedor, ya se está engañando a sí mismo para creer que todavía tiene el control de las cosas, porque está almacenando un carácter multibyte secuencia en un contenedor que no es consciente del concepto multibyte. Incluso algo tan simple como .substr() es una bomba de tiempo. (Debido a que dividir una secuencia multibyte resultará en una cadena (sub-) inválida).

Y tan pronto como intentes algo como std::toupper( ''ß'' ) , en cualquier codificación, estás en un gran problema. (Porque simplemente no es posible hacer esto "correctamente" con la biblioteca estándar, que solo puede proporcionar un carácter de resultado, no el "SS" necesario aquí.) [1] Otro ejemplo sería std::tolower( ''I'' ) , lo que debería dar diferentes resultados dependiendo de la localización . En Alemania, ''i'' sería correcto; en Turquía, el resultado esperado es ''ı'' (LATIN SMALL LETTER DOTLESS I).

Luego está el punto en el que la biblioteca estándar depende de las configuraciones regionales admitidas en la máquina en la que se está ejecutando el software ... y ¿qué hace si no lo es?

Entonces, lo que realmente está buscando es una clase de cadena que sea capaz de manejar todo esto correctamente, y eso no es std::string .

(Nota de C ++ 11: std::u16string y std::u32string son mejores , pero aún no son perfectas)

Mientras que Boost se ve bien, en cuanto a API, Boost.Locale es básicamente una envoltura alrededor de la UCI . Si Boost se compila con el soporte de ICU ... si no lo está, Boost.Locale se limita al soporte de locale compilado para la biblioteca estándar.

Y créeme, conseguir que Boost compile con la UCI a veces puede ser un verdadero dolor. (No hay archivos binarios precompilados para Windows, por lo que tendrías que proporcionarlos junto con tu aplicación, y eso abre una nueva lata de gusanos ...)

Así que personalmente, recomendaría obtener el soporte completo de Unicode directamente desde la boca del caballo y usar la biblioteca de la UCI directamente:

#include <unicode/unistr.h> #include <unicode/ustream.h> #include <unicode/locid.h> #include <iostream> int main() { char const * someString = "Eidenges/xe4/xdf"; icu::UnicodeString someUString( someString, "ISO-8859-1" ); // Setting the locale explicitly here for completeness. // Usually you would use the user-specified system locale. std::cout << someUString.toLower( "de_DE" ) << "/n"; std::cout << someUString.toUpper( "de_DE" ) << "/n"; return 0; }

Compilar (con G ++ en este ejemplo):

g++ -Wall example.cpp -licuuc -licuio

Esto da:

eidengesäß EIDENGESÄSS

[1] En 2017, el Consejo para la ortografía alemana dictaminó que "ẞ" U + 1E9E LATIN CAPITAL LETTER SHARP S podría usarse oficialmente, como una opción junto a la conversión tradicional de "SS" para evitar la ambigüedad, por ejemplo, en los pasaportes (donde los nombres están en mayúsculas). ). Mi hermoso ejemplo, obsoleto por decisión del comité ...


// tolower example (C++) #include <iostream> // std::cout #include <string> // std::string #include <locale> // std::locale, std::tolower int main () { std::locale loc; std::string str="Test String./n"; for (std::string::size_type i=0; i<str.length(); ++i) std::cout << std::tolower(str[i],loc); return 0; }

Para obtener más información: http://www.cplusplus.com/reference/locale/tolower/


//You can really just write one on the fly whenever you need one. #include <string> void _lower_case(std::string& s){ for(unsigned short l = s.size();l;s[--l]|=(1<<5)); } //Here is an example. //http://ideone.com/mw2eDK