Làm thế nào người ta có thể chuyển đổi một chuỗi thành chữ hoa Các ví dụ tôi đã tìm thấy từ googling chỉ phải đối phó với ký tự.
Làm thế nào người ta có thể chuyển đổi một chuỗi thành chữ hoa Các ví dụ tôi đã tìm thấy từ googling chỉ phải đối phó với ký tự.
Câu trả lời:
Tăng cường thuật toán chuỗi:
#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()
có thể được thực hiện như một vĩ mô. Điều này có thể gây ra một vấn đề.
toupper
. Có ý kiến gì không?
Giải pháp ngắn sử dụng C ++ 11 và toupper ().
for (auto & c: str) c = toupper(c);
c
thuộc const char
loại (từ auto
)? Nếu vậy, bạn không thể gán nó (vì const
một phần) cho những gì được trả về toupper(c)
.
c
cần phải được sử dụng để sửa lỗi unsigned char
này.
struct convert {
void operator()(char& c) { c = toupper((unsigned char)c); }
};
// ...
string uc_str;
for_each(uc_str.begin(), uc_str.end(), convert());
Lưu ý: Một vài vấn đề với giải pháp hàng đầu:
21.5 Tiện ích trình tự kết thúc Null
Nội dung của các tiêu đề này sẽ giống như các tiêu đề Thư viện C tiêu chuẩn <ctype.h>, <wctype.h>, <string.h>, <wchar.h> và <stdlib.h> [...]
Điều đó có nghĩa là các cctype
thành viên cũng có thể là các macro không phù hợp để tiêu thụ trực tiếp trong các thuật toán tiêu chuẩn.
Một vấn đề khác với cùng ví dụ là nó không đưa ra đối số hoặc xác minh rằng điều này không âm; Điều này đặc biệt nguy hiểm đối với các hệ thống nơi đồng bằng char
được ký kết. (Lý do là: nếu điều này được triển khai dưới dạng macro, nó có thể sẽ sử dụng bảng tra cứu và lập chỉ mục đối số của bạn vào bảng đó. Một chỉ mục phủ định sẽ cung cấp cho bạn UB.)
Vấn đề này có thể thay đổi được với SIMD cho bộ ký tự ASCII.
Thử nghiệm sơ bộ với x86-64 gcc 5.2 -O3 -march=native
trên Core2Duo (Merom). Cùng một chuỗi gồm 120 ký tự (hỗn hợp chữ thường và chữ thường ASCII), được chuyển đổi trong một vòng lặp 40M lần (không có nội dung tệp chéo, do đó trình biên dịch không thể tối ưu hóa hoặc loại bỏ bất kỳ ký tự nào ra khỏi vòng lặp). Cùng một bộ đệm nguồn và hủy, do đó, không có hiệu ứng trên bộ nhớ đệm hoặc bộ nhớ cache / bộ nhớ cache: dữ liệu luôn nóng trong bộ đệm L1 và chúng tôi hoàn toàn bị ràng buộc bởi CPU.
boost::to_upper_copy<char*, std::string>()
: 198.0s . Vâng, Boost 1.58 trên Ubuntu 15.10 thực sự rất chậm. Tôi đã lược tả và thực hiện một bước trong trình gỡ lỗi và điều đó thực sự rất tệ: có một biến động của một biến cục bộ xảy ra trên mỗi ký tự !!! (Dynamic_cast nhận nhiều cuộc gọi đến strcmp). Điều này xảy ra với LANG=C
và với LANG=en_CA.UTF-8
.
Tôi đã không kiểm tra bằng RangeT khác với std :: string. Có thể hình thức khácto_upper_copy
tối ưu hóa tốt hơn, nhưng tôi nghĩ nó sẽ luôn luôn new
/ malloc
không gian cho bản sao, vì vậy khó kiểm tra hơn. Có lẽ một cái gì đó tôi đã làm khác với trường hợp sử dụng thông thường và có lẽ g ++ thường dừng lại có thể nâng công cụ thiết lập ngôn ngữ ra khỏi vòng lặp cho mỗi ký tự. Vòng lặp của tôi đọc từ một std::string
và viết để char dstbuf[4096]
có ý nghĩa để thử nghiệm.
gọi vòng lặp glibc toupper
: 6,67s (không kiểm tra int
kết quả cho UTF-8 nhiều byte tiềm năng. Tuy nhiên, điều này quan trọng đối với tiếng Thổ Nhĩ Kỳ.)
cmov
, dù sao thì bảng cũng nóng trong L1.Xem thêm câu hỏi này về toupper()
việc chậm trên Windows khi cài đặt ngôn ngữ .
Tôi đã bị sốc khi Boost là một thứ tự cường độ chậm hơn so với các tùy chọn khác. Tôi đã kiểm tra lại xem tôi đã -O3
kích hoạt chưa, và thậm chí chỉ bước một bước để xem nó đang làm gì. Nó gần như chính xác cùng tốc độ với clang ++ 3.8. Nó có chi phí rất lớn bên trong vòng lặp trên mỗi ký tự. Các perf record
/ report
quả (đối với cycles
trường hợp Perf) là:
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 và clang sẽ chỉ tự động vector hóa các vòng lặp khi số lần lặp được biết trước vòng lặp. (tức là các vòng tìm kiếm như triển khai đồng bằng C strlen
sẽ không tự động kiểm tra.)
Do đó, đối với các chuỗi đủ nhỏ để phù hợp với bộ đệm, chúng ta sẽ có được sự tăng tốc đáng kể cho các chuỗi ~ 128 ký tự dài từ strlen
lần đầu tiên thực hiện . Điều này sẽ không cần thiết cho các chuỗi có độ dài rõ ràng (như 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;
}
Bất kỳ libc phong nha nào cũng sẽ có hiệu quả strlen
nhanh hơn nhiều so với việc lặp một byte tại một thời điểm, do đó, các vòng lặp strlen và toupper được vector hóa nhanh hơn.
Đường cơ sở: một vòng lặp kiểm tra kết thúc 0 khi đang bay.
Lần cho 40 lần lặp, trên Core2 (Merom) 2.4GHz. gcc 5.2 -O3 -march=native
. (Ubuntu 15.10). dst != src
(vì vậy chúng tôi tạo một bản sao), nhưng chúng không trùng nhau (và không ở gần đó). Cả hai đều được căn chỉnh.
Một số kết quả là một chút khác nhau với tiếng kêu.
Vòng lặp microbenchmark gọi hàm nằm trong một tệp riêng. Nếu không, nó sẽ nội tuyến và strlen()
được kéo ra khỏi vòng lặp, và nó chạy nhanh hơn đáng kể, đặc biệt. cho 16 chuỗi char (0.187s).
Điều này có lợi thế lớn là gcc có thể tự động vector hóa nó cho bất kỳ kiến trúc nào, nhưng nhược điểm lớn là nó chậm hơn đối với trường hợp thường gặp của các chuỗi nhỏ.
Vì vậy, có những sự tăng tốc lớn, nhưng tự động hóa trình biên dịch không tạo ra mã tuyệt vời, đặc biệt. để dọn dẹp tối đa 15 ký tự cuối cùng.
Dựa trên chức năng lật trường hợp của tôi mà đảo ngược trường hợp của mọi ký tự chữ cái. Nó lợi dụng "thủ thuật so sánh không dấu", trong đó bạn có thể thực hiện low < a && a <= high
với một so sánh không dấu bằng cách dịch chuyển phạm vi, sao cho bất kỳ giá trị nào nhỏ hơn low
kết thúc thành một giá trị lớn hơn high
. (Điều này hoạt động nếu low
và high
không quá xa nhau.)
SSE chỉ có một so sánh được ký lớn hơn, nhưng chúng ta vẫn có thể sử dụng thủ thuật "so sánh không dấu" bằng cách dịch chuyển phạm vi xuống dưới cùng của phạm vi đã ký: Trừ 'a' + 128, vì vậy các ký tự chữ cái nằm trong khoảng từ -128 đến -128 +25 (-128 + 'z' - 'a')
Lưu ý rằng việc thêm 128 và trừ 128 là điều tương tự đối với số nguyên 8 bit. Không có nơi nào để mang đi, vì vậy nó chỉ là xor (addless add), lật bit cao.
#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
}
Với hàm này hoạt động cho một vectơ, chúng ta có thể gọi nó trong một vòng lặp để xử lý toàn bộ chuỗi. Vì chúng tôi đã nhắm mục tiêu SSE2, chúng tôi có thể thực hiện kiểm tra cuối chuỗi được vector hóa cùng một lúc.
Chúng ta cũng có thể làm tốt hơn nhiều cho việc "dọn dẹp" tối đa 15 byte cuối cùng còn sót lại sau khi thực hiện các vectơ 16B: lớp trên là idempotent, vì vậy xử lý lại một số byte đầu vào là tốt. Chúng tôi thực hiện tải không được sắp xếp của 16B cuối cùng của nguồn và lưu trữ nó vào bộ đệm định mệnh chồng lên cửa hàng 16B cuối cùng từ vòng lặp.
Lần duy nhất điều này không hoạt động là khi toàn bộ chuỗi dưới 16B: Ngay cả khi dst=src
, đọc-sửa đổi-ghi không phải nguyên tử không giống như không chạm vào một số byte và có thể phá vỡ mã đa luồng.
Chúng tôi có một vòng vô hướng cho điều đó, và cũng để được src
căn chỉnh. Vì chúng tôi không biết kết thúc 0 sẽ ở đâu, tải không được phân bổ từ src
có thể đi qua trang tiếp theo và segfault. Nếu chúng ta cần bất kỳ byte nào trong một đoạn 16B được căn chỉnh, thì luôn luôn an toàn để tải toàn bộ đoạn 16B được căn chỉnh.
Nguồn đầy đủ: trong một 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;
}
Lần cho 40 lần lặp, trên Core2 (Merom) 2.4GHz. gcc 5.2 -O3 -march=native
. (Ubuntu 15.10). dst != src
(vì vậy chúng tôi tạo một bản sao), nhưng chúng không trùng nhau (và không ở gần đó). Cả hai đều được căn chỉnh.
(Trên thực tế, đã hết thời gian _mm_store
trong vòng lặp, _mm_storeu
bởi vì storeu chậm hơn Merom ngay cả khi địa chỉ được căn chỉnh. Nó vẫn ổn trên Nehalem và sau đó. Tôi cũng đã để lại mã như hiện tại, thay vì sửa lỗi không sao chép chấm dứt 0 trong một số trường hợp, vì tôi không muốn tính lại thời gian cho mọi thứ.)
Vì vậy, đối với các chuỗi ngắn dài hơn 16B, tốc độ này nhanh hơn đáng kể so với tự động véc tơ. Độ dài một chiều dài nhỏ hơn một vectơ không gây ra vấn đề. Chúng có thể là một vấn đề khi hoạt động tại chỗ, vì một gian hàng chuyển tiếp cửa hàng. (Nhưng lưu ý rằng vẫn ổn khi xử lý đầu ra của chúng ta, thay vì đầu vào ban đầu, bởi vì toupper là idempotent).
Có rất nhiều phạm vi để điều chỉnh điều này cho các trường hợp sử dụng khác nhau, tùy thuộc vào những gì mã xung quanh muốn và kiến trúc vi mô đích. Bắt trình biên dịch để phát ra mã đẹp cho phần dọn dẹp là khó khăn. Sử dụng ffs(3)
(biên dịch thành bsf hoặc tzcnt trên x86) có vẻ tốt, nhưng rõ ràng bit đó cần phải suy nghĩ lại vì tôi nhận thấy một lỗi sau khi viết hầu hết câu trả lời này (xem các bình luận FIXME).
Tăng tốc vector cho các chuỗi thậm chí nhỏ hơn có thể được lấy với movq
hoặc movd
tải / cửa hàng. Tùy chỉnh khi cần thiết cho trường hợp sử dụng của bạn.
Chúng ta có thể phát hiện khi vectơ của chúng ta có bất kỳ byte nào với tập bit cao và trong trường hợp đó rơi trở lại vòng lặp nhận biết vô hướng utf-8 cho vectơ đó. Các dst
điểm có thể thúc đẩy bởi một số tiền khác nhau hơn so với src
con trỏ, nhưng một khi chúng ta lấy lại cho một liên kết src
trỏ, chúng tôi sẽ vẫn chỉ làm cửa hàng vector unaligned tới dst
.
Đối với văn bản là UTF-8, nhưng chủ yếu bao gồm tập hợp con ASCII của UTF-8, điều này có thể tốt: hiệu suất cao trong trường hợp phổ biến với hành vi đúng trong mọi trường hợp. Tuy nhiên, khi có rất nhiều phi ASCII, điều đó có thể sẽ tồi tệ hơn là luôn ở trong vòng nhận thức vô hướng UTF-8 mọi lúc.
Làm cho tiếng Anh nhanh hơn với chi phí của các ngôn ngữ khác không phải là một quyết định trong tương lai nếu nhược điểm là đáng kể.
Trong miền địa phương Thổ Nhĩ Kỳ ( tr_TR
), kết quả chính xác toupper('i')
là 'İ'
(U0130), không phải 'I'
(ASCII đơn giản). Xem ý kiến của Martin Bonner về một câu hỏi về tolower()
việc chậm trên Windows.
Chúng ta cũng có thể kiểm tra danh sách ngoại lệ và dự phòng cho vô hướng ở đó, như đối với các ký tự đầu vào UTF8 nhiều byte.
Với sự phức tạp này, SSE4.2 PCMPISTRM
hoặc một cái gì đó có thể có thể thực hiện nhiều kiểm tra của chúng tôi trong một lần.
Bạn có ký tự ASCII hoặc International trong chuỗi không?
Nếu đó là trường hợp thứ hai, "cấp trên" không đơn giản và nó phụ thuộc vào bảng chữ cái được sử dụng. Có bảng chữ cái lưỡng tính và đơn hướng. Chỉ bảng chữ cái lưỡng tính có các ký tự khác nhau cho chữ hoa và chữ thường. Ngoài ra, có các ký tự hỗn hợp, như chữ in hoa Latin 'DZ' (\ u01F1 'DZ') sử dụng trường hợp được gọi là trường hợp tiêu đề . Điều này có nghĩa là chỉ có ký tự đầu tiên (D) được thay đổi.
Tôi đề nghị bạn xem xét ICU và sự khác biệt giữa Ánh xạ trường hợp đơn giản và toàn bộ. Điều này có thể giúp:
string StringToUpper(string strToConvert)
{
for (std::string::iterator p = strToConvert.begin(); strToConvert.end() != p; ++p)
*p = toupper(*p);
return p;
}
Hoặc là,
string StringToUpper(string strToConvert)
{
std::transform(strToConvert.begin(), strToConvert.end(), strToConvert.begin(), ::toupper);
return strToConvert;
}
**
sau các tham số trên giải pháp đầu tiên làm gì?
**
là một lỗi đánh máy còn sót lại khi cố gắng sử dụng phông chữ đậm trong cú pháp mã.
toupper
được gọi với số âm.
Các công việc sau đây cho tôi.
#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
được gọi với số âm.
Sử dụng 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);
Nhanh hơn nếu bạn chỉ sử dụng các ký tự ASCII :
for(i=0;str[i]!=0;i++)
if(str[i]<='z' && str[i]>='a')
str[i]-=32;
Xin lưu ý rằng mã này chạy nhanh hơn nhưng chỉ hoạt động trên ASCII và không phải là giải pháp "trừu tượng".
Nếu bạn cần các giải pháp UNICODE hoặc các giải pháp thông thường và trừu tượng hơn, hãy tìm các câu trả lời khác và làm việc với các phương thức của chuỗi C ++.
C++
, nhưng bạn đã viết một C
câu trả lời ở đây. (Tôi không phải là một trong những kẻ hạ bệ.)
'
?
Miễn là bạn ổn với chỉ ASCII và bạn có thể cung cấp một con trỏ hợp lệ cho bộ nhớ RW, có một lớp lót đơn giản và rất hiệu quả trong C:
void strtoupper(char* str)
{
while (*str) *(str++) = toupper((unsigned char)*str);
}
Điều này đặc biệt tốt cho các chuỗi đơn giản như mã định danh ASCII mà bạn muốn chuẩn hóa thành cùng một trường hợp ký tự. Sau đó, bạn có thể sử dụng bộ đệm để xây dựng một thể hiện 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 ...
. Cũng không có lý do chính đáng để làm cho nó khó đọc như vậy. Điều này cũng sao chép chuỗi đầu tiên và sau đó lặp qua nó. Câu trả lời của @ Luke tốt hơn trong một số cách, ngoại trừ việc không tận dụng các 'a'
hằng số ký tự.
#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());
Điều này sẽ thực hiện tốt hơn tất cả các câu trả lời sử dụng chức năng toupper toàn cầu và có lẽ là những gì boost :: to_upper đang làm bên dưới.
Điều này là do :: toupper phải tra cứu miền địa phương - bởi vì nó có thể đã bị thay đổi bởi một luồng khác nhau - cho mỗi lần gọi, trong khi ở đây chỉ có lệnh gọi miền địa phương () có hình phạt này. Và tìm kiếm địa phương thường liên quan đến việc lấy một khóa.
Điều này cũng hoạt động với C ++ 98 sau khi bạn thay thế tự động, sử dụng str.data () không phải const mới () và thêm một khoảng trắng để phá vỡ việc đóng mẫu (">>" thành ">>" như thế này:
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
và back_inserter
(làm cho chuỗi chỉ được sao chép một lần). 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
được gọi với số âm.
thử toupper()
hàm ( #include <ctype.h>
). nó chấp nhận các ký tự làm đối số, các chuỗi được tạo thành từ các ký tự, vì vậy bạn sẽ phải lặp lại qua từng ký tự riêng lẻ mà khi kết hợp lại bao gồm chuỗi
toupper
được gọi với số âm. Bạn nên đề cập đến các diễn viên cần thiết để unsigned char
.
Đây là mã mới nhất với C ++ 11
std::string cmd = "Hello World";
for_each(cmd.begin(), cmd.end(), [](char& in){ in = ::toupper(in); });
toupper
được gọi với số âm.
Câu trả lời của @dirkgently rất truyền cảm, nhưng tôi muốn nhấn mạnh rằng do mối quan tâm như được hiển thị bên dưới,
Giống như tất cả các hàm khác từ, hành vi của std :: toupper không được xác định nếu giá trị của đối số không thể biểu thị dưới dạng char không dấu cũng như bằng EOF. Để sử dụng các chức năng này một cách an toàn với các ký tự đơn giản (hoặc ký tự đã ký), trước tiên, đối số nên được chuyển đổi thành char không dấu
Tham chiếu : std :: toupper
cách sử dụng đúng std::toupper
nên là:
#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;
}
Đầu ra:
Hello world!
HELLO WORLD!
không chắc chắn có một chức năng tích hợp. Thử cái này:
Bao gồm các thư viện ctype.h HOẶC cctype, cũng như stdlib.h như một phần của các chỉ thị tiền xử lý.
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
được gọi với số âm.
Giải pháp của tôi (xóa bit thứ 6 cho 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
được gọi với số âm.
TẤT CẢ các giải pháp trên trang này khó hơn mức cần thiết.
Làm cái này
RegName = "SomE StRing That you wAnt ConvErTed";
NameLength = RegName.Size();
for (int forLoop = 0; forLoop < NameLength; ++forLoop)
{
RegName[forLoop] = tolower(RegName[forLoop]);
}
RegName
là bạn string
. Nhận kích thước chuỗi của bạn không sử dụng string.size()
làm người thử nghiệm thực tế của bạn, rất lộn xộn và có thể gây ra sự cố. sau đó. for
vòng lặp cơ bản nhất .
nhớ kích thước chuỗi cũng trả về dấu phân cách, vì vậy hãy sử dụng <và không <= trong kiểm tra vòng lặp của bạn.
đầu ra sẽ là: một số chuỗi mà bạn muốn chuyển đổi
tolower
vòng lặp đơn giản và hầu hết chúng sử dụng các tên biến vòng lặp tiêu chuẩn như thế i
, không phải là lạ forLoop
.
Không sử dụng bất kỳ thư viện:
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;
}
Nếu bạn chỉ quan tâm đến các ký tự 8 bit (mà tất cả các câu trả lời khác ngoại trừ Milan Babuškov cũng giả sử), bạn có thể có tốc độ nhanh nhất bằng cách tạo bảng tra cứu tại thời điểm biên dịch bằng cách sử dụng siêu lập trình. Trên ideone.com, nó chạy nhanh hơn 7 lần so với chức năng thư viện và nhanh hơn 3 lần so với phiên bản viết tay ( http://ideone.com/sb1Rup ). Nó cũng có thể tùy chỉnh thông qua các đặc điểm không làm chậm.
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);
}
với trường hợp sử dụng:
std::transform(in.begin(),in.end(),out.begin(),tableToUpper);
Để biết cách phân tích sâu (nhiều trang) về cách thức hoạt động cho phép tôi không biết xấu hổ cắm blog của mình: 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;
}
Hàm c ++ này luôn trả về chuỗi chữ hoa ...
#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;
}
Tôi sử dụng giải pháp này. Tôi biết bạn không cần phải sửa đổi vùng dữ liệu đó .... nhưng tôi nghĩ rằng phần lớn là do lỗi tràn bộ đệm và ký tự null .... những thứ có vỏ trên không giống nhau.
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
- khu vực dữ liệu nào bạn không cần phải sửa đổi?
str[i] = toupper(str[i]);
hoàn toàn tốt (tốt, không hoàn toàn tốt, nhưng nó sửa hầu hết những điều sai).
::toupper
rất có thể giả định ASCII.