Bir dize nasıl büyük harfe dönüştürülebilir. Google'dan bulduğum örnekler yalnızca karakterlerle uğraşmak zorunda.
Bir dize nasıl büyük harfe dönüştürülebilir. Google'dan bulduğum örnekler yalnızca karakterlerle uğraşmak zorunda.
Yanıtlar:
Dize algoritmalarını artırın:
#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()
bir makro olarak uygulanabilir. Bu bir soruna neden olabilir.
toupper
. Herhangi bir fikir?
C ++ 11 ve toupper () kullanarak kısa çözüm.
for (auto & c: str) c = toupper(c);
c
( const char
Tür auto
) türünden olmaz mı? Öyleyse, ( const
kısmen de olsa) tarafından döndürülen öğeye atayamazsınız toupper(c)
.
c
bunun düzeltilmesi için dökülmesi gerekiyor unsigned char
.
struct convert {
void operator()(char& c) { c = toupper((unsigned char)c); }
};
// ...
string uc_str;
for_each(uc_str.begin(), uc_str.end(), convert());
Not: En iyi çözümle ilgili birkaç sorun:
21.5 Boş sonlandırılmış sıra yardımcı programları
Bu başlıkların içeriği <ctype.h>, <wctype.h>, <string.h>, <wchar.h> ve <stdlib.h> [...] Standart C Kütüphane başlıkları ile aynı olmalıdır.
Bu, cctype
üyelerin standart algoritmalarda doğrudan tüketime uygun olmayan makrolar olabileceği anlamına gelir .
Aynı örnekle ilgili bir başka sorun da argümanı yayınlamaması veya bunun negatif olmadığını doğrulamamasıdır; bu özellikle ova char
imzalı sistemler için tehlikelidir . (Bunun nedeni: bu bir makro olarak uygulanırsa, büyük olasılıkla bir arama tablosu kullanır ve argümanınız bu tabloya dizinler. Negatif bir dizin size UB verecektir.)
Bu sorun ASCII karakter kümesi için SIMD ile vektörleştirilebilir .
-O3 -march=native
Bir Core2Duo (Merom) üzerinde x86-64 gcc 5.2 ile ön test . Aynı 120 karakter dizisi (karışık küçük harf ve küçük harf olmayan ASCII), 40M kez bir döngüye dönüştürülür (dosyalar arasında satır içi çizgi olmadan, derleyici döngüden herhangi birini optimize edemez veya kaldıramaz). Aynı kaynak ve hedef arabellekleri, böylece malloc ek yükü veya bellek / önbellek etkisi yok: veriler L1 önbellekte sürekli sıcaktır ve tamamen CPU'ya bağlıyız.
boost::to_upper_copy<char*, std::string>()
: 198.0s . Evet, Ubuntu 15.10'da Boost 1.58 gerçekten çok yavaş. Bir hata ayıklayıcı asm profilli ve tek adım, ve bu gerçekten, gerçekten kötü: karakter başına bir yerel değişken değişken bir dynamic_cast var !!! (dynamic_cast, strcmp'ye birden çok çağrı alır). Bu LANG=C
ve ile olur LANG=en_CA.UTF-8
.
Ben std :: string dışında bir RangeT kullanarak test etmedi. Belki diğer formto_upper_copy
daha iyi optimize eder, ancak bence her zaman new
/ malloc
kopya için alan olacak , bu yüzden test etmek daha zor. Belki yaptığım bir şey normal kullanım durumundan farklıdır ve belki normalde durdurulan g ++, yerel ayar öğelerini karakter başına döngüden kaldırabilir. Bir döngüden okumaya std::string
ve yazmaya kadar olan char dstbuf[4096]
döngüm test için mantıklı.
döngü çağrısı glibc toupper
: 6.67s (yine int
de potansiyel çok baytlık UTF-8 için sonucu kontrol etmiyor . Bu, Türkçe için önemli.)
cmov
, yine de tablo sıcak.Bir yerel ayar ayarlandığında Windows'ta yavaş olma ile ilgili bu soruyatoupper()
da bakın .
Boost'un diğer seçeneklerden daha yavaş bir büyüklük sırası olduğu için şok oldum. -O3
Etkinleştirdiğimi iki kez kontrol ettim ve hatta ne yaptığını görmek için asma tek adım attı. Clang ++ 3.8 ile neredeyse aynı hızda. Karakter başına döngü içinde büyük bir ek yüke sahiptir. perf record
/ report
(İçin sonuç cycles
perf etkinliği) aşağıdaki gibidir:
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 ve clang döngüleri sadece döngüden önce yineleme sayısı bilindiğinde otomatik olarak vektörleştirir. (ör. düz-C uygulaması gibi arama döngüleri strlen
otomatik vektörleştirilmez.)
Bu nedenle, önbelleğe sığacak kadar küçük dizeler için, strlen
ilk önce 128 128 karakter uzunluğunda dizeler için önemli bir hız kazanırız . Bu, açık uzunluklu dizeler için gerekli değildir (C ++ gibi 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;
}
Herhangi bir iyi libc verimli bir strlen
, bir seferde bir baytı döngüye sokmaktan çok daha hızlı , bu nedenle ayrı vektörize strlen ve toupper döngüleri daha hızlıdır.
Temel: anında 0 sonlandırmasını kontrol eden bir döngü.
Core2 (Merom) 2.4GHz'de 40M yineleme zamanı. gcc 5.2 -O3 -march=native
. (Ubuntu 15.10). dst != src
(böylece bir kopya oluştururuz), ancak örtüşmezler (ve yakında değildir). Her ikisi de hizalanır.
Bazı sonuçlar clang ile biraz farklıdır.
İşlevi çağıran mikrobenchmark döngüsü ayrı bir dosyadadır. Aksi takdirde, satır içi ve strlen()
döngüden dışarı çıkar ve çok daha hızlı çalışır, esp. 16 karakter dizisi için (0.187s).
Bu, gcc'nin onu herhangi bir mimari için otomatik olarak vektörleştirebilmesi gibi büyük bir avantaja sahiptir, ancak genellikle yaygın olan küçük dizeler için daha yavaş olmasının en büyük dezavantajı.
Yani büyük hızlanmalar var, ancak derleyici otomatik vektörleştirme büyük kod yapmıyor, esp. son 15 karaktere kadar temizlik için.
Benim dayanarak harf çevirme fonksiyonu her alfabetik karakterin halinde tersine çevirir. low < a && a <= high
Aralık kayması ile tek bir imzasız karşılaştırma ile yapabileceğiniz "işaretsiz karşılaştırma hilesi" avantajından yararlanır , böylece daha küçük herhangi low
bir değer, daha büyük bir değere sarılır high
. (Bu çok uzak değilse low
ve high
çok uzak değilse işe yarar .)
SSE'nin yalnızca işaretli bir karşılaştırması daha büyüktür, ancak yine de işaretsiz aralığın altına kaydırılarak "işaretsiz karşılaştırma" hilesini kullanabiliriz: 'a' + 128'i çıkarın, böylece alfabetik karakterler -128 ile -128 arasında değişir +25 (-128 + 'z' - 'a')
128 ekleme ve 128 çıkarma işleminin 8 bit tamsayılar için aynı şey olduğunu unutmayın. Taşıma için gidecek yer yok, bu yüzden sadece xor (taşımasız ekleme), yüksek biti çeviriyor.
#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
}
Bir vektör için çalışan bu işlev göz önüne alındığında, bir dizenin tamamını işlemek için bir döngüde çağırabiliriz. Zaten SSE2'yi hedeflediğimiz için, aynı zamanda vektörize bir dize sonu kontrolü yapabiliriz.
Ayrıca, 16B vektörleri yaptıktan sonra kalan son 15 baytın "temizlenmesi" için çok daha iyi yapabiliriz: üst kasa idempotenttir, bu nedenle bazı giriş baytlarının yeniden işlenmesi iyidir. Kaynağın son 16B'sinin hizasız bir yükünü yapıyoruz ve bunu döngüden son 16B deposuyla örtüşen dest tamponuna kaydediyoruz.
Bu işe yaramayan tek zaman, tüm dize 16B'nin altında olduğunda: dst=src
Atomik olmayan okuma-değiştirme-yazma özelliği olmasa bile tüm bazı bayt dokunmadan değil aynı şey ve çok iş parçacıklı kodunu bozabilir.
Bunun için bir skaler döngü var ve aynı zamanda src
hizalanmak için. Sonlandırma 0'ın nerede olacağını bilmediğimizden, hizalanmamış bir yük src
sonraki sayfaya ve segfault'a geçebilir. Hizalanmış bir 16B yığınında herhangi bir bayta ihtiyaç duyarsak, tüm hizalanmış 16B yığınını yüklemek her zaman güvenlidir.
Tam kaynak: bir github özünde .
// 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;
}
Core2 (Merom) 2.4GHz'de 40M yineleme zamanı. gcc 5.2 -O3 -march=native
. (Ubuntu 15.10). dst != src
(böylece bir kopya oluştururuz), ancak örtüşmezler (ve yakında değildir). Her ikisi de hizalanır.
(Aslında adrese göre ayarlanmış olsa bile storeu Merom'da daha yavaş olduğu _mm_store
için döngüde zamanlanmış _mm_storeu
. Nehalem ve daha sonra iyi. Kod kopyalama hatasını düzeltmek yerine şimdilik olduğu gibi bıraktım bazı durumlarda sonlandırma 0, çünkü her şeyi yeniden zamanlamak istemiyorum.)
Bu nedenle, 16B'den uzun kısa dizeler için bu, otomatik vektörleştirmekten çok daha hızlıdır. Bir vektör genişliğinden daha küçük uzunluklar sorun oluşturmaz. Mağazaya yönelik bir durak nedeniyle yerinde çalışırken bir sorun olabilir. (Ancak, toupper idempotent olduğundan, orijinal girdiden ziyade kendi çıktımızı işlemenin hala iyi olduğunu unutmayın).
Çevredeki kodun ne istediğine ve hedef mikro mimariye bağlı olarak bunu farklı kullanım durumları için ayarlamak için çok fazla alan vardır. Derleyicinin temizleme kısmı için güzel kod yayınlaması zor. Kullanmak ffs(3)
(hangi bsf veya tzcnt için x86 üzerinde derler) iyi gibi görünüyor, ama bu cevabın çoğunu yazdıktan sonra bir hata fark beri açıkçası bu biraz yeniden düşünmek gerekiyor (FIXME yorumlarına bakın).
Daha küçük dizeler için vektör hızlandırmaları movq
veya movd
yükler / depolar ile elde edilebilir . Kullanım durumunuz için gerektiği şekilde özelleştirin.
Vektörünüzün yüksek bit setiyle herhangi bir bayt içerdiğini tespit edebiliriz ve bu durumda o vektör için skaler utf-8-farkında bir döngüye geri döneriz. dst
Nokta farklı bir miktarda ilerletebilir src
pointer, ama biz geri bir hizalanmış gidince src
pointer, hala sadece karşı unaligned vektör depolarını yapacağız dst
.
UTF-8 olan ancak çoğunlukla UTF-8'in ASCII alt kümesinden oluşan metin için, bu iyi olabilir: tüm durumlarda doğru davranışla ortak durumda yüksek performans. ASCII olmayan bir sürü olduğunda, muhtemelen her zaman skaler UTF-8 farkında döngüde kalmaktan daha kötü olacaktır.
Dezavantajı önemliyse, İngilizceyi diğer diller pahasına daha hızlı yapmak geleceğe dönük bir karar değildir.
Türk yerelinde ( tr_TR
), doğru sonuç toupper('i')
ise 'İ'
(U0130) değil, 'I'
(ASCII). Martin Bonner'ıntolower()
Windows'ta yavaş olma hakkındaki bir soruya bakın .
Ayrıca, çok baytlık UTF8 giriş karakterleri gibi, bir istisna listesi ve skalerlere geri dönüş olup olmadığını kontrol edebiliriz.
Bu kadar karmaşıklıkla, SSE4.2 PCMPISTRM
ya da bir şey tek seferde birçok kontrolümüzü yapabilir.
Dizelerde ASCII veya Uluslararası karakterler var mı?
Eğer ikinci durum söz konusuysa, "büyük harf" o kadar basit değildir ve kullanılan alfabeye bağlıdır. Bikameral ve tek kamaralı alfabe vardır. Sadece bikameral alfabelerde büyük ve küçük harfler için farklı karakterler bulunur. Ayrıca, başlık büyük / küçük harfini kullanan Latince büyük harf 'DZ' (\ u01F1 'DZ') gibi kompozit karakterler de vardır . Bu, yalnızca ilk karakterin (D) değiştiği anlamına gelir.
YBÜ'ye bakmanızı ve Basit ve Tam Vaka Eşlemeleri arasındaki farkı öneririm . Bu yardımcı olabilir:
string StringToUpper(string strToConvert)
{
for (std::string::iterator p = strToConvert.begin(); strToConvert.end() != p; ++p)
*p = toupper(*p);
return p;
}
Veya,
string StringToUpper(string strToConvert)
{
std::transform(strToConvert.begin(), strToConvert.end(), strToConvert.begin(), ::toupper);
return strToConvert;
}
**
İlk çözümdeki parametrelerden sonra yıldızlar ne yapar?
**
bir yazım hatası kod sözdiziminde kalın yazı tipini kullanmaya çalışıyorum.
toupper
Negatif sayılarla çağrıldığında bu kod tanımsız davranışı başlatır .
Aşağıdakiler benim için çalışıyor.
#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
Negatif sayılarla çağrıldığında bu kod tanımsız davranışı başlatır .
Bir lambda kullanın.
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);
Yalnızca ASCII karakterlerini kullanırsanız daha hızlı olanı :
for(i=0;str[i]!=0;i++)
if(str[i]<='z' && str[i]>='a')
str[i]-=32;
Bu kodun daha hızlı çalıştığını, ancak yalnızca ASCII üzerinde çalıştığını ve "soyut" bir çözüm olmadığını lütfen unutmayın .
UNICODE çözümlerine veya daha geleneksel ve soyut çözümlere ihtiyacınız varsa, diğer yanıtları alın ve C ++ dizeleri yöntemleriyle çalışın.
C++
, ancak C
buraya bir cevap yazdınız. (Ben downvoters değilim.)
'
?
Yalnızca ASCII ile iyi olduğunuz ve RW belleğine geçerli bir işaretçi sağlayabildiğiniz sürece, C'de basit ve çok etkili bir astar vardır:
void strtoupper(char* str)
{
while (*str) *(str++) = toupper((unsigned char)*str);
}
Bu, özellikle aynı karakter durumuna normalleştirmek istediğiniz ASCII tanımlayıcıları gibi basit dizeler için iyidir. Ardından std: string örneği oluşturmak için buffer'ı kullanabilirsiniz.
//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 ...
. Okumayı zorlaştırmak için iyi bir neden de yok. Bu ayrıca önce dizeyi kopyalar ve sonra döngüyü kopyalar. @ Luke'un yanıtı, 'a'
karakter sabitlerinden faydalanmamak dışında, bazı açılardan daha iyidir .
#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());
Bu, global toupper işlevini kullanan tüm cevaplardan daha iyi performans gösterecektir ve muhtemelen boost :: to_upper'ın altında yaptığı şeydir.
Bunun nedeni :: toupper'ın yerel ayarı araması gerektiğidir - çünkü farklı bir iş parçacığı tarafından değiştirilmiş olabilir - her çağrı için, burada yalnızca locale () çağrısı bu cezaya sahiptir. Ve yerele bakmak genellikle bir kilit almayı içerir.
Bu, otomatik olarak değiştirildikten, yeni const olmayan str.data () yöntemini kullandıktan ve şablon kapanmasını (">>" - ">>") bu şekilde kırmak için bir boşluk ekledikten sonra C ++ 98 ile de çalışır:
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
ve back_inserter
(dizi sadece bir kez kopyalanır böylece yapma). 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
Negatif sayılarla çağrıldığında bu kod tanımsız davranışı başlatır .
toupper()
( #include <ctype.h>
) işlevini deneyin . karakterleri bağımsız değişken olarak kabul eder, dizeler karakterlerden oluşur, bu nedenle bir araya getirildiğinde dizeyi oluşturan her bir karakter üzerinde yineleme yapmanız gerekir
toupper
, negatif sayılarla çağrıldığında tanımlanmamış davranışı başlatır . Gerekli oyuncu kadrosundan bahsetmeliydin unsigned char
.
İşte C ++ 11 ile en son kod
std::string cmd = "Hello World";
for_each(cmd.begin(), cmd.end(), [](char& in){ in = ::toupper(in); });
toupper
Negatif sayılarla çağrıldığında bu kod tanımsız davranışı başlatır .
Cevap ait @dirkgently çok ilham veriyor ama aşağıda gösterildiği gibi bağlı endişe vurgulamak istiyoruz
Diğer tüm işlevler gibi, bağımsız değişkenin değeri işaretsiz karakter olarak temsil edilemez veya EOF'a eşit değilse std :: toupper davranışı tanımlanmamıştır. Bu işlevleri düz karakterlerle (veya imzalı karakterlerle) güvenle kullanmak için, bağımsız değişken önce işaretsiz karaktere dönüştürülmelidir
Reference : std :: toupper
doğru kullanımı std::toupper
:
#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;
}
Çıktı:
Hello world!
HELLO WORLD!
yerleşik bir fonksiyon olduğundan emin değilim. Bunu dene:
Önişlemci yönergelerinin bir parçası olarak ctype.h OR cctype kitaplıklarının yanı sıra stdlib.h dosyasını da ekleyin.
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
Negatif sayılarla çağrıldığında bu kod tanımsız davranışı başlatır .
Benim çözümüm (alfa için 6. biti temizleme):
#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
Negatif sayılarla çağrıldığında bu kod tanımsız davranışı başlatır .
Bu sayfadaki TÜM çözümlerin TÜMÜ olması gerekenden daha zordur.
Bunu yap
RegName = "SomE StRing That you wAnt ConvErTed";
NameLength = RegName.Size();
for (int forLoop = 0; forLoop < NameLength; ++forLoop)
{
RegName[forLoop] = tolower(RegName[forLoop]);
}
RegName
senin string
. Dize boyutunuzu alın, string.size()
gerçek test cihazınız olarak kullanmayın , çok dağınık ve sorunlara neden olabilir. sonra. en temel for
döngü.
unutmayın string boyutu sınırlayıcıyı da döndürür, bu yüzden döngü testinizde <= değil <= kullanın.
çıktı: dönüştürülmesini istediğiniz bazı dize
tolower
döngü var ve bunların çoğu i
garip değil, standart döngü değişken adları kullanıyor forLoop
.
Herhangi bir kütüphane kullanmadan:
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;
}
Sadece 8 bit karakterlerle ilgileniyorsanız (Milan Babuškov hariç tüm diğer cevaplar da varsayar) derleme zamanında metaprogramlama kullanarak bir arama tablosu oluşturarak en yüksek hızı elde edebilirsiniz. İdeone.com'da bu, kütüphane işlevinden 7 kat, elle yazılmış bir sürümden 3 kat daha hızlı çalışır ( http://ideone.com/sb1Rup ). Ayrıca, yavaşlama olmadan özellikler ile özelleştirilebilir.
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);
}
kullanım durumda:
std::transform(in.begin(),in.end(),out.begin(),tableToUpper);
Nasıl çalıştığına dair derinlemesine (birçok sayfa) bir açıklama için blogumu utanmadan takmama izin verin: 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;
}
Bu c ++ işlevi her zaman büyük harf dizesini döndürür ...
#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;
}
Bu çözümü kullanıyorum. Bu veri alanını değiştirmek zorunda değilsiniz biliyorum .... ama bence çoğunlukla tampon taşması hatalar ve boş karakter .... üst kasa şeyler aynı değil.
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
- hangi veri alanını değiştirmemeniz gerekiyor?
str[i] = toupper(str[i]);
mükemmel bir şekilde değiştirilebilir (iyi, mükemmel değil , ama çoğu şeyi yanlış düzeltir).
::toupper
büyük olasılıkla ASCII olduğu varsayılan i18n avantajına sahiptir .