Bagaimana seseorang dapat mengkonversi string ke huruf besar. Contoh yang saya temukan dari googling hanya harus berurusan dengan karakter.
Bagaimana seseorang dapat mengkonversi string ke huruf besar. Contoh yang saya temukan dari googling hanya harus berurusan dengan karakter.
Jawaban:
Meningkatkan algoritma string:
#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()
bisa diimplementasikan sebagai makro. Ini dapat menyebabkan masalah.
toupper
. Ada ide?
Solusi singkat menggunakan C ++ 11 dan toupper ().
for (auto & c: str) c = toupper(c);
c
menjadi const char
jenis (dari auto
)? Jika demikian, Anda tidak dapat menetapkannya (karena const
sebagian) untuk apa yang dikembalikan oleh toupper(c)
.
c
perlu di-cast agar unsigned char
ini bisa dikorupsi.
struct convert {
void operator()(char& c) { c = toupper((unsigned char)c); }
};
// ...
string uc_str;
for_each(uc_str.begin(), uc_str.end(), convert());
Catatan: Beberapa masalah dengan solusi teratas:
21.5 Utilitas urutan yang diakhiri null
Isi header ini harus sama dengan header Perpustakaan C Standar <ctype.h>, <wctype.h>, <string.h>, <wchar.h>, dan <stdlib.h> [...]
Yang berarti bahwa cctype
anggota mungkin makro tidak cocok untuk konsumsi langsung dalam algoritma standar.
Masalah lain dengan contoh yang sama adalah tidak memberikan argumen atau memverifikasi bahwa ini tidak negatif; ini sangat berbahaya untuk sistem tempat dataran char
ditandatangani. (Alasannya adalah: jika ini diterapkan sebagai makro mungkin akan menggunakan tabel pencarian dan indeks argumen Anda ke dalam tabel itu. Indeks negatif akan memberi Anda UB.)
Masalah ini dapat diubah dengan SIMD untuk rangkaian karakter ASCII.
Pengujian awal dengan x86-64 gcc 5.2 -O3 -march=native
pada Core2Duo (Merom). String yang sama dengan 120 karakter (campuran huruf kecil dan ASCII non-huruf kecil), dikonversikan dalam loop 40M kali (tanpa inline file-silang, sehingga kompiler tidak dapat mengoptimalkan atau menghilangkan semua itu dari loop). Sumber dan buffer yang sama, jadi tidak ada overhead malloc atau efek memori / cache: data panas di L1 cache sepanjang waktu, dan kami murni terikat CPU.
boost::to_upper_copy<char*, std::string>()
: 198.0s . Ya, Boost 1.58 di Ubuntu 15.10 benar-benar lambat. Saya memprofilkan dan melangkah satu langkah dalam debugger, dan itu benar- benar buruk: ada dynamic_cast dari variabel lokal yang terjadi per karakter !!! (dynamic_cast mengambil beberapa panggilan ke strcmp). Ini terjadi dengan LANG=C
dan dengan LANG=en_CA.UTF-8
.
Saya tidak menguji menggunakan RangeT selain std :: string. Mungkin bentuk lainto_upper_copy
mengoptimalkan lebih baik, tapi saya pikir itu akan selalu new
/ malloc
ruang untuk salinan, jadi lebih sulit untuk menguji. Mungkin sesuatu yang saya lakukan berbeda dari kasus penggunaan normal, dan mungkin biasanya berhenti g ++ dapat mengangkat hal-hal pengaturan lokal keluar dari loop per-karakter. Perulangan saya dari std::string
dan menulis hingga char dstbuf[4096]
masuk akal untuk pengujian.
loop calling glibc toupper
: 6.67s (tidak memeriksa int
hasil untuk multi-byte UTF-8, meskipun. Ini penting untuk Turki.)
cmov
, dengan tabel panas di L1.Lihat juga pertanyaan ini tentang toupper()
menjadi lambat di Windows saat lokal diatur .
Saya terkejut bahwa Meningkatkan adalah urutan besarnya lebih lambat daripada opsi lain. Saya memeriksa ulang bahwa saya telah -O3
mengaktifkannya, dan bahkan satu langkah untuk melihat apa yang dilakukannya. Kecepatannya hampir persis sama dengan dentang ++ 3.8. Ini memiliki overhead besar di dalam per-karakter loop. The perf record
/ report
hasil (untuk cycles
acara perf) adalah:
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 dan dentang hanya akan auto-vectorize loop ketika jumlah iterasi diketahui di depan loop. (mis. loop pencarian seperti implementasi plain-C strlen
tidak akan melakukan otomatisasi.)
Jadi, untuk string yang cukup kecil untuk disimpan dalam cache, kita mendapatkan speedup yang signifikan untuk string ~ 128 chars lama dari melakukan strlen
pertama. Ini tidak diperlukan untuk string dengan panjang eksplisit (seperti 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;
}
Setiap libc yang layak akan memiliki efisiensi strlen
yang jauh lebih cepat daripada perulangan byte pada suatu waktu, jadi memisahkan vektor dan loop toupper vektor lebih cepat.
Baseline: loop yang memeriksa untuk mengakhiri 0 dengan cepat.
Waktu untuk iterasi 40M, pada Core2 (Merom) 2.4GHz. gcc 5.2 -O3 -march=native
. (Ubuntu 15.10). dst != src
(jadi kami membuat salinan), tetapi mereka tidak tumpang tindih (dan tidak di dekatnya). Keduanya selaras.
Beberapa hasil sedikit berbeda dengan dentang.
Loop microbenchmark yang memanggil fungsi berada dalam file terpisah. Kalau tidak, inline dan strlen()
diangkat keluar dari loop, dan berjalan secara dramatis lebih cepat, esp. selama 16 string char (0,187s).
Ini memiliki keuntungan besar bahwa gcc dapat melakukan auto-vektorisasi untuk arsitektur apa pun, tetapi kelemahan utama adalah bahwa gcc lebih lambat untuk kasus string kecil yang biasanya umum.
Jadi ada speedup besar, tapi kompilasi otomatis vektor tidak membuat kode yang bagus, khususnya. untuk pembersihan hingga 15 karakter terakhir.
Berdasarkan fungsi case-flip saya yang membalik kasus dari setiap karakter alfabet. Ini mengambil keuntungan dari "trik perbandingan yang tidak ditandatangani", di mana Anda dapat melakukan low < a && a <= high
dengan satu perbandingan yang tidak ditandatangani dengan menggeser rentang, sehingga nilai apa pun yang kurang dari low
nilai yang lebih besar daripada nilai yang lebih besar high
. (Ini berfungsi jika low
dan high
tidak terlalu jauh.)
SSE hanya memiliki perbandingan-ditandatangani yang lebih besar, tetapi kita masih dapat menggunakan trik "perbandingan tidak ditandatangani" dengan menggeser rentang ke bagian bawah rentang yang ditandatangani: Kurangi 'a' + 128, sehingga karakter alfabet berkisar dari -128 hingga -128 +25 (-128 + 'z' - 'a')
Perhatikan bahwa menambahkan 128 dan mengurangi 128 adalah hal yang sama untuk bilangan bulat 8bit. Tidak ada tempat untuk membawa, jadi itu hanya xor (carryless add), membalik bit tinggi.
#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
}
Dengan fungsi ini yang bekerja untuk satu vektor, kita dapat memanggilnya dalam satu lingkaran untuk memproses seluruh string. Karena kami sudah menargetkan SSE2, kami dapat melakukan pemeriksaan end-of-string secara vektor pada saat yang sama.
Kita juga dapat melakukan jauh lebih baik untuk "pembersihan" dari byte terakhir hingga 15 yang tersisa setelah melakukan vektor 16B: casing atas idempoten, jadi memproses ulang beberapa byte input baik-baik saja. Kami melakukan beban yang tidak selaras dari 16B terakhir dari sumber, dan menyimpannya ke buffer dest yang tumpang tindih dengan toko 16B terakhir dari loop.
Satu-satunya saat ini tidak berfungsi adalah ketika seluruh string di bawah 16B: Bahkan ketika dst=src
, baca-modifikasi-tulis non-atom bukan hal yang sama dengan tidak menyentuh beberapa byte sama sekali, dan dapat memecahkan kode multithreaded.
Kami memiliki loop skalar untuk itu, dan juga untuk mendapatkan src
selaras. Karena kita tidak tahu di mana 0 terminating akan berada, beban yang tidak selaras src
mungkin akan masuk ke halaman berikutnya dan segfault. Jika kita membutuhkan byte dalam chunk 16B sejajar, selalu aman untuk memuat chunk 16B sejajar.
Sumber lengkap: dalam inti github .
// 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;
}
Waktu untuk iterasi 40M, pada Core2 (Merom) 2.4GHz. gcc 5.2 -O3 -march=native
. (Ubuntu 15.10). dst != src
(jadi kami membuat salinan), tetapi mereka tidak tumpang tindih (dan tidak di dekatnya). Keduanya selaras.
(Sebenarnya diatur _mm_store
dalam loop, bukan _mm_storeu
, karena storeu lebih lambat pada Merom bahkan ketika alamat disejajarkan. Tidak masalah pada Nehalem dan nanti. Saya juga membiarkan kode apa adanya untuk saat ini, alih-alih memperbaiki kegagalan untuk menyalin penghentian 0 dalam beberapa kasus, karena saya tidak ingin mengatur ulang waktu semuanya.)
Jadi untuk string pendek lebih panjang dari 16B, ini secara dramatis lebih cepat daripada auto-vektor. Panjang satu-kurang-dari-vektor-lebar tidak menimbulkan masalah. Mereka mungkin menjadi masalah ketika beroperasi di tempat, karena kedai toko-forwarding. (Tetapi perhatikan bahwa masih baik untuk memproses output kita sendiri, daripada input asli, karena toupper idempotent).
Ada banyak ruang untuk menyetel ini untuk berbagai kasus penggunaan, tergantung pada apa yang diinginkan kode di sekitarnya, dan mikroarsitektur target. Mendapatkan kompiler untuk mengeluarkan kode yang bagus untuk bagian pembersihan itu sulit. Menggunakan ffs(3)
(yang mengkompilasi bsf atau tzcnt pada x86) tampaknya baik, tetapi jelas bahwa bit perlu dipikirkan kembali karena saya melihat bug setelah menulis sebagian besar jawaban ini (lihat komentar FIXME).
Vektor speedup untuk string yang lebih kecil dapat diperoleh dengan movq
atau movd
memuat / menyimpan. Sesuaikan seperlunya untuk use case Anda.
Kita dapat mendeteksi kapan vektor kita memiliki byte dengan set bit tinggi, dan dalam kasus itu kembali ke loop skalar utf-8-aware untuk vektor itu. The dst
point dapat memajukan dengan jumlah yang berbeda dari src
pointer, tetapi setelah kita kembali ke selaras src
pointer, kami akan tetap lakukan toko vektor unaligned ke dst
.
Untuk teks yang UTF-8, tetapi sebagian besar terdiri dari bagian ASCII dari UTF-8, ini bisa bagus: kinerja tinggi dalam kasus umum dengan perilaku yang benar dalam semua kasus. Ketika ada banyak non-ASCII, itu mungkin akan lebih buruk daripada tetap di loop sadar UTF-8 scalar sepanjang waktu.
Membuat bahasa Inggris lebih cepat dengan mengorbankan bahasa lain bukanlah keputusan yang tahan masa depan jika kelemahannya signifikan.
Di lokal Turki ( tr_TR
), hasil yang benar dari toupper('i')
adalah 'İ'
(U0130), bukan 'I'
(ASCII polos). Lihat komentar Martin Bonner tentang pertanyaan tentang tolower()
memperlambat pada Windows.
Kita juga dapat memeriksa daftar pengecualian dan mundur ke skalar di sana, seperti untuk karakter input UTF8 multi-byte.
Dengan kerumitan sebanyak ini, SSE4.2 PCMPISTRM
atau sesuatu mungkin dapat melakukan banyak pemeriksaan kami dalam sekali jalan.
Apakah Anda memiliki karakter ASCII atau Internasional di string?
Jika ini kasus terakhir, "huruf besar" tidak semudah itu, dan itu tergantung pada alfabet yang digunakan. Ada huruf bikameral dan unikameral. Hanya huruf bikameral yang memiliki karakter berbeda untuk huruf besar dan kecil. Juga, ada karakter gabungan, seperti huruf latin 'DZ' (\ u01F1 'DZ') yang menggunakan case title . Ini berarti bahwa hanya karakter pertama (D) yang diubah.
Saya sarankan Anda melihat ke ICU , dan perbedaan antara Pemetaan Kasus Sederhana dan Lengkap. Ini mungkin membantu:
string StringToUpper(string strToConvert)
{
for (std::string::iterator p = strToConvert.begin(); strToConvert.end() != p; ++p)
*p = toupper(*p);
return p;
}
Atau,
string StringToUpper(string strToConvert)
{
std::transform(strToConvert.begin(), strToConvert.end(), strToConvert.begin(), ::toupper);
return strToConvert;
}
**
setelah parameter pada solusi pertama?
**
ini adalah kesalahan ketik yang tersisa dari mencoba menggunakan font tebal dalam sintaksis kode.
toupper
dipanggil dengan angka negatif.
Berikut ini berfungsi untuk saya.
#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
dipanggil dengan angka negatif.
Gunakan 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);
Yang lebih cepat jika Anda hanya menggunakan karakter ASCII :
for(i=0;str[i]!=0;i++)
if(str[i]<='z' && str[i]>='a')
str[i]-=32;
Harap perhatikan bahwa kode ini berjalan lebih cepat tetapi hanya berfungsi pada ASCII dan bukan merupakan solusi "abstrak".
Jika Anda membutuhkan solusi UNICODE atau solusi yang lebih konvensional dan abstrak, buka jawaban lain dan bekerja dengan metode string C ++.
C++
, tetapi Anda menulis C
jawaban di sini. (Saya bukan salah satu dari para downvoter.)
'
?
Selama Anda baik-baik saja dengan ASCII saja dan Anda dapat memberikan pointer yang valid ke memori RW, ada one-liner sederhana dan sangat efektif di C:
void strtoupper(char* str)
{
while (*str) *(str++) = toupper((unsigned char)*str);
}
Ini sangat baik untuk string sederhana seperti pengidentifikasi ASCII yang ingin Anda normalkan ke dalam case-karakter yang sama. Anda kemudian dapat menggunakan buffer untuk membangun instance string std:.
//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 ...
. Juga tidak ada alasan bagus untuk membuatnya jadi sulit dibaca. Ini juga menyalin string pertama dan kemudian mengulanginya. @ Luke menjawab lebih baik dalam beberapa hal, kecuali untuk tidak memanfaatkan 'a'
konstanta karakter.
#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());
Ini akan berkinerja lebih baik daripada semua jawaban yang menggunakan fungsi toupper global, dan mungkin apa yang meningkatkan :: to_upper lakukan di bawahnya.
Ini karena :: toupper harus mencari lokal - karena mungkin telah diubah oleh utas berbeda - untuk setiap doa, sedangkan di sini hanya panggilan ke lokal () yang memiliki penalti ini. Dan mencari lokasi biasanya melibatkan mengambil kunci.
Ini juga berfungsi dengan C ++ 98 setelah Anda mengganti otomatis, gunakan str.data non-const baru (), dan tambahkan spasi untuk memecahkan penutupan templat (">>" ke ">>") seperti ini:
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
dan back_inserter
(membuatnya jadi hanya disalin sekali). 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
dipanggil dengan angka negatif.
coba toupper()
fungsi ( #include <ctype.h>
). itu menerima karakter sebagai argumen, string terdiri dari karakter, jadi Anda harus beralih setiap karakter individu yang ketika disatukan terdiri dari string
toupper
dipanggil dengan angka negatif. Anda harus menyebutkan pemeran yang diperlukan unsigned char
.
Ini adalah kode terbaru dengan C ++ 11
std::string cmd = "Hello World";
for_each(cmd.begin(), cmd.end(), [](char& in){ in = ::toupper(in); });
toupper
dipanggil dengan angka negatif.
The jawaban dari @dirkgently sangat menginspirasi, tapi saya ingin menekankan bahwa karena kekhawatiran seperti yang ditunjukkan di bawah ini,
Seperti semua fungsi lain dari, perilaku std :: toupper tidak terdefinisi jika nilai argumen tidak diwakili sebagai karakter yang tidak ditandatangani atau sama dengan EOF. Untuk menggunakan fungsi-fungsi ini dengan aman dengan karakter polos (atau karakter bertanda tangan), argumen pertama-tama harus dikonversi ke char yang tidak ditandatangani.
Referensi : std :: toupper
penggunaan yang benar std::toupper
harus:
#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;
}
Keluaran:
Hello world!
HELLO WORLD!
tidak yakin ada fungsi bawaan. Coba ini:
Sertakan pustaka ctype.h ATAU cctype, serta stdlib.h sebagai bagian dari arahan preprocessor.
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
dipanggil dengan angka negatif.
Solusi saya (menghapus bit ke-6 untuk alpha):
#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
dipanggil dengan angka negatif.
SEMUA solusi di halaman ini lebih sulit daripada yang seharusnya.
Melakukan hal ini
RegName = "SomE StRing That you wAnt ConvErTed";
NameLength = RegName.Size();
for (int forLoop = 0; forLoop < NameLength; ++forLoop)
{
RegName[forLoop] = tolower(RegName[forLoop]);
}
RegName
adalah Anda string
. Dapatkan ukuran string Anda tidak digunakan string.size()
sebagai tester Anda yang sebenarnya, sangat berantakan dan dapat menyebabkan masalah. kemudian. for
loop paling dasar .
ingat ukuran string mengembalikan pembatas juga jadi gunakan <dan tidak <= dalam tes loop Anda.
output akan menjadi: beberapa string yang ingin Anda konversi
tolower
loop sederhana , dan kebanyakan dari mereka menggunakan nama variabel loop standar seperti i
, bukan yang aneh forLoop
.
Tanpa menggunakan perpustakaan apa pun:
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;
}
Jika Anda hanya peduli dengan 8 bit karakter (yang semua jawaban lain kecuali Milan Babuškov asumsikan juga), Anda bisa mendapatkan kecepatan tercepat dengan membuat tabel pencarian pada waktu kompilasi menggunakan metaprogramming. Di ideone.com ini berjalan 7x lebih cepat dari fungsi perpustakaan dan 3x lebih cepat dari versi tulisan tangan ( http://ideone.com/sb1Rup ). Ini juga dapat dikustomisasi melalui sifat-sifat tanpa memperlambat.
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);
}
dengan use case:
std::transform(in.begin(),in.end(),out.begin(),tableToUpper);
Untuk penjelasan mendalam (banyak halaman) tentang cara kerjanya, izinkan saya untuk menyambungkan blog saya tanpa malu-malu: 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;
}
Fungsi c ++ ini selalu mengembalikan string huruf besar ...
#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;
}
Saya menggunakan solusi ini. Saya tahu Anda tidak seharusnya memodifikasi area data itu .... tapi saya pikir itu sebagian besar untuk bug buffer overrun dan karakter nol .... casing bagian atas tidak 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
- area data apa yang tidak seharusnya Anda modifikasi?
str[i] = toupper(str[i]);
baik-baik saja (well, tidak sepenuhnya baik, tetapi memperbaiki sebagian besar hal yang salah).
::toupper
kemungkinan besar mengasumsikan ASCII.