std :: stringを小文字に変換する方法は?


777

std::string小文字に変換したい。この機能は知っtolower()ていますが、以前はこの機能に問題std::stringがありました。いずれにしても、を使用して各文字を反復処理する必要があるため、これは理想的ではありません。

100%動作する代替手段はありますか?


34
リストを反復せずに、何か他のリストの各要素を他のどのように変換しますか?文字列は単なる文字のリストであり、各文字に関数を適用する必要がある場合は、文字列を反復処理する必要があります。それを回避する方法はありません。

14
なぜこの質問は評価に値するのですか?私は、文字列を反復処理に問題はありませんが、離れてTOLOWER()、TOUPPER()などの他の機能がある場合、私は求めています
コンラッド・

3
Cスタイルのchar配列がある場合は、4文字の各ブロックにox20202020を追加して(すべて大文字になっている場合)、一度に4文字を小文字に変換できると思います。

13
@ダン:それらがすでに小文字である可能性があるが、間違いなくAZまたはazである場合、追加する代わりに0x20とORすることができます。ほとんど価値のない、とてもスマートな、おそらく馬鹿げた最適化の1つ...
Steve Jessop

4
なぜ反対票が投じられたのかはわかりません...確かに少し奇妙な言葉が使われています(何らかの方法ですべての項目を反復処理する必要があるためです)。これは有効な質問です
ウォーレン

回答:


905

それほどよくない質問からの改作:

#include <algorithm>
#include <cctype>
#include <string>

std::string data = "Abc";
std::transform(data.begin(), data.end(), data.begin(),
    [](unsigned char c){ return std::tolower(c); });

あなたは本当に各キャラクターを反復せずに逃げるつもりはありません。それ以外の場合、文字が小文字か大文字かを知る方法はありません。

あなたが本当に嫌いならtolower()、これは私があなたに使うことをお勧めしない特別なASCIIのみの代替です:

char asciitolower(char in) {
    if (in <= 'Z' && in >= 'A')
        return in - ('Z' - 'z');
    return in;
}

std::transform(data.begin(), data.end(), data.begin(), asciitolower);

tolower()では、1バイト文字ごとの置換しかできないことに注意してください。これは、特にUTF-8のようなマルチバイトエンコーディングを使用している場合、多くのスクリプトには不適切です。


25
(古いかもしれませんが、問題のアルゴリズムはほとんど変更されていません)@Stefan Mai:STLアルゴリズムの呼び出しには、どのような「全体のオーバーヘッド」がありますか?関数はかなり無駄がなく(つまり、単純なforループ)、同じコンパイルユニットで同じテンプレートパラメーターを使用して同じ関数への呼び出しがほとんどないため、インライン化されることがよくあります。
eq-

257
文字がASCIIであると想定するたびに、神は子猫を殺します。:(
ブライアンゴードン14

13
最初の例では、未定義の動作が発生する可能性があります(に渡さchar::tolower(int)ます)。負の値を渡さないようにする必要があります。
juanchopanza 2014年

37
-1この使用は::tolowerクラッシュする可能性があります。非ASCII入力のUBです。
乾杯とhth。-アルフ

7
::は、最下位の名前空間にあることを示すために、tolowerの前に必要です。このコードを別の名前空間で使用する場合、::なしで優先的に選択されることになるtolowerの異なる(おそらく無関係)定義がある可能性があります。
Charles Ofria 16

320

Boostはこのための文字列アルゴリズムを提供します

#include <boost/algorithm/string.hpp>

std::string str = "HELLO, WORLD!";
boost::algorithm::to_lower(str); // modifies str

または、非インプレースの場合

#include <boost/algorithm/string.hpp>

const std::string str = "HELLO, WORLD!";
const std::string lower_str = boost::algorithm::to_lower_copy(str);

2
これはASCII入力のtolowerと同じ問題がないと思いますか?
ポール2015年

19
非ASCII-7では失敗します。
DevSolar 2015

1
これの非インプレースバージョンはありますか?
レイ

5
@Ray、はい、to_lower_copy
smac89 2017

234

tl; dr

ICUライブラリを使用しますそうしないと、変換ルーチンは、存在していることにさえ気付いていない可能性のあるケースを黙って中断します。


最初にあなたは質問に答える必要があります:あなたのエンコーディングは何std::stringですか?ISO-8859-1ですか?それともISO-8859-8ですか?またはWindowsコードページ1252?あなたが大文字から小文字に変換するために使用しているものは何でもそれを知っていますか?(またはそれは文字以上の惨めに失敗し0x7fますか?)

std::stringコンテナーとしてUTF-8(8ビットエンコーディングの中で唯一の健全な選択)を使用している場合、マルチバイト文字シーケンスをコンテナーに格納しているため、自分がまだ制御していると信じ込んでいます。これはマルチバイトの概念を認識していません。.substr()時限爆弾のように単純なものでさえ。(マルチバイトシーケンスを分割すると、無効な(サブ)文字列になるためです。)

そしてstd::toupper( 'ß' )どのようなエンコーディングで、のようなものを試すとすぐに、深刻な問題に直面します。(標準ライブラリではこれを「正しく」行うことは単純に不可能であり、1つの結果文字しか配信できず、"SS"ここでは必要ありません。)[1]別の例は、ロケールに応じてstd::tolower( 'I' )異なる結果を生成するはずです。ドイツで'i'は正しいでしょう。トルコでは、'ı'(ラテン小文字のドットI)が期待される結果です(これも、UTF-8エンコーディングでは1バイト以上です)。さらに別の例は、ギリシャ語であるシグマ大文字、'∑'小文字、'σ'それは言葉の最後を除いて... 'ς'

だから、任意の、一度に文字の上に働く、あるいは最悪の場合変換バイトを一度には、設計によって破壊されます。

次に、標準ライブラリが実行できること、ソフトウェアが実行されているマシンでサポートされているロケールに依存しているという点があります...そうでない場合はどうしますか?

それでは、あなたがしている本当にを探しているすべて正しくこれに対処することのできる文字列クラスで、それはありませんいずれかのstd::basic_string<>変種

(C ++ 11の注:std::u16stringおよびstd::u32stringより良いですが、まだ完全ではありません。C++ 20はをもたらしましたstd::u8stringが、これらはすべてエンコードを指定することです。他の多くの点で、正規化、照合などのUnicodeの仕組みをまだ知らないままです。 。)

Boost は見栄えがよく、API的にも優れていますが、Boost.Localeは基本的にICUのラッパーです。場合はブーストがされてコンパイルさ ICUサポートとそうでない場合は...、Boost.Localeは標準ライブラリ用にコンパイルされたロケールのサポートに限定されています。

そして、私を信じてブーストは、ICUでコンパイルすることは時々本当の痛みをすることができます。(Windows用の事前にコンパイルされたバイナリはないため、アプリケーションと一緒にそれらを提供する必要があり、それによってまったく新しいワームの缶が開きます...)

したがって、個人的には、完全なUnicodeサポートを馬の口から直接取得し、ICUライブラリを直接使用することをお勧めします。

#include <unicode/unistr.h>
#include <unicode/ustream.h>
#include <unicode/locid.h>

#include <iostream>

int main()
{
    /*                          "Odysseus" */
    char const * someString = u8"ΟΔΥΣΣΕΥΣ";
    icu::UnicodeString someUString( someString, "UTF-8" );
    // Setting the locale explicitly here for completeness.
    // Usually you would use the user-specified system locale,
    // which *does* make a difference (see ı vs. i above).
    std::cout << someUString.toLower( "el_GR" ) << "\n";
    std::cout << someUString.toUpper( "el_GR" ) << "\n";
    return 0;
}

コンパイル(この例ではG ++を使用):

g++ -Wall example.cpp -licuuc -licuio

これは与える:

ὀδυσσεύς

単語の途中でΣ<->σ変換し、単語の最後でΣ<->ς変換することに注意してください。<algorithm>ベースのソリューションはそれを与えることができません。


[1] 2017年、ドイツ語表記法審議会は、パスポートなどのあいまいさを回避するための従来の「SS」変換の横のオプションとして、「U」U + 1E9Eラテン大文字Sを正式に使用できると決定しました(名前が大文字の場合) )。私の美しい頼りになる例は、委員会の決定によって廃止されました...


19
これは一般的な場合の正解です。標準は、嘘と欺瞞を除いて「ASCII」以外のものを処理するために何も与えません。それはあなたが多分UTF-16を処理できるかもしれないと思わせますが、それはできません。この答えが言うように、独自のユニコード処理を行わないと、UTF-16文字列の適切な文字長(バイト長ではない)を取得できません。実際のテキストを処理する必要がある場合は、ICUを使用してください。おかげで、@ DevSolar
限定

ICUはUbuntu / Windowsでデフォルトで使用できますか、それとも個別にインストールする必要がありますか?また、この答えはどうですか:stackoverflow.com/a/35075839/207661
Shital Shah、2016

1
ねえ、見て、本当の答え!DevSolar、私を正しい方向に向けてくれてありがとう。
Dan Bechard

2
@DevSolar同意した!長さの概念は、テキストではかなり意味がありません(合法を犯罪者のリストに追加できます)。とはいえ、人々はタブを使用して1つの長さの単位を占める文字を制御することに慣れているので、コードポイントはより直感的な測定になります。ああ、そして正しい答えを与えてくれてありがとう、これまでずっと見ていて悲しいです:-(
masaers

3
@LFやや良い。しかし、たくさんのことがまだカバーされていない。toupperそしてtolower、まだ単一の文字に取り組んでいます。文字列クラスには正規化の概念がまだありません(たとえば、「ü」が「uを分音符号付き」または「u +結合分音符号」としてエンコードされているかどうか)、または文字列が分離されている場合とされていない場合。リストは続く。u8stringは(他の標準文字列クラスと同様に)「パススルー」に適しています。ただし、Unicode を処理する場合は、 ICU が必要です。
DevSolar

36

C ++ 11の範囲ベースのforループを使用すると、より単純なコードは次のようになります。

#include <iostream>       // std::cout
#include <string>         // std::string
#include <locale>         // std::locale, std::tolower

int main ()
{
  std::locale loc;
  std::string str="Test String.\n";

 for(auto elem : str)
    std::cout << std::tolower(elem,loc);
}

9
ただし、フランス語のマシンでは、このプログラムはフランス語で許可されている非ASCII文字を変換しません。たとえば、文字列 'Test String123。ÉÏ\ n 'は次のように変換されます:' test string123。ÉÏ\ n 'は、フランス語で使用できますが、文字ÉÏと、それらの小文字の「é」および「ï」を使用できます。このスレッドの他のメッセージによってそれに対する解決策が提供されなかったようです。
2013年

そのための適切なロケールを設定する必要があると思います。
user1095108 2013

@incises、これはそれから誰かがICUについての回答を投稿しました、そしてそれは確かに行く方法です。ロケールを理解しようとする他のほとんどのソリューションよりも簡単です。
Alexis Wilke 2016

個人的には、可能であれば外部ライブラリを使用しない方がいいです。
kayleeFrye_onDeck 2017


15

これは、Stefan Maiの応答のフォローアップです。変換の結果を別の文字列に配置する場合は、を呼び出す前に、ストレージスペースを事前に割り当てる必要がありますstd::transform。STLは変換された文字を宛先のイテレーターに格納するため(ループの各反復で文字をインクリメントします)、宛先の文字列は自動的にサイズ変更されず、メモリを踏み外す危険があります。

#include <string>
#include <algorithm>
#include <iostream>

int main (int argc, char* argv[])
{
  std::string sourceString = "Abc";
  std::string destinationString;

  // Allocate the destination space
  destinationString.resize(sourceString.size());

  // Convert the source string to lower case
  // storing the result in destination string
  std::transform(sourceString.begin(),
                 sourceString.end(),
                 destinationString.begin(),
                 ::tolower);

  // Output the result of the conversion
  std::cout << sourceString
            << " -> "
            << destinationString
            << std::endl;
}

1
これは私のために
re

手動でサイズを変更する代わりに、ここでバックインサーターイテレーターを使用することもできます。
チリ

11

参照変数を使用した範囲ベースのforループを使用した別のアプローチ

string test = "Hello World";
for(auto& c : test)
{
   c = tolower(c);
}

cout<<test<<endl;

6

私が見る限り、Boostライブラリはパフォーマンスの面で本当に悪いです。私はそれらのunordered_mapをSTLにテストしましたが、平均で3倍遅くなりました(最良のケース2、最悪の場合は10倍)。また、このアルゴリズムは低すぎるように見えます。

違いが非常に大きいのでtolower、「必要に応じて」ブーストと同等にするために追加する必要がある追加は、ブーストよりもはるかに高速になると確信しています。

私はAmazon EC2でこれらのテストを行ったため、テスト中にパフォーマンスが変化しましたが、まだアイデアは分かります。

./test
Elapsed time: 12365milliseconds
Elapsed time: 1640milliseconds
./test
Elapsed time: 26978milliseconds
Elapsed time: 1646milliseconds
./test
Elapsed time: 6957milliseconds
Elapsed time: 1634milliseconds
./test
Elapsed time: 23177milliseconds
Elapsed time: 2421milliseconds
./test
Elapsed time: 17342milliseconds
Elapsed time: 14132milliseconds
./test
Elapsed time: 7355milliseconds
Elapsed time: 1645milliseconds

-O2 このようにしました:

./test
Elapsed time: 3769milliseconds
Elapsed time: 565milliseconds
./test
Elapsed time: 3815milliseconds
Elapsed time: 565milliseconds
./test
Elapsed time: 3643milliseconds
Elapsed time: 566milliseconds
./test
Elapsed time: 22018milliseconds
Elapsed time: 566milliseconds
./test
Elapsed time: 3845milliseconds
Elapsed time: 569milliseconds

ソース:

string str;
bench.start();
for(long long i=0;i<1000000;i++)
{
    str="DSFZKMdskfdsjfsdfJDASFNSDJFXCKVdnjsafnjsdfjdnjasnJDNASFDJDSFSDNJjdsanjfsdnfjJNFSDJFSD";
    boost::algorithm::to_lower(str);
}
bench.end();

bench.start();
for(long long i=0;i<1000000;i++)
{
    str="DSFZKMdskfdsjfsdfJDASFNSDJFXCKVdnjsafnjsdfjdnjasnJDNASFDJDSFSDNJjdsanjfsdnfjJNFSDJFSD";
    for(unsigned short loop=0;loop < str.size();loop++)
    {
        str[loop]=tolower(str[loop]);
    }
}
bench.end();

私は専用のマシンでテストする必要があると思いますが、私はこのEC2を使用するので、自分のマシンでテストする必要はありません。


1
コンパイル時に最適化オプションを開きましたか?STLヘビーブーストライブラリは、高い最適化レベルでより適切に実行できると考えています。
Wei Song、

1
私はテストの1つで-O2を使用し、他には何も使用しませんでした。
Etherealone 2012

2
unordered_mapのパフォーマンスは、使用しているデータと組み合わせたハッシュアルゴリズムに依存します。unordered_mapを可能な限り高速にするために、すべてのデータに対して機能する魔法のハッシュアルゴリズムはありません。ベンチマークをして、さまざまなことを試してください。パフォーマンスが低下している理由は、使用しているハッシュを使用すると、多くの衝突が発生するためです。これにより、基本的にリストが検索されます。 詳細については、このサイトをチェックしてください:fgda.pl/post/7/gcc-hash-map-vs-unordered-map私の目的のために、リンクで提供された機能は衝突を減らし、したがって非常に高速でした。
leetNightshade 2012

6

std名前空間を気にせずに文字列を小文字に変換する最も簡単な方法は次のとおりです

1:スペース付き/なしの文字列

#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
int main(){
    string str;
    getline(cin,str);
//------------function to convert string into lowercase---------------
    transform(str.begin(), str.end(), str.begin(), ::tolower);
//--------------------------------------------------------------------
    cout<<str;
    return 0;
}

2:スペースなしの文字列

#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
int main(){
    string str;
    cin>>str;
//------------function to convert string into lowercase---------------
    transform(str.begin(), str.end(), str.begin(), ::tolower);
//--------------------------------------------------------------------
    cout<<str;
    return 0;
}

5

std::ctype::tolower()標準のC ++ローカリゼーションライブラリから、これを正しく行います。以下は、tolowerのリファレンスページから抽出した例です。

#include <locale>
#include <iostream>

int main () {
  std::locale::global(std::locale("en_US.utf8"));
  std::wcout.imbue(std::locale());
  std::wcout << "In US English UTF-8 locale:\n";
  auto& f = std::use_facet<std::ctype<wchar_t>>(std::locale());
  std::wstring str = L"HELLo, wORLD!";
  std::wcout << "Lowercase form of the string '" << str << "' is ";
  f.tolower(&str[0], &str[0] + str.size());
  std::wcout << "'" << str << "'\n";
}

文字を適切な場所に変換できる限り、いいですね。ソース文字列が次の場合はどうなりますconstか?f.tolower()新しい文字列に文字を入力する必要があるため、少し面倒になります(たとえば、を使用できないように見えます)。あなたが使用するtransform()と、のようなものstd::bind1st( std::mem_fun() )オペレータのため?
クワザー

const文字列の場合、ローカルコピーを作成して、適切な場所に変換できます。
2016

ただし、コピーを作成するとオーバーヘッドが増加します。
quazar

std :: transformは、ポインタをとらないctype :: tolowerのバージョンで使用できます。バックインサーターイテレーターアダプターを使用すれば、出力文字列のサイズを事前に設定する必要はありません。
チリ

特にlibstdc ++のtolowerwith localeパラメータでは、への暗黙的な呼び出しがuse_facetパフォーマンスのボトルネックになっているように見えるため、特にそうです。私の同僚の1人は、boost::iequals(この問題がある)use_facetループの外で一度だけ呼び出されるバージョンに置き換えることで、数100%の速度向上を達成しました。
Arne Vogel

3

Boostの代替はPOCO(pocoproject.org)です。

POCOには2つのバリアントがあります。

  1. 最初のバリアントは、元の文字列を変更せずにコピーを作成します。
  2. 2番目のバリアントは元の文字列を変更します。
    「インプレース」バージョンには、常に名前に「インプレース」があります。

両方のバージョンを以下に示します。

#include "Poco/String.h"
using namespace Poco;

std::string hello("Stack Overflow!");

// Copies "STACK OVERFLOW!" into 'newString' without altering 'hello.'
std::string newString(toUpper(hello));

// Changes newString in-place to read "stack overflow!"
toLowerInPlace(newString);

3

ifテストを行わずに大文字を小文字に変換する方法があり、それは非常に簡単です。isupper()関数/マクロでのclocale.hの使用により、位置に関連する問題に対処する必要がありますが、そうでない場合は、いつでもUtoL []を思いのままに調整できます。

Cの文字が実際には8ビット整数(現時点ではワイド文字セットを無視)であるとすると、代替文字セットを保持する256バイトの配列を作成でき、変換関数では、文字列内の文字を添え字として変換配列。

ただし、1対1のマッピングの代わりに、大文字の配列メンバーに小文字のBYTE int値を指定します。ここではislower()とisupper()が便利です。

ここに画像の説明を入力してください

コードは次のようになります...

#include <clocale>
static char UtoL[256];
// ----------------------------------------------------------------------------
void InitUtoLMap()  {
    for (int i = 0; i < sizeof(UtoL); i++)  {
        if (isupper(i)) {
            UtoL[i] = (char)(i + 32);
        }   else    {
            UtoL[i] = i;
        }
    }
}
// ----------------------------------------------------------------------------
char *LowerStr(char *szMyStr) {
    char *p = szMyStr;
    // do conversion in-place so as not to require a destination buffer
    while (*p) {        // szMyStr must be null-terminated
        *p = UtoL[*p];  
        p++;
    }
    return szMyStr;
}
// ----------------------------------------------------------------------------
int main() {
    time_t start;
    char *Lowered, Upper[128];
    InitUtoLMap();
    strcpy(Upper, "Every GOOD boy does FINE!");

    Lowered = LowerStr(Upper);
    return 0;
}

この方法では、同時に、変更したい他の文字を再マッピングすることができます。

最新のプロセッサで実行する場合、このアプローチには大きな利点が1つあります。分岐を構成するifテストがないため、分岐予測を行う必要はありません。これにより、他のループのCPUの分岐予測ロジックが節約され、パイプラインのストールを防ぐ傾向があります。

ここで、EBCDICをASCIIに変換するために使用されたものと同じアプローチを認識する人もいます。


2
「テストの場合を行わずに大文字を小文字に変換する方法はありますか」ルックアップテーブルについて聞いたことがありますか?
ガーボルBuella

1
負の文字の未定義の動作。
Roland Illig 2017年

最近のCPUはCPUではなくメモリでボトルネックになっています。ベンチマークは興味深いでしょう。
Contango

3

答えのどれもが、C ++ 20以降標準ライブラリで提供され、今後の範囲のライブラリーを、言及していない、そして現在は個別に利用できるので、GitHubの上としてrange-v3、私はそれを使用して、この変換を実行する方法を追加したいと思います。

文字列をインプレースで変更するには:

str |= action::transform([](unsigned char c){ return std::tolower(c); });

新しい文字列を生成するには:

auto new_string = original_string
    | view::transform([](unsigned char c){ return std::tolower(c); });

#include <cctype>必要なRangesヘッダーとを忘れないでください。)

注:unsigned charラムダの引数としてのの使用は、cppreferenceに触発されており、次のように述べています。

の他のすべての関数と同様に、引数の値がとしても表現可能でも等しくない場合のの<cctype>動作std::tolowerは未定義です。これらの関数をプレーンs(またはs)で安全に使用するには、最初に引数を次のように変換する必要があります。unsigned charEOFcharsigned charunsigned char

char my_tolower(char ch)
{
    return static_cast<char>(std::tolower(static_cast<unsigned char>(ch)));
}

同様に、イテレータの値タイプがcharまたはの場合、標準アルゴリズムで直接使用しないでくださいsigned char。代わりに、値をunsigned char最初に変換します。

std::string str_tolower(std::string s) {
    std::transform(s.begin(), s.end(), s.begin(), 
                // static_cast<int(*)(int)>(std::tolower)         // wrong
                // [](int c){ return std::tolower(c); }           // wrong
                // [](char c){ return std::tolower(c); }          // wrong
                   [](unsigned char c){ return std::tolower(c); } // correct
                  );
    return s;
}

3

大文字/小文字を実行する私自身のテンプレート関数。

#include <string>
#include <algorithm>

//
//  Lowercases string
//
template <typename T>
std::basic_string<T> lowercase(const std::basic_string<T>& s)
{
    std::basic_string<T> s2 = s;
    std::transform(s2.begin(), s2.end(), s2.begin(), tolower);
    return std::move(s2);
}

//
// Uppercases string
//
template <typename T>
std::basic_string<T> uppercase(const std::basic_string<T>& s)
{
    std::basic_string<T> s2 = s;
    std::transform(s2.begin(), s2.end(), s2.begin(), toupper);
    return std::move(s2);
}

これは私が必要としたものです。私towlowerはUTF-16をサポートするワイド文字にforを使用しました。
Juv

2

簡単なものが必要な場合のマクロテクニックを次に示します。

#define STRTOLOWER(x) std::transform (x.begin(), x.end(), x.begin(), ::tolower)
#define STRTOUPPER(x) std::transform (x.begin(), x.end(), x.begin(), ::toupper)
#define STRTOUCFIRST(x) std::transform (x.begin(), x.begin()+1, x.begin(),  ::toupper); std::transform (x.begin()+1, x.end(),   x.begin()+1,::tolower)

ただし、この回答に関する@AndreasSpindlerのコメントは、ASCII文字だけではないものに取り組んでいる場合は、重要な考慮事項であることに注意してください。


1
私は完全に良い解決策が存在するときにマクロを与えるためにこれに反対票を投じています-あなたはそれらの解決策さえ与えるでしょう。
クリア

2
マクロテクニックは、プログラミングでよく使用されるコードの入力を減らすことを意味します。なぜそれを使わないのですか?そうでなければ、なぜマクロがあるのですか?
Volomike、2017年

3
マクロはCからの遺産であり、取り除くために懸命に取り組んでいます。タイピングの量を減らしたい場合は、関数またはラムダを使用します。void strtoupper(std::string& x) { std::transform (x.begin(), x.end(), x.begin(), ::toupper); }
クリア

1
@Clearer私はより優れたコーダーになりたいので、ANSI C ++委員会が「C ++からマクロを取り除くために会議を呼び出す必要がある」という効果について何かANSI C ++委員会が言っているリンクを教えてもらえますか?または他のいくつかのロードマップ?
Volomike、2017年

2
いいえ、できません。このトピックに関するBjarneのスタンスは、いくつかのケースでかなり明確にされています。さらに、CおよびC ++でマクロを使用しない理由はたくさんあります。x有効な式である可能性があります。これはたまたま正しくコンパイルされますが、マクロのために完全に偽の結果をもたらします。
クリア

2
// tolower example (C++)
#include <iostream>       // std::cout
#include <string>         // std::string
#include <locale>         // std::locale, std::tolower

int main ()
{
  std::locale loc;
  std::string str="Test String.\n";
  for (std::string::size_type i=0; i<str.length(); ++i)
    std::cout << std::tolower(str[i],loc);
  return 0;
}

詳細情報:http : //www.cplusplus.com/reference/locale/tolower/


2

100%動作する代替手段はありますか?

番号

小文字の方法を選択する前に、自問する必要があるいくつかの質問があります。

  1. 文字列はどのようにエンコードされますか?プレーンASCII?UTF-8?何らかの形式の拡張ASCIIレガシーエンコーディング?
  2. とにかく小文字とはどういう意味ですか?ケースマッピングルールは言語によって異なります。ユーザーのロケールにローカライズされたものをご希望ですか?ソフトウェアが実行されるすべてのシステムで一貫して動作するものを望みますか?ASCII文字を小文字にして他のすべてを通過させたいですか?
  3. どのライブラリーが利用できますか?

これらの質問に対する回答が得られたら、ニーズに合ったソリューションを探し始めることができます。あらゆる場所で機能するすべてに適合する1つのサイズはありません!


2

この機能を試してください:)

string toLowerCase(string str) {
    int str_len = str.length();
    string final_str = "";
    for(int i=0; i<str_len; i++) {
        char character = str[i];
        if(character>=65 && character<=92) {
            final_str += (character+32);
        } else {
            final_str += character;
        }
    }
    return final_str;
}

1

Microsoftプラットフォームstrlwrでは、関数ファミリーを使用できます。http ://msdn.microsoft.com/en-us/library/hkxwh33z.aspx

// crt_strlwr.c
// compile with: /W3
// This program uses _strlwr and _strupr to create
// uppercase and lowercase copies of a mixed-case string.
#include <string.h>
#include <stdio.h>

int main( void )
{
   char string[100] = "The String to End All Strings!";
   char * copy1 = _strdup( string ); // make two copies
   char * copy2 = _strdup( string );

   _strlwr( copy1 ); // C4996
   _strupr( copy2 ); // C4996

   printf( "Mixed: %s\n", string );
   printf( "Lower: %s\n", copy1 );
   printf( "Upper: %s\n", copy2 );

   free( copy1 );
   free( copy2 );
}

0

コードスニペット

#include<bits/stdc++.h>
using namespace std;


int main ()
{
    ios::sync_with_stdio(false);

    string str="String Convert\n";

    for(int i=0; i<str.size(); i++)
    {
      str[i] = tolower(str[i]);
    }
    cout<<str<<endl;

    return 0;
}


0

回答を改善することは許可されていなかったため、コピーしてください。ありがとうSO


string test = "Hello World";
for(auto& c : test)
{
   c = tolower(c);
}

説明:

for(auto& c : test)されているループの範囲はベース種類の:
for (range_declaration:range_expression)loop_statement

  1. range_declarationauto& c
    ここでは、自動指定子は自動型推論に使用されます。したがって、型は変数初期化子から差し引かれます。

  2. range_expressiontest
    この場合の範囲はstringの文字testです。

文字列の文字testは、for loop through identifier内の参照として使用できますc


回答をどこからコピーしたかを明確にしてください。
bfontaine 2018

0

C ++には、tolowerまたはtoupperメソッドをstringに実装する必要はありませんが、charには使用できます。文字列の各文字を簡単に読み取って、必要なケースに変換し、文字列に戻すことができます。サードパーティのライブラリを使用しないサンプルコード:

#include<iostream>

int main(){
  std::string str = std::string("How IS The Josh");
  for(char &ch : str){
    ch = std::tolower(ch);
  }
  std::cout<<str<<std::endl;
  return 0;
}

文字列の文字ベースの操作の場合文字列のすべての文字に対して


-1

これは、大文字を小文字に、またはその逆に変換する別の単純なバージョンである可能性があります。VS2017コミュニティバージョンを使用して、このソースコードをコンパイルしました。

#include <iostream>
#include <string>
using namespace std;

int main()
{
    std::string _input = "lowercasetouppercase";
#if 0
    // My idea is to use the ascii value to convert
    char upperA = 'A';
    char lowerA = 'a';

    cout << (int)upperA << endl; // ASCII value of 'A' -> 65
    cout << (int)lowerA << endl; // ASCII value of 'a' -> 97
    // 97-65 = 32; // Difference of ASCII value of upper and lower a
#endif // 0

    cout << "Input String = " << _input.c_str() << endl;
    for (int i = 0; i < _input.length(); ++i)
    {
        _input[i] -= 32; // To convert lower to upper
#if 0
        _input[i] += 32; // To convert upper to lower
#endif // 0
    }
    cout << "Output String = " << _input.c_str() << endl;

    return 0;
}

注:特殊文字がある場合は、条件チェックを使用して処理する必要があります。


-8

私はstd :: transformを試しました、200年前のドルイドだけが理解できるabominable stl cripticコンパイルエラーです(から変換できませんflibidi flabidi fluに変換できません)

これは問題なく機能し、簡単に調整できます

string LowerCase(string s)
{
    int dif='a'-'A';
    for(int i=0;i<s.length();i++)
    {
        if((s[i]>='A')&&(s[i]<='Z'))
            s[i]+=dif;
    }
   return s;
}

string UpperCase(string s)
{
   int dif='a'-'A';
    for(int i=0;i<s.length();i++)
    {
        if((s[i]>='a')&&(s[i]<='z'))
            s[i]-=dif;
    }
   return s;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.