कैसे निचली स्थिति में std :: string कन्वर्ट करने के लिए?


777

मैं एक std::stringको लोअरकेस में बदलना चाहता हूं । मैं फ़ंक्शन से अवगत हूं tolower(), हालांकि अतीत में मेरे पास इस फ़ंक्शन के साथ समस्याएँ हैं और यह वैसे भी शायद ही आदर्श है क्योंकि उपयोग के साथ std::stringप्रत्येक चरित्र पर पुनरावृत्ति की आवश्यकता होगी।

क्या कोई विकल्प है जो 100% समय पर काम करता है?


34
सूची के माध्यम से पुनरावृत्ति किए बिना आप किसी भी चीज़ की सूची के प्रत्येक तत्व को किसी अन्य चीज़ में कैसे परिवर्तित करेंगे? एक स्ट्रिंग सिर्फ पात्रों की एक सूची है, यदि आपको प्रत्येक वर्ण के लिए कुछ फ़ंक्शन लागू करने की आवश्यकता है, तो आपको स्ट्रिंग के माध्यम से पुनरावृति करना होगा। उसके आसपास कोई रास्ता नहीं।

14
क्यों यह सवाल रेटिंग को नीचे गिरा देता है? मुझे अपनी स्ट्रिंग के माध्यम से पुनरावृत्ति करने में कोई समस्या नहीं है, लेकिन मैं पूछ रहा हूं कि क्या टोलर (), टौपर () आदि के अलावा अन्य कार्य हैं
कोनराड

3
यदि आपके पास सी स्टाइल चार सरणी है, तो मुझे लगता है कि आप 4 वर्णों के प्रत्येक ब्लॉक में ऑक्सी 20202020 को जोड़ने में सक्षम हो सकते हैं (बशर्ते वे एक समय में 4 वर्णों को लोअरकेस में बदलने के लिए हों।

13
@ दान: यदि वे पहले से ही कम हो सकते हैं, लेकिन निश्चित रूप से AZ या az हैं, तो आप जोड़ने के बजाय 0x20 के साथ OR कर सकते हैं। उन लोगों में से एक स्मार्ट-यह-शायद-गूंगा आशावादी हैं जो लगभग कभी भी इसके लायक नहीं हैं ...
स्टीव जेसप

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() केवल एक प्रति-एकल-बाइट-वर्ण प्रतिस्थापन हो सकता है, जो कई लिपियों के लिए बीमार है, खासकर अगर यूटीएफ -8 जैसे मल्टी-बाइट-एन्कोडिंग का उपयोग किया जाता है।


25
(पुराना यह हो सकता है, प्रश्न में एल्गोरिदम थोड़ा बदल गया है) @ स्तेफ़ान माई: एसटीएल एल्गोरिदम को कॉल करने में "ओवरहेड का पूरा लॉट" किस तरह का है? फ़ंक्शंस लीन हैं (यानी लूप्स के लिए सरल) और अक्सर इनबिल्ड होते हैं क्योंकि आपके पास समान कंपाइल यूनिट में समान टेम्प्लेट मापदंडों के साथ समान फ़ंक्शन के लिए शायद ही कभी कई कॉल होते हैं।
eq-

257
हर बार जब आप अक्षर को ASCII मानते हैं, भगवान एक बिल्ली का बच्चा मारता है। :(
ब्रायन गॉर्डन

13
आपके पहले उदाहरण में संभवतः अपरिभाषित व्यवहार (पास charकरना ::tolower(int)) है । आपको यह सुनिश्चित करने की आवश्यकता है कि आप एक नकारात्मक मान पास न करें।
जुआनकोपंजा

37
-1 का यह उपयोग ::tolowerअच्छी तरह से दुर्घटनाग्रस्त हो सकता है, यह गैर-एएससीआईआई इनपुट के लिए यूबी है।
चीयर्स एंड हीथ। - अल्फ

7
यह इंगित करने के लिए कि यह सबसे बाहरी नाम स्थान पर है, :: tolower से पहले जरूरत है। यदि आप इस कोड को किसी अन्य नामस्थान में उपयोग करते हैं, तो टोलवर की एक अलग (संभवतः असंबंधित) परिभाषा हो सकती है जो अंतत: बिना तरजीह के चयनित हो सकती है।
चार्ल्स जूल 30'16

320

बूस्ट इसके लिए एक स्ट्रिंग एल्गोरिथ्म प्रदान करता है :

#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 इनपुट के साथ टोलवर के समान मुद्दों को नहीं मिला है?
पल्म pa

19
गैर-एएससीआईआई -7 के लिए विफल।
देवसोलर

1
क्या इसका कोई गैर-इन-प्लेस संस्करण है?
रे

5
@ रे, हाँ,to_lower_copy
smac89

233

tl; डॉ

ICU लाइब्रेरी का उपयोग करें । यदि आप ऐसा नहीं करते हैं, तो आपका रूपांतरण रूटीन उन मामलों पर चुपचाप टूट जाएगा, जिनके बारे में आप शायद जानते भी नहीं हैं।


क्या है: सबसे पहले आप एक सवाल का जवाब देने के लिए है एन्कोडिंग अपने की std::string? क्या यह ISO-8859-1 है? या शायद ISO-8859-8? या विंडोज कोडपेज 1252? क्या जो भी आप ऊपरी-से-निचले हिस्से में बदलने के लिए उपयोग कर रहे हैं, वह जानते हैं? (या यह पात्रों के लिए बुरी तरह से विफल रहता है 0x7f?)

यदि आप std::stringकंटेनर के रूप में UTF-8 (8-बिट एन्कोडिंग के बीच एकमात्र समझदार विकल्प) का उपयोग कर रहे हैं, तो आप पहले से ही अपने आप को विश्वास में धोखा दे रहे हैं कि आप अभी भी चीजों के नियंत्रण में हैं, क्योंकि आप एक कंटेनर में मल्टीबायट सीक्वेंस स्टोर कर रहे हैं यह मल्टीबाइट अवधारणा के बारे में पता नहीं है। यहां तक ​​कि कुछ के रूप में सरल .substr()एक टिक टाइमबॉम्ब है। (क्योंकि मल्टीबाइट अनुक्रम को विभाजित करने से अमान्य (उप-) स्ट्रिंग हो जाएगा।)

और जैसे ही आप किसी तरह की कोशिश करते हैं std::toupper( 'ß' ), किसी भी एन्कोडिंग में, आप गहरी मुसीबत में हैं। (क्योंकि मानक पुस्तकालय के साथ यह "सही" करना संभव नहीं है, जो केवल एक परिणाम चरित्र प्रदान कर सकता है , "SS"यहां आवश्यक नहीं है।) [1] एक और उदाहरण होगा std::tolower( 'I' ), जिसमें स्थानीय आधार पर अलग-अलग परिणाम प्राप्त होने चाहिए । जर्मनी में, 'i'सही होगा; तुर्की में, 'ı'(LATIN SMALL LETTER DOTLESS I) अपेक्षित परिणाम है (जो, फिर से, UTF-8 एन्कोडिंग में एक से अधिक बाइट है)। फिर भी एक और उदाहरण ग्रीक सिग्मा , अपरकेस '∑', लोअरकेस 'σ'... एक शब्द के अंत को छोड़कर, जहां यह है 'ς'

इसलिए, कोई भी केस रूपांतरण जो एक समय में एक चरित्र पर काम करता है, या इससे भी बदतर, एक बार में एक बाइट , डिजाइन द्वारा टूट जाता है।

फिर यह बिंदु है कि मानक पुस्तकालय, जो यह करने में सक्षम है, उसके आधार पर यह पता लगाया जाता है कि आपके सॉफ्टवेयर पर चलने वाली मशीन पर कौन से स्थान समर्थित हैं ... और यदि यह नहीं है तो आप क्या करते हैं?

तो क्या आप कर रहे हैं वास्तव में की तलाश में एक स्ट्रिंग वर्ग है कि सभी इस के साथ सही ढंग से निपटने में सक्षम है, और वह यह है कि नहीं के किसी भी std::basic_string<>संस्करण

(सी ++ 11 ध्यान दें: std::u16stringऔर std::u32stringकर रहे हैं बेहतर ।, लेकिन अभी भी सही नहीं सी ++ 20 लाया std::u8stringहै, लेकिन इन सब करते एन्कोडिंग निर्दिष्ट है कई अन्य मामलों में वे अभी भी यूनिकोड यांत्रिकी से अनभिज्ञ रहते हैं, सामान्य, मिलान की तरह, ..। ।)

जबकि बूस्ट अच्छा लग रहा है , एपीआई बुद्धिमान, बूस्ट.लोकेल मूल रूप से आईसीयू के आसपास एक आवरण है । अगर बूस्ट को ICU सपोर्ट के साथ संकलित किया जाता है ... यदि यह नहीं है, तो Boost.Locale मानक लाइब्रेरी के लिए संकलित लोकेल सपोर्ट तक सीमित है।

और मेरा विश्वास करो, आईसीयू के साथ संकलन करने के लिए बूस्ट प्राप्त करना कभी-कभी एक वास्तविक दर्द हो सकता है। (विंडोज के लिए कोई पूर्व-संकलित बायनेरिज़ नहीं हैं, इसलिए आपको उन्हें अपने आवेदन के साथ एक साथ आपूर्ति करना होगा, और इससे कीड़े की एक पूरी नई परत खुलती है ...)

इसलिए व्यक्तिगत रूप से मैं घोड़े के मुंह से सीधे यूनिकोड समर्थन प्राप्त करने और सीधे आईसीयू पुस्तकालय का उपयोग करने की सलाह दूंगा :

#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

यह देता है:

ὀδυσσεύς

ध्यान दें कि शब्द के मध्य में that <-> Σ रूपांतरण, और शब्द के अंत में Σ <-> Σ रूपांतरण। कोई भी <algorithm>समाधान आपको दे सकता है।


[१] २०१, में, जर्मन ऑर्थोग्राफी के लिए परिषद ने फैसला किया कि "+" U + 1E9E लेटिन कैपिटल लेटर शाफ़्ट एस को आधिकारिक रूप से इस्तेमाल किया जा सकता है, पासपोर्ट में अस्पष्ट "बचने" के लिए पारंपरिक "एसएस" रूपांतरण के बगल में एक विकल्प के रूप में (जहां नाम पूंजीकृत हैं) )। मेरा सुंदर उदाहरण, समिति के निर्णय से अप्रचलित ...


19
सामान्य मामले में यह सही उत्तर है। झूठ और धोखे को छोड़कर मानक "ASCII" के अलावा कुछ भी संभालने के लिए कुछ भी नहीं देता है। यह आपको लगता है कि आप शायद UTF-16 के साथ सौदा कर सकते हैं, लेकिन आप नहीं कर सकते। जैसा कि यह उत्तर कहता है, आप यूनिकएफ -16 स्ट्रिंग के उचित चरित्र-लंबाई (बाइट-लंबाई नहीं) प्राप्त कर सकते हैं, बिना अपनी यूनिकोड हैंडलिंग के। यदि आपको वास्तविक पाठ से निपटना है, तो ICU का उपयोग करें। धन्यवाद, @DevSolar
सीमित प्रायश्चित

क्या ICU उबंटू / विंडोज पर डिफ़ॉल्ट रूप से उपलब्ध है या अलग से इंस्टॉल करने की आवश्यकता है? इस उत्तर के बारे में भी कैसे: stackoverflow.com/a/35075839/207661 ?
शीतल शाह

1
अरे, देखो, एक असली जवाब! मुझे सही निर्देशन में संकेत देने के लिए धन्यवाद, DevSolar।
दान बेखर जूल

2
@DevSolar सहमत! लंबाई की अवधारणा पाठ पर व्यर्थ है (हम अपराधियों की सूची में जोड़ जोड़ सकते हैं)। कहा कि, जब से लोगों को टैब और एक लंबाई इकाई लेने के चार्ट को नियंत्रित करने के लिए उपयोग किया जाता है, कोड बिंदु अधिक सहज उपाय होंगे। ओह, सही उत्तर देने के लिए धन्यवाद और इसे इतना नीचे देखने के लिए दु: खी:
मास्टर्स

3
@LF मार्जिन बेहतर है। लेकिन इतनी सारी चीजें अभी भी शामिल नहीं हैं: toupperऔर tolowerअभी भी एकल पात्रों पर काम करते हैं। स्ट्रिंग वर्ग में अभी भी सामान्यीकरण की कोई धारणा नहीं है (उदाहरण के लिए कि क्या एक "ü" को "यू विद डाइरेसिस" या "यू + संयोजन डायरिसिस" कहा जाता है) या जहां एक स्ट्रिंग अलग हो सकता है या नहीं हो सकता है। सूची चलती जाती है। u8string (अन्य मानक स्ट्रिंग वर्गों की तरह) "गुजरने" के लिए उपयुक्त है। लेकिन अगर आप यूनिकोड को संसाधित करना चाहते हैं , तो आपको आईसीयू की आवश्यकता है
DevSolar

36

C ++ 11 के लूप के लिए रेंज-आधारित का उपयोग करना एक सरल कोड होगा:

#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 वर्णों को फ्रेंच भाषा में अनुमति नहीं देता है। उदाहरण के लिए एक स्ट्रिंग 'टेस्ट String123। É '\ n' में परिवर्तित कर दिया जाएगा: 'test string123। 'Ï \ n' हालांकि वर्ण É n और उनके निचले मामले के युग्मक 'é' और 'allowed', को फ्रेंच में अनुमति है। ऐसा लगता है कि इसके लिए कोई समाधान इस धागे के अन्य संदेशों द्वारा प्रदान नहीं किया गया था।
incises

मुझे लगता है कि आपको इसके लिए एक उचित स्थान निर्धारित करने की आवश्यकता है।
user1095108

@incises, तब किसी ने आईसीयू के बारे में एक जवाब पोस्ट किया और यह निश्चित रूप से जाने का रास्ता है। अधिकांश अन्य समाधानों की तुलना में आसान है जो लोकेल को समझने का प्रयास करेंगे।
एलेक्सिस विल्के

जब संभव हो, व्यक्तिगत रूप से बाहरी पुस्तकालयों का उपयोग नहीं करना चाहूंगा।
kayleeFrye_onDeck

31

यदि स्ट्रिंग में ASCII रेंज के बाहर UTF-8 वर्ण हैं, तो :: :: एल्गोरिथ्म :: to_lower को बढ़ावा नहीं देगा। जब UTF-8 शामिल हो, तो बेहतर उपयोग को बढ़ावा देना :: लोकेल :: to_lower। Http://www.boost.org/doc/libs/1_51_0/libs/locale/doc/html/conversions.html देखें


15

यह स्टीफन माई की प्रतिक्रिया का अनुवर्ती है: यदि आप रूपांतरण का परिणाम किसी अन्य स्ट्रिंग में रखना चाहते हैं, तो आपको कॉल करने से पहले इसके संग्रहण स्थान को पूर्व-आवंटित करना होगा 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
यह मेरे लिए for में नहीं
बदलता

मैनुअल रिसाइज़ के बजाय यहाँ एक बैक इंसटर इटरेटर का भी उपयोग कर सकते हैं।
मिर्च

11

संदर्भ चर के साथ लूप के लिए सीमा का उपयोग करते हुए एक और दृष्टिकोण

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

cout<<test<<endl;

6

जहां तक ​​मैं देखता हूं कि बूस्ट लाइब्रेरी वास्तव में खराब प्रदर्शन के लिहाज से खराब हैं। मैंने एसटीएल के लिए उनके unordered_map का परीक्षण किया है और यह औसत 3 गुना धीमा था (सबसे अच्छा मामला 2, सबसे खराब 10 बार था)। इसके अलावा यह एल्गोरिथ्म बहुत कम दिखता है।

अंतर इतना बड़ा है कि मुझे यकीन है कि जो कुछ भी इसके अलावा आप के लिए करने की आवश्यकता होगी tolowerयह "अपनी आवश्यकताओं के लिए" बढ़ावा के बराबर बनाने के लिए किया जाएगा जिस तरह से तेजी से बढ़ावा से।

मैंने इन परीक्षणों को अमेजन 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
क्या आपने इसे संकलित करते समय अनुकूलन विकल्प खोले हैं? मुझे लगता है कि एसटीएल भारी बूस्ट लाइब्रेरी को उच्च अनुकूलन स्तर के साथ बेहतर चलना चाहिए।
वी सोंग

1
मैंने एक परीक्षण में -O2 का उपयोग किया, और कुछ नहीं।
इथरेलोन

2
Unordered_map का प्रदर्शन आपके द्वारा उपयोग किए जा रहे डेटा के साथ संयुक्त हैशिंग एल्गोरिथ्म पर निर्भर करता है। एक मैजिक हैशिंग एल्गोरिथ्म नहीं है जो सभी और किसी भी डेटा के लिए जितनी जल्दी हो सके unordered_map बनाने के लिए काम करता है। बेंचमार्क और विभिन्न चीजों का प्रयास करें। आपके द्वारा खराब प्रदर्शन का कारण यह है, क्योंकि आप जिस हैश का उपयोग कर रहे हैं, उससे आपको बहुत सारे टकराव हो रहे हैं, जो मूल रूप से एक सूची में देखने का कारण बनता है। अधिक जानकारी के लिए इस साइट की जाँच करें: fgda.pl/post/7/gcc-hash-map-vs-unordered-map मेरे प्रयोजनों के लिए, लिंक पर दिए गए फ़ंक्शन ने कम टकरावों को प्रदान किया और इस प्रकार बहुत तेज था।
leetNightshade

6

Std namepace के बारे में परेशान किए बिना string को loweercase में बदलने का सबसे सरल तरीका इस प्रकार है

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() )ऑपरेटर के लिए कुछ पसंद करेंगे?
6

एक तार स्ट्रिंग के लिए, हम बस एक स्थानीय प्रतिलिपि बना सकते हैं और फिर इसे जगह में बदल सकते हैं।
समीर

हाँ, हालांकि, एक प्रतिलिपि बनाने से अधिक उपरि जुड़ जाता है।
क्वांर

आप std :: ctype के संस्करण के साथ बदल सकते हैं :: tolower जो पॉइंटर्स नहीं लेता है। एक बैक इटरेटर एडप्टर एडेप्टर का उपयोग करें और आपको अपने आउटपुट स्ट्रिंग को पूर्व-आकार देने के बारे में चिंता करने की आवश्यकता नहीं है।
चिली

महान, विशेष रूप से क्योंकि libstdc ++ tolowerके localeपैरामीटर के साथ , अंतर्निहित कॉल use_facetएक प्रदर्शन अड़चन प्रतीत होती है। मेरे एक सहकर्मी ने boost::iequalsएक संस्करण के साथ कई 100% गति वृद्धि हासिल की है (जिसमें यह समस्या है) एक संस्करण के साथ जहां use_facetकेवल एक बार लूप के बाहर बुलाया जाता है।
अर्ने वोगेल

3

बूस्ट का एक विकल्प POCO (pocoproject.org) है।

पोको दो संस्करण प्रदान करता है:

  1. पहला संस्करण मूल स्ट्रिंग में बदलाव किए बिना एक प्रतिलिपि बनाता है।
  2. दूसरा संस्करण मूल स्ट्रिंग को जगह में बदलता है।
    "प्लेस" संस्करणों में हमेशा "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

यदि परीक्षण किए बिना ऊपरी मामले को निचले में बदलने का एक तरीका है , और यह बहुत सीधा है। Isupper () फ़ंक्शन / मैक्रो का उपयोग clocale.h आपके स्थान से संबंधित समस्याओं का ध्यान रखना चाहिए, लेकिन यदि नहीं, तो आप हमेशा अपने दिल की सामग्री के लिए UtoL [] को ट्विक कर सकते हैं।

यह देखते हुए कि सी के अक्षर वास्तव में सिर्फ 8-बिट इनट्स हैं (पल के लिए विस्तृत वर्ण सेटों को अनदेखा करते हुए) आप वर्णों के वैकल्पिक सेट को पकड़कर एक 256 बाइट सरणी बना सकते हैं, और रूपांतरण फ़ंक्शन में सबस्क्राइबर्स के रूप में आपके स्ट्रिंग में वर्णों का उपयोग करते हैं। रूपांतरण सरणी।

हालांकि, 1-के-लिए -1 मैपिंग के बजाय, ऊपरी-केस सरणी सदस्यों को निम्न-केस वर्णों के लिए BYTE int मान दें। आप यहाँ उपयोगी () और 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;
}

यह दृष्टिकोण, उसी समय, आपको किसी अन्य वर्ण को बदलने की अनुमति देता है जिसे आप बदलना चाहते हैं।

आधुनिक प्रोसेसरों पर चलने के दौरान इस दृष्टिकोण का एक बड़ा फायदा है, शाखा भविष्यवाणी करने की कोई आवश्यकता नहीं है क्योंकि अगर ब्रांचिंग में परीक्षण शामिल नहीं हैं। यह अन्य छोरों के लिए सीपीयू की शाखा भविष्यवाणी तर्क बचाता है, और पाइपलाइन स्टालों को रोकने के लिए जाता है।

यहां कुछ लोग इस दृष्टिकोण को पहचान सकते हैं क्योंकि EBCDIC को ASCII में बदलने के लिए उपयोग किया जाता है।


2
"लुकअप टेबल्स के बारे में कभी सुना है कि परीक्षण किए बिना ऊपरी मामले को लोअर में बदलने का एक तरीका है?"
गेबर बुएला

1
नकारात्मक वर्णों के लिए अपरिभाषित व्यवहार।
रोलैंड इलिग

आधुनिक सीपीयू को स्मृति में नहीं सीपीयू में अड़चन होती है। बेंचमार्किंग दिलचस्प होगा।
कंटेंगो

3

चूंकि किसी भी उत्तर ने आगामी रेंज लाइब्रेरी का उल्लेख नहीं किया है, जो मानक लाइब्रेरी में सी ++ 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> आवश्यक रेंजरों हेडर के ।)

नोट: unsigned charलैम्ब्डा के तर्क के रूप में उपयोग cppreference द्वारा प्रेरित है , जो बताता है:

से अन्य सभी कार्यों की तरह <cctype>, का व्यवहार std::tolowerअपरिभाषित है यदि तर्क का मूल्य न तो प्रतिनिधित्व योग्य है और न unsigned charही बराबर है EOF। प्लेन charएस (या signed charएस) के साथ सुरक्षित रूप से इन कार्यों का उपयोग करने के लिए , तर्क को पहले रूपांतरित किया जाना चाहिए unsigned 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यूटीएफ -16 का समर्थन करने वाले व्यापक पात्रों के लिए उपयोग किया है ।
जुव

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
मैक्रो तकनीक का मतलब है कि किसी चीज़ के लिए कोड का कम टाइपिंग करना, जो आमतौर पर प्रोग्रामिंग में बहुत उपयोग होता है। उसका उपयोग क्यों नहीं किया? नहीं तो मैक्रों आखिर क्यों?
वोलोमाइक

3
मैक्रोज़ सी से एक विरासत हैं जिसे निकालने के लिए कड़ी मेहनत की जा रही है। यदि आप टाइपिंग की मात्रा कम करना चाहते हैं, तो फ़ंक्शन या लंबो का उपयोग करें। void strtoupper(std::string& x) { std::transform (x.begin(), x.end(), x.begin(), ::toupper); }
क्लीयर

1
@ क्लेयर जैसा कि मैं एक बेहतर कोडर बनना चाहता हूं, क्या आप मुझे कोई एएनएसआई डॉक लिंक प्रदान कर सकते हैं, जहां कोई एएनएसआई सी ++ समितियों के प्रभाव के लिए कुछ कहता है, "हमें सी ++ से मैक्रोज़ से छुटकारा पाने के लिए एक बैठक बुलाने की आवश्यकता है"? या कोई और रोडमैप?
Volomike

2
नहीं, मैं नहीं कर सकता। हालांकि कई मौकों पर इस विषय पर बज्ने के रुख को स्पष्ट किया गया है। इसके अलावा, 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. क्या पुस्तकालय उपलब्ध हैं?

एक बार जब आप उन सवालों के जवाब दे देते हैं, तो आप एक ऐसे समाधान की तलाश शुरू कर सकते हैं, जो आपकी आवश्यकताओं के अनुरूप हो। कोई भी एक आकार नहीं है जो सभी के लिए हर जगह काम करता है!


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 (range_declaration:range_expression)loop_statement

  1. range_declaration: auto& c
    यहां ऑटो स्पेसियर का उपयोग स्वचालित प्रकार की कटौती के लिए किया जाता है। तो प्रकार वैरिएबल इनिशियलाइज़र से काटा जाता है।

  2. range_expression: test
    इस मामले में रेंज स्ट्रिंग के अक्षर हैं test

स्ट्रिंग के अक्षर testपहचानकर्ता के माध्यम से लूप के अंदर एक संदर्भ के रूप में उपलब्ध हैं c


कृपया स्पष्ट करें कि आपने अपना उत्तर कहां से कॉपी किया है।
bfontaine

0

C ++ में स्ट्रिंग के लिए टोलॉवर या टौपर विधियाँ नहीं हैं, लेकिन यह चार के लिए उपलब्ध है। स्ट्रिंग के प्रत्येक चार्ट को आसानी से पढ़ सकते हैं, इसे आवश्यक मामले में बदल सकते हैं और इसे वापस स्ट्रिंग में डाल सकते हैं। किसी तीसरे पक्ष के पुस्तकालय का उपयोग किए बिना एक नमूना कोड:

#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 :: ट्रांस्फ़ॉर्म की कोशिश की, सब मुझे मिलता है घिनौना stl criptic संकलन त्रुटि है जो केवल 200 साल पहले से druids समझ सकते हैं (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;
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.