Jak można przekonwertować ciąg na wielkie litery. Przykłady, które znalazłem w Google, dotyczą tylko znaków.
Jak można przekonwertować ciąg na wielkie litery. Przykłady, które znalazłem w Google, dotyczą tylko znaków.
Odpowiedzi:
Algorytmy ciągu wzmocnionego:
#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()może być zaimplementowany jako makro. Może to powodować problem.
toupper. Jakieś pomysły?
Krótkie rozwiązanie przy użyciu C ++ 11 i toupper ().
for (auto & c: str) c = toupper(c);
cbyłby const chartypu (od auto)? Jeśli tak, nie możesz przypisać go (z powodu constczęści) do tego, co zwraca toupper(c).
cnależy go rzucić, unsigned charaby został skorygowany.
struct convert {
void operator()(char& c) { c = toupper((unsigned char)c); }
};
// ...
string uc_str;
for_each(uc_str.begin(), uc_str.end(), convert());
Uwaga: kilka problemów z najlepszym rozwiązaniem:
21.5 Narzędzia sekwencyjne zakończone zerem
Treść tych nagłówków powinna być taka sama, jak nagłówki Standardowej biblioteki C <ctype.h>, <wctype.h>, <string.h>, <wchar.h> i <stdlib.h> [...]
Co oznacza, że cctypeczłonkami mogą być makra nieodpowiednie do bezpośredniego wykorzystania w standardowych algorytmach.
Innym problemem związanym z tym samym przykładem jest to, że nie rzuca on argumentu ani nie weryfikuje, czy nie jest on ujemny; jest to szczególnie niebezpieczne dla systemów, w których charpodpisany jest zwykły . (Powodem jest to, że jeśli jest to zaimplementowane jako makro, prawdopodobnie użyje tabeli odnośników, a twój argument będzie indeksował tę tabelę. Ujemny indeks da ci UB.)
Ten problem można rozwiązać za pomocą SIMD dla zestawu znaków ASCII.
Wstępne testy z x86-64 gcc 5.2 -O3 -march=nativena Core2Duo (Merom). Ten sam ciąg 120 znaków (mieszane małe i małe litery ASCII), przekonwertowany w pętli 40 mln razy (bez wstawiania pliku krzyżowego, więc kompilator nie może zoptymalizować ani wyciągnąć żadnego z niego z pętli). Te same bufory źródłowy i docelowy, więc nie ma narzutu malloc ani efektów pamięci / pamięci podręcznej: dane są gorące w pamięci podręcznej L1 przez cały czas, a my jesteśmy całkowicie związani z procesorem.
boost::to_upper_copy<char*, std::string>(): 198,0 . Tak, Boost 1.58 na Ubuntu 15.10 jest naprawdę tak powolny. Profilowałem i jednym krokiem asm w debuggerze, i to jest naprawdę bardzo złe: jest dynamiczny rzut zmiennej regionalnej na znak !!! (dynamic_cast przyjmuje wiele wywołań do strcmp). Dzieje się tak z LANG=Ci z LANG=en_CA.UTF-8.
Nie testowałem przy użyciu RangeT innego niż std :: string. Może inna formato_upper_copy optymalizacji lepiej, ale myślę, że zawsze będzie new/ mallocmiejsce na kopię, więc trudniej jest przetestować. Może coś, co zrobiłem, różni się od zwykłego przypadku użycia, a może normalnie zatrzymany g ++ może wyciągnąć elementy ustawień regionalnych z pętli dla poszczególnych znaków. Moje czytanie w pętli od std::stringi pisanie do char dstbuf[4096]sensownego do testowania.
Wywołanie pętli glibc toupper: 6,67s (nie sprawdza intwyniku dla potencjalnego wielobajtowego UTF-8. To ma znaczenie dla tureckiego.)
cmov, a tabela w każdym razie jest gorąca w L1.Zobacz także to pytanie dotyczące toupper()spowolnienia w systemie Windows, gdy ustawione są ustawienia regionalne .
Byłem zszokowany, że Boost jest o rząd wielkości wolniejszy niż inne opcje. Dokładnie sprawdziłem, czy mam -O3włączony, a nawet przeskoczyłem asm, aby zobaczyć, co robi. Jest prawie dokładnie taka sama prędkość z clang ++ 3.8. Ma ogromne obciążenie w pętli dla poszczególnych postaci. Wynik perf record/ report(dla cycleszdarzenia perf) to:
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 i clang będą automatycznie wektoryzować pętle tylko wtedy, gdy liczba iteracji jest znana przed pętlą. (tzn. pętle wyszukiwania, takie jak implementacja zwykłego C strlen, nie będą się automatycznie włączać).
Tak więc, dla łańcuchów wystarczająco małych, aby zmieściły się w pamięci podręcznej, otrzymujemy znaczne przyspieszenie dla łańcuchów ~ 128 znaków długo od strlenpierwszego. Nie będzie to konieczne w przypadku ciągów o wyraźnej długości (takich jak C ++ std::string).
// 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;
}
Przyzwoite libc będzie miało wydajność strlenznacznie szybszą niż zapętlanie bajtu naraz, więc oddzielne wektoryzowane pętle strlen i touper są szybsze.
Linia bazowa: pętla, która w locie sprawdza zakończenie 0.
Czasy dla 40M iteracji na Core2 (Merom) 2,4 GHz. gcc 5.2 -O3 -march=native. (Ubuntu 15.10). dst != src(więc tworzymy kopię), ale nie nakładają się (i nie są w pobliżu). Oba są wyrównane.
Niektóre wyniki są nieco inne w przypadku clang.
Pętla microbenchmark, która wywołuje tę funkcję, znajduje się w osobnym pliku. W przeciwnym razie strlen()wyskoczy z pętli i zostanie wyciągnięty z pętli, i działa znacznie szybciej, szczególnie. dla 16 ciągów znaków (0,187).
Ma to tę główną zaletę, że gcc może automatycznie wektoryzować ją dla dowolnej architektury, ale główną wadą jest to, że jest wolniejsza w przypadku zwykle zwykłego przypadku małych łańcuchów.
Istnieją więc duże przyspieszenia, ale auto-wektoryzacja kompilatora nie tworzy świetnego kodu, szczególnie. do czyszczenia ostatnich do 15 znaków.
Na podstawie mojej funkcji odwracania wielkości liter, która odwraca wielkość liter każdego znaku alfabetu. Korzysta z „sztuczki polegającej na porównywaniu bez znaku”, która umożliwia wykonanie low < a && a <= highpojedynczego porównania bez znaku poprzez przesunięcie zakresu, dzięki czemu dowolna wartość mniejsza niż lowwraca do wartości większej niż high. (Działa to, jeśli lowi highnie są zbyt daleko od siebie.)
SSE ma tylko podpisane porównanie-większe, ale nadal możemy użyć sztuczki „niepodpisane porównanie”, przesuwając zakres na dół podpisanego zakresu: Odejmij „a” + 128, więc znaki alfabetu mieszczą się w zakresie od -128 do -128 +25 (-128 + „z” - „a”)
Zauważ, że dodawanie 128 i odejmowanie 128 to to samo dla liczb całkowitych 8-bitowych. Nie ma dokąd pójść, więc jest to po prostu xor (dodawanie bez noszenia), przewracając wysoki bit.
#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
}
Biorąc pod uwagę tę funkcję, która działa dla jednego wektora, możemy wywołać go w pętli w celu przetworzenia całego łańcucha. Ponieważ już celujemy w SSE2, możemy jednocześnie przeprowadzić wektoryzowaną kontrolę końca łańcucha.
Możemy również zrobić znacznie lepiej dla „czyszczenia” ostatnich do 15 bajtów pozostałych po wykonaniu wektorów 16B: górna obudowa jest idempotentna, więc ponowne przetwarzanie niektórych bajtów wejściowych jest w porządku. Wykonujemy nierównomierne ładowanie ostatniego 16B źródła i przechowujemy go w buforze docelowym pokrywającym ostatni sklep 16B z pętli.
Jedyny raz to nie działa, gdy cały ciąg jest poniżej 16B: Nawet gdy dst=srcnieatomowy odczyt-modyfikacja-zapis nie jest tym samym, co w ogóle nie dotykanie niektórych bajtów i może złamać wielowątkowy kod.
Mamy do tego pętlę skalarną, a także do srcwyrównania. Ponieważ nie wiemy, gdzie będzie kończące się 0, niezaangażowane ładowanie z srcmoże przejść do następnej strony i spowodować awarię. Jeśli potrzebujemy bajtów w wyrównanym fragmencie 16B, zawsze można bezpiecznie załadować cały wyrównany fragment 16B.
Pełne źródło: w github gist .
// 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;
}
Czasy dla 40M iteracji na Core2 (Merom) 2,4 GHz. gcc 5.2 -O3 -march=native. (Ubuntu 15.10). dst != src(więc tworzymy kopię), ale nie nakładają się (i nie są w pobliżu). Oba są wyrównane.
(Właściwie taktowane _mm_storew pętli, nie _mm_storeu, ponieważ storeu działa wolniej na Meromie, nawet gdy adres jest wyrównany. Nie ma problemu na Nehalem i później. Zostawiłem też kod na razie, zamiast naprawiać błąd kopiowania kończące 0 w niektórych przypadkach, ponieważ nie chcę wszystkiego zmieniać na nowo.)
Tak więc w przypadku krótkich łańcuchów dłuższych niż 16B jest to znacznie szybsze niż wektoryzacja automatyczna. Długości o szerokości mniejszej niż wektor nie stanowią problemu. Mogą one stanowić problem podczas pracy w miejscu, z powodu przeciągnięcia spedycji. (Zauważ jednak, że nadal dobrze jest przetwarzać nasze własne dane wyjściowe, niż oryginalne dane wejściowe, ponieważ toupper jest idempotentny).
Istnieje wiele możliwości dostrojenia tego do różnych przypadków użycia, w zależności od tego, czego chce otaczający kod i docelowej mikroarchitektury. Nakłonienie kompilatora do wydania ładnego kodu dla części czyszczenia jest trudne. Używanie ffs(3)(które kompiluje się do bsf lub tzcnt na x86) wydaje się być dobre, ale oczywiście ten bit wymaga ponownego przemyślenia, ponieważ zauważyłem błąd po napisaniu większości tej odpowiedzi (patrz komentarze FIXME).
Przyspieszenia wektorowe dla jeszcze mniejszych ciągów można uzyskać za pomocą movqlub movdładunków / sklepów. Dostosuj odpowiednio do swojego przypadku użycia.
Możemy wykryć, kiedy nasz wektor ma jakieś bajty z ustawionym wysokim bitem, i w takim przypadku wracamy do skalarnej pętli rozpoznającej utf-8 dla tego wektora. dstPunkt może przejść przez inną kwotę niż srcwskaźnik, ale kiedy wrócimy do wyrównanego srcwskaźnika, będziemy nadal tak robić aligné sklepów wektorowej dst.
W przypadku tekstu UTF-8, ale w większości składającego się z podzbioru ASCII UTF-8, może to być dobre: wysoka wydajność we wspólnym przypadku z prawidłowym zachowaniem we wszystkich przypadkach. Jednak gdy jest dużo non-ASCII, prawdopodobnie będzie to gorsze niż pozostawanie w pętli rozpoznawania skalarnej UTF-8 przez cały czas.
Szybsze posługiwanie się językiem angielskim kosztem innych języków nie jest decyzją na przyszłość, jeśli wada jest znacząca.
W tureckich ustawieniach regionalnych ( tr_TR) poprawny wynik toupper('i')to 'İ'(U0130), a nie 'I'(zwykły ASCII). Zobacz komentarze Martina Bonnera dotyczące pytania o tolower()powolność w systemie Windows.
Możemy również sprawdzić listę wyjątków i wrócić do skalarnego, na przykład w przypadku wielobajtowych znaków wejściowych UTF8.
Przy takiej złożoności, SSE4.2 PCMPISTRMlub coś może być w stanie wykonać wiele naszych kontroli za jednym razem.
Czy masz ciągi znaków ASCII lub międzynarodowe?
W drugim przypadku „wielkie litery” nie są takie proste i zależą od użytego alfabetu. Istnieją alfabety dwuizbowe i jednoizbowe. Tylko dwuizbowe alfabety mają różne znaki dla wielkich i małych liter. Istnieją również znaki złożone, takie jak łacińska wielka litera „DZ” (\ u01F1 „DZ”), które używają tak zwanego tytułu . Oznacza to, że zmienia się tylko pierwszy znak (D).
Proponuję przyjrzeć się OIOM i różnicę między mapowaniem prostych i pełnych przypadków. To może pomóc:
string StringToUpper(string strToConvert)
{
for (std::string::iterator p = strToConvert.begin(); strToConvert.end() != p; ++p)
*p = toupper(*p);
return p;
}
Lub,
string StringToUpper(string strToConvert)
{
std::transform(strToConvert.begin(), strToConvert.end(), strToConvert.begin(), ::toupper);
return strToConvert;
}
**po parametrach pierwszego rozwiązania?
**jest to literówka, która pozostała po próbie użycia pogrubionej czcionki w składni kodu.
toupperjest wywoływany z liczbami ujemnymi.
Poniższe działa dla mnie.
#include <algorithm>
void toUpperCase(std::string& str)
{
std::transform(str.begin(), str.end(), str.begin(), ::toupper);
}
int main()
{
std::string str = "hello";
toUpperCase(&str);
}
toupperjest wywoływany z liczbami ujemnymi.
Użyj 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);
Szybszy, jeśli używasz tylko znaków ASCII :
for(i=0;str[i]!=0;i++)
if(str[i]<='z' && str[i]>='a')
str[i]-=32;
Pamiętaj, że ten kod działa szybciej, ale działa tylko na ASCII i nie jest rozwiązaniem „abstrakcyjnym”.
Jeśli potrzebujesz rozwiązań UNICODE lub bardziej konwencjonalnych i abstrakcyjnych, skorzystaj z innych odpowiedzi i pracuj z metodami napisów w C ++.
C++, ale Ctutaj napisałeś odpowiedź. (Nie jestem jednym z downvoters.)
'?
Tak długo, jak nie przeszkadza ci tylko ASCII i możesz podać poprawny wskaźnik do pamięci RW, w C jest prosta i bardzo skuteczna jednowierszowa:
void strtoupper(char* str)
{
while (*str) *(str++) = toupper((unsigned char)*str);
}
Jest to szczególnie przydatne w przypadku prostych ciągów znaków, takich jak identyfikatory ASCII, które chcesz znormalizować do tej samej wielkości znaków. Następnie możesz użyć bufora do skonstruowania instancji std: string.
//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 .... Nie ma też żadnego powodu, aby utrudniać czytanie. To również najpierw kopiuje ciąg, a następnie zapętla go. Odpowiedź Łukasza jest lepsza pod pewnymi względami, z wyjątkiem tego, że nie wykorzystuje 'a'stałych postaci.
#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());
Będzie to działać lepiej niż wszystkie odpowiedzi, które używają funkcji globalnego touppera, i prawdopodobnie jest to, co robi pod spacją :: to_upper.
Wynika to z tego, że :: toupper musi wyszukiwać ustawienia regionalne - ponieważ mogły zostać zmienione przez inny wątek - dla każdego wywołania, podczas gdy tutaj tylko wywołanie ustawienia narodowego () ma tę karę. A wyszukiwanie regionu zazwyczaj wymaga zablokowania.
Działa to również z C ++ 98 po zastąpieniu auto, użyciu nowego non-const str.data () i dodaniu spacji, aby przerwać zamykanie szablonu („>>” do „>>”) w następujący sposób:
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 );
reservei back_inserter(dzięki czemu ciąg jest kopiowany tylko raz). 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);
toupperjest wywoływany z liczbami ujemnymi.
spróbuj toupper()funkcji ( #include <ctype.h>). akceptuje znaki jako argumenty, ciągi znaków składają się ze znaków, więc będziesz musiał iterować każdy poszczególny znak, który po złożeniu składa się z ciągu
toupperjest wywoływana z liczbami ujemnymi. Powinieneś był wspomnieć o niezbędnej obsadzie unsigned char.
Oto najnowszy kod z C ++ 11
std::string cmd = "Hello World";
for_each(cmd.begin(), cmd.end(), [](char& in){ in = ::toupper(in); });
toupperjest wywoływany z liczbami ujemnymi.
Odpowiedź od @dirkgently jest bardzo inspirujący, ale chcę podkreślić, że ze względu na obawy, jak pokazano poniżej,
Podobnie jak wszystkie inne funkcje z, zachowanie std :: toupper jest niezdefiniowane, jeśli wartość argumentu nie jest reprezentowalna jako znak bez znaku ani równa EOF. Aby bezpiecznie korzystać z tych funkcji w przypadku zwykłych znaków (lub znaków podpisanych), argument należy najpierw przekonwertować na znak bez znaku
Odniesienie : std :: toupper
Prawidłowe użycie std::toupperpowinno być:
#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;
}
Wynik:
Hello world!
HELLO WORLD!
nie jestem pewien, czy istnieje wbudowana funkcja. Spróbuj tego:
Dołącz biblioteki ctype.h OR cctype oraz stdlib.h jako część dyrektyw preprocesora.
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
}
toupperjest wywoływany z liczbami ujemnymi.
Moje rozwiązanie (wyczyszczenie szóstego bitu dla alfa):
#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++;
}
}
toupperjest wywoływany z liczbami ujemnymi.
Wszystkie te rozwiązania na tej stronie są trudniejsze niż muszą.
Zrób to
RegName = "SomE StRing That you wAnt ConvErTed";
NameLength = RegName.Size();
for (int forLoop = 0; forLoop < NameLength; ++forLoop)
{
RegName[forLoop] = tolower(RegName[forLoop]);
}
RegNamejest twój string. Uzyskaj rozmiar łańcucha nie używaj go string.size()jako rzeczywistego testera, jest bardzo nieuporządkowany i może powodować problemy. następnie. najbardziej podstawowa forpętla.
pamiętaj, że rozmiar łańcucha zwraca również ogranicznik, więc użyj <, a nie <= w teście pętli.
wynik będzie: ciąg, który chcesz przekonwertować
tolowerpętli, a większość z nich używa standardowych nazw zmiennych pętli i, a nie dziwnych forLoop.
Bez użycia bibliotek:
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;
}
Jeśli zajmujesz się tylko 8-bitowymi znakami (które zakładają wszystkie inne odpowiedzi oprócz Milana Babuškova), możesz uzyskać największą prędkość, generując tablicę przeglądową w czasie kompilacji za pomocą metaprogramowania. Na ideone.com działa to 7 razy szybciej niż funkcja biblioteki i 3 razy szybciej niż wersja napisana ręcznie ( http://ideone.com/sb1Rup ). Można go również dostosować za pomocą cech bez spowolnienia.
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);
}
z przypadkiem użycia:
std::transform(in.begin(),in.end(),out.begin(),tableToUpper);
Aby uzyskać szczegółową (wiele stron) opis tego, jak to działa, mogę bezwstydnie podłączyć mojego bloga: 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;
}
Ta funkcja c ++ zawsze zwraca ciąg wielkich liter ...
#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;
}
Korzystam z tego rozwiązania. Wiem, że nie powinieneś modyfikować tego obszaru danych ... ale myślę, że dotyczy to głównie błędów przepełnienia bufora i znaku zerowego ... górna część obudowy nie jest taka sama.
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- jaki obszar danych nie należy modyfikować?
str[i] = toupper(str[i]);idealnie w porządku (cóż, niezupełnie w porządku, ale naprawia większość rzeczy źle).
::touppernajprawdopodobniej przyjmuje ASCII.