ฉันต้องการแปลง a เป็นstd::string
ตัวพิมพ์เล็ก ฉันรู้ถึงฟังก์ชั่นtolower()
นี้ แต่ในอดีตที่ฉันเคยมีปัญหากับฟังก์ชั่นนี้และมันก็แทบจะไม่เหมาะอย่างยิ่งถ้าใช้กับ a std::string
จะต้องวนซ้ำตัวละครแต่ละตัว
มีทางเลือกอื่นที่ใช้งานได้ 100% หรือไม่
ฉันต้องการแปลง a เป็นstd::string
ตัวพิมพ์เล็ก ฉันรู้ถึงฟังก์ชั่นtolower()
นี้ แต่ในอดีตที่ฉันเคยมีปัญหากับฟังก์ชั่นนี้และมันก็แทบจะไม่เหมาะอย่างยิ่งถ้าใช้กับ a std::string
จะต้องวนซ้ำตัวละครแต่ละตัว
มีทางเลือกอื่นที่ใช้งานได้ 100% หรือไม่
คำตอบ:
ที่ดัดแปลงมาจากคำถามที่พบไม่บ่อย :
#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()
สามารถทำการทดแทนอักขระต่อไบต์เดียวซึ่งไม่เหมาะสมสำหรับสคริปต์จำนวนมากโดยเฉพาะอย่างยิ่งหากใช้การเข้ารหัสหลายไบต์เช่น UTF-8
char
ไป::tolower(int)
.) คุณต้องให้แน่ใจว่าคุณไม่ผ่านค่าลบ
::tolower
อาจผิดพลาดเป็น UB สำหรับอินพุตที่ไม่ใช่ ASCII
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);
to_lower_copy
TL; DR
ใช้ห้องสมุดห้องไอซียู หากคุณไม่ทำขั้นตอนการแปลงของคุณจะหยุดลงอย่างเงียบ ๆ ในบางกรณีที่คุณอาจไม่ทราบด้วยซ้ำว่ามีอยู่จริง
ก่อนอื่นคุณต้องตอบคำถาม: การเข้ารหัสของคุณstd::string
คืออะไร? เป็น ISO-8859-1 หรือไม่ หรือบางที ISO-8859-8 หรือ Windows Codepage 1252 สิ่งที่คุณใช้ในการแปลงบนเป็นตัวเล็กรู้หรือไม่ (หรือมันล้มเหลวอย่างน่าสมเพชสำหรับตัวละครมากกว่า0x7f
?)
หากคุณใช้ UTF-8 (ตัวเลือกที่มีเหตุผลเพียงอย่างเดียวในการเข้ารหัส 8 บิต) พร้อมกับstd::string
คอนเทนเนอร์คุณกำลังหลอกตัวเองให้เชื่อว่าคุณยังควบคุมสิ่งต่าง ๆ ได้เนื่องจากคุณกำลังเก็บลำดับอักขระหลายไบต์ในคอนเทนเนอร์ ที่ไม่ทราบถึงแนวคิดของมัลติไบต์ แม้แต่บางสิ่งที่เรียบง่ายเช่นเดียวกับ.substr()
ช่วงเวลาที่ฟ้องร้อง (เนื่องจากการแยกลำดับหลายไบต์จะส่งผลให้เกิดสตริงที่ไม่ถูกต้อง (sub-))
และเร็วที่สุดเท่าที่คุณจะลองสิ่งที่ต้องการstd::toupper( 'ß' )
ในใด ๆเข้ารหัสคุณอยู่ในปัญหาลึก (เพราะมันก็ไม่ได้ที่จะทำเช่นนี้ "สิทธิ" กับห้องสมุดมาตรฐานซึ่งสามารถส่งมอบหนึ่งในตัวละครที่ผลไม่"SS"
จำเป็นที่นี่.) [1] อีกตัวอย่างหนึ่งจะstd::tolower( 'I' )
ซึ่งจะให้ผลลัพธ์ที่แตกต่างกันขึ้นอยู่กับสถานที่เกิดเหตุ ในประเทศเยอรมนี'i'
จะถูกต้อง; ในตุรกี'ı'
(LATIN เล็กตัวอักษร DOTLESS I) เป็นผลลัพธ์ที่คาดหวัง (ซึ่งอีกครั้งคือมากกว่าหนึ่งไบต์ในการเข้ารหัส UTF-8) อีกตัวอย่างหนึ่งคือกรีกSigma , พิมพ์ใหญ่'∑'
พิมพ์เล็ก'σ'
... 'ς'
ยกเว้นตอนท้ายของคำที่ว่ามันอยู่ที่ไหน
ดังนั้นการแปลงกรณีใด ๆที่ทำงานกับตัวละครในแต่ละครั้งหรือแย่กว่านั้นเป็นไบต์ในแต่ละครั้งจะถูกทำลายโดยการออกแบบ
จากนั้นก็มีจุดที่ห้องสมุดมาตรฐานสำหรับสิ่งที่มันเป็นความสามารถในการทำขึ้นอยู่กับสถานที่ซึ่งได้รับการสนับสนุนบนเครื่องซอฟต์แวร์ของคุณกำลังทำงานอยู่บน ... และสิ่งที่คุณทำถ้ามันไม่ได้?
ดังนั้นสิ่งที่คุณกำลังจริงๆมองหาเป็นชั้นสตริงที่มีความสามารถในการจัดการกับทั้งหมดนี้ได้อย่างถูกต้องและนั่นคือไม่ได้ใด ๆ ของstd::basic_string<>
สายพันธุ์
(หมายเหตุ C ++ 11: std::u16string
และstd::u32string
ยังดีกว่าแต่ก็ยังไม่สมบูรณ์แบบ C ++ 20 ที่นำมาstd::u8string
แต่สิ่งเหล่านี้จะระบุการเข้ารหัสในส่วนอื่น ๆ อีกมากมายพวกเขายังคงหลงลืมกลไก Unicode เช่นการปรับมาตรฐานการเรียงใหม่ .. .)
ในขณะที่การเพิ่มลักษณะดี API ฉลาด Boost.Locale เป็นพื้นห่อหุ้มรอบห้องไอซียู ถ้า Boost ถูกคอมไพล์ด้วยการสนับสนุน ICU ... หากไม่ได้บูสต์ Boost.Locale จะถูก จำกัด เฉพาะการสนับสนุนโลแคลที่รวบรวมไว้สำหรับไลบรารีมาตรฐาน
และเชื่อฉันเถอะการได้รับ Boost เพื่อคอมไพล์ด้วย 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
สิ่งนี้ให้:
ὀδυσσεύς
โปรดทราบว่าการแปลงΣ <-> σอยู่ตรงกลางของคำและการแปลงΣ <-> at ที่ท้ายคำ <algorithm>
วิธีการแก้ปัญหาที่ไม่มีพื้นฐานสามารถให้คุณได้ว่า
[1] ในปี 2560 สภาการันต์เยอรมันได้ตัดสินว่า "ẞ" U + 1E9E LATIN CAPT LATTER SHARP S สามารถใช้งานได้อย่างเป็นทางการเป็นตัวเลือกข้างการแปลง "SS" แบบดั้งเดิมเพื่อหลีกเลี่ยงความคลุมเครือเช่นในหนังสือเดินทาง ) ตัวอย่างที่สวยงามของฉันทำให้ล้าสมัยจากการตัดสินใจของคณะกรรมการ ...
toupper
และtolower
ยังสามารถใช้อักขระเดี่ยวได้ คลาสสตริงยังคงไม่มีความคิดในการทำให้เป็นมาตรฐาน (เช่นว่า "ü" ถูกเข้ารหัสเป็น "u กับ diaeresis" หรือ "u + รวม diaeresis") หรือที่สตริงอาจหรือไม่อาจถูกแยกออก รายการดำเนินต่อไป u8string เป็น (เช่นคลาสสตริงมาตรฐานอื่น ๆ ) ที่เหมาะสมสำหรับ "การผ่าน" แต่ถ้าคุณต้องการประมวลผล Unicode คุณต้อง ICU
การใช้ range-based สำหรับ loop ของ 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);
}
หากสตริงมีอักขระ UTF-8 นอกช่วง ASCII ดังนั้นการเพิ่ม :: algorithm :: to_lower จะไม่แปลง เพิ่มการใช้งานที่ดีขึ้น :: locale :: to_lower เมื่อเกี่ยวข้องกับ UTF-8 ดูhttp://www.boost.org/doc/libs/1_51_0/libs/locale/doc/html/conversions.html
นี่คือการติดตามเพื่อตอบสนองต่อสเตฟานเชียงใหม่: 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;
}
อีกวิธีหนึ่งที่ใช้ช่วงสำหรับลูปพร้อมตัวแปรอ้างอิง
string test = "Hello World";
for(auto& c : test)
{
c = tolower(c);
}
cout<<test<<endl;
เท่าที่ฉันเห็นห้องสมุด 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 นี้ดังนั้นฉันไม่จำเป็นต้องทดสอบกับเครื่องของฉัน
วิธีที่ง่ายที่สุดในการแปลงสตริงให้เป็น loweercase โดยไม่ต้องกังวลเกี่ยวกับ std namespace มีดังนี้
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;
}
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() )
สำหรับผู้ประกอบการหรือไม่
tolower
มีlocale
พารามิเตอร์การโทรโดยนัยที่use_facet
ปรากฏเป็นคอขวดของประสิทธิภาพ หนึ่งในเพื่อนร่วมงานของฉันได้รับความเร็วเพิ่มขึ้น 100% โดยการแทนที่boost::iequals
(ซึ่งมีปัญหานี้) ด้วยรุ่นที่use_facet
มีการเรียกเพียงครั้งเดียวนอกวง
อีกทางเลือกหนึ่งสำหรับ Boost คือ POCO (pocoproject.org)
POCO มีสองรูปแบบ:
ทั้งสองรุ่นแสดงให้เห็นด้านล่าง:
#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);
มีวิธีการแปลงตัวพิมพ์ใหญ่เพื่อลดโดยไม่ต้องทำถ้าการทดสอบและมันค่อนข้างตรงไปข้างหน้า isupper () ฟังก์ชั่น / มาโครการใช้ clocale.h ควรดูแลปัญหาที่เกี่ยวข้องกับตำแหน่งของคุณ แต่ถ้าไม่คุณสามารถปรับแต่ง UtoL [] กับเนื้อหาในหัวใจของคุณ
เนื่องจากอักขระของ C นั้นเป็น ints 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;
}
วิธีการนี้จะช่วยให้คุณสามารถทำการแมปตัวละครอื่น ๆ ที่คุณต้องการเปลี่ยนแปลงได้ในเวลาเดียวกัน
วิธีการนี้มีข้อดีอย่างมากเมื่อใช้กับโปรเซสเซอร์ที่ทันสมัยไม่จำเป็นต้องทำการคาดการณ์สาขาเนื่องจากไม่มีการทดสอบหากประกอบไปด้วยการแยกสาขา สิ่งนี้จะช่วยประหยัดตรรกะการคาดคะเนสาขาของ CPU สำหรับลูปอื่น ๆ และมีแนวโน้มที่จะป้องกันไม่ให้แผงลอยไปป์ไลน์
บางคนที่นี่อาจรู้จักวิธีนี้เหมือนกับวิธีที่ใช้ในการแปลง EBCDIC เป็น ASCII
เนื่องจากไม่มีคำตอบที่กล่าวถึงไลบรารี Ranges ที่กำลังจะมาซึ่งมีอยู่ในไลบรารี่มาตรฐานตั้งแต่ 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
จะไม่ได้กำหนดถ้าค่าอาร์กิวเมนต์คือที่แทนค่าเป็นมิได้เท่ากับunsigned char
EOF
ในการใช้ฟังก์ชั่นเหล่านี้อย่างปลอดภัยด้วยchar
s (signed char
) อาร์กิวเมนต์ควรถูกแปลงเป็นunsigned char
:char my_tolower(char ch) { return static_cast<char>(std::tolower(static_cast<unsigned char>(ch))); }
ในทำนองเดียวกันพวกเขาไม่ควรนำมาใช้โดยตรงกับขั้นตอนวิธีมาตรฐานเมื่อประเภทค่า iterator คือหรือ
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; }
ฟังก์ชั่นเทมเพลตของฉันเองที่ใช้ตัวพิมพ์เล็ก / ใหญ่
#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
นี่เป็นเทคนิคมาโครหากคุณต้องการอะไรที่เรียบง่าย:
#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
void strtoupper(std::string& x) { std::transform (x.begin(), x.end(), x.begin(), ::toupper); }
x
อาจเป็นนิพจน์ที่ถูกต้องซึ่งเกิดขึ้นกับการคอมไพล์อย่างถูกต้อง แต่จะให้ผลลัพธ์ที่สมบูรณ์โดยสมบูรณ์เนื่องจากมาโคร
// 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/
มีทางเลือกอื่นที่ใช้งานได้ 100% หรือไม่
ไม่
มีคำถามหลายข้อที่คุณต้องถามตัวเองก่อนเลือกวิธีลดขนาด
เมื่อคุณมีคำตอบสำหรับคำถามเหล่านั้นคุณสามารถเริ่มมองหาคำตอบที่เหมาะกับความต้องการของคุณ ไม่มีขนาดที่เหมาะกับทุกสิ่งที่เหมาะกับทุกคนในทุกที่!
ลองใช้ฟังก์ชั่นนี้ :)
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;
}
บนแพลตฟอร์ม 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 );
}
#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;
}
ใช้ fplus :: to_lower_case ()
(fplus: https://github.com/Dobiasd/FunctionalPlus https://github.com/Dobiasd/FunctionalPlus
ค้นหา 'to_lower_case' ในhttp://www.editgym.com/fplus-api-search/ )
fplus::to_lower_case(std::string("ABC")) == std::string("abc");
คัดลอกเพราะไม่ได้รับอนุญาตให้ปรับปรุงคำตอบ ขอบคุณมาก
string test = "Hello World";
for(auto& c : test)
{
c = tolower(c);
}
คำอธิบาย:
for(auto& c : test)
เป็นช่วงสำหรับวงวนชนิด:
for (
range_declaration
:
range_expression
)
loop_statement
range_declaration
: ที่auto& c
นี่ตัวระบุอัตโนมัติใช้สำหรับการหักประเภทอัตโนมัติ ดังนั้นประเภทจะถูกหักออกจากตัวแปรเริ่มต้น
range_expression
: ช่วงในกรณีนี้มีตัวอักษรของสตริงtest
test
ตัวละครของสตริงที่มีอยู่เป็นข้อมูลอ้างอิงภายในสำหรับห่วงผ่านตัวระบุtest
c
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;
}
สำหรับการดำเนินการตามอักขระบนสตริง: สำหรับอักขระทุกตัวในสตริง
นี่อาจเป็นอีกเวอร์ชั่นที่ง่ายในการแปลงตัวพิมพ์ใหญ่เป็นตัวพิมพ์เล็กและในทางกลับกัน ฉันใช้ 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;
}
หมายเหตุ: หากมีอักขระพิเศษคุณจะต้องจัดการโดยใช้การตรวจสอบสภาพ
ฉันพยายาม std :: transform ทั้งหมดที่ฉันได้รับคือข้อผิดพลาดในการรวบรวม stl criptic ที่น่ารังเกียจที่ดรูอิดเมื่อ 200 ปีก่อนเท่านั้นที่สามารถเข้าใจได้ (ไม่สามารถแปลงจากเป็น flibidi flabidi ไข้หวัดใหญ่)
ใช้งานได้ดีและสามารถปรับแต่งได้อย่างง่ายดาย
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;
}