C++의 문자열을 대문자로 변환합니다.
어떻게 문자열을 대문자로 변환할 수 있죠?제가 구글링에서 찾은 예는 chars만 다루면 됩니다.
#include <algorithm>
#include <string>
std::string str = "Hello World";
std::transform(str.begin(), str.end(), str.begin(), ::toupper);
문자열 알고리즘을 부스트합니다.
#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");
C++11과 Toupper()를 사용한 쇼트 용액입니다.
for (auto & c: str) c = toupper(c);
이 문제는 ASCII 문자 집합의 SIMD를 통해 벡터화할 수 있습니다.
비교 속도를 높입니다.
gcc 5.2 x86-64 gcc 5.2로 예비 테스트를 실시합니다.-O3 -march=native
Core2Duo(메롬)입니다.120자로 구성된 동일한 문자열(소문자와 소문자가 혼합된 ASCII)이 40M회 루프에서 변환됩니다(크로스 파일 인라인 기능이 없으므로 컴파일러는 이를 최적화하거나 루프 밖으로 끌어올릴 수 없습니다).소스 버퍼와 타깃 버퍼가 동일하므로 malloc 오버헤드나 메모리/캐시 효과가 없습니다. 데이터는 L1 캐시에서 항상 핫하므로 CPU에 바인딩되어 있습니다.
boost::to_upper_copy<char*, std::string>()
: 198.0초입니다.예, Ubuntu 15.10의 Boost 1.58은 정말 느립니다.디버거에서 ASM을 프로파일링하고 싱글 스텝으로 처리했는데 정말 안 좋아요dynamic_cast
문자당 발생하는 로케일 변수의 수입니다!!! ) 。 ( ) 。dynamic_cast
는 여러 개의 호출을 받습니다.strcmp
)에서는 이런 현상이 발생합니다.LANG=C
그리고 ★★★★★★★★★★★★★★★★★★★★★LANG=en_CA.UTF-8
요.제가 시험 안 요.
RangeT
외외 than 이외에요.std::string
아마도 다른 형태의 최적화가 더 잘 될 것입니다. 하지만 저는 항상 그렇게 할 것이라고 생각합니다.new
/ / / // 이요.malloc
복사를 위한 공간이 필요하기 때문에 테스트하기가 더 어렵습니다.일반적인 사용 사례와 다른 점이 있을 수 있으며, 일반적으로 중지된 g++는 문자별 루프에서 로케일 설정 정보를 끌어올릴 수 있습니다.내 루프가 a에서 읽힙니다.std::string
그리고 글씨를 쓰세요.char dstbuf[4096]
테스트에 이치에 맞습니다.glibc glibc를 호출합니다.
toupper
: 6.67s(확인 안 함)입니다.int
결과에는 잠재적인 멀티바이트 UTF-8이 포함됩니다.이는 터키어의 일반적인 테스트 사례를 포함하여 일부 지역에서 문제가 됩니다.)ASCII 전용 루프: 8.79s(아래 결과에 대한 기준 버전)입니다.테이블 룩업이 더 빠르다고 합니다.
cmov
L1입니다.ASCII 전용 자동 벡터화: 2.51s(120자는 최악의 경우와 최상의 경우 중간 문자, 아래 참조)입니다.
ASCII 전용 수동 벡터화: 1.35s입니다.
로케일이 설정될 때 Windows에서 속도가 느려지는 것에 대한 이 질문도 참조하십시오.
Boost가 다른 옵션보다 훨씬 느리다는 사실에 놀랐습니다.가 확인해보니 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★」-O3
활성화 되어 있고 심지어 ASM을 한 번 돌려서 뭘 하는지 볼 수도 있습니다.꽝+3입니다.8면 됩니다.문자당 루프 내부에 엄청난 오버헤드가 있습니다.»는 다음과 같습니다.perf record
/ / / / / / / / / / / / / / / / / / 。report
결과입니다.cycles
이렇게 이야기합니다.
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% ...
자동 벡터화입니다.
및 clang은 반복 횟수가 루프에 앞서 알려진 경우에만 루프를 자동 벡터화합니다(즉, Gcc - clang의 플레인-C 구현과 같은 검색 루프).strlen
을 사용하세요.)
따라서 캐시에 수 있을 정도로 작은 의 경우 문자열의 속도가 상당히 빨라집니다. 문자열 길이는 128자까지입니다.strlen
먼저 명시적 길이의 문자열(예: C++면, 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;
}
어떤 libc라도 효율적인 libc를 가질 수 있습니다.strlen
한 번에 1바이트를 루프하는 것보다 훨씬 빠르기 때문에 벡터화된 스트렌과 터퍼 루프가 분리되는 것이 더 빠릅니다.
기준선: 종단 0을 즉시 확인하는 루프입니다.
4Core2(Merom) 2.4 또는 4,000입니다.. gcc 5.2GHz. gcc 5.2GHz입니다.-O3 -march=native
Ubuntu15.10) 입니다. (Ubuntu 15.10)라고 합니다. dst != src
(복사본을 만들지만) 겹치지 않고 가까이 있지 않습니다.그러하다, 그러게요.
- 15자 문자열: 기준선: 1.08초, 자동 검색: 1.34초입니다.
- 16 문자 문자열: 기준선: 1.16s, 자동 검색: 1.52s입니다.
- 127 문자 문자열: 기준선: 8.91s. autovec: 2.98s // 처리할 문자가 15개 있습니다.
- 128 문자 문자열: 기준선: 9.00초, 자동 검색: 2.06초입니다.
- 129 문자 문자열: 기준선: 9.04s. autovec: 2.07s // 처리할 문자가 1개 있습니다.
쨍그랑 소리가 나면 결과가 조금 다를 수 있습니다.
함수를 호출하는 마이크로벤치마크 루프는 별도의 파일에 있습니다.안 그러면 줄서고, 줄서고, 줄서고, 줄서고, 줄서고, 줄서고.strlen()
루프에서 들어올려지며, 특히 16자 문자열(0.16초)에 대해 훨씬 더 빨리 실행됩니다.
이는 gcc가 모든 아키텍처에 대해 자동 벡터화할 수 있다는 주요 장점이 있지만, 일반적으로 작은 문자열의 경우 속도가 느리다는 주요 단점이 있습니다.
따라서 속도가 크게 향상되지만 컴파일러 자동 벡터화는 특히 마지막 15자까지 정리하는 데 좋은 코드가 되지 않습니다.
SSE 내장 함수를 사용한 수동 벡터화:
모든 알파벳 대소문자를 반전시키는 제 대소문자 플립 함수에 기초합니다.이는 "서명되지 않은 비교 트릭"을 활용하여 다음과 같은 작업을 수행할 수 있습니다.low < a && a <= high
범위 이동에 따른 단일 부호 없는 비교를 하여 값이 less less 이이 이 음 음 음 음 음 음 음 음 음 음 음 음 음 음 음 음 than than than than than than than than than than than any any any any with with with with with with with with with with with with with with 。low
쌈을 큰 값으로 쌉니다.high
. (이거는 만약에...) 이면 됩니다low
그리고요.high
을 사용하세요.)
SSE에는 서명된 비교-대수만 있지만, 서명된 범위의 맨 아래로 범위를 이동하여 "서명되지 않은 비교" 기술을 사용할 수 있습니다.'a'+128을 빼서 -128에서 -128+25(-128+'z'-'a')' 사이의 알파벳 문자를 지정합니다.
128을 더하는 것과 128을 빼는 것은 8비트 정수의 경우 같습니다.캐리어가 들어갈 곳이 없어서 그냥 xor(캐리리스 애드)일 뿐입니다.
#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
}
하나의 벡터에 대해 작동하는 이 함수를 루프에서 호출하여 전체 문자열을 처리할 수 있습니다.이미 SSE2를 대상으로 하고 있기 때문에 동시에 벡터화된 문자열 끝 검사를 수행할 수 있습니다.
또한 16B의 벡터를 수행한 후 남은 마지막 최대 15바이트의 "정리"를 훨씬 더 잘 수행할 수 있습니다. 즉, 상위 캐싱은 유휴 상태이므로 일부 입력 바이트를 다시 처리하는 것이 좋습니다.소스의 마지막 16B에 대해 정렬되지 않은 로드를 수행하고 루프의 마지막 16B 저장소와 겹치는 대상 버퍼에 저장합니다.
이 기능이 하지 않는 유일한 때는 전체 문자열이 16B 미만일 입니다. 16B 미만일 때도 마찬가지입니다.dst=src
non-atomic read-sign-write는 일부 바이트에 전혀 영향을 미치지 않으며 멀티스레드 코드를 손상시킬 수 있습니다.
스칼라 루프가 스칼라 루프가 있습니다. 그리고 그 루프가src
정렬되어 있습니다. 0이 어디에 있을 지 때문에 0에서 나오는 비정렬 부하가 됩니다.src
청크에 바이트가 필요한 경우 정렬된 16B청크 전체를 로드하는 것이 항상 안전합니다.정렬된 16B 청크에 바이트가 필요한 경우 정렬된 16B 청크 전체를 로드하는 것이 항상 안전합니다.
전체 출처: Github Gest에 있습니다.
// 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;
}
4Core2(Merom) 2.4 또는 4,000입니다.. gcc 5.2GHz. gcc 5.2GHz입니다.-O3 -march=native
Ubuntu15.10) 입니다. (Ubuntu 15.10)라고 합니다. dst != src
(복사본을 만들지만) 겹치지 않고 가까이 있지 않습니다.그러하다, 그러게요.
- 15글자 문자열: 기준선: 1.08s. autovec: 1.34s. 수동: 1.29s입니다.
- 16 문자 문자열: 기준선: 1.16초, 자동 입력: 1.52초, 수동: 0.335초입니다.
- 31자 문자열: 수동: 0.479s입니다.
- 127 문자 문자열: 기준선: 8.91초, 자동 입력: 2.98초, 수동: 0.925초입니다.
- 128 문자 문자열: 기준선: 9.00s. autovec: 2.06s. 수동: 0.931s입니다.
- 129 문자 문자열: 기준선: 9.04초, 자동 입력: 2.07초, 수동: 1.02초입니다.
실제로 (와) 시간이 맞았습니다.)_mm_store
루프가 아닌 루프에 있지 않습니다._mm_storeu
주소가 정렬되어 있어도 스토어가 Merom에서 느리기 때문입니다. 종료된 을 복사하지 못한 경우 수정하지 않고 코드를 그대로. 모든 시간을 다시 설정하고 싶지 않기 때문입니다또한 종료된 0을 복사하지 못한 경우 수정하지 않고 코드를 현재 상태로 두었습니다. 모든 시간을 재지정하고 싶지 않기 때문입니다.
따라서 짧은 문자열이 16B보다 길면 자동 벡터화보다 훨씬 빠릅니다.길이가 벡터 폭보다 작으면 문제가 되지 않습니다.스토어 포워딩 스톨로 인해 인플레이스 운영 시 문제가 될 수 있습니다. 그러나 터퍼는 유휴 상태이므로 원래 입력이 아닌 자체 출력을 처리하는 것은 여전히 문제 없습니다.
주변 코드와 대상 마이크로 아키텍처에 따라 다양한 사용 사례에 맞게 조정할 수 있는 범위가 다양합니다.컴파일러가 정리 부분에 대해 멋진 코드를 내보내도록 하는 것은 어렵습니다.용용을 사용합니다.ffs(3)
(x86에서 bsf 또는 tzcnt로 컴파일됨) 좋은 것처럼 보이지만, 이 답변의 대부분을 작성한 후 버그를 발견했기 때문에 해당 비트는 다시 생각해봐야 합니다(FIXME 주석 참조).
더 작은 문자열에 대한 벡터 속도 향상은 더 작은 문자열에 대한 벡터 속도 향상으로 얻을 수 있습니다.movq
아니면요?movd
적재/저장합니다.사용 사례에 맞게 필요에 따라 사용자 정의합니다.
UTF-8은 다음과 같습니다.
벡터에 높은 비트 집합의 바이트가 있는 경우를 감지할 수 있으며, 이 경우 해당 벡터에 대한 스칼라 utf-8 인식 루프로 폴백됩니다.»는 다음과 같습니다.dst
이렇게 하다 보면 '점'은 '점'이 '점'보다 '점'이 올라갈 수 있어요.src
포인터, 하지만 정렬된 상태로 돌아가면요src
포인터 그래도 정렬되지 않은 벡터 스토어를 ㄴㄴ, ㄴㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ)로 할게요.dst
요.
UTF-8이지만 대부분 UTF-8의 ASCII 하위 집합으로 구성되어 있는 텍스트의 경우, 모든 경우에 올바른 동작과 함께 일반적인 경우 고성능이 좋습니다.그러나 ASCII가 아닌 다른 항목이 많을 경우 스칼라 UTF-8 인식 루프에 항상 있는 것보다 더 나쁠 수 있습니다.
다른 언어를 희생시키면서 영어를 더 빨리 하는 것은 단점이 크다면 미래를 대비할 수 있는 결정이 아니다.
SIMD 최적화 UTF-8 검증 및 ASCII 전용 특수 사례 탐지:
- https://github.com/simdutf/
- https://lemire.me/blog/2020/10/20/ridiculously-fast-unicode-utf-8-validation/
- https://lemire.me/blog/2018/05/16/validating-utf-8-strings-using-as-little-as-0-7-cycles-per-byte/ - detecting is string은 UTF-8의 ASCII 하위 집합입니다. 입력 바이트당 0.07 ~ 0.1 사이클(2018년에는 Skylake 시대일 수 있음)
로케일 인식:
일부 로케일에서 ASCII 의 터퍼가 ASC가 아닌 ASC 문자를 생성합니다.2번입니다.터키어입니다tr_TR
)은(는) 여러 가지 이상한 기능이 있는 로케일의 예입니다. 즉, 의 올바른 결과입니다 이겁니다.toupper('i')
는 에요요입니다.'İ'
U0130), (U0130), 아니다.'I'
(일반 ASCII)입니다.다음 질문에 대한 Martin Bonner의 의견을 참조하십시오.tolower()
Windows 서서 windows windows windows windows windows windows windows windows windows windows windows 。
또한 멀티바이트 UTF8 입력 문자와 같이 예외 목록을 확인하고 스칼라로 폴백할 수 있습니다.
SSE4.2 SSE4는 이렇게 복잡합니다.2면 됩니다.PCMPISTRM
아니면 한 번에 많은 체크를 할 수 있을 거예요
struct convert {
void operator()(char& c) { c = toupper((unsigned char)c); }
};
// ...
string uc_str;
for_each(uc_str.begin(), uc_str.end(), convert());
참고: 상위 솔루션에는 몇 가지 문제가 있습니다.
21.5 시퀀스 유틸리티는 null로 종료됩니다.
이러한 헤더의 내용은 Standard C Library 헤더 <ctype>과 동일해야 합니다.h>, <wctpe>를 선택합니다.h>, <문자열입니다.h >, <wchar.h > 및 <stdlib>를 선택합니다.h> [...]을 클릭합니다.
그 말은 즉, 그 말은...
cctype
구성원은 표준 알고리즘에서 직접 사용하기에 적합하지 않은 매크로일 수 있습니다.같은 의 또 다른 문제점은 이것이 부정적이지 않다는 것을 입증하거나 주장을 제시하지 않는다는 것입니다. 이는 특히 일반 시스템이 부정적이지 않다는 것입니다. 이겁니다.
char
왜냐하면매크로로 구현되면 조회 테이블과 인수 인덱스를 사용할 수 있기 때문입니다.(그 이유는 이것이 매크로로 구현될 경우 룩업 테이블과 인수 인덱스를 해당 테이블로 사용할 수 있기 때문입니다.UB를 사용합니다.)
string StringToUpper(string strToConvert)
{
for (std::string::iterator p = strToConvert.begin(); strToConvert.end() != p; ++p)
*p = toupper(*p);
return p;
}
아니면요.
string StringToUpper(string strToConvert)
{
std::transform(strToConvert.begin(), strToConvert.end(), strToConvert.begin(), ::toupper);
return strToConvert;
}
저는 다음과 같이 하면 됩니다.
#include <algorithm>
void toUpperCase(std::string& str)
{
std::transform(str.begin(), str.end(), str.begin(), ::toupper);
}
int main()
{
std::string str = "hello";
toUpperCase(&str);
}
문자열에 ASCII 또는 국제 문자가 있습니까?
후자의 경우, "대문자"는 그렇게 간단하지 않고, 사용된 알파벳에 따라 달라집니다.양원 알파벳과 단원 알파벳이 있습니다.대문자와 소문자의 문자가 다른 것은 양원 알파벳뿐입니다.또한 라틴 대문자 'DZ'(\u01F1 'DZ')와 같이 제목 대소문자를 사용하는 복합 문자도 있습니다.즉, 첫 번째 문자(D)만 변경됩니다.
ICU와 단순 케이스 매핑과 전체 케이스 매핑의 차이점을 알아보는 것이 좋습니다.도움이 될 수 있습니다.
http://userguide.icu-project.org/transforms/casemappings
ASCII 문자만 사용하는 경우 더 빠릅니다.
for(i=0;str[i]!=0;i++)
if(str[i]<='z' && str[i]>='a')
str[i]+='A'-'a';
이 코드는 더 빨리 실행되지만 ASCII에서만 작동하며 "추상" 솔루션은 아닙니다.
다른 UTF8 알파벳의 확장 버전입니다.
...
if(str[i]<='z' && str[i]>='a') //is latin
str[i]+='A'-'a';
else if(str[i]<='я' && str[i]>='а') //cyrillic
str[i]+='Я'-'я'
else if(str[i]<='ω' && str[i]>='α') //greek
str[i]+='Ω'-'ω'
//etc...
전체 UNICODE 솔루션이나 더 일반적이고 추상적인 솔루션이 필요한 경우, 다른 답변으로 이동하여 C++ 문자열 메서드로 작업하십시오.
ASCII만 사용할 수 있고 RW 메모리에 대한 유효한 포인터를 제공할 수 있다면 C:에 간단하고 매우 효과적인 단일 라이너가 있습니다.
void strtoupper(char* str)
{
while (*str) *(str++) = toupper((unsigned char)*str);
}
이것은 ASCII 식별자와 같이 동일한 문자 대/소문자로 정규화하려는 단순 문자열에 특히 유용합니다.그런 다음 버퍼를 사용하여 std:string 인스턴스를 구성할 수 있습니다.
람다를 사용하세요.
std::string s("change my case");
std::locale locale;
auto to_upper = [&locale] (char ch) { return std::use_facet<std::ctype<char>>(locale).toupper(ch); };
std::transform(s.begin(), s.end(), s.begin(), to_upper);
//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;
}
#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());
이 기능은 글로벌 터퍼 기능을 사용하는 모든 응답보다 더 잘 수행되며, 아마도 부스트::to_uper가 아래에서 수행하는 작업일 것입니다.
이는 ::toupper가 호출할 때마다 다른 스레드에 의해 변경되었을 수 있기 때문에 로케일을 검색해야 하는 반면, 여기서는 local() 호출에만 이 패널티가 있기 때문입니다.그리고 그 장소를 찾는 건 보통 자물쇠를 잠그는 것과 관련이 있어요
또한 auto를 교체하고 새로운 non-const str.data()를 사용한 후 다음과 같이 템플릿 닫힘(">"에서 "> >")을 해제할 공간을 추가한 후 C++98과 함께 작동합니다.
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());
std::string str = "STriNg oF mIxID CasE lETteRS"
C++ 11입니다.
각각에 사용합니다.
std::for_each(str.begin(), str.end(), [](char & c){ c = ::toupper(c); });
변환을 사용합니다.
std::transform(str.begin(), str.end(), str.begin(), ::toupper);
C++(Winodw만 해당)
_strupr_s(str, str.length());
C++(부스트 라이브러리 사용)
boost::to_upper_copy(str)
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 );
@dirkgently의 답변은 매우 고무적이지만, 아래와 같은 우려 때문에 강조하고 싶습니다.
의 다른 모든 함수와 마찬가지로 인수 값이 부호 없는 문자로 표시되지 않거나 EOF와 동일하지 않으면 std::toupper의 동작이 정의되지 않습니다.이러한 함수를 일반 문자(또는 부호 있는 문자)와 함께 안전하게 사용하려면 먼저 인수를 부호 없는 문자로 변환해야 합니다.
참조: std::toupper입니다.
기준이 평이한지 아닌지가 명시되어 있지 않습니다.char
서명되었거나 서명되지 않은 [1], 올바른 사용법입니다.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;
}
출력은 다음과 같습니다.
Hello world!
HELLO WORLD!
std::string value;
for (std::string::iterator p = value.begin(); value.end() != p; ++p)
*p = toupper(*p);
시험삼아 해 보세요.toupper()
기능을 합니다#include <ctype.h>
)는 글자를인수로 받아들이고 문자열은 글자로 구성되기 때문에 문자열로 구성될 때 각각의 글자에 대해 반복해야 합니다.
//Since I work on a MAC, and Windows methods mentioned do not work for me, I //just built this quick method.
string str;
str = "This String Will Print Out in all CAPS";
int len = str.size();
char b;
for (int i = 0; i < len; i++){
b = str[i];
b = toupper(b);
// b = to lower(b); //alternately
str[i] = b;
}
cout<<str;
다음은 C++11의 최신 코드입니다.
std::string cmd = "Hello World";
for_each(cmd.begin(), cmd.end(), [](char& in){ in = ::toupper(in); });
부스트를 사용합니다.텍스트 - 유니코드 텍스트에 사용할 수 있습니다.
boost::text::text t = "Hello World";
boost::text::text uppered;
boost::text::to_title(t, std::inserter(uppered, uppered.end()));
std::string newstr = uppered.extract();
대문자로만 사용하려는 경우 이 기능을 사용해 보십시오.
#include <iostream>
using namespace std;
string upper(string text){
string upperCase;
for(int it : text){
if(it>96&&it<123){
upperCase += char(it-32);
}else{
upperCase += char(it);
}
}
return upperCase;
}
int main() {
string text = "^_abcdfghopqrvmwxyz{|}";
cout<<text<<"/";
text = upper(text);
cout<<text;
return 0;
}
Kyle_the_hacker의 ---------------------------------------------------------------
우분투입니다
터미널에서 모든 로케일을 나열합니다.
locale -a
모든 로케일을 설치합니다.
sudo apt-get install -y locales locales-all
main.cppmain.cppp를 컴파일합니다.
$ g++ main.cpp
컴파일된 프로그램을 실행합니다.
$ ./a.out
결과.
Zoë Saldaña played in La maldición del padre Cardona. ëèñ αω óóChloë
Zoë Saldaña played in La maldición del padre Cardona. ëèñ αω óóChloë
ZOË SALDAÑA PLAYED IN LA MALDICIÓN DEL PADRE CARDONA. ËÈÑ ΑΩ ÓÓCHLOË
ZOË SALDAÑA PLAYED IN LA MALDICIÓN DEL PADRE CARDONA. ËÈÑ ΑΩ ÓÓCHLOË
zoë saldaña played in la maldición del padre cardona. ëèñ αω óóchloë
zoë saldaña played in la maldición del padre cardona. ëèñ αω óóchloë
창문들
에서 VCVARS 개발자 toolscmd를 실행합니다.
"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"
main.cppmain.cppp를 컴파일합니다.
> cl /EHa main.cpp /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /std:c++17 /DYNAMICBASE "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" /MTd
Compilador de optimización de C/C++ de Microsoft (R) versión 19.27.29111 para x64
(C) Microsoft Corporation. Todos los derechos reservados.
main.cpp
Microsoft (R) Incremental Linker Version 14.27.29111.0
Copyright (C) Microsoft Corporation. All rights reserved.
/out:main.exe
main.obj
kernel32.lib
user32.lib
gdi32.lib
winspool.lib
comdlg32.lib
advapi32.lib
shell32.lib
ole32.lib
oleaut32.lib
uuid.lib
odbc32.lib
odbccp32.lib
메인 실행하세요.실행할 수 있습니다.
>main.exe
결과.
Zoë Saldaña played in La maldición del padre Cardona. ëèñ αω óóChloë
Zoë Saldaña played in La maldición del padre Cardona. ëèñ αω óóChloë
ZOË SALDAÑA PLAYED IN LA MALDICIÓN DEL PADRE CARDONA. ËÈÑ ΑΩ ÓÓCHLOË
ZOË SALDAÑA PLAYED IN LA MALDICIÓN DEL PADRE CARDONA. ËÈÑ ΑΩ ÓÓCHLOË
zoë saldaña played in la maldición del padre cardona. ëèñ αω óóchloë
zoë saldaña played in la maldición del padre cardona. ëèñ αω óóchloë
코드 - main.cpp입니다.
이 코드는 Windows x64 및 Ubuntu Linux x64에서만 테스트되었습니다.
/*
* Filename: c:\Users\x\Cpp\main.cpp
* Path: c:\Users\x\Cpp
* Filename: /home/x/Cpp/main.cpp
* Path: /home/x/Cpp
* Created Date: Saturday, October 17th 2020, 10:43:31 pm
* Author: Joma
*
* No Copyright 2020
*/
#include <iostream>
#include <set>
#include <string>
#include <locale>
// WINDOWS
#if (_WIN32)
#include <Windows.h>
#include <conio.h>
#define WINDOWS_PLATFORM 1
#define DLLCALL STDCALL
#define DLLIMPORT _declspec(dllimport)
#define DLLEXPORT _declspec(dllexport)
#define DLLPRIVATE
#define NOMINMAX
//EMSCRIPTEN
#elif defined(__EMSCRIPTEN__)
#include <emscripten/emscripten.h>
#include <emscripten/bind.h>
#include <unistd.h>
#include <termios.h>
#define EMSCRIPTEN_PLATFORM 1
#define DLLCALL
#define DLLIMPORT
#define DLLEXPORT __attribute__((visibility("default")))
#define DLLPRIVATE __attribute__((visibility("hidden")))
// LINUX - Ubuntu, Fedora, , Centos, Debian, RedHat
#elif (__LINUX__ || __gnu_linux__ || __linux__ || __linux || linux)
#define LINUX_PLATFORM 1
#include <unistd.h>
#include <termios.h>
#define DLLCALL CDECL
#define DLLIMPORT
#define DLLEXPORT __attribute__((visibility("default")))
#define DLLPRIVATE __attribute__((visibility("hidden")))
#define CoTaskMemAlloc(p) malloc(p)
#define CoTaskMemFree(p) free(p)
//ANDROID
#elif (__ANDROID__ || ANDROID)
#define ANDROID_PLATFORM 1
#define DLLCALL
#define DLLIMPORT
#define DLLEXPORT __attribute__((visibility("default")))
#define DLLPRIVATE __attribute__((visibility("hidden")))
//MACOS
#elif defined(__APPLE__)
#include <unistd.h>
#include <termios.h>
#define DLLCALL
#define DLLIMPORT
#define DLLEXPORT __attribute__((visibility("default")))
#define DLLPRIVATE __attribute__((visibility("hidden")))
#include "TargetConditionals.h"
#if TARGET_OS_IPHONE && TARGET_IPHONE_SIMULATOR
#define IOS_SIMULATOR_PLATFORM 1
#elif TARGET_OS_IPHONE
#define IOS_PLATFORM 1
#elif TARGET_OS_MAC
#define MACOS_PLATFORM 1
#else
#endif
#endif
typedef std::string String;
typedef std::wstring WString;
#define EMPTY_STRING u8""s
#define EMPTY_WSTRING L""s
using namespace std::literals::string_literals;
class Strings
{
public:
static String WideStringToString(const WString& wstr)
{
if (wstr.empty())
{
return String();
}
size_t pos;
size_t begin = 0;
String ret;
#if WINDOWS_PLATFORM
int size;
pos = wstr.find(static_cast<wchar_t>(0), begin);
while (pos != WString::npos && begin < wstr.length())
{
WString segment = WString(&wstr[begin], pos - begin);
size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, &segment[0], segment.size(), NULL, 0, NULL, NULL);
String converted = String(size, 0);
WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, &segment[0], segment.size(), &converted[0], converted.size(), NULL, NULL);
ret.append(converted);
ret.append({ 0 });
begin = pos + 1;
pos = wstr.find(static_cast<wchar_t>(0), begin);
}
if (begin <= wstr.length())
{
WString segment = WString(&wstr[begin], wstr.length() - begin);
size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, &segment[0], segment.size(), NULL, 0, NULL, NULL);
String converted = String(size, 0);
WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, &segment[0], segment.size(), &converted[0], converted.size(), NULL, NULL);
ret.append(converted);
}
#elif LINUX_PLATFORM || MACOS_PLATFORM || EMSCRIPTEN_PLATFORM
size_t size;
pos = wstr.find(static_cast<wchar_t>(0), begin);
while (pos != WString::npos && begin < wstr.length())
{
WString segment = WString(&wstr[begin], pos - begin);
size = wcstombs(nullptr, segment.c_str(), 0);
String converted = String(size, 0);
wcstombs(&converted[0], segment.c_str(), converted.size());
ret.append(converted);
ret.append({ 0 });
begin = pos + 1;
pos = wstr.find(static_cast<wchar_t>(0), begin);
}
if (begin <= wstr.length())
{
WString segment = WString(&wstr[begin], wstr.length() - begin);
size = wcstombs(nullptr, segment.c_str(), 0);
String converted = String(size, 0);
wcstombs(&converted[0], segment.c_str(), converted.size());
ret.append(converted);
}
#else
static_assert(false, "Unknown Platform");
#endif
return ret;
}
static WString StringToWideString(const String& str)
{
if (str.empty())
{
return WString();
}
size_t pos;
size_t begin = 0;
WString ret;
#ifdef WINDOWS_PLATFORM
int size = 0;
pos = str.find(static_cast<char>(0), begin);
while (pos != std::string::npos) {
std::string segment = std::string(&str[begin], pos - begin);
std::wstring converted = std::wstring(segment.size() + 1, 0);
size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, &segment[0], segment.size(), &converted[0], converted.length());
converted.resize(size);
ret.append(converted);
ret.append({ 0 });
begin = pos + 1;
pos = str.find(static_cast<char>(0), begin);
}
if (begin < str.length()) {
std::string segment = std::string(&str[begin], str.length() - begin);
std::wstring converted = std::wstring(segment.size() + 1, 0);
size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, segment.c_str(), segment.size(), &converted[0], converted.length());
converted.resize(size);
ret.append(converted);
}
#elif LINUX_PLATFORM || MACOS_PLATFORM || EMSCRIPTEN_PLATFORM
size_t size;
pos = str.find(static_cast<char>(0), begin);
while (pos != String::npos)
{
String segment = String(&str[begin], pos - begin);
WString converted = WString(segment.size(), 0);
size = mbstowcs(&converted[0], &segment[0], converted.size());
converted.resize(size);
ret.append(converted);
ret.append({ 0 });
begin = pos + 1;
pos = str.find(static_cast<char>(0), begin);
}
if (begin < str.length())
{
String segment = String(&str[begin], str.length() - begin);
WString converted = WString(segment.size(), 0);
size = mbstowcs(&converted[0], &segment[0], converted.size());
converted.resize(size);
ret.append(converted);
}
#else
static_assert(false, "Unknown Platform");
#endif
return ret;
}
static WString ToUpper(const WString& data)
{
WString result = data;
auto& f = std::use_facet<std::ctype<wchar_t>>(std::locale());
f.toupper(&result[0], &result[0] + result.size());
return result;
}
static String ToUpper(const String& data)
{
return WideStringToString(ToUpper(StringToWideString(data)));
}
static WString ToLower(const WString& data)
{
WString result = data;
auto& f = std::use_facet<std::ctype<wchar_t>>(std::locale());
f.tolower(&result[0], &result[0] + result.size());
return result;
}
static String ToLower(const String& data)
{
return WideStringToString(ToLower(StringToWideString(data)));
}
};
enum class ConsoleTextStyle
{
DEFAULT = 0,
BOLD = 1,
FAINT = 2,
ITALIC = 3,
UNDERLINE = 4,
SLOW_BLINK = 5,
RAPID_BLINK = 6,
REVERSE = 7,
};
enum class ConsoleForeground
{
DEFAULT = 39,
BLACK = 30,
DARK_RED = 31,
DARK_GREEN = 32,
DARK_YELLOW = 33,
DARK_BLUE = 34,
DARK_MAGENTA = 35,
DARK_CYAN = 36,
GRAY = 37,
DARK_GRAY = 90,
RED = 91,
GREEN = 92,
YELLOW = 93,
BLUE = 94,
MAGENTA = 95,
CYAN = 96,
WHITE = 97
};
enum class ConsoleBackground
{
DEFAULT = 49,
BLACK = 40,
DARK_RED = 41,
DARK_GREEN = 42,
DARK_YELLOW = 43,
DARK_BLUE = 44,
DARK_MAGENTA = 45,
DARK_CYAN = 46,
GRAY = 47,
DARK_GRAY = 100,
RED = 101,
GREEN = 102,
YELLOW = 103,
BLUE = 104,
MAGENTA = 105,
CYAN = 106,
WHITE = 107
};
class Console
{
private:
static void EnableVirtualTermimalProcessing()
{
#if defined WINDOWS_PLATFORM
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD dwMode = 0;
GetConsoleMode(hOut, &dwMode);
if (!(dwMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING))
{
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
SetConsoleMode(hOut, dwMode);
}
#endif
}
static void ResetTerminalFormat()
{
std::cout << u8"\033[0m";
}
static void SetVirtualTerminalFormat(ConsoleForeground foreground, ConsoleBackground background, std::set<ConsoleTextStyle> styles)
{
String format = u8"\033[";
format.append(std::to_string(static_cast<int>(foreground)));
format.append(u8";");
format.append(std::to_string(static_cast<int>(background)));
if (styles.size() > 0)
{
for (auto it = styles.begin(); it != styles.end(); ++it)
{
format.append(u8";");
format.append(std::to_string(static_cast<int>(*it)));
}
}
format.append(u8"m");
std::cout << format;
}
public:
static void Clear()
{
#ifdef WINDOWS_PLATFORM
std::system(u8"cls");
#elif LINUX_PLATFORM || defined MACOS_PLATFORM
std::system(u8"clear");
#elif EMSCRIPTEN_PLATFORM
emscripten::val::global()["console"].call<void>(u8"clear");
#else
static_assert(false, "Unknown Platform");
#endif
}
static void Write(const String& s, ConsoleForeground foreground = ConsoleForeground::DEFAULT, ConsoleBackground background = ConsoleBackground::DEFAULT, std::set<ConsoleTextStyle> styles = {})
{
#ifndef EMSCRIPTEN_PLATFORM
EnableVirtualTermimalProcessing();
SetVirtualTerminalFormat(foreground, background, styles);
#endif
String str = s;
#ifdef WINDOWS_PLATFORM
WString unicode = Strings::StringToWideString(str);
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), unicode.c_str(), static_cast<DWORD>(unicode.length()), nullptr, nullptr);
#elif defined LINUX_PLATFORM || defined MACOS_PLATFORM || EMSCRIPTEN_PLATFORM
std::cout << str;
#else
static_assert(false, "Unknown Platform");
#endif
#ifndef EMSCRIPTEN_PLATFORM
ResetTerminalFormat();
#endif
}
static void WriteLine(const String& s, ConsoleForeground foreground = ConsoleForeground::DEFAULT, ConsoleBackground background = ConsoleBackground::DEFAULT, std::set<ConsoleTextStyle> styles = {})
{
Write(s, foreground, background, styles);
std::cout << std::endl;
}
static void Write(const WString& s, ConsoleForeground foreground = ConsoleForeground::DEFAULT, ConsoleBackground background = ConsoleBackground::DEFAULT, std::set<ConsoleTextStyle> styles = {})
{
#ifndef EMSCRIPTEN_PLATFORM
EnableVirtualTermimalProcessing();
SetVirtualTerminalFormat(foreground, background, styles);
#endif
WString str = s;
#ifdef WINDOWS_PLATFORM
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), str.c_str(), static_cast<DWORD>(str.length()), nullptr, nullptr);
#elif LINUX_PLATFORM || MACOS_PLATFORM || EMSCRIPTEN_PLATFORM
std::cout << Strings::WideStringToString(str);
#else
static_assert(false, "Unknown Platform");
#endif
#ifndef EMSCRIPTEN_PLATFORM
ResetTerminalFormat();
#endif
}
static void WriteLine(const WString& s, ConsoleForeground foreground = ConsoleForeground::DEFAULT, ConsoleBackground background = ConsoleBackground::DEFAULT, std::set<ConsoleTextStyle> styles = {})
{
Write(s, foreground, background, styles);
std::cout << std::endl;
}
static void WriteLine()
{
std::cout << std::endl;
}
static void Pause()
{
char c;
do
{
c = getchar();
std::cout << "Press Key " << std::endl;
} while (c != 64);
std::cout << "KeyPressed" << std::endl;
}
static int PauseAny(bool printWhenPressed = false, ConsoleForeground foreground = ConsoleForeground::DEFAULT, ConsoleBackground background = ConsoleBackground::DEFAULT, std::set<ConsoleTextStyle> styles = {})
{
int ch;
#ifdef WINDOWS_PLATFORM
ch = _getch();
#elif LINUX_PLATFORM || MACOS_PLATFORM || EMSCRIPTEN_PLATFORM
struct termios oldt, newt;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
ch = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
#else
static_assert(false, "Unknown Platform");
#endif
if (printWhenPressed)
{
Console::Write(String(1, ch), foreground, background, styles);
}
return ch;
}
};
int main()
{
std::locale::global(std::locale(u8"en_US.UTF-8"));
String dataStr = u8"Zoë Saldaña played in La maldición del padre Cardona. ëèñ αω óóChloë";
WString dataWStr = L"Zoë Saldaña played in La maldición del padre Cardona. ëèñ αω óóChloë";
std::string locale = u8"";
//std::string locale = u8"de_DE.UTF-8";
//std::string locale = u8"en_US.UTF-8";
Console::WriteLine(dataStr);
Console::WriteLine(dataWStr);
dataStr = Strings::ToUpper(dataStr);
dataWStr = Strings::ToUpper(dataWStr);
Console::WriteLine(dataStr);
Console::WriteLine(dataWStr);
dataStr = Strings::ToLower(dataStr);
dataWStr = Strings::ToLower(dataWStr);
Console::WriteLine(dataStr);
Console::WriteLine(dataWStr);
Console::WriteLine(u8"Press any key to exit"s, ConsoleForeground::DARK_GRAY);
Console::PauseAny();
return 0;
}
내장된 기능이 있는지 확실하지 않습니다.다음을 시도해 보십시오.
사전 프로세서 지시문의 일부로 ctype.h OR cctpe 라이브러리와 stdlib.h를 포함합니다.
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
}
내 솔루션(알파용 6번째 비트를 지웁니다.
#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++;
}
}
이 페이지의 모든 솔루션은 필요 이상으로 어렵습니다.
이렇게 하세요.
RegName = "SomE StRing That you wAnt ConvErTed";
NameLength = RegName.Size();
for (int forLoop = 0; forLoop < NameLength; ++forLoop)
{
RegName[forLoop] = tolower(RegName[forLoop]);
}
RegName
당신의 것입니다string
문자열 크기를 가져오십시오. 사용하지 마십시오.string.size()
그럼 이렇게 해 주세요가장 기본적인 것 입니다. 이겁니다.for
루우프요.
remember string size도 구분 기호를 반환하므로 루프 테스트에서 <=가 아닌 <를 사용합니다.
출력: 변환할 문자열이 있습니다.
라이브러리를 사용하지 않습니다.
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;
}
8비트 문자(Milan Babushkov를 제외한 다른 모든 답변도 마찬가지라고 가정함)에만 관심이 있는 경우 메타프로그래밍을 사용하여 컴파일 시간에 조회 테이블을 생성함으로써 가장 빠른 속도를 얻을 수 있습니다.ideone.com에서는 라이브러리 기능보다 7배, 손으로 쓴 버전(http://ideone.com/sb1Rup))보다 3배 빠르게 실행됩니다.또한 속도가 느려지지 않는 특성을 통해 사용자 지정이 가능합니다.
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);
}
다음과 같은 이점이 있습니다.
std::transform(in.begin(),in.end(),out.begin(),tableToUpper);
작동 원리에 대한 자세한 설명(많은 페이지)을 듣고 싶으시다면 제 블로그 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;
}
이 c++ 함수는 항상 대문자 문자열을 반환합니다.
#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;
}
언급URL : https://stackoverflow.com/questions/735204/convert-a-string-in-c-to-upper-case 입니다.
'programing' 카테고리의 다른 글
명령줄에서 모든 환경 변수를 나열합니다. (0) | 2023.04.25 |
---|---|
Excel 날짜를 yyymmd에서 mm/dd/yyyy로 변환합니다. (0) | 2023.04.25 |
GCD의 dispatch_once in Objective-C를 사용하여 싱글톤을 생성합니다. (0) | 2023.04.25 |
목록을 C#의 문자열로 변환합니다. (0) | 2023.04.25 |
mongoose 스키마에 중첩된 개체 (0) | 2023.04.20 |