std :: string을 소문자로 변환하는 방법?


777

std::string을 소문자 로 변환하고 싶습니다 . 나는 그 기능을 알고 tolower()있지만, 과거에는이 기능에 문제가 있었고 어쨌든 std::string각 문자를 반복해야하므로 이상적인 것은 아닙니다 .

100 % 효과가있는 대안이 있습니까?


34
목록의 각 요소를 목록을 반복하지 않고 다른 것으로 변환하는 방법은 무엇입니까? 문자열은 문자 목록 일뿐입니다. 각 문자에 일부 기능을 적용 해야하는 경우 문자열을 반복해야합니다. 그 주위에 방법이 없습니다.

14
이 질문이 정확히 등급을 낮추는 이유는 무엇입니까? 문자열을 반복하는 데 문제가 없지만 tolower (), toupper () 등을 제외한 다른 함수가 있는지 묻습니다.
Konrad

3
C 스타일 char 배열이 있다면 한 번에 4 문자를 소문자로 변환하기 위해 ox20202020을 4 문자 (각각 모두 대문자 인 경우)의 각 블록에 추가 할 수 있습니다.

13
@ Dan : 이미 소문자 일 수는 있지만 AZ 또는 az 인 경우 추가하는 대신 0x20으로 OR 할 수 있습니다. 가치가 거의 결코 그 중 하나는 이른바 스마트 키우면 - 아마 - 바보 최적화 ...
스티브 Jessop

4
이되어 아래로 투표를 한 이유를 나는 (당신은 모든 항목 든을 반복하는 데이 때문에) 확실히는 이상한 조금 말로있다 ... 모르겠지만, 그것은 유효한 질문
워렌

답변:


905

자주 묻는 질문 (FAQ) 에서 적응 :

#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- November

257
당신이 문자가 ASCII라고 가정 할 때마다, 신은 고양이를 죽인다. :(
Brian Gordon

13
첫 번째 예는 잠재적으로이 정의되지 않은 동작 (통과 char로를 ::tolower(int).) 당신은 당신이 음의 값을 전달하지 않도록해야합니다.
juanchopanza

37
-1이 사용 ::tolower은 잘 충돌 할 수 있습니다. 비 ASCII 입력의 경우 UB입니다.
건배와 hth. -Alf

7
::는 가장 바깥 쪽 네임 스페이스에 있음을 나타 내기 위해 낮춰지기 전에 필요합니다. 다른 네임 스페이스에서이 코드를 사용하는 경우 ::없이 우선적으로 선택되는 tolower에 대한 다른 (관련되지 않은) 정의가있을 수 있습니다.
Charles Ofria

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 입력으로 낮추는 것과 같은 문제가 없다고 생각합니까?
paulm

19
비 ASCII-7에 실패합니다.
DevSolar

1
현재 위치에없는 버전이 있습니까?
Ray

5
@Ray, yes,to_lower_copy
smac89

234

tl; dr

ICU 라이브러리를 사용하십시오 . 그렇지 않은 경우 기존 루틴조차 모르는 경우 변환 루틴이 자동으로 중단됩니다.


먼저 질문에 대답해야합니다 : 인코딩 은 무엇입니까 std::string? ISO-8859-1입니까? 아니면 ISO-8859-8입니까? 아니면 Windows Codepage 1252? 대문자에서 소문자로 변환하는 데 사용하는 것이 무엇인지 알고 있습니까? (또는 이상 문자에 대해 비참하게 실패 0x7f합니까?)

std::string컨테이너로 UTF-8 (8 비트 인코딩 중 유일한 선택)을 사용 하는 경우 컨테이너에 멀티 바이트 문자 시퀀스를 저장하기 때문에 여전히 사물을 제어하고 있다고 믿지 않습니다. 그것은 멀티 바이트 개념을 인식하지 못합니다. .substr()시한 폭탄 처럼 단순한 것조차도 . (멀티 바이트 시퀀스를 분할하면 유효하지 않은 (하위) 문자열이됩니다.)

이 같은 노력으로 그리고 즉시 std::toupper( 'ß' )에, 어떤 인코딩을, 당신은 곤경에 있습니다. 표준 라이브러리로는이 "올바른"작업을 수행 할 수 없기 때문에 여기 에는 필요 하지 않은 하나의 결과 문자 만 제공 할 수 "SS"있습니다. [1] 로케일에 따라std::tolower( 'I' ) 다른 결과를 얻을 수있는 또 다른 예가 있습니다 . 독일에서는 정확할 것입니다. 터키에서는 (LATIN SMALL LETTER DOTLESS I)이 예상되는 결과입니다 (UTF-8 인코딩에서 1 바이트 이상임). 또 다른 예로는 그리스어 시그마 , 대문자 , 소문자 등 이 있습니다.'i''ı''∑''σ''ς'

따라서 한 번에 한 문자 또는 한 번에 한 바이트 씩 작동하는 모든 경우 변환 은 설계에 의해 중단됩니다.

그런 다음 지점이 그것이 무엇을위한 표준 라이브러리 이며 , 로케일이되는에 따라되는 일을 할 수있는 지원 소프트웨어가 실행중인 컴퓨터에를 ... 그리고, 그렇지 않은 경우 당신은 무엇을해야합니까?

그래서 당신이 정말 찾고 올바르게 모든 처리 할 수있는 캐릭터 클래스는, 그는 없는 임의의 std::basic_string<>변형 .

(C ++ 11 참고 : std::u16string하고 std::u32string있습니다 더 나은 .하지만 아직 완벽하지 C ++ (20)는 가져왔다 std::u8string,하지만이 모든 할 일이 인코딩을 지정이다 다른 많은면에서 그들은 여전히 정상화, 정렬과 같은 유니 코드 역학의 무지 남아 ... .)

Boost API와 비슷하게 보이지만 Boost.Locale은 기본적으로 ICU를 감싸는 래퍼 입니다. 경우 부스트가되어 컴파일 된 ICU 지원, 그렇지 않은 경우는 ... Boost.Locale는 표준 라이브러리의 컴파일 된 로케일 지원 제한됩니다.

그리고 ICU로 컴파일하도록 Boost를 얻는 것은 때때로 고통 스러울 수 있습니다. (Windows 용 사전 컴파일 된 바이너리는 없으므로 응용 프로그램과 함께 제공해야 하며 완전히 새로운 웜 캔 엽니 다 ...)

따라서 개인적으로 말의 입에서 직접 유니 코드를 완벽하게 지원하고 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 년 독일 정형 외과위원회는 "+"U + 1E9E 라틴 대문자 레터 샤프 S를 공식적으로 사용할 수 있으며, 예를 들어 여권 (예 : 이름이 대문자 인 경우)에서 모호함을 피하기 위해 전통적인 "SS"변환 옆의 옵션으로 사용할 수 있다고 판결했습니다. ). 위원회 결정에 의해 쓸모없는 나의 아름다운 예가 ...


19
이것이 일반적인 경우의 정답입니다. 이 표준은 거짓말과기만을 제외하고 "ASCII"이외의 것을 다루는 데는 아무 것도 제공하지 않습니다. UTF-16을 다룰 수 있다고 생각 하게 만들 수는 있지만 그렇게 할 수는 없습니다. 이 답변에서 알 수 있듯이 고유 한 유니 코드 처리를 수행하지 않으면 UTF-16 문자열의 적절한 문자 길이 (바이트 길이 아님)를 얻을 수 없습니다. 실제 텍스트를 다루어야하는 경우 ICU를 사용하십시오. 감사합니다, @DevSolar
제한적 속죄

ICU는 기본적으로 Ubuntu / Windows에서 사용 가능합니까 아니면 별도로 설치해야합니까? 또한이 답변은 어떻습니까 : stackoverflow.com/a/35075839/207661 ?
Shital Shah

1
이봐, 진짜 대답! 바로 올바른 DevSolar를 알려 주셔서 감사합니다.
Dan Bechard

2
@DevSolar 합의! 길이의 개념은 텍스트에서 의미가 없습니다 (범죄자 목록에 합자를 추가 할 수 있음). 즉, 사람들은 하나의 길이 단위를 사용하는 문자를 탭하고 제어하는 ​​데 익숙하기 때문에 코드 포인트가보다 직관적 인 측정 기준이 될 것입니다. 아, 그리고 정답을 줘서 고마워, 지금까지 그것을보고 슬프다 :-(
masaers

3
@LF 조금 더 좋습니다. 그러나 많은 일들이 아직 적용되지 않은 : toupper그리고 tolower여전히 단일 문자 작동합니다. 문자열 클래스에는 여전히 정규화 개념이 없습니다 (예 : "ü"가 "u with diaeresis"또는 "u + Combine diaeresis"로 인코딩되는지 여부) 또는 문자열이 분리되거나 분리되지 않을 수 있습니다. 목록은 계속됩니다. u8string은 (다른 표준 문자열 클래스와 마찬가지로) "통과"에 적합합니다. 그러나 유니 코드 를 처리 하려면 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 '문자 É Ï 및 소문자 couterparts'é '및'ï '는 프랑스어로 허용됩니다. 이 스레드의 다른 메시지에서 해당 솔루션을 제공하지 않은 것 같습니다.
incises

적절한 로케일을 설정해야한다고 생각합니다.
user1095108

@incises, 이것은 누군가 누군가 ICU에 대한 답변을 올렸으며 그것은 확실히 갈 길입니다. 로케일을 이해하려고 시도하는 대부분의 다른 솔루션보다 쉽습니다.
Alexis Wilke

가능하면 개인적으로 외부 라이브러리를 사용하지 않는 것이 좋습니다.
kayleeFrye_onDeck


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
이것은 나를 위해 Ä 크기를 ä로 바꾸지 않았습니다
Purefan

수동 크기 조정 대신 후면 삽입 기 반복기를 사용할 수도 있습니다.
chili

11

참조 변수와 함께 루프 기반 범위를 사용하는 또 다른 접근법

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

cout<<test<<endl;

6

내가 아는 한 Boost 라이브러리는 실제로 성능면에서 좋지 않습니다. 나는 unorder_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 헤비 부스트 라이브러리는 높은 최적화 수준으로 더 잘 실행되어야한다고 생각합니다.
웨이 노래

1
테스트 중 하나에서 -O2를 사용했지만 그 밖의 것은 없습니다.
Etherealone

2
unorder_map의 성능은 사용중인 데이터와 결합 된 해싱 알고리즘에 따라 다릅니다. unorder_map을 가능한 빨리 만들기 위해 모든 데이터에 작동하는 매직 해싱 알고리즘은 없습니다. 벤치마킹하고 다른 것을 시도하십시오. 성능이 저하되는 이유는 사용하는 해시로 인해 많은 충돌이 발생하기 때문에 기본적으로 목록에서 조회가 발생하기 때문입니다. 자세한 내용은이 사이트를 확인하십시오. fgda.pl/post/7/gcc-hash-map-vs-unorder-map 내 목적을 위해 링크에서 제공되는 기능이 충돌을 줄 였으므로 매우 빠릅니다.
leetNightshade

6

표준 네임 스페이스를 신경 쓰지 않고 문자열을 소문자로 변환하는 가장 간단한 방법은 다음과 같습니다.

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 ++ Localization 라이브러리에서 올바르게 수행합니다. 다음은 참조 페이지 에서 추출한 예입니다 .

#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() )?
quazar

const 문자열의 경우 로컬 복사본을 만든 다음 그 자리에서 변환하면됩니다.
Sameer

그래도 복사본을 만들면 더 많은 오버 헤드가 발생합니다.
quazar

포인터를 사용하지 않는 ctype :: tolower 버전과 함께 std :: transform을 사용할 수 있습니다. 백 인서 터 반복기 어댑터를 사용하면 출력 문자열의 사전 크기를 걱정할 필요가 없습니다.
chili

좋아요, 특히 때문에에 된 libstdc ++의 tolowerlocale매개 변수에 대한 암시 적 호출 use_facet이 나타납니다이 성능 병목합니다. 동료 중 한 명이 루프 외부에서 한 번만 호출 boost::iequals되는 버전으로 (이 문제가있는) 대체하여 100 % 속도가 몇 배 증가했습니다 use_facet.
Arne Vogel

3

Boost의 대안은 POCO (pocoproject.org)입니다.

POCO는 두 가지 변형을 제공합니다.

  1. 첫 번째 변형은 원래 문자열을 변경하지 않고 사본을 만듭니다.
  2. 두 번째 변형은 원래 문자열을 변경합니다.
    "In Place"버전의 이름은 항상 "InPlace"입니다.

두 버전 모두 아래에 설명되어 있습니다.

#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 tests를 수행하지 않고 대문자를 소문자로 변환하는 방법이 있으며 매우 간단합니다. clocale.h를 사용하는 isupper () 함수 / 매크로는 사용자의 위치와 관련된 문제를 처리해야하지만, 그렇지 않은 경우 언제든지 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;
}

이 방법을 사용하면 변경하려는 다른 문자를 다시 매핑 할 수 있습니다.

이 접근 방식은 최신 프로세서에서 실행할 때 큰 이점이 있으며 분기를 포함하는 if 테스트가 없으므로 분기 예측을 수행 할 필요가 없습니다. 이는 다른 루프에 대한 CPU의 분기 예측 로직을 저장하고 파이프 라인 중단을 방지하는 경향이 있습니다.

여기서 일부는이 방법을 EBCDIC을 ASCII로 변환하는 데 사용 된 것과 동일한 방식으로 인식 할 수 있습니다.


2
조회 테이블에 대해 들어 본 적이 없다면 "테스트를 수행하지 않고 대문자를 소문자로 변환하는 방법이 있습니까?"
Gábor Buella

1
음수 문자에 대해 정의되지 않은 동작.
Roland Illig

최신 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 에서 영감을 얻었습니다 .

from의 다른 모든 함수와 마찬가지로 인수 값이로 표현할 수 없거나 같지 않은 경우 <cctype>동작 std::tolower은 정의되지 않습니다 . 이러한 함수를 plain 또는 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);
}

이것이 내가 필요한 것입니다. towlowerUTF-16을 지원하는 와이드 문자에 방금 사용했습니다 .
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
완벽하게 좋은 솔루션이 존재할 때 매크로를 제공하기 위해 이것을 하향 조정하고 있습니다.
Clearer

2
매크로 기술은 프로그래밍에서 일반적으로 많이 사용하는 코드를 덜 타이핑하는 것을 의미합니다. 왜 사용하지 않습니까? 그렇지 않으면 왜 매크로가 있습니까?
Volomike

3
매크로는 C의 유산으로 제거하기 위해 열심히 노력하고 있습니다. 입력량을 줄이려면 함수 또는 람다를 사용하십시오. void strtoupper(std::string& x) { std::transform (x.begin(), x.end(), x.begin(), ::toupper); }
Clearer

1
@Clearer 더 나은 코더가되기를 원한다면, ANSI C ++위원회가 "C ++에서 매크로를 제거하기 위해 회의를 불러야한다"는 효과가있는 ANSI 문서 링크를 제공해 주시겠습니까? 아니면 다른 로드맵?
Volomike

2
아니, 난 못해 그러나이 주제에 대한 Bjarne의 입장은 여러 차례 분명 해졌다. 게다가 C와 C ++에서 매크로를 사용하지 않는 데는 많은 이유가 있습니다. x올바른 식일 수 있습니다.이 식은 올바르게 컴파일되지만 매크로 때문에 완전히 잘못된 결과를 제공합니다.
Clearer

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. 어떤 도서관이 있습니까?

이러한 질문에 대한 답변이 있으면 필요에 맞는 soloution을 찾을 수 있습니다. 어느 곳에서나 모든 사람에게 적합한 크기는 없습니다!


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

답변을 개선 할 수 없었기 때문에 복사하십시오. 감사합니다


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

설명:

for(auto& c : test)종류 의 범위 기반 for 루프 입니다 .
for (range_declaration:range_expression)loop_statement

  1. range_declaration: auto& c
    여기서 자동 지정 자는 자동 유형 공제에 사용됩니다. 따라서 변수 초기화 프로그램에서 유형이 차감됩니다.

  2. range_expression: test
    이 경우의 범위는 문자열의 문자입니다 test.

문자열의 문자 test는 for loop through identifier 내부의 참조로 사용 가능 c합니다.


답을 어디에서 복사했는지 명확히하십시오.
bfontaine

0

C ++에는 문자열에 대해 구현 된 tolower 또는 toupper 메서드가 없지만 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 년 전에 만 드루이드 만 이해할 수있는 가증스러운 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.