C ++の文字列を大文字に変換する


回答:


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
これにはi18nの利点もあります。i18n ::toupperはASCIIを想定している可能性が高いです。
ベンストラウブ

4
あなたの最後の行はコンパイルされません-あなたのようなものに変更する必要があります:std::string newstr(boost::to_upper_copy<std::string>("Hello World"));
maxschlepzig

58
ブーストが必要なため、これは受け入れられる答えではありません。または、タイトルを変更する必要があります。
Andrea

44
はい、to_upperのためだけにboostをインストールします...素晴らしいアイデアです!</ sarcasm> :)
thang '31

12
「C ++でxを実行するにはどうすればよいですか?」に対する答えとして、私はブーストに対して個人的に気分が悪いです。ブーストは軽量なソリューションではないためです。フレームワーク(またはACEまたはQtまたはRecusion ToolKit ++または...)としてboostを購入するか、購入しないようです。言語ソリューションを見たいです。
jwm 2018年

486
#include <algorithm>
#include <string>

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

8
実際にtoupper()は、マクロとして実装できます。これにより問題が発生する可能性があります。
2009

3
bind.::toupper、construct<unsigned char>(_ 1))とboost.lambdaは完全にうまく機能すると思います。
Johannes Schaub-litb 2009

11
このアプローチはASCIIではうまく機能しますが、マルチバイト文字エンコーディングや、ドイツ語の「ß」のような特別な大文字の規則では失敗します。
dan04 2010

9
ブーストライブラリを使用したものに受け入れられた回答を変更しました。これは、(非公式のテストで)高速で、使いやすく、このソリューションに関連する問題がないためです。ブーストを使用できない場合でも、優れたソリューションです。
OrangeAlmondSoap 2011年

2
::修飾子beforeなしでコンパイラがこのコードを拒否する理由を理解できませんtoupper。何か案は?
sasha.sochka 2013

89

C ++ 11とtoupper()を使用した短いソリューション。

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

ではないだろうcともconst charタイプ(からauto)?もしそうなら、それが(const一部のため)によって返されるものに割り当てることはできませんtoupper(c)
PolGraphic 2016

5
@PolGraphic:Range-に基づいて、コンテナのbegin()/ end()メソッドを使用して、そのコンテンツを反復します。std :: basic_stringにはconstと可変イテレータの両方があります(それぞれcbegin()とbegin()によって返されます。std :: basic_string :: beginを参照してください)。したがって、for(:)はstrが適切な場合(cbegin()を使用します)宣言されたconst、auto =:= const char、begin()それ以外の場合、auto =:= char)。
Thanasis Papoutsidakis 2016

5
以下のdirkgentlyのanserを参照してください。これを相関cさせるにunsigned charはキャストする必要があります。
クリスルエンゴ2017

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メンバーは、標準アルゴリズムでの直接消費には適さないマクロである可能性があります。

  • 同じ例のもう1つの問題は、引数をキャストしないか、これが負でないことを確認しないことです。これは、プレーンcharが署名されているシステムでは特に危険です。(理由は、これがマクロとして実装されている場合、おそらくルックアップテーブルとそのテーブルへの引数インデックスを使用することです。負のインデックスはUBを提供します。)


通常のcctypeメンバーはマクロです。C90標準のコピーがなく、明示的に記述されているかどうかはわかりませんが、それらも関数である必要があったことを読んだことを覚えています。
David Thornley、

1
Cがマクロであることを許可している場合でも、C ++の関数である必要があります。キャスティングについての2番目の点にも同意します。一番上のソリューションは負の値を渡し、それによってUBを引き起こす可能性があります。それが私が賛成票を投じなかった理由です(しかし私も反対票を投じませんでした):)
Johannes Schaub-litb

1
標準的な引用が欠落してはいけません:7.4.2.2/1(貧弱なlitb、これはC99 TC2ドラフトのみを参照しています)、および栄光のc ++ 98標準のC ++ 17.4.1.2/6。
Johannes Schaub-litb 2009

1
(脚注に注意してください:「これはマスキングマクロを提供するという一般的な慣習を禁止します。...C ++でそれを行う唯一の方法は、externインライン関数を提供することです。」:)
Johannes Schaub -litb 2009

1
...この策略によって達成されます:stackoverflow.com/questions/650461/...
ヨハネス・シャウブ- 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.0s。はい、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からの読み取りとa std::stringへの書き込みのループchar dstbuf[4096]は、テストに意味があります。

  • glibcを呼び出すループtoupper6.67sintただし、マルチバイトUTF-8の可能性について結果をチェックしません。これはトルコ語では重要です。)

  • ASCIIのみのループ:8.79秒 (以下の結果の私のベースラインバージョン。)どうやらテーブルの検索は、テーブルよりも高速で、cmovいずれにしてもL1のテーブルはホットです。
  • ASCIIのみで自動ベクトル化:2.51s。(120文字は、最悪の場合と最良の場合の中間です。以下を参照してください)
  • 手動でベクトル化されたASCIIのみ:1.35秒

ロケールが設定されている場合、Windowsの動作が遅いというこの質問toupper()も参照してください。


Boostは他のオプションよりも桁違いに遅いのでショックを受けました。私は自分が-O3有効にしたことを再確認し、さらにasmをシングルステップで実行して何をしているのかを確認しました。clang ++ 3.8とほぼ同じ速度です。これは、文字ごとのループ内に大きなオーバーヘッドがあります。perf record/ report(のための結果cyclesPERFイベント)は、次のとおりです。

  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、一度に1バイトをループするよりもはるかに高速な効率を持つため、別々のベクトル化されたstrlenループとtoupperループの方が高速です。

ベースライン:その場で終了0をチェックするループ。

Core2(Merom)2.4GHzでの40M反復の時間。gcc 5.2 -O3 -march=native。(Ubuntu 15.10)。 dst != src(それで私たちはコピーを作成します)、しかしそれらは重なりません(そして近くにありません)。両方が揃っています。

  • 15文字の文字列:ベースライン:1.08秒。autovec:1.34秒
  • 16文字の文字列:ベースライン:1.16秒。autovec:1.52s
  • 127文字の文字列:ベースライン:8.91秒。autovec:2.98s //ベクター以外のクリーンアップには処理する15文字があります
  • 128文字の文字列:ベースライン:9.00秒。autovec:2.06s
  • 129文字の文字列:ベースライン:9.04秒。autovec:2.07s //非ベクタークリーンアップには処理する1文字があります

一部の結果はclangとは少し異なります。

関数を呼び出すマイクロベンチマークループは別のファイルにあります。それ以外の場合は、インライン化strlen()されてループから引き上げられ、特に高速で実行されます。16文字の文字列(0.187秒)。

これには、gccがすべてのアーキテクチャで自動ベクトル化できるという大きな利点がありますが、小さな文字列の通常よくあるケースでは、速度が遅くなるという大きな欠点があります。


したがって、大幅なスピードアップがありますが、コンパイラの自動ベクトル化は、特に優れたコードにはなりません。最後の15文字までのクリーンアップ用。

SSE組み込みによる手動のベクトル化:

すべてのアルファベット文字の大文字と小文字を逆にする私のケースフリップ関数に基づいています。これは「符号なし比較トリック」を利用します。この場合low < a && a <= high、範囲シフトによって単一の符号なし比較を行うことができるため、より小さい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
}

1つのベクトルに対して機能するこの関数を指定すると、ループ内でこの関数を呼び出して文字列全体を処理できます。既にSSE2をターゲットにしているので、ベクトル化された文字列の終わりのチェックを同時に実行できます。

また、16Bのベクトルを実行した後に残った最後の最大15バイトの "クリーンアップ"をより適切に行うことができます。大文字はべき等なので、一部の入力バイトの再処理は問題ありません。ソースの最後の16Bのアラインされていないロードを行い、それをループの最後の16Bストアとオーバーラップするdestバッファーに格納します。

これが機能しないのは、文字列全体が16B未満の場合のみですdst=src。非アトムのread-modify-writeは、一部のバイトにまったく触れないことと同じではなく、マルチスレッドコードを破壊する可能性があります。

そのためのスカラーループがあり、これもsrc調整されます。終端の0がどこにあるかわからないので、からの整列されていないロードsrcが次のページに渡ってsegfaultになる可能性があります。整列された16Bチャンクにバイトが必要な場合は、整列された16Bチャンク全体をロードしても常に安全です。

完全なソース: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;
}

Core2(Merom)2.4GHzでの40M反復の時間。gcc 5.2 -O3 -march=native。(Ubuntu 15.10)。 dst != src(それで私たちはコピーを作成します)、しかしそれらは重なりません(そして近くにありません)。両方が揃っています。

  • 15文字の文字列:ベースライン:1.08秒。autovec:1.34s。マニュアル:1.29s
  • 16文字の文字列:ベースライン:1.16秒。autovec:1.52s。マニュアル:0.335s
  • 31文字の文字列:手動:0.479秒
  • 127文字の文字列:ベースライン:8.91秒。autovec:2.98s。マニュアル:0.925s
  • 128文字の文字列:ベースライン:9.00秒。autovec:2.06s。マニュアル:0.931s
  • 129文字の文字列:ベースライン:9.04秒。autovec:2.07s。マニュアル:1.02s

(実際_mm_storeにはループではなく_mm_storeu、ループ内でタイミングがとられます。アドレスが揃えられていても、Meromではstoreuが遅いためです。Nehalem以降では問題ありません。コピーの失敗を修正する代わりに、コードを現状のまま残しました。すべてを再調整したくないので、場合によっては終了0を使用します。)

したがって、16Bより長い短い文字列の場合、これは自動ベクトル化よりも劇的に高速です。長さがベクトル幅より1小さい場合、問題はありません。ストア転送のストールのため、インプレースでの操作時に問題になる可能性があります。(ただし、toupperはべき等であるため、元の入力ではなく独自の出力を処理しても問題ありません)。

周囲のコードが何を望んでいるか、およびターゲットのマイクロアーキテクチャーに応じて、さまざまなユースケースに対してこれを調整するための多くのスコープがあります。コンパイラーにクリーンアップ部分の適切なコードを発行させるのは難しい作業です。使用すると、ffs(3)(x86版BSFまたはtzcntにコンパイルされた)良いようだが、私は(FIXMEコメントを参照してください)この回答のほとんどを書いた後のバグに気づいたので、ビットが必要であることを明らかに再-と思います。

さらに小さい文字列のベクトル速度向上は、movqまたはmovdロード/ストアで取得できます。ユースケースに応じて必要に応じてカスタマイズします。


UTF-8:

ベクトルに上位ビットが設定されたバイトがあることを検出できます。その場合、そのベクトルのスカラーutf-8対応ループにフォールバックします。dstポイントは、より異なる量で進めることができsrc、ポインタが、我々は戻って整列に得ればsrcポインタ、我々はまだだけに整列していないベクトルストアをやりますdst

UTF-8であるが、ほとんどがUTF-8のASCIIサブセットで構成されているテキストの場合、これは適切な場合があります。ただし、ASCII以外のものがたくさんある場合は、常にスカラーUTF-8対応ループに留まるよりも悪いでしょう。

他の言語を犠牲にして英語を速くすることは、マイナス面が大きい場合、将来を見据えた決定ではありません。


ロケール対応:

トルコ語のロケール(IN tr_TR)から正しい結果がtoupper('i')ある'İ'、(U0130)ではない'I'(プレーンASCII)。Windowsの動作が遅いことについての質問に関するMartin Bonnerのコメントを参照してくださいtolower()

マルチバイトUTF8入力文字の場合のように、例外リストをチェックして、そこでスカラーにフォールバックすることもできます。

このように複雑なため、SSE4.2 PCMPISTRMなどは、一度に多くのチェックを実行できる可能性があります。


20

文字列にASCII文字または国際文字が含まれていますか?

後者の場合、「大文字」はそれほど単純ではなく、使用するアルファベットによって異なります。二院制と一院制のアルファベットがあります。大文字と小文字の文字が異なるのは、二院アルファベットのみです。また、いわゆる大文字小文字を使用するラテン大文字「DZ」(\ u01F1「DZ」)などの複合文字もあります。つまり、最初の文字(D)のみが変更されます。

ICUと、シンプルケースマッピングとフルケースマッピングの違いを確認することをお勧めします。これは役立つかもしれません:

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


7
または、ドイツ語のeszet(sp?)、ギリシャ文字のベータ版のように見え、「ss」を意味します。大文字に相当する「SS」を意味するドイツ語の単一文字はありません。ドイツ語の「ストリート」を大文字にすると、1文字長くなります。
David Thornley、

6
別の特殊なケースはギリシャ語の文字シグマ(Σ)で、単語の終わりにある(ς)かそうでない(σ)かによって、2つの小文字バージョンがあります。そして、トルコ語のように大文字と小文字のマッピングがI↔ıとİ↔iのように、言語固有のルールがあります。
dan04 2010

1
「大文字」はケースフォールディングと呼ばれます。
コロンボ2015

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
あなたが2番目のソリューションを後押しするためのアクセス権を持っていない場合は、おそらくあなたが得ることができる最高のものです。**最初の解のパラメータの後の星は何をしますか?
サムブリンク

1
私は**、コード構文でボールドフォントを使用しようとすることから残されたタイプミスだと確信しています。
MasterHD、2015年

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 '26

はい。この#インクルードは必須です、#include <algorithm>
Pabitra Dash 2017

1
このコードはtoupper、負の数で呼び出されると、未定義の動作を呼び出します。
Roland Illig

ユーザーの回答の複製648545 – -1
ピョートル・ドブロゴスト2018

@PiotrDobrogost私はuser648545からの回答を知りません。私はそれをコピーしていません.2つのメソッドを比較すると、両方の関数でライブラリ関数変換が使用されますが、メソッドシグネチャはまったく異なります。
Pabitra Dash 2018

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
バイロン、他のコメントについては心配しないでください。あなたがしたように新しい(現代の)解決策で古い質問に答えることは全く問題ありません。
キベリアス2014

13

ASCII文字のみを使用する場合は、より高速になります

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

このコードは はより高速に実行されますが、ASCIIでのみ機能し、「抽象的な」ソリューションではない。

UNICODEソリューションまたはより一般的で抽象的なソリューションが必要な場合は、他の答えを探して、C ++文字列のメソッドを操作してください。


1
質問にはのタグが付けられてC++いますが、Cここに回答を書き込んでいます。(私は賛成投票の1つではありません。)
hkBattousai 2013

6
私はCの回答とC ++の回答を書きました。なぜなら、C ++はCソースと完全に互換性があるように書かれているため、どのCソリューションもC ++正しいソリューションです
LucaC。13年

しかし、C ++の方法を尊重する答えを出す方がはるかに優れています。
Dmitriy Yurchenko 2014年

標準のc ++の方法は、toupperでstd :: transformを使用することです。これはコードが少なく、確実に移植可能です。このコードは、システムが文字エンコードメカニズムとしてASCIIを使用するという「事実」に依存しています。すべてのシステムがこのエンコーディングに基づいているかどうかわからないため、これが移植可能かどうかはわかりません。
AlexTheo 2017

1
で囲まれた文字の代わりにASCIIコードを使用することにしたのはなぜ'ですか?
HolyBlackCat 2018

11

ASCIIのみで問題がなく、RWメモリへの有効なポインタを提供できる限り、Cにはシンプルで非常に効果的なワンライナーがあります。

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

これは、同じ文字ケースに正規化したいASCII識別子のような単純な文字列に特に適しています。次に、バッファーを使用してstd:stringインスタンスを作成できます。


この回答はstd :: stringではなく
C

これには、明らかに固有のセキュリティ欠陥があります。私はこれをしません。
バイロン

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は実装によってはunsigned 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; }
エヴァンテラン


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は、非常に感激されていますが、私は以下の通りです懸念に起因することを強調したいです

の他のすべての関数と同様に、引数の値がunsigned charとして表せず、EOFと等しくない場合のstd :: toupperの動作は未定義です。これらの関数をプレーン文字(または符号付き文字)で安全に使用するには、まず引数を符号なし文字に変換する必要があります
Referencestd :: 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は非負の値でのみ機能します...
アントニンガブレル2018

-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互換エンコーディングでのみ機能します。あなたの答えではなく質問もこの制限について言及していません。それらの1つはする必要があります。
Roland Illig

-1

8ビット文字(ミランバブスコフ以外の他のすべての回答でも同様)に関心がある場合は、メタプログラミングを使用してコンパイル時にルックアップテーブルを生成することにより、最速の速度を得ることができます。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

このソリューションを使用します。私はあなたがそのデータ領域を変更することになっていないことを知っています....しかし、それは主にバッファオーバーランのバグとnull文字のためだと思います...大文字の大文字小文字は同じではありません。

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 2013

3
これは遅いですが、一体何ですか?そのクレイジーなラインはstr[i] = toupper(str[i]);完全に細かいものに置き換えることができます(まあ、完全に細かいわけではありませんが、問題のほとんどは修正されています)。
クリス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.