Wie könnte man einen String in Großbuchstaben umwandeln? Die Beispiele, die ich beim Googeln gefunden habe, müssen sich nur mit Zeichen befassen.
Wie könnte man einen String in Großbuchstaben umwandeln? Die Beispiele, die ich beim Googeln gefunden habe, müssen sich nur mit Zeichen befassen.
Antworten:
Boost-String-Algorithmen:
#include <boost/algorithm/string.hpp>
#include <string>
std::string str = "Hello World";
boost::to_upper(str);
std::string newstr = boost::to_upper_copy<std::string>("Hello World");
std::string newstr(boost::to_upper_copy<std::string>("Hello World"));
#include <algorithm>
#include <string>
std::string str = "Hello World";
std::transform(str.begin(), str.end(),str.begin(), ::toupper);
toupper()
kann als Makro implementiert werden. Dies kann ein Problem verursachen.
toupper
. Irgendwelche Ideen?
Kurze Lösung mit C ++ 11 und toupper ().
for (auto & c: str) c = toupper(c);
c
vom const char
Typ (von auto
)? Wenn ja, können Sie es (aufgrund eines const
Teils) nicht dem zuweisen , was von zurückgegeben wird toupper(c)
.
c
muss gegossen werden, unsigned char
damit dies korrigiert wird.
struct convert {
void operator()(char& c) { c = toupper((unsigned char)c); }
};
// ...
string uc_str;
for_each(uc_str.begin(), uc_str.end(), convert());
Hinweis: Einige Probleme mit der Top-Lösung:
21.5 Nullterminierte Sequenzdienstprogramme
Der Inhalt dieser Header muss mit den Standard-C-Bibliotheksheadern <ctype.h>, <wctype.h>, <string.h>, <wchar.h> und <stdlib.h> [...] identisch sein.
Dies bedeutet, dass die cctype
Mitglieder möglicherweise Makros sind, die für den direkten Verbrauch in Standardalgorithmen nicht geeignet sind.
Ein weiteres Problem mit demselben Beispiel besteht darin, dass das Argument nicht umgewandelt oder überprüft wird, dass dies nicht negativ ist. Dies ist besonders gefährlich für Systeme, in denen die Ebene char
signiert ist. (Der Grund dafür ist: Wenn dies als Makro implementiert ist, wird wahrscheinlich eine Nachschlagetabelle verwendet und Ihr Argument wird in diese Tabelle indiziert. Ein negativer Index gibt Ihnen UB.)
Dieses Problem ist mit SIMD für den ASCII-Zeichensatz vektorisierbar .
Vorläufiger Test mit x86-64 gcc 5.2 -O3 -march=native
auf einem Core2Duo (Merom). Dieselbe Zeichenfolge mit 120 Zeichen (gemischtes ASCII in Klein- und Nicht-Kleinbuchstaben), die 40 Millionen Mal in eine Schleife konvertiert wurde (ohne Inlining zwischen Dateien, sodass der Compiler nichts davon optimieren oder aus der Schleife herausheben kann). Gleiche Quell- und Zielpuffer, also kein Malloc-Overhead oder Speicher- / Cache-Effekte: Daten sind die ganze Zeit im L1-Cache heiß und wir sind rein CPU-gebunden.
boost::to_upper_copy<char*, std::string>()
: 198,0 s . Ja, Boost 1.58 unter Ubuntu 15.10 ist wirklich so langsam. Ich habe den ASM in einem Debugger profiliert und in einem Schritt ausgeführt, und es ist wirklich sehr, sehr schlecht: Es gibt einen dynamic_cast einer Gebietsschemavariablen pro Charakter !!! (dynamic_cast nimmt mehrere Aufrufe von strcmp entgegen). Das passiert mit LANG=C
und mit LANG=en_CA.UTF-8
.
Ich habe keinen anderen RangeT als std :: string getestet. Vielleicht ist die andere Formto_upper_copy
besser optimiert, aber ich denke , es wird immer new
/ malloc
Platz für die Kopie, so dass es schwieriger zu testen ist. Vielleicht unterscheidet sich etwas, das ich getan habe, von einem normalen Anwendungsfall, und vielleicht kann normalerweise gestopptes g ++ das Gebietsschema-Setup-Zeug aus der Zeichenschleife herausheben. Meine Schleife, die von a liest std::string
und in a schreibt, char dstbuf[4096]
macht zum Testen Sinn.
Schleifenaufruf glibc toupper
: 6.67s (das int
Ergebnis wird jedoch nicht auf potenzielle Multi-Byte-UTF-8 überprüft . Dies ist für Türkisch wichtig.)
cmov
, wobei die Tabelle in L1 sowieso heiß ist.Siehe auch diese Frage toupper()
zur Langsamkeit unter Windows, wenn ein Gebietsschema festgelegt ist .
Ich war schockiert, dass Boost eine Größenordnung langsamer ist als die anderen Optionen. Ich überprüfte noch einmal, ob ich -O3
aktiviert hatte, und trat sogar in einem Schritt auf den Asm, um zu sehen, was er tat. Mit clang ++ 3.8 ist es fast genau die gleiche Geschwindigkeit. Es hat einen enormen Overhead innerhalb der Zeichenschleife. Das perf record
/ report
Ergebnis (für das cycles
Perf-Event) ist:
32.87% flipcase-clang- libstdc++.so.6.0.21 [.] _ZNK10__cxxabiv121__vmi_class_type_info12__do_dyncastElNS_17__class_type_info10__sub_kindEPKS1_PKvS4_S6_RNS1_16
21.90% flipcase-clang- libstdc++.so.6.0.21 [.] __dynamic_cast
16.06% flipcase-clang- libc-2.21.so [.] __GI___strcmp_ssse3
8.16% flipcase-clang- libstdc++.so.6.0.21 [.] _ZSt9use_facetISt5ctypeIcEERKT_RKSt6locale
7.84% flipcase-clang- flipcase-clang-boost [.] _Z16strtoupper_boostPcRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
2.20% flipcase-clang- libstdc++.so.6.0.21 [.] strcmp@plt
2.15% flipcase-clang- libstdc++.so.6.0.21 [.] __dynamic_cast@plt
2.14% flipcase-clang- libstdc++.so.6.0.21 [.] _ZNKSt6locale2id5_M_idEv
2.11% flipcase-clang- libstdc++.so.6.0.21 [.] _ZNKSt6locale2id5_M_idEv@plt
2.08% flipcase-clang- libstdc++.so.6.0.21 [.] _ZNKSt5ctypeIcE10do_toupperEc
2.03% flipcase-clang- flipcase-clang-boost [.] _ZSt9use_facetISt5ctypeIcEERKT_RKSt6locale@plt
0.08% ...
Gcc und clang werden Schleifen nur dann automatisch vektorisieren, wenn die Iterationszahl vor der Schleife bekannt ist. (dh Suchschleifen wie die Plain-C-Implementierung von strlen
werden nicht automatisch synchronisiert.)
Daher erhalten wir für Zeichenfolgen, die klein genug sind, um in den Cache zu passen, eine erhebliche Beschleunigung für Zeichenfolgen mit einer Länge von ~ 128 Zeichen strlen
. Dies ist für Zeichenfolgen mit expliziter Länge (wie C ++ std::string
) nicht erforderlich .
// char, not int, is essential: otherwise gcc unpacks to vectors of int! Huge slowdown.
char ascii_toupper_char(char c) {
return ('a' <= c && c <= 'z') ? c^0x20 : c; // ^ autovectorizes to PXOR: runs on more ports than paddb
}
// gcc can only auto-vectorize loops when the number of iterations is known before the first iteration. strlen gives us that
size_t strtoupper_autovec(char *dst, const char *src) {
size_t len = strlen(src);
for (size_t i=0 ; i<len ; ++i) {
dst[i] = ascii_toupper_char(src[i]); // gcc does the vector range check with psubusb / pcmpeqb instead of pcmpgtb
}
return len;
}
Jede anständige libc hat eine Effizienz strlen
, die viel schneller ist als das Schleifen eines Bytes, sodass separate vektorisierte Strlen- und Toupper-Schleifen schneller sind.
Baseline: Eine Schleife, die im laufenden Betrieb nach einer endenden 0 sucht.
Zeiten für 40 Millionen Iterationen auf einem Core2 (Merom) 2,4 GHz. gcc 5.2 -O3 -march=native
. (Ubuntu 15.10). dst != src
(also machen wir eine Kopie), aber sie überlappen sich nicht (und sind nicht in der Nähe). Beide sind ausgerichtet.
Einige Ergebnisse sind bei Clang etwas anders.
Die Microbenchmark-Schleife, die die Funktion aufruft, befindet sich in einer separaten Datei. Andernfalls wird es inline und strlen()
aus der Schleife gehoben , und es läuft dramatisch schneller, insb. für 16 Zeichenfolgen (0,187 s).
Dies hat den Hauptvorteil, dass gcc es für jede Architektur automatisch vektorisieren kann, aber den Hauptnachteil, dass es für den normalerweise üblichen Fall kleiner Zeichenfolgen langsamer ist.
Es gibt also große Beschleunigungen, aber die automatische Vektorisierung von Compilern macht keinen großartigen Code, insb. zur Bereinigung der letzten bis zu 15 Zeichen.
Basierend auf meiner Case-Flip-Funktion , die den Fall jedes alphabetischen Zeichens invertiert. Es nutzt den "vorzeichenlosen Vergleichstrick", bei dem Sie low < a && a <= high
einen einzelnen vorzeichenlosen Vergleich durch Bereichsverschiebung durchführen können, sodass jeder Wert, der kleiner als ist, low
auf einen Wert umbrochen wird, der größer als ist high
. (Dies funktioniert, wenn low
und high
nicht zu weit voneinander entfernt.)
SSE hat nur einen vorzeichenbehafteten Vergleich größer, aber wir können den Trick "vorzeichenloser Vergleich" weiterhin verwenden, indem wir den Bereich an den unteren Rand des vorzeichenbehafteten Bereichs verschieben: Subtrahieren Sie 'a' + 128, sodass die alphabetischen Zeichen zwischen -128 und -128 liegen +25 (-128 + 'z' - 'a')
Beachten Sie, dass das Addieren von 128 und das Subtrahieren von 128 für 8-Bit-Ganzzahlen dasselbe sind. Es gibt keinen Ort, an den der Carry gehen kann, also ist es nur xor (Carryless Add), das das hohe Bit umdreht.
#include <immintrin.h>
__m128i upcase_si128(__m128i src) {
// The above 2 paragraphs were comments here
__m128i rangeshift = _mm_sub_epi8(src, _mm_set1_epi8('a'+128));
__m128i nomodify = _mm_cmpgt_epi8(rangeshift, _mm_set1_epi8(-128 + 25)); // 0:lower case -1:anything else (upper case or non-alphabetic). 25 = 'z' - 'a'
__m128i flip = _mm_andnot_si128(nomodify, _mm_set1_epi8(0x20)); // 0x20:lcase 0:non-lcase
// just mask the XOR-mask so elements are XORed with 0 instead of 0x20
return _mm_xor_si128(src, flip);
// it's easier to xor with 0x20 or 0 than to AND with ~0x20 or 0xFF
}
Angesichts dieser Funktion, die für einen Vektor funktioniert, können wir sie in einer Schleife aufrufen, um eine ganze Zeichenfolge zu verarbeiten. Da wir bereits auf SSE2 abzielen, können wir gleichzeitig eine vektorisierte Überprüfung des String-Endes durchführen.
Wir können auch viel besser für die "Bereinigung" der letzten bis zu 15 Bytes tun, die nach dem Ausführen von Vektoren von 16B übrig bleiben: Das obere Gehäuse ist idempotent, daher ist die erneute Verarbeitung einiger Eingabebytes in Ordnung. Wir laden die letzten 16B der Quelle nicht ausgerichtet und speichern sie im Zielpuffer, der den letzten 16B-Speicher der Schleife überlappt.
Dies funktioniert nur dann nicht, wenn die gesamte Zeichenfolge unter 16B liegt: Auch wenn dst=src
nicht-atomares Lesen, Ändern, Schreiben nicht das Gleiche ist, als würden einige Bytes überhaupt nicht berührt, und kann Multithread-Code beschädigen.
Wir haben eine Skalarschleife dafür und auch um uns src
auszurichten. Da wir nicht wissen, wo sich die abschließende 0 befindet, wird möglicherweise eine nicht ausgerichtete Last von src
auf die nächste Seite und den Segfault übertragen. Wenn wir Bytes in einem ausgerichteten 16B-Block benötigen, ist es immer sicher, den gesamten ausgerichteten 16B-Block zu laden.
Vollständige Quelle: in einem Github-Kern .
// FIXME: doesn't always copy the terminating 0.
// microbenchmarks are for this version of the code (with _mm_store in the loop, instead of storeu, for Merom).
size_t strtoupper_sse2(char *dst, const char *src_begin) {
const char *src = src_begin;
// scalar until the src pointer is aligned
while ( (0xf & (uintptr_t)src) && *src ) {
*(dst++) = ascii_toupper(*(src++));
}
if (!*src)
return src - src_begin;
// current position (p) is now 16B-aligned, and we're not at the end
int zero_positions;
do {
__m128i sv = _mm_load_si128( (const __m128i*)src );
// TODO: SSE4.2 PCMPISTRI or PCMPISTRM version to combine the lower-case and '\0' detection?
__m128i nullcheck = _mm_cmpeq_epi8(_mm_setzero_si128(), sv);
zero_positions = _mm_movemask_epi8(nullcheck);
// TODO: unroll so the null-byte check takes less overhead
if (zero_positions)
break;
__m128i upcased = upcase_si128(sv); // doing this before the loop break lets gcc realize that the constants are still in registers for the unaligned cleanup version. But it leads to more wasted insns in the early-out case
_mm_storeu_si128((__m128i*)dst, upcased);
//_mm_store_si128((__m128i*)dst, upcased); // for testing on CPUs where storeu is slow
src += 16;
dst += 16;
} while(1);
// handle the last few bytes. Options: scalar loop, masked store, or unaligned 16B.
// rewriting some bytes beyond the end of the string would be easy,
// but doing a non-atomic read-modify-write outside of the string is not safe.
// Upcasing is idempotent, so unaligned potentially-overlapping is a good option.
unsigned int cleanup_bytes = ffs(zero_positions) - 1; // excluding the trailing null
const char* last_byte = src + cleanup_bytes; // points at the terminating '\0'
// FIXME: copy the terminating 0 when we end at an aligned vector boundary
// optionally special-case cleanup_bytes == 15: final aligned vector can be used.
if (cleanup_bytes > 0) {
if (last_byte - src_begin >= 16) {
// if src==dest, this load overlaps with the last store: store-forwarding stall. Hopefully OOO execution hides it
__m128i sv = _mm_loadu_si128( (const __m128i*)(last_byte-15) ); // includes the \0
_mm_storeu_si128((__m128i*)(dst + cleanup_bytes - 15), upcase_si128(sv));
} else {
// whole string less than 16B
// if this is common, try 64b or even 32b cleanup with movq / movd and upcase_si128
#if 1
for (unsigned int i = 0 ; i <= cleanup_bytes ; ++i) {
dst[i] = ascii_toupper(src[i]);
}
#else
// gcc stupidly auto-vectorizes this, resulting in huge code bloat, but no measurable slowdown because it never runs
for (int i = cleanup_bytes - 1 ; i >= 0 ; --i) {
dst[i] = ascii_toupper(src[i]);
}
#endif
}
}
return last_byte - src_begin;
}
Zeiten für 40 Millionen Iterationen auf einem Core2 (Merom) 2,4 GHz. gcc 5.2 -O3 -march=native
. (Ubuntu 15.10). dst != src
(also machen wir eine Kopie), aber sie überlappen sich nicht (und sind nicht in der Nähe). Beide sind ausgerichtet.
(Tatsächlich zeitgesteuert mit _mm_store
in der Schleife, nicht _mm_storeu
, da storeu auf Merom langsamer ist, selbst wenn die Adresse ausgerichtet ist. Es ist in Nehalem und später in Ordnung. Ich habe den Code vorerst auch unverändert gelassen, anstatt den Fehler beim Kopieren zu beheben die abschließende 0 in einigen Fällen, weil ich nicht alles neu einstellen möchte.)
Für kurze Strings, die länger als 16B sind, ist dies dramatisch schneller als automatisch vektorisiert. Längen von weniger als einer Vektorbreite sind kein Problem. Sie können aufgrund eines Standes für die Weiterleitung von Geschäften ein Problem beim Betrieb vor Ort darstellen. (Beachten Sie jedoch, dass es immer noch in Ordnung ist, unsere eigene Ausgabe anstelle der ursprünglichen Eingabe zu verarbeiten, da toupper idempotent ist.)
Es gibt viel Spielraum, dies für verschiedene Anwendungsfälle zu optimieren, abhängig von den Anforderungen des umgebenden Codes und der Zielmikroarchitektur. Es ist schwierig, den Compiler dazu zu bringen, netten Code für den Bereinigungsteil auszugeben. Die Verwendung ffs(3)
(die auf x86 zu bsf oder tzcnt kompiliert wird) scheint gut zu sein, aber offensichtlich muss dieses Bit überdacht werden, da ich nach dem Schreiben des größten Teils dieser Antwort einen Fehler festgestellt habe (siehe die FIXME-Kommentare).
Vektorbeschleunigungen für noch kleinere Zeichenfolgen können mit movq
oder movd
Laden / Speichern erhalten werden. Passen Sie nach Bedarf Ihren Anwendungsfall an.
Wir können erkennen, wann unser Vektor Bytes mit gesetztem High-Bit hat, und in diesem Fall auf eine skalare utf-8-fähige Schleife für diesen Vektor zurückgreifen. Der dst
Punkt kann um einen anderen Betrag als der src
Zeiger vorrücken , aber sobald wir zu einem ausgerichteten src
Zeiger zurückkehren, führen wir immer noch nur nicht ausgerichtete Vektorspeicher durch dst
.
Für Text, der UTF-8 ist, aber hauptsächlich aus der ASCII-Teilmenge von UTF-8 besteht, kann dies gut sein: hohe Leistung im allgemeinen Fall mit korrektem Verhalten in allen Fällen. Wenn es viele Nicht-ASCII-Dateien gibt, ist dies wahrscheinlich schlimmer, als die ganze Zeit in der skalaren UTF-8-fähigen Schleife zu bleiben.
Englisch auf Kosten anderer Sprachen schneller zu machen, ist keine zukunftssichere Entscheidung, wenn der Nachteil erheblich ist.
In der türkischen locale ( tr_TR
), das richtige Ergebnis aus toupper('i')
ist 'İ'
(U0130) nicht 'I'
(plain ASCII). Siehe Martin Bonners Kommentare zu einer Frage tolower()
, wie man unter Windows langsam ist.
Wir können dort auch nach einer Ausnahmeliste suchen und auf Skalar zurückgreifen, wie bei Multi-Byte-UTF8-Eingabezeichen.
Mit dieser Komplexität kann SSE4.2 PCMPISTRM
oder ähnliches möglicherweise viele unserer Überprüfungen auf einmal durchführen.
Haben Sie ASCII- oder internationale Zeichen in Zeichenfolgen?
Wenn es der letztere Fall ist, ist "Großbuchstaben" nicht so einfach und hängt vom verwendeten Alphabet ab. Es gibt Zweikammer- und Einkammer-Alphabete. Nur Zweikammeralphabete haben unterschiedliche Zeichen für Groß- und Kleinschreibung. Es gibt auch zusammengesetzte Zeichen wie den lateinischen Großbuchstaben 'DZ' (\ u01F1 'DZ'), die die sogenannte Groß- und Kleinschreibung verwenden . Dies bedeutet, dass nur das erste Zeichen (D) geändert wird.
Ich schlage vor, Sie untersuchen die Intensivstation und den Unterschied zwischen einfachen und vollständigen Fallzuordnungen. Dies könnte helfen:
string StringToUpper(string strToConvert)
{
for (std::string::iterator p = strToConvert.begin(); strToConvert.end() != p; ++p)
*p = toupper(*p);
return p;
}
Oder,
string StringToUpper(string strToConvert)
{
std::transform(strToConvert.begin(), strToConvert.end(), strToConvert.begin(), ::toupper);
return strToConvert;
}
**
nach den Parametern der ersten Lösung?
**
ein Tippfehler ist, der von dem Versuch übrig geblieben ist, fette Schrift in der Codesyntax zu verwenden.
toupper
er mit negativen Zahlen aufgerufen wird.
Folgendes funktioniert für mich.
#include <algorithm>
void toUpperCase(std::string& str)
{
std::transform(str.begin(), str.end(), str.begin(), ::toupper);
}
int main()
{
std::string str = "hello";
toUpperCase(&str);
}
toupper
er mit negativen Zahlen aufgerufen wird.
Verwenden Sie ein Lambda.
std::string s("change my case");
auto to_upper = [] (char_t ch) { return std::use_facet<std::ctype<char_t>>(std::locale()).toupper(ch); };
std::transform(s.begin(), s.end(), s.begin(), to_upper);
Das schnellere, wenn Sie nur ASCII-Zeichen verwenden :
for(i=0;str[i]!=0;i++)
if(str[i]<='z' && str[i]>='a')
str[i]-=32;
Bitte beachten Sie, dass dieser Code schneller ausgeführt wird, aber nur unter ASCII funktioniert und keine "abstrakte" Lösung ist.
Wenn Sie UNICODE-Lösungen oder konventionellere und abstraktere Lösungen benötigen, suchen Sie nach anderen Antworten und arbeiten Sie mit Methoden von C ++ - Zeichenfolgen.
C++
, aber Sie C
haben hier eine Antwort geschrieben. (Ich bin nicht einer der Downvoter.)
'
?
Solange Sie nur mit ASCII gut umgehen können und einen gültigen Zeiger auf den RW-Speicher bereitstellen können, gibt es in C einen einfachen und sehr effektiven Einzeiler:
void strtoupper(char* str)
{
while (*str) *(str++) = toupper((unsigned char)*str);
}
Dies ist besonders gut für einfache Zeichenfolgen wie ASCII-Bezeichner geeignet, die Sie in die gleiche Groß- und Kleinschreibung normalisieren möchten. Sie können dann den Puffer verwenden, um eine std: string-Instanz zu erstellen.
//works for ASCII -- no clear advantage over what is already posted...
std::string toupper(const std::string & s)
{
std::string ret(s.size(), char());
for(unsigned int i = 0; i < s.size(); ++i)
ret[i] = (s[i] <= 'z' && s[i] >= 'a') ? s[i]-('a'-'A') : s[i];
return ret;
}
for (size_t i = 0 ...
. Es gibt auch keinen guten Grund, das Lesen so schwer zu machen. Dadurch wird auch zuerst die Zeichenfolge kopiert und dann eine Schleife durchlaufen. @ Lukes Antwort ist in mancher Hinsicht besser, außer dass 'a'
Zeichenkonstanten nicht ausgenutzt werden.
#include <string>
#include <locale>
std::string str = "Hello World!";
auto & f = std::use_facet<std::ctype<char>>(std::locale());
f.toupper(str.data(), str.data() + str.size());
Dies ist besser als alle Antworten, die die globale Toupper-Funktion verwenden, und ist vermutlich das, was boost :: to_upper darunter tut.
Dies liegt daran, dass :: toupper bei jedem Aufruf das Gebietsschema nachschlagen muss - da es möglicherweise von einem anderen Thread geändert wurde -, während hier nur der Aufruf von locale () diese Strafe hat. Zum Nachschlagen des Gebietsschemas gehört im Allgemeinen das Sperren.
Dies funktioniert auch mit C ++ 98, nachdem Sie das Auto ersetzt, die neue nicht-const str.data () verwendet und ein Leerzeichen hinzugefügt haben, um das Schließen der Vorlage (">>" bis ">>") wie folgt zu unterbrechen:
std::use_facet<std::ctype<char> > & f =
std::use_facet<std::ctype<char> >(std::locale());
f.toupper(const_cast<char *>(str.data()), str.data() + str.size());
typedef std::string::value_type char_t;
char_t up_char( char_t ch )
{
return std::use_facet< std::ctype< char_t > >( std::locale() ).toupper( ch );
}
std::string toupper( const std::string &src )
{
std::string result;
std::transform( src.begin(), src.end(), std::back_inserter( result ), up_char );
return result;
}
const std::string src = "test test TEST";
std::cout << toupper( src );
reserve
und back_inserter
(damit die Zeichenfolge nur einmal kopiert wird). inline std::string to_lower(const std::string &s) { std::string result; result.reserve(s.size()); std::transform(s.begin(), s.end(), std::back_inserter( result ), static_cast<int(*)(int)>(std::tolower)); return result; }
std::string value;
for (std::string::iterator p = value.begin(); value.end() != p; ++p)
*p = toupper(*p);
toupper
er mit negativen Zahlen aufgerufen wird.
Probieren Sie die toupper()
Funktion ( #include <ctype.h>
) aus. Zeichen werden als Argumente akzeptiert, Zeichenfolgen bestehen aus Zeichen, sodass Sie jedes einzelne Zeichen durchlaufen müssen, das zusammen die Zeichenfolge umfasst
toupper
er mit negativen Zahlen aufgerufen wird. Du hättest die notwendige Besetzung erwähnen sollen unsigned char
.
Hier ist der neueste Code mit C ++ 11
std::string cmd = "Hello World";
for_each(cmd.begin(), cmd.end(), [](char& in){ in = ::toupper(in); });
toupper
er mit negativen Zahlen aufgerufen wird.
Die Antwort von @dirkgently ist sehr inspirierend, aber ich möchte dies aufgrund der unten gezeigten Besorgnis hervorheben.
Wie bei allen anderen Funktionen von ist das Verhalten von std :: toupper undefiniert, wenn der Wert des Arguments weder als vorzeichenloses Zeichen noch als EOF darstellbar ist. Um diese Funktionen sicher mit einfachen Zeichen (oder vorzeichenbehafteten Zeichen) zu verwenden, sollte das Argument zuerst in vorzeichenloses Zeichen konvertiert werden.
Referenz : std :: toupper
Die korrekte Verwendung von std::toupper
sollte sein:
#include <algorithm>
#include <cctype>
#include <iostream>
#include <iterator>
#include <string>
void ToUpper(std::string& input)
{
std::for_each(std::begin(input), std::end(input), [](char& c) {
c = static_cast<char>(std::toupper(static_cast<unsigned char>(c)));
});
}
int main()
{
std::string s{ "Hello world!" };
std::cout << s << std::endl;
::ToUpper(s);
std::cout << s << std::endl;
return 0;
}
Ausgabe:
Hello world!
HELLO WORLD!
Ich bin mir nicht sicher, ob eine Funktion integriert ist. Versuche dies:
Fügen Sie entweder die Bibliotheken ctype.h ODER cctype sowie stdlib.h als Teil der Präprozessor-Direktiven hinzu.
string StringToUpper(string strToConvert)
{//change each element of the string to upper case
for(unsigned int i=0;i<strToConvert.length();i++)
{
strToConvert[i] = toupper(strToConvert[i]);
}
return strToConvert;//return the converted string
}
string StringToLower(string strToConvert)
{//change each element of the string to lower case
for(unsigned int i=0;i<strToConvert.length();i++)
{
strToConvert[i] = tolower(strToConvert[i]);
}
return strToConvert;//return the converted string
}
toupper
er mit negativen Zahlen aufgerufen wird.
Meine Lösung (6. Bit für Alpha löschen):
#include <ctype.h>
inline void toupper(char* str)
{
while (str[i]) {
if (islower(str[i]))
str[i] &= ~32; // Clear bit 6 as it is what differs (32) between Upper and Lowercases
i++;
}
}
toupper
er mit negativen Zahlen aufgerufen wird.
ALLE diese Lösungen auf dieser Seite sind schwieriger als nötig.
Mach das
RegName = "SomE StRing That you wAnt ConvErTed";
NameLength = RegName.Size();
for (int forLoop = 0; forLoop < NameLength; ++forLoop)
{
RegName[forLoop] = tolower(RegName[forLoop]);
}
RegName
ist dein string
. Holen Sie sich Ihre Stringgröße nicht string.size()
als eigentlicher Tester verwenden, sehr chaotisch und kann Probleme verursachen. dann. die grundlegendste for
Schleife.
Denken Sie daran, dass die Zeichenfolgengröße auch das Trennzeichen zurückgibt. Verwenden Sie daher <und nicht <= in Ihrem Schleifentest.
Die Ausgabe lautet: eine Zeichenfolge, die konvertiert werden soll
tolower
Schleifen, und die meisten von ihnen verwenden Standardnamen für Schleifenvariablen i
, nicht die seltsamen forLoop
.
Ohne Verwendung von Bibliotheken:
std::string YourClass::Uppercase(const std::string & Text)
{
std::string UppperCaseString;
UppperCaseString.reserve(Text.size());
for (std::string::const_iterator it=Text.begin(); it<Text.end(); ++it)
{
UppperCaseString.push_back(((0x60 < *it) && (*it < 0x7B)) ? (*it - static_cast<char>(0x20)) : *it);
}
return UppperCaseString;
}
Wenn Sie sich nur mit 8-Bit-Zeichen befassen (von denen alle anderen Antworten außer Milan Babuškov ebenfalls ausgehen), können Sie die schnellste Geschwindigkeit erzielen, indem Sie zur Kompilierungszeit mithilfe der Metaprogrammierung eine Nachschlagetabelle erstellen. Auf ideone.com läuft dies 7x schneller als die Bibliotheksfunktion und 3x schneller als eine handgeschriebene Version ( http://ideone.com/sb1Rup ). Es kann auch durch Merkmale ohne Verlangsamung angepasst werden.
template<int ...Is>
struct IntVector{
using Type = IntVector<Is...>;
};
template<typename T_Vector, int I_New>
struct PushFront;
template<int ...Is, int I_New>
struct PushFront<IntVector<Is...>,I_New> : IntVector<I_New,Is...>{};
template<int I_Size, typename T_Vector = IntVector<>>
struct Iota : Iota< I_Size-1, typename PushFront<T_Vector,I_Size-1>::Type> {};
template<typename T_Vector>
struct Iota<0,T_Vector> : T_Vector{};
template<char C_In>
struct ToUpperTraits {
enum { value = (C_In >= 'a' && C_In <='z') ? C_In - ('a'-'A'):C_In };
};
template<typename T>
struct TableToUpper;
template<int ...Is>
struct TableToUpper<IntVector<Is...>>{
static char at(const char in){
static const char table[] = {ToUpperTraits<Is>::value...};
return table[in];
}
};
int tableToUpper(const char c){
using Table = TableToUpper<typename Iota<256>::Type>;
return Table::at(c);
}
mit Anwendungsfall:
std::transform(in.begin(),in.end(),out.begin(),tableToUpper);
Für eine ausführliche (viele Seiten) Beschreibung der Funktionsweise kann ich mein Blog schamlos einbinden: http://metaporky.blogspot.de/2014/07/part-4-generating-look-up-tables-at.html
template<size_t size>
char* toupper(char (&dst)[size], const char* src) {
// generate mapping table once
static char maptable[256];
static bool mapped;
if (!mapped) {
for (char c = 0; c < 256; c++) {
if (c >= 'a' && c <= 'z')
maptable[c] = c & 0xdf;
else
maptable[c] = c;
}
mapped = true;
}
// use mapping table to quickly transform text
for (int i = 0; *src && i < size; i++) {
dst[i] = maptable[*(src++)];
}
return dst;
}
Diese c ++ - Funktion gibt immer die Zeichenfolge in Großbuchstaben zurück ...
#include <locale>
#include <string>
using namespace std;
string toUpper (string str){
locale loc;
string n;
for (string::size_type i=0; i<str.length(); ++i)
n += toupper(str[i], loc);
return n;
}
Ich benutze diese Lösung. Ich weiß, dass Sie diesen Datenbereich nicht ändern sollen ... aber ich denke, das ist hauptsächlich für Pufferüberlauffehler und Nullzeichen gedacht ... die Dinge im oberen Gehäuse sind nicht die gleichen.
void to_upper(const std::string str) {
std::string::iterator it;
int i;
for ( i=0;i<str.size();++i ) {
((char *)(void *)str.data())[i]=toupper(((char *)str.data())[i]);
}
}
I know you're not supposed to modify that data area
- Welchen Datenbereich sollen Sie nicht ändern?
str[i] = toupper(str[i]);
vollkommen in Ordnung ersetzt werden ( na ja , nicht vollkommen in Ordnung, aber sie behebt die meisten Fehler).
::toupper
höchstwahrscheinlich ASCII angenommen wird.