C ++에서 문자열을 대문자로 변환


268

어떻게 문자열을 대문자로 변환 할 수 있습니까? 인터넷 검색에서 찾은 예는 문자 만 다루면됩니다.

답변:


205

부스트 문자열 알고리즘 :

#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");

5
또한 ::toupperASCII를 가정 하는 i18n의 이점도 있습니다.
Ben Straub

4
마지막 줄은 컴파일되지 않습니다. 다음과 같이 변경해야합니다.std::string newstr(boost::to_upper_copy<std::string>("Hello World"));
maxschlepzig

58
부스트가 필요하거나 제목을 변경해야하므로 허용되는 대답이 아닙니다.
Andrea

44
예, 나는 단지 to_upper에 대한 부스트를 설치하려고합니다 ... 훌륭한 아이디어! </ sarcasm> :)
thang

12
" C ++에서 x 를 어떻게합니까 ?"에 대한 답변으로 개인적으로 부스트 처리되지 않았습니다. 부스트는 가벼운 솔루션이 아니기 때문입니다. 프레임 워크 (또는 ACE 또는 Qt 또는 Recusion ToolKit ++ 또는 ...)로 부스트를 구매하거나 그렇지 않은 것 같습니다. 언어 솔루션을 선호합니다.
jwm

486
#include <algorithm>
#include <string>

std::string str = "Hello World";
std::transform(str.begin(), str.end(),str.begin(), ::toupper);

8
실제로 toupper()는 매크로로 구현할 수 있습니다. 문제가 발생할 수 있습니다.
dirkgently 2009

3
boost.lambda가있는 bind (:: toupper, construct <unsigned char> (_ 1)) 완벽하게 잘 작동합니다.
Johannes Schaub-litb

11
이 방법은 ASCII에는 적합하지만 멀티 바이트 문자 인코딩 또는 독일어 'ß'와 같은 특수한 케이싱 규칙에는 실패합니다.
dan04

9
나는 (비공식 테스트에서) 더 빠르고 사용하기 쉽고이 솔루션과 관련된 문제가 없기 때문에 부스트 라이브러리를 사용하여 수락 된 답변을 변경했습니다. 부스트를 사용할 수없는 경우에는 여전히 좋은 솔루션입니다.
OrangeAlmondSoap 2019 년

2
컴파일러가 :: 한정자 없이이 코드를 거부하는 이유를 알 수 없습니다 toupper. 어떤 아이디어?
sasha.sochka

89

C ++ 11 및 toupper ()를 사용하는 짧은 솔루션.

for (auto & c: str) c = toupper(c);

형식이 아닌 c것 입니까? 그렇다면 ( 부분으로 인해 )에서 반환 한 내용을 할당 할 수 없습니다 . const charautoconsttoupper(c)
PolGraphic

5
@PolGraphic : 범위-기반은 컨테이너의 begin () / end () 메소드를 사용하여 내용을 반복합니다. std :: basic_string은 const 및 가변 반복자 (cbegin () 및 begin ()으로 각각 리턴 됨, std :: basic_string :: begin 참조 )를 가지고 있으므로 for (:)는 str이 다음과 같은 경우 적절한 하나 (cbegin () 선언 된 const, auto = : = const char, begin () 그렇지 않으면 auto = : = char).
Thanasis Papoutsidakis

5
아래의 dirkgently의 anser를 참조하십시오 .이 문제를 c해결하려면 캐스팅해야합니다 unsigned char.
Cris Luengo

boost의 to_upper ()는 toupper보다 c ++ STL 함수와 훨씬 더 일관된 것처럼 보입니다.
tartaruga_casco_mole

29
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를 제공합니다.)


일반적인 cctype 멤버는 매크로입니다. 나는 C90 표준의 사본이 없으며 명시 적으로 명시되어 있는지 여부를 알지 못하더라도 그것들도 기능이어야한다는 것을 읽었습니다.
David Thornley

1
C가 매크로가되도록 허용하더라도 C ++의 함수 여야합니다. 그래도 캐스팅에 대한 두 번째 요점에 동의합니다. 최상위 솔루션은 음수 값을 전달하여 UB를 유발할 수 있습니다. 그것이 내가 투표하지 않은 이유입니다 (그러나 투표도하지 않았습니다) :)
Johannes Schaub-litb

1
표준 인용문이 누락되어서는 안됩니다 : 7.4.2.2/1 (빈약 한 조명, C99 TC2 초안 만 참조) 및 영광 C ++ 98 표준의 C ++ 17.4.1.2/6.
Johannes Schaub-litb

1
(여기에 발-참고 참고 : "이 것을 허용하지를 ++ 유일한 방법 C에서 그것을 할 ... 마스킹 매크로 .... ㅋ blupp를 제공하는 관행이 통근 인라인 함수를 제공하는 것입니다.") :
요하네스 SCHAUB -litb

1
...이 속임수에 의해 달성됩니다 : stackoverflow.com/questions/650461/…
Johannes Schaub-litb

27

이 문제는 ASCII 문자 집합에 대해 SIMD벡터화 할 수 있습니다.


가속 비교 :

-O3 -march=nativeCore2Duo (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 의 결과는 확인하지 않습니다 . 터키어에 중요합니다.)

  • ASCII 전용 루프 : 8.79 초 (아래 결과에 대한 기본 버전) 분명히 cmovL1에서 테이블이 뜨거워 테이블 조회가.보다 빠릅니다 .
  • ASCII 전용 자동 벡터화 : 2.51s . (120 문자는 최악의 경우와 최상의 경우의 절반입니다. 아래 참조)
  • ASCII 전용 수동 벡터화 : 1.35 초

로케일이 설정 될 때 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(따라서 사본을 만들지 만) 겹치지 않으며 근처에 있지 않습니다. 둘 다 정렬됩니다.

  • 15 자 문자열 : 기준선 : 1.08 초 오토 벡 : 1.34s
  • 16 자 문자열 : 기준선 : 1.16 초 autovec : 1.52 초
  • 127 자 문자열 : 기준선 : 8.91 초 autovec : 2.98s // 비 벡터 정리에는 15 개의 문자가 처리됩니다.
  • 128 자 문자열 : 기준선 : 9.00 초 오토 벡 : 2.06s
  • 129 자 문자열 : 기준선 : 9.04 초 autovec : 2.07s // 비 벡터 정리에는 처리 할 문자가 1 개 있습니다.

일부 결과는 clang과 약간 다릅니다.

함수를 호출하는 마이크로 벤치 마크 루프는 별도의 파일에 있습니다. 그렇지 않으면 strlen()루프에서 인라인되어 들어 올려 져 매우 빠르게 실행됩니다. 16 개의 문자열 (0.187)

이것은 gcc가 모든 아키텍처에서 자동 벡터화 할 수 있다는 주요 이점이 있지만 일반적으로 작은 문자열의 경우에는 느리다는 큰 단점이 있습니다.


따라서 빠른 속도 향상이 있지만 컴파일러 자동 벡터화는 훌륭한 코드를 만들지 않습니다. 마지막 최대 15자를 정리합니다.

SSE 내장 함수를 사용한 수동 벡터화 :

모든 알파벳 문자의 대소 문자를 뒤집는 필자 의 플립 기능 을 기반으로 합니다. "서명되지 않은 비교 트릭"을 활용 low < a && a <= high하여 범위 이동으로 단일 부호없는 비교를 수행 할 수 있으므로보다 작은 low값은보다 큰 값으로 줄 바꿈됩니다 high. (경우에 작동 lowhigh너무 멀리 떨어져되지 않습니다.)

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(따라서 사본을 만들지 만) 겹치지 않으며 근처에 있지 않습니다. 둘 다 정렬됩니다.

  • 15 자 문자열 : 기준선 : 1.08 초 autovec : 1.34 초 수동 : 1.29s
  • 16 자 문자열 : 기준선 : 1.16 초 autovec : 1.52 초 수동 : 0.335s
  • 31 자 문자열 : 수동 : 0.479 초
  • 127 자 문자열 : 기준선 : 8.91 초 오토 벡 : 2.98 초. 수동 : 0.925s
  • 128 자 문자열 : 기준선 : 9.00 초 autovec : 2.06 초 수동 : 0.931s
  • 129 자 문자열 : 기준선 : 9.04 초 autovec : 2.07 초 수동 : 1.02s

(실제로 주소가 정렬되어 있어도 storeu가 Merom에서 느리기 때문에 _mm_store루프에서 시간이 초과 되지 않습니다 _mm_storeu. Nehalem 이상에서는 괜찮습니다. 또한 복사 실패를 수정하는 대신 코드를 그대로 두었습니다. 모든 경우에 시간을 다시 지정하고 싶지 않기 때문에 경우에 따라 0을 종료합니다.)

따라서 16B보다 긴 짧은 문자열의 경우 자동 벡터화보다 훨씬 빠릅니다. 벡터보다 너비가 1보다 작은 길이는 문제가되지 않습니다. 상점 전달 스톨로 인해 내부 조작시 문제점이 될 수 있습니다. (그러나 toupper는 idempotent이기 때문에 원래 입력이 아닌 자체 출력을 처리하는 것이 좋습니다.)

주변 코드가 원하는 것과 대상 마이크로 아키텍처에 따라 다양한 사용 사례에 맞게이를 조정할 수있는 범위가 많이 있습니다. 컴파일러가 정리 부분을위한 멋진 코드를 생성하도록하는 것은 까다 롭습니다. 사용ffs(3)(x86에서 bsf 또는 tzcnt로 컴파일)을 하는 것이 좋지만이 대답의 대부분을 작성한 후 버그를 발견 한 이후 비트를 다시 생각해야합니다 (FIXME 주석 참조).

더 작은 스트링에 대한 벡터 속도 향상은 로드 또는 저장 movq하거나 얻을 수 있습니다 movd. 사용 사례에 맞게 사용자 정의하십시오.


UTF-8 :

벡터에 높은 비트 세트가있는 바이트가있는 경우를 감지 할 수 있으며이 경우 해당 벡터에 대한 스칼라 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또는 다른 것이 한 번에 많은 점검을 수행 할 수 있습니다.


20

문자열에 ASCII 또는 국제 문자가 있습니까?

후자의 경우 "대문자"는 그렇게 간단하지 않으며 사용 된 알파벳에 따라 다릅니다. 양수 알파벳과 단수 알파벳이 있습니다. 바이 카메라 알파벳 만 대문자와 소문자가 다릅니다. 또한 라틴 대문자 'DZ'(\ u01F1 'DZ')와 같이 소위 title case 를 사용하는 복합 문자가 있습니다 . 즉, 첫 문자 (D) 만 변경됩니다.

ICU 를 살펴보고 Simple과 Full Case Mappings의 차이점 을 제안합니다 . 도움이 될 수 있습니다.

http://userguide.icu-project.org/transforms/casemappings


7
또는 그리스 문자 베타처럼 보이는 독일 eszet (sp?)는 "ss"를 의미합니다. 대문자 "SS"를 의미하는 단일 독일어 문자는 없습니다. 대문자 인 경우 "street"에 대한 독일어 단어는 한 글자 더 길어집니다.
David Thornley

6
또 다른 특별한 경우가 그리스 문자 시그마 (Σ)이며, 단어의 끝에 있는지 (ς) 또는 아닌지 (σ)에 따라 소문자 버전이 있습니다. 그리고 터키어와 같이 I↔ı와 İ↔i를 매핑하는 언어 별 규칙이 있습니다.
dan04

1
"어퍼 케이싱"을 케이스 폴딩이라고합니다.
Columbo

20
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;
}

4
두 번째 솔루션을 향상시킬 수있는 권한이 없다면 아마도 가장 좋은 방법 일 것입니다. **첫 번째 솔루션의 매개 변수 뒤 의 별 은 무엇을합니까?
Sam Brinck

1
**코드 구문에서 굵은 글꼴을 사용하려고 시도한 것에서 오타가 남아 있다고 확신 합니다.
MasterHD

1
이 코드는 toupper음수로 호출 될 때 정의되지 않은 동작을 호출 합니다.
Roland Illig

17

다음은 나를 위해 작동합니다.

#include <algorithm>
void  toUpperCase(std::string& str)
{
    std::transform(str.begin(), str.end(), str.begin(), ::toupper);
}

int main()
{
   std::string str = "hello";
   toUpperCase(&str);
}

std :: transform은 <algorithm>
edj

예. 이 # include가 필요합니다. #include <algorithm>
Pabitra Dash

1
이 코드는 toupper음수로 호출 될 때 정의되지 않은 동작을 호출 합니다.
Roland Illig

user648545 – -1
Piotr Dobrogost

@PiotrDobrogost user648545의 답변에 대해 전혀 모른다. 두 함수를 비교할 때 두 함수가 모두 라이브러리 함수 변환을 사용하지만 메소드 서명이 완전히 다릅니다.
Pabitra Dash

13

람다를 사용하십시오.

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);

2
바이런, 다른 의견에 대해서는 걱정하지 마십시오. 당신이했던 것처럼 새로운 (현대적인) 솔루션으로 오래된 질문에 대답하는 것이 좋습니다.
Kyberias

13

ASCII 문자 만 사용하는 경우 더 빠릅니다 .

for(i=0;str[i]!=0;i++)
  if(str[i]<='z' && str[i]>='a')
    str[i]-=32;

이 코드 는 더 빠르게 실행되지만 ASCII에서만 작동 하며 "추상적 인"솔루션은 아닙니다.

유니 코드 솔루션이나보다 일반적인 추상 솔루션이 필요한 경우 다른 답변을 찾아 C ++ 문자열의 메서드를 사용하십시오.


1
질문에 태그가 지정되어 C++있지만 C여기 에 답변 을 작성했습니다 . (나는 downvoters 중 하나가 아닙니다.)
hkBattousai

6
C 답변과 C ++ 답변을 작성했습니다. C ++은 C 소스와 완벽하게 호환되도록 작성되었으므로 모든 C 솔루션은 C ++의 올바른 솔루션입니다
Luca C.

그러나 C ++ 방식을 존중하는 답변을 제공하는 것이 훨씬 좋습니다.
Dmitriy Yurchenko

표준 C ++ 방식은 std :: transform을 toupper와 함께 사용하는 것입니다. 코드가 적고 휴대하기 편리합니다. 이 코드는 시스템이 문자 인코딩 메커니즘으로 ASCII를 사용할 것이라는 "사실"에 의존합니다. 모든 시스템이이 인코딩을 기반으로하는지 확실하지 않으므로 이식 가능한지 확실하지 않습니다.
AlexTheo

1
'?로 묶인 문자 대신 ASCII 코드를 사용하기로 결정한 이유는 무엇 입니까?
HolyBlackCat

11

ASCII만으로도 충분하고 RW 메모리에 대한 유효한 포인터를 제공 할 수있는 한 C에는 간단하고 매우 효과적인 단일 라이너가 있습니다.

void strtoupper(char* str)
{ 
    while (*str) *(str++) = toupper((unsigned char)*str);
}

이것은 동일한 문자 대소 문자로 정규화하려는 ASCII 식별자와 같은 간단한 문자열에 특히 좋습니다. 그런 다음 버퍼를 사용하여 std : string 인스턴스를 구성 할 수 있습니다.


이 답변은 std :: string이 아닌 ac 문자열에 대한 것입니다.
EvilTeach

여기에는 명백한 보안 결함이 있습니다. 나는 이것을하지 않을 것입니다.
바이런

9
//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;
}

s.size ()는 std :: size_t 유형이며, 구현에 따라 AFAIK가 서명되지 않은 int 일 수 있습니다.
odinthenerd

std :: string :: size의 결과가 서명 된 최신 구현이 없다고 생각합니다. 의미 적으로나 실제로, 음의 크기와 같은 것은 없다는 것을 감안할 때 size_t는 적어도 32 비트 부호없는 정수가됩니다.
user1329482

쓰지 않을 이유가 없습니다 for (size_t i = 0 .... 읽기가 어려운 이유도 없습니다. 또한 문자열을 먼저 복사 한 다음 반복합니다. @Luke의 대답은 'a'문자 상수 를 사용하지 않는 것을 제외하고는 어떤면에서 더 좋습니다 .
Peter Cordes

9
#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());

7
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 );

이미 길이를 알고 있으므로 back_inserter를 권장하지 않습니다. std :: string result (src.size ())를 사용하십시오. std :: transform (src.begin (), src.end (), result.begin (), up_char);
Viktor Sehr

나는 당신이 이것을 알고 있다고 확신합니다.
Viktor Sehr

@Viktor Sehr, @bayda : 나는 이것이 2 살이라는 것을 알고 있습니다. reserveand를 사용하십시오 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; }
Evan Teran

4
std::string value;
for (std::string::iterator p = value.begin(); value.end() != p; ++p)
    *p = toupper(*p);

이 코드는 toupper음수로 호출 될 때 정의되지 않은 동작을 호출 합니다.
Roland Illig

2

toupper()기능 ( #include <ctype.h>)을 시도하십시오 . 문자를 인수로 허용하고 문자열은 문자로 구성되므로 문자열을 구성하는 각 개별 문자를 반복해야합니다.


이 제안은 toupper음수로 호출 될 때 정의되지 않은 동작을 호출 합니다. 에 필요한 출연자를 언급 했어야합니다 unsigned char.
Roland Illig

2

다음은 C ++ 11의 최신 코드입니다.

std::string cmd = "Hello World";
for_each(cmd.begin(), cmd.end(), [](char& in){ in = ::toupper(in); });

이 코드는 toupper음수로 호출 될 때 정의되지 않은 동작을 호출 합니다.
Roland Illig

1

Unicode 텍스트에 작동하는 Boost.Text 사용

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();

1

대답@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!

0

내장 기능이 있는지 확실하지 않습니다. 이 시도:

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
}

.length ()는 'unsigned int'형식이 아닙니다
malat

이 코드는 toupper음수로 호출 될 때 정의되지 않은 동작을 호출 합니다.
Roland Illig

0

내 솔루션 (알파에 대해 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음수로 호출 될 때 정의되지 않은 동작을 호출 합니다.
Roland Illig

아니요 ... 다운 보팅하기 직전에 확인하십시오. Islower는 음수가 아닌 값에 대해서만 작동합니다 ...
Antonin GAVREL

-1

이 페이지의 모든 솔루션은 필요 이상으로 어렵습니다.

이 작업을 수행

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루프.

문자열 크기를 기억하면 구분 기호도 반환되므로 루프 테스트에서 <=가 아닌 <=를 사용하십시오.

출력은 다음과 같습니다. 변환하려는 문자열


4
이것이 boost :: toupper 솔루션보다 얼마나 간단한 지 알 수 없습니다. 정교하게 할 수 있습니까?
tr9sh

2
이미 많은 간단한 tolower루프가 있으며, 대부분 i이상한 루프가 아닌 표준 루프 변수 이름을 사용합니다 forLoop.
Peter Cordes

-1

라이브러리를 사용하지 않고 :

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;
}

위의 코드는 ASCII 호환 인코딩에만 작동합니다. 귀하의 답변이 아닌 질문 에이 제한 사항이 언급되어 있지 않습니다. 그들 중 하나가되어야합니다.
Roland Illig

-1

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


-1
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;
}

-1

이 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;
}

-3

이 솔루션을 사용합니다. 나는 당신이 그 데이터 영역을 수정해서는 안된다는 것을 알고 있습니다 .... 나는 그것이 주로 버퍼 오버런 버그와 널 문자에 대한 것이라고 생각합니다 .... 상부 케이스는 같지 않습니다.

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-어떤 데이터 영역을 수정하지 않아야합니까?
user93353

3
이것은 늦었지만 지구상에서 무엇입니까? 그 미친 줄은 str[i] = toupper(str[i]);완벽하게 훌륭하게 대체 될 수 있습니다 ( 완벽 하지는 않지만 대부분의 문제를 수정합니다).
chris
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.