1033 Stimmen

Wie konvertiert man eine Instanz von std::string in Kleinbuchstaben?

Ich möchte eine std::string zu Kleinbuchstaben. Die Funktion ist mir bekannt tolower() . In der Vergangenheit hatte ich jedoch Probleme mit dieser Funktion, und sie ist ohnehin nicht ideal, da sie mit einer std::string würde eine Iteration über jedes Zeichen erfordern.

Gibt es eine Alternative, die zu 100 % funktioniert?

5voto

Sameer Punkte 2295

std::ctype::tolower() aus der Standard-C++-Lokalisierungsbibliothek wird dies korrekt für Sie erledigen. Hier ist ein Beispiel, das aus der Untere Referenzseite

#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";
}

4voto

L. F. Punkte 17912

Da in keiner der Antworten die kommende Ranges-Bibliothek erwähnt wurde, die seit C++20 in der Standardbibliothek verfügbar ist und derzeit separat erhältlich ist auf GitHub como range-v3 Ich würde gerne eine Möglichkeit hinzufügen, diese Konvertierung mit ihr durchzuführen.

Um die Zeichenfolge an Ort und Stelle zu ändern:

str |= action::transform([](unsigned char c){ return std::tolower(c); });

Um eine neue Zeichenfolge zu erzeugen:

auto new_string = original_string
    | view::transform([](unsigned char c){ return std::tolower(c); });

(Vergessen Sie nicht #include <cctype> und die erforderlichen Ranges-Kopfzeilen).

Hinweis: Die Verwendung von unsigned char als Argument für das Lambda ist inspiriert von cpp-Referenz in der es heißt:

Wie alle anderen Funktionen von <cctype> das Verhalten von std::tolower ist undefiniert, wenn der Wert des Arguments weder als unsigned char noch gleich EOF . Zur sicheren Verwendung dieser Funktionen mit einfachen char s (oder signed char s), sollte das Argument zunächst in unsigned char :

char my_tolower(char ch)
{
    return static_cast<char>(std::tolower(static_cast<unsigned char>(ch)));
}

Ebenso sollten sie nicht direkt mit Standardalgorithmen verwendet werden, wenn der Wertetyp des Iterators char o signed char . Konvertieren Sie stattdessen den Wert in unsigned char Erstens:

std::string str_tolower(std::string s) {
    std::transform(s.begin(), s.end(), s.begin(), 
                // static_cast<int(*)(int)>(std::tolower)         // wrong
                // [](int c){ return std::tolower(c); }           // wrong
                // [](char c){ return std::tolower(c); }          // wrong
                   [](unsigned char c){ return std::tolower(c); } // correct
                  );
    return s;
}

4voto

Jason Enochs Punkte 1380

Eine Alternative zu Boost ist POCO (pocoproject.org).

POCO bietet zwei Varianten an:

  1. Bei der ersten Variante wird eine Kopie erstellt, ohne die ursprüngliche Zeichenfolge zu verändern.
  2. Bei der zweiten Variante wird die ursprüngliche Zeichenfolge stattdessen geändert.
    Die "In Place"-Versionen haben immer "InPlace" im Namen.

Beide Versionen sind unten dargestellt:

#include "Poco/String.h"
using namespace Poco;

std::string hello("Stack Overflow!");

// Copies "STACK OVERFLOW!" into 'newString' without altering 'hello.'
std::string newString(toUpper(hello));

// Changes newString in-place to read "stack overflow!"
toLowerInPlace(newString);

3voto

Autodidact Punkte 27160

Auf Microsoft-Plattformen können Sie die strlwr Familie von Funktionen: 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 );
}

3voto

user2548100 Punkte 4361

Es gibt eine Möglichkeit, Großbuchstaben in Kleinbuchstaben umzuwandeln OHNE if-Tests durchzuführen und es ist ziemlich einfach. Die Funktion isupper() bzw. die Verwendung von clocale.h durch das Makro sollte die Probleme in Bezug auf Ihren Standort beheben, aber wenn nicht, können Sie die UtoL[] nach Herzenslust verändern.

Angesichts der Tatsache, dass C's Zeichen wirklich nur 8-Bit-Ints sind (ohne Berücksichtigung der breiten Zeichensätze für den Moment), können Sie ein 256-Byte-Array erstellen, das einen alternativen Zeichensatz enthält, und in der Konvertierungsfunktion die Zeichen in Ihrer Zeichenkette als Subscripts in das Konvertierungs-Array verwenden.

Anstelle einer 1-zu-1-Zuordnung geben Sie den Arrayelementen mit Großbuchstaben die BYTE int-Werte für die Kleinbuchstaben. Sie finden vielleicht islower() und isupper() hier nützlich.

enter image description here

Der Code sieht wie folgt aus...

#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;
}

Auf diese Weise können Sie gleichzeitig alle anderen Zeichen, die Sie ändern möchten, neu zuordnen.

Dieser Ansatz hat einen großen Vorteil, wenn er auf modernen Prozessoren ausgeführt wird: Es besteht keine Notwendigkeit, Verzweigungsvorhersagen zu machen, da es keine if-Tests mit Verzweigungen gibt. Dadurch wird die Verzweigungsvorhersagelogik der CPU für andere Schleifen eingespart und ein Abwürgen der Pipeline wird tendenziell verhindert.

Einige hier werden diesen Ansatz als den gleichen erkennen, der auch für die Umwandlung von EBCDIC in ASCII verwendet wird.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X