แปลงสตริงใน C ++ เป็นตัวพิมพ์ใหญ่


268

วิธีหนึ่งสามารถแปลงสตริงเป็นตัวพิมพ์ใหญ่ ตัวอย่างที่ฉันพบจาก googling มีเพียงการจัดการกับตัวอักษร

คำตอบ:


205

เพิ่มอัลกอริธึมสตริง:

#include <boost/algorithm/string.hpp>
#include <string>

std::string str = "Hello World";

boost::to_upper(str);

std::string newstr = boost::to_upper_copy<std::string>("Hello World");

5
สิ่งนี้ยังมีประโยชน์ของ i18n ซึ่ง::toupperเป็นไปได้มากที่สุดที่จะสมมติว่า ASCII
Ben Straub

4
บรรทัดสุดท้ายของคุณไม่ได้คอมไพล์ - คุณต้องเปลี่ยนเป็นดังนี้:std::string newstr(boost::to_upper_copy<std::string>("Hello World"));
maxschlepzig

58
สิ่งนี้ไม่ควรเป็นคำตอบที่ยอมรับได้เนื่องจากต้องการการเพิ่มหรือควรเปลี่ยนชื่อ
Andrea

44
ใช่ฉันกำลังจะติดตั้งบูสต์สำหรับ to_upper ... ความคิดที่ยอดเยี่ยม! </ ถากถาง> :)
Thang

12
ฉันเป็นการส่วนตัวที่ไม่ดีต่อการส่งเสริมว่าเป็นคำตอบของ "ฉันจะทำxใน C ++ ได้อย่างไร" เพราะบูสต์ไม่ใช่โซลูชันที่มีน้ำหนักเบาเลย ดูเหมือนว่าคุณจะซื้อเพื่อเพิ่มเป็นกรอบ (หรือ ACE หรือ Qt หรือ Recusion ToolKit ++ หรือ ... ) หรือคุณไม่ ฉันต้องการดูโซลูชันภาษา
jwm

486
#include <algorithm>
#include <string>

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

8
จริงๆแล้วtoupper()สามารถนำมาใช้เป็นมาโครได้ นี่อาจทำให้เกิดปัญหา
dirkgently

3
การผูก (:: toupper, สร้าง <char ที่ไม่ได้ลงชื่อ> (_ 1)) ด้วย boost.lambda จะทำหน้าที่ได้อย่างสมบูรณ์แบบฉันคิดว่า
Johannes Schaub - litb

11
วิธีการนี้ใช้งานได้ดีสำหรับ ASCII แต่ล้มเหลวในการเข้ารหัสอักขระแบบหลายไบต์หรือสำหรับกฎตัวเรือนพิเศษเช่น German 'ß'
dan04

9
ฉันเปลี่ยนคำตอบที่ยอมรับเป็นคำสั่งโดยใช้ห้องสมุดเพิ่มเพราะมันเร็วกว่า (ในการทดสอบแบบไม่เป็นทางการ) ใช้งานง่ายกว่าและไม่มีปัญหาที่เกี่ยวข้องกับวิธีแก้ปัญหานี้ ยังเป็นวิธีแก้ปัญหาที่ดีสำหรับกรณีที่ไม่สามารถเพิ่มการใช้งานได้
OrangeAlmondSoap

2
ฉันไม่สามารถรับทำไมคอมไพเลอร์ปฏิเสธรหัสนี้โดย :: toupperรอบคัดเลือกก่อน ความคิดใด ๆ
sasha.sochka

89

วิธีแก้ปัญหาแบบสั้นโดยใช้ C ++ 11 และ toupper ()

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

จะไม่cเป็นconst charประเภท (จากauto) ถ้าเป็นเช่นนั้นคุณจะไม่สามารถกำหนด (เพราะconstบางส่วน) toupper(c)กับสิ่งที่ถูกส่งกลับโดย
PolGraphic

5
@PolGraphic: Range - ใช้สำหรับเมธอด start () / end () ของคอนเทนเนอร์เพื่อวนซ้ำเนื้อหา std :: basic_string มีทั้งตัวแปลงและตัววนซ้ำไม่แน่นอน (ส่งกลับโดย cbegin () และเริ่มต้น () ตามลำดับดูstd :: basic_string :: เริ่มต้น ) ดังนั้น (:) ใช้อันที่เหมาะสม (cbegin () ถ้า str คือ ประกาศ const พร้อมกับ auto =: = const char เริ่มต้น () มิฉะนั้นด้วย auto =: = ถ่าน)
Thanasis Papoutsidakis

5
ดูเซอร์เซิร์ฟของ dirkgently ด้านล่าง, cต้องทำการ cast เพื่อunsigned charให้ corred นี้
Cris Luengo

boost's to_upper () ดูเหมือนจะสอดคล้องกับฟังก์ชั่น c ++ STL มากกว่า toupper
tartaruga_casco_mole

29
struct convert {
   void operator()(char& c) { c = toupper((unsigned char)c); }
};

// ... 
string uc_str;
for_each(uc_str.begin(), uc_str.end(), convert());

หมายเหตุ:สองสามปัญหาเกี่ยวกับวิธีแก้ปัญหายอดนิยม:

21.5 ยูทิลิตี้ลำดับต่อเนื่องที่สิ้นสุดลง

เนื้อหาของส่วนหัวเหล่านี้จะเหมือนกับส่วนหัวของ Standard C Library <ctype.h>, <wctype.h>, <string.h>, <wchar.h> และ <stdlib.h> [... ]

  • ซึ่งหมายความว่าcctypeสมาชิกอาจเป็นมาโครที่ไม่เหมาะสำหรับการบริโภคโดยตรงในอัลกอริทึมมาตรฐาน

  • อีกปัญหาหนึ่งที่มีตัวอย่างเดียวกันคือมันไม่ได้ทำการโต้แย้งหรือตรวจสอบว่านี่ไม่ใช่เชิงลบ สิ่งนี้เป็นอันตรายอย่างยิ่งสำหรับระบบที่charลงชื่อแบบธรรมดา (เหตุผลคือ: หากสิ่งนี้ถูกนำมาใช้เป็นมาโครอาจจะใช้ตารางการค้นหาและดัชนีอาร์กิวเมนต์ของคุณลงในตารางนั้นดัชนีเชิงลบจะให้ UB แก่คุณ)


สมาชิก cctype ปกติคือมาโคร ฉันจำได้ว่าการอ่านมันต้องมีฟังก์ชั่นด้วยแม้ว่าฉันจะไม่มีสำเนาของมาตรฐาน C90 และไม่รู้ว่ามันระบุไว้อย่างชัดเจนหรือไม่
David Thornley

1
พวกเขาจะต้องมีฟังก์ชั่นใน C ++ - แม้ว่า C อนุญาตให้เป็นมาโคร ฉันเห็นด้วยกับประเด็นที่สองของคุณเกี่ยวกับการคัดเลือกนักแสดง โซลูชันอันดับต้น ๆ สามารถส่งผ่านค่าลบและทำให้เกิด UB ได้ นั่นคือเหตุผลที่ฉันไม่ได้ลงคะแนน (แต่ฉันไม่ได้ลงคะแนนด้วยเช่นกัน) :)
344902 Johannes Schaub - litb

1
คำพูดมาตรฐานจะต้องไม่หายไป: 7.4.2.2/1 (litb ที่ไม่ดีนั่นคือการอ้างอิงแบบร่าง C99 TC2 เท่านั้น) และ C ++ 17.4.1.2/6 ในมาตรฐานความรุ่งโรจน์ c ++ 98
Johannes Schaub - litb

1
(โปรดทราบว่า foot-note: "สิ่งนี้ไม่อนุญาตให้ใช้ร่วมกับมาสก์ที่ปิดบัง .... blah blupp .. วิธีเดียวที่จะทำได้ใน C ++ คือการจัดหาฟังก์ชั่นอินไลน์ภายนอก") :)
Johannes Schaub - litb

1
... ที่ทำได้โดยการใช้เล่ห์เหลี่ยมนี้: stackoverflow.com/questions/650461/…
Johannes Schaub - litb

27

ปัญหานี้สามารถเวกเตอร์ได้ด้วย SIMDสำหรับชุดอักขระ ASCII


การเปรียบเทียบความเร็ว:

การทดสอบเบื้องต้นด้วย x86-64 gcc 5.2 -O3 -march=nativeบน Core2Duo (Merom) สตริงเดียวกันของอักขระ 120 ตัว (ตัวพิมพ์เล็กผสมและ ASCII ไม่ใช่ตัวพิมพ์เล็ก), แปลงเป็นลูป 40M ครั้ง (โดยไม่มีการอินไลน์ cross-file ดังนั้นคอมไพเลอร์ไม่สามารถปรับให้เหมาะสมหรือยกออกจากลูปได้) บัฟเฟอร์ต้นทางและปลายทางเดียวกันดังนั้นจึงไม่มีโอเวอร์เฮดของ Malloc หรือเอฟเฟกต์หน่วยความจำ / แคช: ข้อมูลมีความร้อนในแคช L1 ตลอดเวลาและเราใช้ CPU ล้วนๆ

  • boost::to_upper_copy<char*, std::string>(): 198.0s ใช่ Boost 1.58 บน Ubuntu 15.10 ช้ามาก ฉันทำประวัติและก้าว asm ใน debugger และมันก็แย่จริงๆ : มี dynamic_cast ของตัวแปร locale ที่เกิดขึ้นต่อตัวละคร !!! (dynamic_cast ใช้การเรียกหลายครั้งไปยัง strcmp) สิ่งนี้เกิดขึ้นกับLANG=Cและด้วยLANG=en_CA.UTF-8และมีการ

    ฉันไม่ได้ทดสอบการใช้ RangeT อื่นนอกเหนือจาก std :: string บางทีรูปแบบอื่นของการto_upper_copyเพิ่มประสิทธิภาพที่ดีขึ้น แต่ฉันคิดว่ามันจะnew/ mallocพื้นที่สำหรับคัดลอกเสมอจึงยากที่จะทดสอบ บางทีสิ่งที่ฉันทำแตกต่างจากกรณีการใช้งานปกติและบางทีการหยุด g ++ สามารถยกการตั้งค่าโลแคลออกจากลูปต่ออักขระได้ ลูปของฉันอ่านจากstd::stringและเขียนไปยังchar dstbuf[4096]เหมาะสมสำหรับการทดสอบ

  • การเรียกลูป glibc toupper: 6.67s (ไม่ได้ตรวจสอบintผลลัพธ์สำหรับ UTF-8 หลายไบต์ที่เป็นไปได้ แต่สิ่งนี้สำคัญสำหรับตุรกี)

  • ASCII-only loop: 8.79s (เวอร์ชันพื้นฐานของฉันสำหรับผลลัพธ์ด้านล่าง) เห็นได้ชัดว่าการค้นหาตารางเร็วกว่าcmovโดยที่ตารางนั้นร้อนใน L1 อยู่ดี
  • ASCII-only auto-vectorized: 2.51s 2.51s(120 ตัวอักษรเป็นครึ่งทางระหว่างกรณีที่เลวร้ายที่สุดและกรณีที่ดีที่สุดดูด้านล่าง)
  • ASCII-vectorized ด้วยตนเองเท่านั้น: 1.35s

ดูคำถามนี้เกี่ยวกับtoupper()การช้าบน Windows เมื่อมีการตั้งค่าภาษา


ฉันตกใจที่ Boost เป็นลำดับความสำคัญช้ากว่าตัวเลือกอื่น ๆ ฉันตรวจสอบอีกครั้งว่าฉัน-O3เปิดใช้งานแล้วและแม้แต่ asm ก็ก้าวเดียวเพื่อดูว่ามันกำลังทำอะไรอยู่ มันเกือบจะเหมือนกับความเร็วด้วย clang ++ 3.8 มันมีค่าใช้จ่ายมากในวงต่อตัวละคร perf record/ reportผล (สำหรับcyclesเหตุการณ์ perf) เป็น:

  32.87%  flipcase-clang-  libstdc++.so.6.0.21   [.] _ZNK10__cxxabiv121__vmi_class_type_info12__do_dyncastElNS_17__class_type_info10__sub_kindEPKS1_PKvS4_S6_RNS1_16
  21.90%  flipcase-clang-  libstdc++.so.6.0.21   [.] __dynamic_cast                                                                                                 
  16.06%  flipcase-clang-  libc-2.21.so          [.] __GI___strcmp_ssse3                                                                                            
   8.16%  flipcase-clang-  libstdc++.so.6.0.21   [.] _ZSt9use_facetISt5ctypeIcEERKT_RKSt6locale                                                                     
   7.84%  flipcase-clang-  flipcase-clang-boost  [.] _Z16strtoupper_boostPcRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE                                   
   2.20%  flipcase-clang-  libstdc++.so.6.0.21   [.] strcmp@plt                                                                                                     
   2.15%  flipcase-clang-  libstdc++.so.6.0.21   [.] __dynamic_cast@plt                                                                                             
   2.14%  flipcase-clang-  libstdc++.so.6.0.21   [.] _ZNKSt6locale2id5_M_idEv                                                                                       
   2.11%  flipcase-clang-  libstdc++.so.6.0.21   [.] _ZNKSt6locale2id5_M_idEv@plt                                                                                   
   2.08%  flipcase-clang-  libstdc++.so.6.0.21   [.] _ZNKSt5ctypeIcE10do_toupperEc                                                                                  
   2.03%  flipcase-clang-  flipcase-clang-boost  [.] _ZSt9use_facetISt5ctypeIcEERKT_RKSt6locale@plt                                                                 
   0.08% ...

Autovectorization

Gcc และ clang จะทำการวนซ้ำอัตโนมัติเวกเตอร์เมื่อทราบจำนวนการวนซ้ำก่อนลูป (นั่นคือลูปการค้นหาเช่นการใช้ C ธรรมดาstrlenจะไม่ทำให้เป็นอัตโนมัติ)

ดังนั้นสำหรับสตริงที่มีขนาดเล็กพอที่จะใส่ในแคชเราจะได้รับการเร่งความเร็วอย่างมีนัยสำคัญสำหรับสตริง ~ 128 ตัวอักษรให้ยาวstrlenก่อน สิ่งนี้ไม่จำเป็นสำหรับสตริงที่มีความยาวอย่างชัดเจน (เช่น C ++ std::string)

// char, not int, is essential: otherwise gcc unpacks to vectors of int!  Huge slowdown.
char ascii_toupper_char(char c) {
    return ('a' <= c && c <= 'z') ? c^0x20 : c;    // ^ autovectorizes to PXOR: runs on more ports than paddb
}

// gcc can only auto-vectorize loops when the number of iterations is known before the first iteration.  strlen gives us that
size_t strtoupper_autovec(char *dst, const char *src) {
    size_t len = strlen(src);
    for (size_t i=0 ; i<len ; ++i) {
        dst[i] = ascii_toupper_char(src[i]);  // gcc does the vector range check with psubusb / pcmpeqb instead of pcmpgtb
    }
    return len;
}

libc ที่เหมาะสมจะมีประสิทธิภาพstrlenที่เร็วกว่าการวนลูปทีละครั้งดังนั้นการแยกเวกเตอร์ strlen และลูปลูปให้เร็วขึ้น

Baseline: การวนซ้ำที่ตรวจสอบการยกเลิก 0 ในทันที

คูณ 40M ซ้ำบน Core2 (Merom) 2.4GHz GCC -O3 -march=native5.2 (Ubuntu 15.10) dst != src(ดังนั้นเราจึงทำสำเนา) แต่จะไม่ทับซ้อนกัน (และไม่ใกล้เคียง) ทั้งสองอยู่ในแนวเดียวกัน

  • 15 อักขระสตริง: พื้นฐาน: 1.08s autovec: 1.34 วินาที
  • 16 ถ่านสตริง: พื้นฐาน: 1.16s autovec: 1.52 วินาที
  • 127 อักขระสตริง: พื้นฐาน: 8.91s autovec: 2.98s // การล้างข้อมูลที่ไม่ใช่เวกเตอร์มี 15 ตัวประมวลผล
  • 128 อักขระสตริง: พื้นฐาน: 9.00s autovec: 2.06 วินาที
  • 129 อักขระสตริง: พื้นฐาน: 9.04s autovec: 2.07s // การล้างข้อมูลที่ไม่ใช่เวกเตอร์มี 1 อักขระที่ต้องดำเนินการ

ผลลัพธ์บางอย่างมีความแตกต่างเล็กน้อยกับเสียงดังกราว

ลูป microbenchmark ที่เรียกใช้ฟังก์ชันอยู่ในไฟล์แยกต่างหาก ไม่เช่นนั้นจะอินไลน์และstrlen()ดึงออกจากลูปและจะทำงานเร็วขึ้นอย่างมากโดยเฉพาะ สำหรับ 16 อักขระสตริง (0.187s)

นี่เป็นข้อได้เปรียบที่สำคัญที่ gcc สามารถทำให้เป็นเวกเตอร์อัตโนมัติสำหรับสถาปัตยกรรมใด ๆ ก็ได้ แต่ข้อเสียเปรียบหลักที่ทำให้ช้าลงสำหรับกรณีที่พบบ่อยของสตริงขนาดเล็ก


ดังนั้นการเร่งความเร็วครั้งยิ่งใหญ่ แต่คอมไพเลอร์อัตโนมัติ - การทำให้เป็นเวกเตอร์ไม่ได้สร้างโค้ดที่ดี สำหรับการล้างข้อมูลอักขระสูงสุดถึง 15 ตัวสุดท้าย

vectorization แบบแมนนวลที่มี SSE ภายใน:

ขึ้นอยู่กับฟังก์ชั่นตัวพิมพ์ใหญ่ - เล็กของฉันที่พลิกกรณีของตัวอักษรทุกตัว มันต้องใช้ประโยชน์จาก "เคล็ดลับเปรียบเทียบไม่ได้ลงนาม" ซึ่งคุณสามารถทำได้low < a && a <= highด้วยการเปรียบเทียบที่ไม่ได้ลงชื่อเดียวโดยช่วงการขยับเพื่อให้ค่าใด ๆ ที่น้อยกว่าการตัดค่าที่เป็นมากกว่าlow high(ใช้งานได้หากlowและhighอยู่ไม่ห่างกัน)

SSE มีเพียงการเปรียบเทียบที่ได้รับการลงนามแล้วเท่านั้น แต่เรายังคงสามารถใช้เคล็ดลับ "การเปรียบเทียบที่ไม่ได้ลงชื่อ" โดยการเลื่อนช่วงไปทางด้านล่างของช่วงที่เซ็นชื่อ: ลบ 'a' + 128 ดังนั้นอักขระที่เป็นตัวอักษรจะอยู่ในช่วง -128 ถึง -128 +25 (-128 + 'z' - 'a')

โปรดทราบว่าการเพิ่ม 128 และการลบ 128 เป็นสิ่งเดียวกันสำหรับจำนวนเต็ม 8 บิต ไม่มีที่ใดที่จะนำติดตัวไปได้ดังนั้นจึงเป็นเพียงแค่แฮคเกอร์

#include <immintrin.h>

__m128i upcase_si128(__m128i src) {
    // The above 2 paragraphs were comments here
    __m128i rangeshift = _mm_sub_epi8(src, _mm_set1_epi8('a'+128));
    __m128i nomodify   = _mm_cmpgt_epi8(rangeshift, _mm_set1_epi8(-128 + 25));  // 0:lower case   -1:anything else (upper case or non-alphabetic).  25 = 'z' - 'a'

    __m128i flip  = _mm_andnot_si128(nomodify, _mm_set1_epi8(0x20));            // 0x20:lcase    0:non-lcase

    // just mask the XOR-mask so elements are XORed with 0 instead of 0x20
    return          _mm_xor_si128(src, flip);
    // it's easier to xor with 0x20 or 0 than to AND with ~0x20 or 0xFF
}

เนื่องจากฟังก์ชั่นนี้ใช้งานได้กับเวกเตอร์หนึ่งตัวเราสามารถเรียกมันเป็นลูปเพื่อประมวลผลสตริงทั้งหมด เนื่องจากเรากำหนดเป้าหมายไปที่ SSE2 แล้วเราสามารถทำการตรวจสอบจุดสิ้นสุดของสตริงแบบเวกเตอร์ได้ในเวลาเดียวกัน

นอกจากนี้เรายังสามารถทำได้ดีกว่าสำหรับ "การล้างข้อมูล" ของไบต์สูงสุด 15 ไบต์สุดท้ายที่เหลือหลังจากทำเวกเตอร์ 16B: ปลอกด้านบนเป็น idempotent ดังนั้นการประมวลผลอินพุตไบต์บางครั้งจึงไม่เป็นผล เราทำการโหลดที่ไม่ตรงแนวของ 16B สุดท้ายของแหล่งที่มาและเก็บไว้ในบัฟเฟอร์ปลายทางทับซ้อนที่เก็บ 16B สุดท้ายจากลูป

ครั้งเดียวที่ใช้งานไม่ได้คือเมื่อสตริงทั้งหมดมีค่าต่ำกว่า 16B: แม้ว่าdst=srcการอ่าน - แก้ไข - เขียนที่ไม่ใช่อะตอมไม่ใช่สิ่งเดียวกับที่ไม่ได้สัมผัสบางไบต์เลยและสามารถทำลายรหัสแบบมัลติเธรดได้

เรามีสเกลาร์วนรอบสำหรับสิ่งนั้นและเพื่อให้ได้srcแนวเดียวกัน เนื่องจากเราไม่ทราบว่าจุดสิ้นสุดของ 0 จะเป็นอย่างไรการโหลดที่ไม่ได้แนวจากsrcอาจข้ามไปยังหน้าถัดไปและ segfault หากเราต้องการไบต์ใด ๆ ในก้อนขนาด 16B ที่เรียงกันจะปลอดภัยเสมอที่จะโหลดก้อนขนาด 16B ที่เรียงกันทั้งหมด

แหล่งที่มาเต็มรูปแบบ: ในส่วนสำคัญ GitHub

// FIXME: doesn't always copy the terminating 0.
// microbenchmarks are for this version of the code (with _mm_store in the loop, instead of storeu, for Merom).
size_t strtoupper_sse2(char *dst, const char *src_begin) {
    const char *src = src_begin;
    // scalar until the src pointer is aligned
    while ( (0xf & (uintptr_t)src) && *src ) {
        *(dst++) = ascii_toupper(*(src++));
    }

    if (!*src)
        return src - src_begin;

    // current position (p) is now 16B-aligned, and we're not at the end
    int zero_positions;
    do {
        __m128i sv = _mm_load_si128( (const __m128i*)src );
        // TODO: SSE4.2 PCMPISTRI or PCMPISTRM version to combine the lower-case and '\0' detection?

        __m128i nullcheck = _mm_cmpeq_epi8(_mm_setzero_si128(), sv);
        zero_positions = _mm_movemask_epi8(nullcheck);
        // TODO: unroll so the null-byte check takes less overhead
        if (zero_positions)
            break;

        __m128i upcased = upcase_si128(sv);   // doing this before the loop break lets gcc realize that the constants are still in registers for the unaligned cleanup version.  But it leads to more wasted insns in the early-out case

        _mm_storeu_si128((__m128i*)dst, upcased);
        //_mm_store_si128((__m128i*)dst, upcased);  // for testing on CPUs where storeu is slow
        src += 16;
        dst += 16;
    } while(1);

    // handle the last few bytes.  Options: scalar loop, masked store, or unaligned 16B.
    // rewriting some bytes beyond the end of the string would be easy,
    // but doing a non-atomic read-modify-write outside of the string is not safe.
    // Upcasing is idempotent, so unaligned potentially-overlapping is a good option.

    unsigned int cleanup_bytes = ffs(zero_positions) - 1;  // excluding the trailing null
    const char* last_byte = src + cleanup_bytes;  // points at the terminating '\0'

    // FIXME: copy the terminating 0 when we end at an aligned vector boundary
    // optionally special-case cleanup_bytes == 15: final aligned vector can be used.
    if (cleanup_bytes > 0) {
        if (last_byte - src_begin >= 16) {
            // if src==dest, this load overlaps with the last store:  store-forwarding stall.  Hopefully OOO execution hides it
            __m128i sv = _mm_loadu_si128( (const __m128i*)(last_byte-15) ); // includes the \0
            _mm_storeu_si128((__m128i*)(dst + cleanup_bytes - 15), upcase_si128(sv));
        } else {
            // whole string less than 16B
            // if this is common, try 64b or even 32b cleanup with movq / movd and upcase_si128
#if 1
            for (unsigned int i = 0 ; i <= cleanup_bytes ; ++i) {
                dst[i] = ascii_toupper(src[i]);
            }
#else
            // gcc stupidly auto-vectorizes this, resulting in huge code bloat, but no measurable slowdown because it never runs
            for (int i = cleanup_bytes - 1 ;  i >= 0 ; --i) {
                dst[i] = ascii_toupper(src[i]);
            }
#endif
        }
    }

    return last_byte - src_begin;
}

คูณ 40M ซ้ำบน Core2 (Merom) 2.4GHz GCC -O3 -march=native5.2 (Ubuntu 15.10) dst != src(ดังนั้นเราจึงทำสำเนา) แต่จะไม่ทับซ้อนกัน (และไม่ใกล้เคียง) ทั้งสองอยู่ในแนวเดียวกัน

  • 15 อักขระสตริง: พื้นฐาน: 1.08s autovec: 1.34 วินาที คู่มือ: 1.29 วินาที
  • 16 ถ่านสตริง: พื้นฐาน: 1.16s autovec: 1.52 วินาที คู่มือ: 0.335 วินาที
  • 31 char string: manual: 0.479s
  • 127 อักขระสตริง: พื้นฐาน: 8.91s autovec: 2.98s คู่มือ: 0.925 วินาที
  • 128 อักขระสตริง: พื้นฐาน: 9.00s autovec: 2.06 วินาที คู่มือ: 0.931 วินาที
  • 129 อักขระสตริง: พื้นฐาน: 9.04s autovec: 2.07s คู่มือ: 1.02 วินาที

(หมดเวลาจริง_mm_storeในวงไม่_mm_storeuเพราะ storeu ช้าลงใน Merom แม้ว่าที่อยู่จะถูกจัดตำแหน่งมันใช้ได้กับ Nehalem และใหม่กว่าฉันยังทิ้งรหัสตามเดิมไว้ตอนนี้แทนที่จะแก้ไขความล้มเหลวในการคัดลอก 0 ที่ยุติในบางกรณีเพราะฉันไม่ต้องการเวลาทุกอย่างอีกครั้ง)

ดังนั้นสำหรับสตริงสั้น ๆ ที่ยาวกว่า 16B จะเร็วกว่าการปรับเวกเตอร์อัตโนมัติอย่างมาก ความยาวหนึ่งน้อยกว่าความกว้างเวกเตอร์ไม่แสดงปัญหา พวกเขาอาจมีปัญหาเมื่อใช้งานในสถานที่เนื่องจากแผงลอยส่งต่อร้านค้า (แต่โปรดทราบว่าการประมวลผลเอาต์พุตของเราเองนั้นยังดีกว่าอินพุตดั้งเดิมเพราะ toupper เป็น idempotent)

มีขอบเขตจำนวนมากสำหรับการปรับจูนนี้สำหรับการใช้งานที่แตกต่างกันขึ้นอยู่กับสิ่งที่ต้องการโดยรอบโค้ดและสถาปัตยกรรมไมโครเป้าหมาย รับคอมไพเลอร์ที่จะปล่อยรหัสที่ดีสำหรับส่วนการทำความสะอาดเป็นเรื่องยุ่งยาก การใช้ffs(3) (ซึ่งคอมไพล์กับ bsf หรือ tzcnt บน x86) ดูเหมือนว่าจะดี แต่เห็นได้ชัดว่าบิตต้องคิดใหม่เนื่องจากฉันสังเกตเห็นข้อผิดพลาดหลังจากเขียนคำตอบส่วนใหญ่ (ดูความคิดเห็น FIXME)

speedups เวกเตอร์สำหรับสตริงแม้มีขนาดเล็กสามารถรับกับmovqหรือmovdโหลด / ร้านค้า ปรับแต่งตามความจำเป็นสำหรับการใช้งานของคุณ


UTF-8:

เราสามารถตรวจจับได้เมื่อเวกเตอร์ของเรามีไบต์ใด ๆ ที่มีชุดบิตสูงและในกรณีนั้นกลับไปเป็นวนรอบสเกลาร์ UTF-8 ที่ทราบสำหรับเวกเตอร์นั้น dstจุดสามารถล่วงหน้าตามจำนวนเงินที่แตกต่างจากsrcตัวชี้ แต่เมื่อเราได้รับกลับไปชิดsrcชี้เราจะยังคงเป็นเพียงทำร้านค้าเวกเตอร์ unaligned dstไป

สำหรับข้อความที่เป็น UTF-8 แต่ส่วนใหญ่ประกอบด้วยชุดย่อย ASCII ของ UTF-8 สิ่งนี้อาจดี: ประสิทธิภาพสูงในกรณีทั่วไปที่มีพฤติกรรมที่ถูกต้องในทุกกรณี เมื่อมี non-ASCII จำนวนมากมันอาจจะแย่กว่าการอยู่ใน scal วน UTF-8 ที่รู้อยู่ตลอดเวลา

การทำให้ภาษาอังกฤษเร็วขึ้นด้วยค่าใช้จ่ายของภาษาอื่นไม่ใช่การตัดสินใจในอนาคตหากข้อเสียมีความสำคัญ


รู้สถานที่:

ในโลแคลภาษาตุรกี ( tr_TR) ผลที่ถูกต้องtoupper('i')คือ'İ'(U0130) ไม่ใช่'I'(ASCII ธรรมดา) ดูความคิดเห็นของ Martin Bonnerเกี่ยวกับคำถามtolower()ว่า Windows ทำงานช้า

นอกจากนี้เรายังสามารถตรวจสอบรายการยกเว้นและย้อนกลับไปยังเซนต์คิตส์และเนวิสที่นั่นเช่นอักขระอินพุตหลายไบต์ UTF8

ด้วยความซับซ้อนที่มากนี้ SSE4.2 PCMPISTRMหรือบางสิ่งบางอย่างอาจทำให้เช็คของเรามากมายในครั้งเดียว


20

คุณมีอักขระ ASCII หรืออักขระสากลหรือไม่?

หากเป็นกรณีหลัง "ตัวพิมพ์ใหญ่" นั้นไม่ใช่เรื่องง่ายและขึ้นอยู่กับตัวอักษรที่ใช้ มีตัวอักษรสองส่วนและตัวเดียว เฉพาะตัวอักษรแบบสองส่วนเท่านั้นที่มีอักขระต่างกันสำหรับตัวพิมพ์ใหญ่และตัวพิมพ์เล็ก นอกจากนี้ยังมีอักขระผสมเช่นอักษรละตินตัวพิมพ์ใหญ่ 'DZ' (\ u01F1 'DZ') ซึ่งใช้ชื่อตัวพิมพ์ใหญ่ ซึ่งหมายความว่าเฉพาะอักขระตัวแรก (D) เท่านั้นที่ได้รับการเปลี่ยนแปลง

ฉันขอแนะนำให้คุณดูเป็นICUและความแตกต่างระหว่างการแมปแบบง่ายและแบบเต็ม สิ่งนี้อาจช่วย:

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


7
หรือ eszet เยอรมัน (sp?) สิ่งที่ดูเหมือนตัวอักษรกรีกเบต้าและหมายถึง "เอสเอส" ไม่มีอักขระภาษาเยอรมันเดียวที่หมายถึง "SS" ซึ่งเทียบเท่ากับตัวพิมพ์ใหญ่ คำภาษาเยอรมันสำหรับ "ถนน" เมื่อตัวพิมพ์ใหญ่ได้รับตัวละครอีกต่อไป
David Thornley

6
อีกกรณีพิเศษคืออักษรกรีกซิกม่า (Σ) ซึ่งมีสองตัวพิมพ์เล็ก ๆ ขึ้นอยู่กับว่ามันจะอยู่ที่ท้ายคำ (ς) หรือไม่ (σ) แล้วก็มีกฎเฉพาะทางภาษาเช่นภาษาตุรกีที่มีการจับคู่กรณีและI↔ı
dan04

1
"ตัวพิมพ์ใหญ่" เรียกว่า case folding
Columbo

20
string StringToUpper(string strToConvert)
{
   for (std::string::iterator p = strToConvert.begin(); strToConvert.end() != p; ++p)
       *p = toupper(*p);

   return p;
}

หรือ,

string StringToUpper(string strToConvert)
{
    std::transform(strToConvert.begin(), strToConvert.end(), strToConvert.begin(), ::toupper);

    return strToConvert;
}

4
หากคุณไม่มีสิทธิ์เข้าถึงเพื่อเพิ่มโซลูชันที่สองน่าจะเป็นวิธีที่ดีที่สุดที่คุณจะได้รับ ดาว**หลังจากพารามิเตอร์ในการแก้ปัญหาแรกทำอะไร
Sam Brinck

1
ฉันค่อนข้างแน่ใจว่า**เป็นตัวพิมพ์ที่หลงเหลืออยู่จากการพยายามใช้แบบอักษรตัวหนาในไวยากรณ์ของรหัส
MasterHD

1
รหัสนี้จะเรียกพฤติกรรมที่ไม่ได้กำหนดเมื่อtoupperถูกเรียกด้วยจำนวนลบ
Roland Illig

17

งานต่อไปนี้สำหรับฉัน

#include <algorithm>
void  toUpperCase(std::string& str)
{
    std::transform(str.begin(), str.end(), str.begin(), ::toupper);
}

int main()
{
   std::string str = "hello";
   toUpperCase(&str);
}

โปรดทราบว่า std :: transform ถูกกำหนดใน <algorithm>
edj

ใช่. จำเป็นต้องใช้รหัสนี้รวม #include <algorithm>
Pabitra Dash

1
รหัสนี้จะเรียกพฤติกรรมที่ไม่ได้กำหนดเมื่อtoupperถูกเรียกด้วยจำนวนลบ
Roland Illig

ซ้ำกันของคำตอบที่ได้รับจาก user648545 - -1
Piotr Dobrogost

@PiotrDobrogost ฉันไม่มีความคิดเกี่ยวกับคำตอบที่ได้รับจาก user648545 ฉันยังไม่ได้คัดลอกนั้นเมื่อฉันเปรียบเทียบสองวิธีลายเซ็นของวิธีที่แตกต่างกันโดยสิ้นเชิงแม้ว่าทั้งสองฟังก์ชั่นจะใช้ฟังก์ชั่นการแปลงห้องสมุด
Pabitra Dash

13

ใช้แลมบ์ดา

std::string s("change my case");

auto to_upper = [] (char_t ch) { return std::use_facet<std::ctype<char_t>>(std::locale()).toupper(ch); };

std::transform(s.begin(), s.end(), s.begin(), to_upper);

2
ไบรอนไม่ต้องกังวลเกี่ยวกับความคิดเห็นอื่น ๆ มันค่อนข้างโอเคที่จะตอบคำถามเก่าด้วยโซลูชันใหม่ (ทันสมัย) เหมือนที่คุณทำ
Kyberias

13

เร็วกว่าถ้าคุณใช้อักขระ ASCII เท่านั้น :

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

โปรดทราบว่ารหัสนี้ทำงานได้เร็วขึ้น แต่ใช้ได้กับ ASCII เท่านั้นและไม่ใช่วิธีการแก้ปัญหา "นามธรรม"

หากคุณต้องการโซลูชัน UNICODE หรือโซลูชันทั่วไปและนามธรรมให้ไปที่คำตอบอื่น ๆ และทำงานกับวิธีการของสตริง C ++


1
คำถามถูกแท็กเป็นC++แต่คุณเขียนCคำตอบที่นี่ (ฉันไม่ได้หนึ่งใน downvoters ได้.)
hkBattousai

6
ผมเขียนคำตอบ C และ C ++ คำตอบที่นี่เพราะว่า C ++ ถูกเขียนไปอย่างเข้ากันได้กับแหล่ง C, C เพื่อแก้ปัญหาใด ๆ นอกจากนี้ยังมีวิธีการแก้ปัญหาที่ถูกต้อง c ++
Luca ซี

แต่จะดีกว่ามากที่จะให้คำตอบที่เคารพวิธี C ++
Dmitriy Yurchenko

วิธี c ++ มาตรฐานจะใช้ std :: transform กับ toupper นั่นคือรหัสน้อยและสำหรับพกพาแน่นอน รหัสนี้อาศัย "ความจริง" ที่ระบบจะใช้ ascii เป็นกลไกการเข้ารหัสตัวอักษร ไม่แน่ใจว่าระบบทั้งหมดเป็นไปตามการเข้ารหัสนี้และไม่แน่ใจว่าเป็นแบบพกพา
AlexTheo

1
ทำไมคุณถึงตัดสินใจใช้รหัส ASCII แทนตัวอักษรที่อยู่ในนั้น'?
HolyBlackCat

11

ตราบใดที่คุณยังใช้งานได้กับ ASCII เท่านั้นและคุณสามารถให้ตัวชี้ที่ถูกต้องไปยังหน่วยความจำ RW มีหนึ่งซับในที่ง่ายและมีประสิทธิภาพมากใน C:

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

สิ่งนี้เป็นสิ่งที่ดีโดยเฉพาะอย่างยิ่งสำหรับสตริงอย่างง่ายเช่นตัวระบุ ASCII ซึ่งคุณต้องการทำให้ปกติเป็นตัวอักษรตัวพิมพ์ใหญ่ จากนั้นคุณสามารถใช้บัฟเฟอร์เพื่อสร้างอินสแตนซ์ของสตริง:


มีข้อสังเกตว่าคำตอบนี้มีไว้สำหรับสตริง ac แทนที่จะเป็น std :: string
EvilTeach

นี่เป็นข้อบกพร่องด้านความปลอดภัยที่ชัดเจนโดยธรรมชาติ ฉันจะไม่ทำสิ่งนี้
Byron

9
//works for ASCII -- no clear advantage over what is already posted...

std::string toupper(const std::string & s)
{
    std::string ret(s.size(), char());
    for(unsigned int i = 0; i < s.size(); ++i)
        ret[i] = (s[i] <= 'z' && s[i] >= 'a') ? s[i]-('a'-'A') : s[i];
    return ret;
}

s.size () เป็นประเภท std :: size_t ซึ่ง AFAIK อาจไม่ได้รับการลงทะเบียน int ขึ้นอยู่กับการนำไปใช้งาน
odinthenerd

ฉันไม่คิดว่าจะมีการใช้งานที่ทันสมัยซึ่งผลของ std :: string :: size ได้รับการลงนาม ระบุว่าทั้งความหมายและในทางปฏิบัติไม่มีสิ่งนั้นเป็นขนาดลบฉันจะไปกับ size_t เป็นอย่างน้อยเป็นจำนวนเต็ม 32 บิตที่ไม่ได้ลงชื่อ
user1329482

for (size_t i = 0 ...มีเหตุผลที่จะไม่ที่จะเขียน ไม่มีเหตุผลที่ดีที่จะอ่านยาก สิ่งนี้จะคัดลอกสตริงก่อนแล้วจึงวนซ้ำมัน @ คำตอบของลุคนั้นดีกว่าในบางวิธียกเว้นการไม่ใช้ประโยชน์จาก'a'ค่าคงที่ของตัวละคร
Peter Cordes

9
#include <string>
#include <locale>

std::string str = "Hello World!";
auto & f = std::use_facet<std::ctype<char>>(std::locale());
f.toupper(str.data(), str.data() + str.size());

สิ่งนี้จะทำงานได้ดีกว่าคำตอบทั้งหมดที่ใช้ฟังก์ชัน toupper ทั่วโลกและน่าจะเป็นสิ่งที่ boost :: to_upper ทำงานภายใต้

นี่เป็นเพราะ :: toupper ต้องค้นหาโลแคล - เนื่องจากอาจมีการเปลี่ยนแปลงโดยเธรดที่แตกต่างกัน - สำหรับการเรียกใช้ทุกครั้งในขณะที่การเรียกไปยังโลแคล () มีโทษเท่านั้น และการค้นหาสถานที่โดยทั่วไปเกี่ยวข้องกับการล็อค

นอกจากนี้ยังใช้งานได้กับ C ++ 98 หลังจากที่คุณแทนที่รถยนต์การใช้ str.data () ที่ไม่ใช่ const ใหม่ () และเพิ่มพื้นที่เพื่อหยุดการปิดเทมเพลต (">>" เป็น ">>") ดังนี้:

std::use_facet<std::ctype<char> > & f = 
    std::use_facet<std::ctype<char> >(std::locale());
f.toupper(const_cast<char *>(str.data()), str.data() + str.size());

7
typedef std::string::value_type char_t;

char_t up_char( char_t ch )
{
    return std::use_facet< std::ctype< char_t > >( std::locale() ).toupper( ch );
}

std::string toupper( const std::string &src )
{
    std::string result;
    std::transform( src.begin(), src.end(), std::back_inserter( result ), up_char );
    return result;
}

const std::string src  = "test test TEST";

std::cout << toupper( src );

จะไม่แนะนำให้ back_inserter ตามที่คุณทราบความยาวแล้ว; ใช้ std :: ผลสตริง (src.size ()); std :: transform (src.begin (), src.end (), result.begin (), up_char);
Viktor Sehr

ค่อนข้างแน่ใจว่าคุณรู้เรื่องนี้
Viktor Sehr

@Viktor Sehr, @bayda: ฉันรู้ว่านี่คือ 2 ปี แต่ทำไมไม่ได้รับสิ่งที่ดีที่สุดของทั้งสองโลก ใช้reserveและback_inserter(ทำให้สตริงถูกคัดลอกเพียงครั้งเดียว) inline std::string to_lower(const std::string &s) { std::string result; result.reserve(s.size()); std::transform(s.begin(), s.end(), std::back_inserter( result ), static_cast<int(*)(int)>(std::tolower)); return result; }
Evan Teran

4
std::string value;
for (std::string::iterator p = value.begin(); value.end() != p; ++p)
    *p = toupper(*p);

รหัสนี้จะเรียกพฤติกรรมที่ไม่ได้กำหนดเมื่อtoupperถูกเรียกด้วยจำนวนลบ
Roland Illig

2

ลองใช้toupper()ฟังก์ชัน ( #include <ctype.h>) มันยอมรับอักขระเป็นอาร์กิวเมนต์สตริงประกอบด้วยอักขระดังนั้นคุณจะต้องวนซ้ำอักขระแต่ละตัวที่เมื่อรวมเข้าด้วยกันจะประกอบด้วยสตริง


คำแนะนำนี้เรียกใช้ลักษณะการทำงานที่ไม่ได้กำหนดเมื่อtoupperถูกเรียกด้วยจำนวนลบ unsigned charคุณควรจะได้กล่าวถึงความจำเป็นที่จะต้องโยน
Roland Illig

2

นี่คือรหัสล่าสุดที่มี C ++ 11

std::string cmd = "Hello World";
for_each(cmd.begin(), cmd.end(), [](char& in){ in = ::toupper(in); });

รหัสนี้จะเรียกพฤติกรรมที่ไม่ได้กำหนดเมื่อtoupperถูกเรียกด้วยจำนวนลบ
Roland Illig

1

ใช้ Boost.Text ซึ่งจะทำงานกับข้อความ Unicode

boost::text::text t = "Hello World";
boost::text::text uppered;
boost::text::to_title(t, std::inserter(uppered, uppered.end()));
std::string newstr = uppered.extract();

1

คำตอบของ@dirkgentlyเป็นอย่างมากสร้างแรงบันดาลใจ แต่ผมอยากจะเน้นว่าเนื่องจากความกังวลเป็นที่แสดงด้านล่าง

เช่นเดียวกับฟังก์ชั่นอื่น ๆ จากพฤติกรรมของ std :: toupper นั้นไม่ได้ถูกกำหนดถ้าค่าของอาร์กิวเมนต์ไม่สามารถแทนค่าได้เป็น char ที่ไม่ได้ลงนามหรือเท่ากับ EOF หากต้องการใช้ฟังก์ชันเหล่านี้อย่างปลอดภัยด้วยตัวอักษรธรรมดา (หรือตัวอักษรที่ลงนาม) อาร์กิวเมนต์ควรถูกแปลงเป็นถ่านที่ไม่ได้ลงชื่อก่อน
อ้างอิง : std :: toupper

การใช้งานที่ถูกต้องของstd::toupperควรเป็น:

#include <algorithm>
#include <cctype>
#include <iostream>
#include <iterator>
#include <string>

void ToUpper(std::string& input)
{
    std::for_each(std::begin(input), std::end(input), [](char& c) {
        c = static_cast<char>(std::toupper(static_cast<unsigned char>(c)));
    });
}

int main()
{
    std::string s{ "Hello world!" };
    std::cout << s << std::endl;
    ::ToUpper(s);
    std::cout << s << std::endl;

    return 0;
}

เอาท์พุท:

Hello world!
HELLO WORLD!

0

ไม่แน่ใจว่ามีฟังก์ชั่นในตัว ลองสิ่งนี้:

รวมไลบรารี ctype.h OR cctype รวมถึง stdlib.h เป็นส่วนหนึ่งของคำสั่งตัวประมวลผลล่วงหน้า

string StringToUpper(string strToConvert)
{//change each element of the string to upper case
   for(unsigned int i=0;i<strToConvert.length();i++)
   {
      strToConvert[i] = toupper(strToConvert[i]);
   }
   return strToConvert;//return the converted string
}

string StringToLower(string strToConvert)
{//change each element of the string to lower case
   for(unsigned int i=0;i<strToConvert.length();i++)
   {
      strToConvert[i] = tolower(strToConvert[i]);
   }
   return strToConvert;//return the converted string
}

.length () ไม่ใช่ประเภท 'unsigned int'
malat

รหัสนี้จะเรียกพฤติกรรมที่ไม่ได้กำหนดเมื่อtoupperถูกเรียกด้วยจำนวนลบ
Roland Illig

0

โซลูชันของฉัน (การล้างบิตที่ 6 สำหรับอัลฟา):

#include <ctype.h>

inline void toupper(char* str)
{
    while (str[i]) {
        if (islower(str[i]))
            str[i] &= ~32; // Clear bit 6 as it is what differs (32) between Upper and Lowercases
        i++;
    }
}

รหัสนี้จะเรียกพฤติกรรมที่ไม่ได้กำหนดเมื่อtoupperถูกเรียกด้วยจำนวนลบ
Roland Illig

ไม่ ... กรุณาตรวจสอบว่าคุณถูกต้องก่อนการลงคะแนน Islower จะทำงานกับค่าที่ไม่เป็นลบเท่านั้น ...
Antonin GAVREL

-1

โซลูชันทั้งหมดในหน้านี้ยากกว่าที่ควรจะเป็น

ทำเช่นนี้

RegName = "SomE StRing That you wAnt ConvErTed";
NameLength = RegName.Size();
for (int forLoop = 0; forLoop < NameLength; ++forLoop)
{
     RegName[forLoop] = tolower(RegName[forLoop]);
}

RegNamestringเป็นของคุณ รับขนาดสตริงของคุณไม่ได้ใช้string.size()เป็นผู้ทดสอบที่แท้จริงของคุณยุ่งมากและอาจทำให้เกิดปัญหา แล้วก็ forวง พื้นฐานที่สุด

โปรดจำไว้ว่าขนาดสตริงส่งคืนตัวคั่นด้วยดังนั้นให้ใช้ <และไม่ใช่ <= ในการทดสอบลูปของคุณ

เอาต์พุตจะเป็น: สตริงที่คุณต้องการแปลง


4
ฉันไม่เห็นว่าสิ่งนี้ง่ายกว่าโซลูชัน boost :: toupper คุณสามารถทำอย่างละเอียด?
tr9sh

2
มีอยู่แล้วจำนวนมากง่ายtolowerลูปและส่วนใหญ่ของพวกเขาใช้ชื่อตัวแปรห่วงมาตรฐานเช่นไม่แปลกi forLoop
Peter Cordes

-1

โดยไม่ต้องใช้ไลบรารีใด ๆ :

std::string YourClass::Uppercase(const std::string & Text)
{
    std::string UppperCaseString;
    UppperCaseString.reserve(Text.size());
    for (std::string::const_iterator it=Text.begin(); it<Text.end(); ++it)
    {
        UppperCaseString.push_back(((0x60 < *it) && (*it < 0x7B)) ? (*it - static_cast<char>(0x20)) : *it);
    }
    return UppperCaseString;
}

รหัสด้านบนใช้ได้กับการเข้ารหัสที่เข้ากันได้กับ ASCII เท่านั้น คำถามที่ไม่ใช่คำตอบของคุณไม่ได้กล่าวถึงข้อ จำกัด นี้ หนึ่งในนั้นควร
Roland Illig

-1

หากคุณกังวลกับตัวอักษร 8 บิตเท่านั้น (ซึ่งคำตอบอื่น ๆ ทั้งหมดยกเว้น Milan Babuškovถือว่าดี) คุณสามารถรับความเร็วที่เร็วที่สุดโดยสร้างตารางค้นหาในเวลารวบรวมโดยใช้เมตาโพแกรม บน ideone.com สิ่งนี้จะทำงานเร็วกว่าฟังก์ชั่นไลบรารี 7x และเร็วกว่ารุ่นเขียนด้วยมือ 3 เท่า ( http://ideone.com/sb1Rup ) นอกจากนี้ยังสามารถปรับแต่งได้ตามลักษณะโดยไม่ช้าลง

template<int ...Is>
struct IntVector{
using Type = IntVector<Is...>;
};

template<typename T_Vector, int I_New>
struct PushFront;
template<int ...Is, int I_New>
struct PushFront<IntVector<Is...>,I_New> : IntVector<I_New,Is...>{};

template<int I_Size, typename T_Vector = IntVector<>>
struct Iota : Iota< I_Size-1, typename PushFront<T_Vector,I_Size-1>::Type> {};
template<typename T_Vector>
struct Iota<0,T_Vector> : T_Vector{};

template<char C_In>
struct ToUpperTraits {
    enum { value = (C_In >= 'a' && C_In <='z') ? C_In - ('a'-'A'):C_In };
};

template<typename T>
struct TableToUpper;
template<int ...Is>
struct TableToUpper<IntVector<Is...>>{
    static char at(const char in){
        static const char table[] = {ToUpperTraits<Is>::value...};
        return table[in];
    }
};

int tableToUpper(const char c){
    using Table = TableToUpper<typename Iota<256>::Type>;
    return Table::at(c);
}

กับกรณีการใช้งาน:

std::transform(in.begin(),in.end(),out.begin(),tableToUpper);

สำหรับการตัดสินใจเชิงลึก (หลายหน้า) ว่ามันทำงานอย่างไรให้ฉันเสียบบล็อกของฉันอย่างไร้ยางอาย: http://metaporky.blogspot.de/2014/07/part-4-generating-look-up-tables-at.html


-1
template<size_t size>
char* toupper(char (&dst)[size], const char* src) {
    // generate mapping table once
    static char maptable[256];
    static bool mapped;
    if (!mapped) {
        for (char c = 0; c < 256; c++) {
            if (c >= 'a' && c <= 'z')
                maptable[c] = c & 0xdf;
            else
                maptable[c] = c;
        }
        mapped = true;
    }

    // use mapping table to quickly transform text
    for (int i = 0; *src && i < size; i++) {
        dst[i] = maptable[*(src++)];
    }
    return dst;
}

-1

ฟังก์ชัน c ++ นี้ส่งคืนสตริงตัวพิมพ์ใหญ่เสมอ ...

#include <locale> 
#include <string>
using namespace std; 
string toUpper (string str){
    locale loc; 
    string n; 
    for (string::size_type i=0; i<str.length(); ++i)
        n += toupper(str[i], loc);
    return n;
}

-3

ฉันใช้วิธีนี้ ฉันรู้ว่าคุณไม่ควรที่จะแก้ไขพื้นที่ข้อมูลนั้น .... แต่ฉันคิดว่าส่วนใหญ่สำหรับบัฟเฟอร์ที่มีข้อบกพร่องมากเกินไปและตัวละครที่เป็นโมฆะ

void to_upper(const std::string str) {
    std::string::iterator it;
    int i;
    for ( i=0;i<str.size();++i ) {
        ((char *)(void *)str.data())[i]=toupper(((char *)str.data())[i]);
    }
}

I know you're not supposed to modify that data area- พื้นที่ข้อมูลใดที่คุณไม่ควรแก้ไข
user93353

3
นี่มันสายแล้ว แต่บนโลกนี้ล่ะ? บรรทัดบ้านั้นสามารถถูกแทนที่ด้วยstr[i] = toupper(str[i]);ดีอย่างสมบูรณ์ ( ดีไม่ดีอย่างสมบูรณ์แต่มันแก้ไขส่วนใหญ่ของสิ่งที่ผิด)
chris
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.