어떻게 문자열을 대문자로 변환 할 수 있습니까? 인터넷 검색에서 찾은 예는 문자 만 다루면됩니다.
어떻게 문자열을 대문자로 변환 할 수 있습니까? 인터넷 검색에서 찾은 예는 문자 만 다루면됩니다.
답변:
부스트 문자열 알고리즘 :
#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()
는 매크로로 구현할 수 있습니다. 문제가 발생할 수 있습니다.
toupper
. 어떤 아이디어?
C ++ 11 및 toupper ()를 사용하는 짧은 솔루션.
for (auto & c: str) c = toupper(c);
c
것 입니까? 그렇다면 ( 부분으로 인해 )에서 반환 한 내용을 할당 할 수 없습니다 . const char
auto
const
toupper(c)
c
해결하려면 캐스팅해야합니다 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());
참고 : 최고의 솔루션과 관련된 몇 가지 문제 :
21.5 널 종료 시퀀스 유틸리티
이 헤더의 내용은 표준 C 라이브러리 헤더 <ctype.h>, <wctype.h>, <string.h>, <wchar.h> 및 <stdlib.h> [...]와 동일해야합니다.
이는 cctype
멤버가 표준 알고리즘에서의 직접 소비에 적합하지 않은 매크로 일 수 있음을 의미합니다 .
동일한 예제의 또 다른 문제점은 인수를 캐스트하지 않거나 이것이 음이 아닌지 확인한다는 것입니다. 이것은 평이 char
서명 된 시스템에 특히 위험합니다 . (이유 : 매크로로 구현 된 경우 조회 테이블과 인수 색인을 해당 테이블에 사용합니다. 음수 색인은 UB를 제공합니다.)
이 문제는 ASCII 문자 집합에 대해 SIMD 로 벡터화 할 수 있습니다.
-O3 -march=native
Core2Duo (Merom)에서 x86-64 gcc 5.2 를 사용한 예비 테스트 . 동일한 문자열 (120 자 (소문자와 소문자가 아닌 ASCII가 혼합 된 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
.
std :: string 이외의 RangeT를 사용하여 테스트하지 않았습니다. 아마 다른 형태의to_upper_copy
더 나은 최적화 그러나 나는 항상 생각 new
/ malloc
이 테스트에 열심히 그래서, 복사를위한 공간. 어쩌면 내가 한 일이 일반적인 유스 케이스와 다르고 일반적으로 중지 된 g ++은 문자 당 루프에서 로케일 설정 항목을 끌어 올릴 수 있습니다. a에서 읽고 std::string
쓰는 루프 char dstbuf[4096]
는 테스트에 적합합니다.
루프 호출 glibc toupper
: 6.67s ( int
그러나 잠재적 인 멀티 바이트 UTF-8 의 결과는 확인하지 않습니다 . 터키어에 중요합니다.)
cmov
L1에서 테이블이 뜨거워 테이블 조회가.보다 빠릅니다 .로케일이 설정 될 때 Windows에서 속도가 느려지 는 toupper()
것에 대한이 질문 도 참조하십시오 .
Boost가 다른 옵션보다 훨씬 느리다는 것에 놀랐습니다. 나는 내가 -O3
가능하게했는지 다시 한 번 확인 하고 심지어 일을 수행하기 위해 asm을 단계별로 진행했습니다. clang ++ 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% ...
Gcc와 clang은 반복 횟수가 루프보다 먼저 알려진 경우에만 루프를 자동 벡터화합니다. (예 : 평범한 C 구현과 같은 검색 루프strlen
는 자동 벡터화되지 않습니다.)
따라서 캐시에 들어갈 정도로 작은 문자열의 경우, strlen
처음 부터 문자열 길이가 ~ 128 자까지 크게 향상됩니다 . 명시적인 길이의 문자열 (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는 효율적입니다 strlen
한 번에 바이트를 루핑하는 것보다 훨씬 빠른 을 가지므로 별도의 벡터화 된 strlen 및 toupper 루프가 더 빠릅니다.
기준선 : 즉석에서 종료 0을 확인하는 루프.
Core2 (Merom) 2.4GHz에서 40M 반복 시간. gcc 5.2 -O3 -march=native
. (우분투 15.10). dst != src
(따라서 사본을 만들지 만) 겹치지 않으며 근처에 있지 않습니다. 둘 다 정렬됩니다.
일부 결과는 clang과 약간 다릅니다.
함수를 호출하는 마이크로 벤치 마크 루프는 별도의 파일에 있습니다. 그렇지 않으면 strlen()
루프에서 인라인되어 들어 올려 져 매우 빠르게 실행됩니다. 16 개의 문자열 (0.187)
이것은 gcc가 모든 아키텍처에서 자동 벡터화 할 수 있다는 주요 이점이 있지만 일반적으로 작은 문자열의 경우에는 느리다는 큰 단점이 있습니다.
따라서 빠른 속도 향상이 있지만 컴파일러 자동 벡터화는 훌륭한 코드를 만들지 않습니다. 마지막 최대 15자를 정리합니다.
모든 알파벳 문자의 대소 문자를 뒤집는 필자 의 플립 기능 을 기반으로 합니다. "서명되지 않은 비교 트릭"을 활용 low < a && a <= high
하여 범위 이동으로 단일 부호없는 비교를 수행 할 수 있으므로보다 작은 low
값은보다 큰 값으로 줄 바꿈됩니다 high
. (경우에 작동 low
과 high
너무 멀리 떨어져되지 않습니다.)
SSE는 부호있는 비교 만 가능하지만 부호있는 범위의 맨 아래로 범위를 이동하여 "부호없는 비교"트릭을 계속 사용할 수 있습니다. 'a'+ 128 빼기-영문자의 범위는 -128에서 -128 +25 (-128 + 'z'- 'a')
128을 더하고 128을 빼는 것은 8 비트 정수의 경우와 같습니다. 캐리가 갈 곳이 없기 때문에 xor (carryless add)이므로 높은 비트를 뒤집습니다.
#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 바이트의 "정리"에 대해 훨씬 더 잘 수행 할 수 있습니다. 대문자는 i 등이므로 일부 입력 바이트를 다시 처리하는 것이 좋습니다. 소스의 마지막 16B에 대해 정렬되지 않은로드를 수행하고 루프에서 마지막 16B 저장소와 겹치는 dest 버퍼에 저장합니다.
전체 문자열이 16B 중일 때이 작동하지 않는 유일한 시간은 다음과 같습니다 경우에도 dst=src
, 비 원자 읽기 - 수정 - 쓰기가 되지 모두에서 일부 바이트를 접촉하지 같은 일 및 멀티 스레드 코드를 깰 수 있습니다.
이를위한 스칼라 루프가 있으며 src
정렬됩니다. 종료 0이 어디에 있는지 알지 못하므로 정렬되지 않은로드 src
가 다음 페이지와 segfault로 넘어갈 수 있습니다. 정렬 된 16B 청크에 바이트가 필요한 경우 정렬 된 전체 16B 청크를로드하는 것이 항상 안전합니다.
전체 소스 : 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;
}
Core2 (Merom) 2.4GHz에서 40M 반복 시간. gcc 5.2 -O3 -march=native
. (우분투 15.10). dst != src
(따라서 사본을 만들지 만) 겹치지 않으며 근처에 있지 않습니다. 둘 다 정렬됩니다.
(실제로 주소가 정렬되어 있어도 storeu가 Merom에서 느리기 때문에 _mm_store
루프에서 시간이 초과 되지 않습니다 _mm_storeu
. Nehalem 이상에서는 괜찮습니다. 또한 복사 실패를 수정하는 대신 코드를 그대로 두었습니다. 모든 경우에 시간을 다시 지정하고 싶지 않기 때문에 경우에 따라 0을 종료합니다.)
따라서 16B보다 긴 짧은 문자열의 경우 자동 벡터화보다 훨씬 빠릅니다. 벡터보다 너비가 1보다 작은 길이는 문제가되지 않습니다. 상점 전달 스톨로 인해 내부 조작시 문제점이 될 수 있습니다. (그러나 toupper는 idempotent이기 때문에 원래 입력이 아닌 자체 출력을 처리하는 것이 좋습니다.)
주변 코드가 원하는 것과 대상 마이크로 아키텍처에 따라 다양한 사용 사례에 맞게이를 조정할 수있는 범위가 많이 있습니다. 컴파일러가 정리 부분을위한 멋진 코드를 생성하도록하는 것은 까다 롭습니다. 사용ffs(3)
(x86에서 bsf 또는 tzcnt로 컴파일)을 하는 것이 좋지만이 대답의 대부분을 작성한 후 버그를 발견 한 이후 비트를 다시 생각해야합니다 (FIXME 주석 참조).
더 작은 스트링에 대한 벡터 속도 향상은 로드 또는 저장 movq
하거나 얻을 수 있습니다 movd
. 사용 사례에 맞게 사용자 정의하십시오.
벡터에 높은 비트 세트가있는 바이트가있는 경우를 감지 할 수 있으며이 경우 해당 벡터에 대한 스칼라 utf-8 인식 루프로 대체됩니다. dst
포인트가 아닌 다른 금액으로 발전 할 수 src
포인터,하지만 우리는 다시 정렬에 일단 src
포인터, 우리는 여전히에 정렬되지 않은 벡터 저장을 할 수 있습니다 dst
.
UTF-8이지만 대부분 UTF-8의 ASCII 하위 세트로 구성되는 텍스트의 경우이 방법이 좋습니다. 모든 경우에 올바른 동작을하는 일반적인 경우의 고성능입니다. 비 ASCII가 많으면 스칼라 UTF-8 인식 루프에 항상 머무르는 것보다 나쁠 것입니다.
다른 언어를 희생하면서 영어를 더 빨리 만드는 것은 단점이 심각하다면 미래를위한 확실한 결정이 아닙니다.
터키어 로캘 ( tr_TR
)에서 올바른 결과 toupper('i')
는 (일반 ASCII)가 'İ'
아니라 'I'
( U0130 )입니다. Windows 속도 저하에 대한 질문은 Martin Bonner의 의견 을 참조하십시오 tolower()
.
멀티 바이트 UTF8 입력 문자와 같이 예외 목록을 확인하고 스칼라로 대체 할 수도 있습니다.
이처럼 많은 복잡성으로 인해 SSE4.2 PCMPISTRM
또는 다른 것이 한 번에 많은 점검을 수행 할 수 있습니다.
문자열에 ASCII 또는 국제 문자가 있습니까?
후자의 경우 "대문자"는 그렇게 간단하지 않으며 사용 된 알파벳에 따라 다릅니다. 양수 알파벳과 단수 알파벳이 있습니다. 바이 카메라 알파벳 만 대문자와 소문자가 다릅니다. 또한 라틴 대문자 'DZ'(\ u01F1 'DZ')와 같이 소위 title case 를 사용하는 복합 문자가 있습니다 . 즉, 첫 문자 (D) 만 변경됩니다.
ICU 를 살펴보고 Simple과 Full Case Mappings의 차이점 을 제안합니다 . 도움이 될 수 있습니다.
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;
}
**
첫 번째 솔루션의 매개 변수 뒤 의 별 은 무엇을합니까?
**
코드 구문에서 굵은 글꼴을 사용하려고 시도한 것에서 오타가 남아 있다고 확신 합니다.
toupper
음수로 호출 될 때 정의되지 않은 동작을 호출 합니다.
다음은 나를 위해 작동합니다.
#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
음수로 호출 될 때 정의되지 않은 동작을 호출 합니다.
람다를 사용하십시오.
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);
ASCII 문자 만 사용하는 경우 더 빠릅니다 .
for(i=0;str[i]!=0;i++)
if(str[i]<='z' && str[i]>='a')
str[i]-=32;
이 코드 는 더 빠르게 실행되지만 ASCII에서만 작동 하며 "추상적 인"솔루션은 아닙니다.
유니 코드 솔루션이나보다 일반적인 추상 솔루션이 필요한 경우 다른 답변을 찾아 C ++ 문자열의 메서드를 사용하십시오.
C++
있지만 C
여기 에 답변 을 작성했습니다 . (나는 downvoters 중 하나가 아닙니다.)
'
?로 묶인 문자 대신 ASCII 코드를 사용하기로 결정한 이유는 무엇 입니까?
ASCII만으로도 충분하고 RW 메모리에 대한 유효한 포인터를 제공 할 수있는 한 C에는 간단하고 매우 효과적인 단일 라이너가 있습니다.
void strtoupper(char* str)
{
while (*str) *(str++) = toupper((unsigned char)*str);
}
이것은 동일한 문자 대소 문자로 정규화하려는 ASCII 식별자와 같은 간단한 문자열에 특히 좋습니다. 그런 다음 버퍼를 사용하여 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 ...
. 읽기가 어려운 이유도 없습니다. 또한 문자열을 먼저 복사 한 다음 반복합니다. @Luke의 대답은 'a'
문자 상수 를 사용하지 않는 것을 제외하고는 어떤면에서 더 좋습니다 .
#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());
이것은 전역 toupper 기능을 사용하는 모든 답변보다 성능이 좋으며 아마도 boost :: to_upper가 수행하는 것입니다.
이것은 :: toupper가 모든 호출에 대해 다른 스레드에 의해 변경되었을 수 있기 때문에 로케일을 찾아야하기 때문이며, 여기서 locale ()에 대한 호출 만이 패널티를 갖습니다. 로케일을 찾으려면 일반적으로 잠금을 수행해야합니다.
또한 auto를 바꾸고 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());
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
and를 사용하십시오 back_inserter
(문자열이 한 번만 복사되도록). 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
음수로 호출 될 때 정의되지 않은 동작을 호출 합니다.
toupper()
기능 ( #include <ctype.h>
)을 시도하십시오 . 문자를 인수로 허용하고 문자열은 문자로 구성되므로 문자열을 구성하는 각 개별 문자를 반복해야합니다.
toupper
음수로 호출 될 때 정의되지 않은 동작을 호출 합니다. 에 필요한 출연자를 언급 했어야합니다 unsigned char
.
다음은 C ++ 11의 최신 코드입니다.
std::string cmd = "Hello World";
for_each(cmd.begin(), cmd.end(), [](char& in){ in = ::toupper(in); });
toupper
음수로 호출 될 때 정의되지 않은 동작을 호출 합니다.
대답 의 @dirkgently 매우 아름답습니다,하지만 난 아래와 같습니다 인해 우려 것을 강조하고 싶다
from의 다른 모든 함수와 마찬가지로 std :: toupper의 동작은 인수 값이 부호없는 char 또는 EOF와 같지 않은 경우 정의되지 않습니다. 일반 문자 (또는 부호있는 문자)와 함께이 함수를 안전하게 사용하려면 먼저 인수를 부호없는 문자 참조 로 변환해야합니다 . std :: toupper
올바른 사용법 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!
내장 기능이 있는지 확실하지 않습니다. 이 시도:
ctype.h 또는 cctype 라이브러리와 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
}
toupper
음수로 호출 될 때 정의되지 않은 동작을 호출 합니다.
내 솔루션 (알파에 대해 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++;
}
}
toupper
음수로 호출 될 때 정의되지 않은 동작을 호출 합니다.
이 페이지의 모든 솔루션은 필요 이상으로 어렵습니다.
이 작업을 수행
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
루프.
문자열 크기를 기억하면 구분 기호도 반환되므로 루프 테스트에서 <=가 아닌 <=를 사용하십시오.
출력은 다음과 같습니다. 변환하려는 문자열
tolower
루프가 있으며, 대부분 i
이상한 루프가 아닌 표준 루프 변수 이름을 사용합니다 forLoop
.
라이브러리를 사용하지 않고 :
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 Babuškov를 제외한 다른 모든 답변도 가정) 메타 프로그래밍을 사용하여 컴파일 타임에 조회 테이블을 생성하여 가장 빠른 속도를 얻을 수 있습니다. 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;
}
이 솔루션을 사용합니다. 나는 당신이 그 데이터 영역을 수정해서는 안된다는 것을 알고 있습니다 .... 나는 그것이 주로 버퍼 오버런 버그와 널 문자에 대한 것이라고 생각합니다 .... 상부 케이스는 같지 않습니다.
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
-어떤 데이터 영역을 수정하지 않아야합니까?
str[i] = toupper(str[i]);
완벽하게 훌륭하게 대체 될 수 있습니다 ( 완벽 하지는 않지만 대부분의 문제를 수정합니다).
::toupper
ASCII를 가정 하는 i18n의 이점도 있습니다.