Unicode รองรับได้ดีแค่ไหนใน C ++ 11?


183

ฉันอ่านแล้วได้ยินว่า C ++ 11 รองรับ Unicode คำถามสองสามข้อเกี่ยวกับเรื่องนี้:

  • ไลบรารีมาตรฐาน C ++ รองรับ Unicode ได้ดีแค่ไหน
  • ไม่std::stringทำในสิ่งที่ควร?
  • ฉันจะใช้มันได้อย่างไร
  • ปัญหาที่อาจเกิดขึ้นอยู่ที่ไหน

19
"std :: string ทำสิ่งที่ควรทำหรือไม่" คุณคิดว่าควรทำอย่างไร
R. Martinho Fernandes

2
ฉันใช้utfcpp.sourceforge.netสำหรับความต้องการของฉัน utf8 มันเป็นไฟล์ส่วนหัวที่เรียบง่ายซึ่งมีตัววนซ้ำสำหรับสตริง Unicode
fscan

2
std :: string ควรเก็บไบต์เช่นลำดับรหัสหน่วยของการเข้ารหัส UTF-8 ใช่มันเป็นเช่นนั้นตั้งแต่เริ่มต้น utf8everywhere.org
Pavel Radzivilovsky

3
ปัญหาที่ใหญ่ที่สุดที่อาจเกิดขึ้นได้จากการรองรับ Unicode นั้นอยู่ใน Unicode และการใช้เทคโนโลยีสารสนเทศเอง Unicode ไม่เหมาะสม (และไม่ได้ออกแบบมา) สำหรับสิ่งที่ใช้ Unicode ถูกออกแบบมาเพื่อทำซ้ำสัญลักษณ์ที่เป็นไปได้ที่ถูกเขียนโดยใครบางคนในบางครั้งด้วยความแตกต่างที่ไม่น่าเชื่อและเป็นไปได้ทุกอย่างรวมถึงความหมายที่แตกต่างกัน 3 หรือ 4 รูปแบบและ 3 หรือ 4 วิธี มันไม่ได้มีไว้เพื่อเป็นประโยชน์สำหรับการใช้งานในชีวิตประจำวันและไม่ได้มีไว้เพื่อให้สามารถนำไปใช้หรือนำไปประมวลผลได้อย่างง่ายดายหรือไม่คลุมเครือ
Damon

11
ใช่มันถูกออกแบบมาเพื่อใช้สำหรับภาษาประจำวัน ของฉันอย่างน้อย และคุณก็อาจจะเช่นกัน มันกลับกลายเป็นว่าการประมวลผลข้อความของมนุษย์โดยทั่วไปเป็นงานที่ยากมาก มันเป็นไปไม่ได้ที่จะกำหนดอย่างไม่น่าสงสัยว่าตัวละครคืออะไร การสืบพันธุ์ glyph ทั่วไปไม่ได้เป็นส่วนหนึ่งของกฎบัตร Unicode
Jean-Denis Muys

คำตอบ:


267

ไลบรารี่มาตรฐาน C ++ รองรับ Unicode ได้ดีแค่ไหน?

ชะมัด.

การสแกนอย่างรวดเร็วผ่านสิ่งอำนวยความสะดวกห้องสมุดที่อาจให้การสนับสนุน Unicode ให้ฉันรายการนี้:

  • ไลบรารีสตริง
  • ห้องสมุดรองรับหลายภาษา
  • ไลบรารีอินพุต / เอาต์พุต
  • ไลบรารีนิพจน์ปกติ

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

ไม่std::stringทำในสิ่งที่ควร?

ใช่. ตามมาตรฐาน C ++ นี่คือสิ่งที่std::stringและพี่น้องควรทำ:

เท็มเพลตคลาสbasic_stringอธิบายถึงวัตถุที่สามารถเก็บลำดับที่ประกอบด้วยจำนวน char-like object ที่แตกต่างกันจำนวนหนึ่งด้วยองค์ประกอบแรกของลำดับที่ตำแหน่งศูนย์

ดีstd::stringไม่ว่าเพียงแค่ปรับ นั่นมีฟังก์ชั่นเฉพาะ Unicode หรือไม่? เลขที่

ควรเป็น? อาจจะไม่. std::stringเป็นไปตามลำดับของcharวัตถุ นั่นเป็นประโยชน์ สิ่งเดียวที่น่ารำคาญก็คือมันเป็นมุมมองที่ต่ำมากของข้อความและ C ++ มาตรฐานไม่ได้ให้มุมมองที่สูงกว่า

ฉันจะใช้มันได้อย่างไร

ใช้เป็นลำดับของcharวัตถุ การแกล้งทำเป็นว่ามันเป็นเรื่องอื่นที่ต้องจบลงด้วยความเจ็บปวด

ปัญหาที่อาจเกิดขึ้นอยู่ที่ไหน

ทั่วทุกสถานที่? มาดูกัน...

ไลบรารีสตริง

ห้องสมุดสตริงให้เราbasic_stringซึ่งเป็นเพียงลำดับของสิ่งที่มาตรฐานเรียกว่า "วัตถุคล้ายถ่าน" ฉันเรียกพวกเขาว่าหน่วยรหัส หากคุณต้องการมุมมองระดับสูงของข้อความนี่ไม่ใช่สิ่งที่คุณกำลังมองหา นี่คือมุมมองของข้อความที่เหมาะสมสำหรับการทำให้เป็นอนุกรม / deserialization / storage

นอกจากนี้ยังมีเครื่องมือบางอย่างจากห้องสมุด C ที่สามารถนำมาใช้เพื่อลดช่องว่างระหว่างโลกแคบและโลก Unicode นี้c16rtomb/ mbrtoc16และ/c32rtombmbrtoc32

ห้องสมุดรองรับหลายภาษา

ห้องสมุดการแปลยังคงเชื่อว่าหนึ่งใน "วัตถุที่มีลักษณะคล้ายถ่าน" หนึ่งในนั้นมีค่าเท่ากับ "อักขระ" หนึ่งตัว แน่นอนว่ามันโง่และทำให้มันเป็นไปไม่ได้ที่จะได้รับสิ่งต่าง ๆ มากมายทำงานอย่างถูกต้องนอกเหนือจากชุดย่อยของ Unicode เช่น ASCII

ลองพิจารณาตัวอย่างเช่นสิ่งที่มาตรฐานเรียกว่า "ความสะดวกสบาย" ใน<locale>ส่วนหัว:

template <class charT> bool isspace (charT c, const locale& loc);
template <class charT> bool isprint (charT c, const locale& loc);
template <class charT> bool iscntrl (charT c, const locale& loc);
// ...
template <class charT> charT toupper(charT c, const locale& loc);
template <class charT> charT tolower(charT c, const locale& loc);
// ...

คุณคาดหวังว่าฟังก์ชั่นใด ๆ เหล่านี้จะจัดหมวดหมู่พูดอย่างถูกต้อง U + 1F34C ʙᴀɴᴀɴᴀเช่นเดียวกับในu8"🍌"หรือu8"\U0001F34C"อย่างไร มันไม่มีทางที่จะทำงานได้เพราะฟังก์ชั่นเหล่านั้นใช้หน่วยรหัสเดียวเป็นอินพุต

สิ่งนี้สามารถทำงานกับโลแคลที่เหมาะสมหากคุณใช้char32_tเท่านั้น: U'\U0001F34C'เป็นหน่วยรหัสเดียวใน UTF-32

อย่างไรก็ตามนั่นก็หมายความว่าคุณจะได้รับการแปลงแบบง่าย ๆ ด้วยtoupperและtolowerเท่านั้นซึ่งไม่ดีพอสำหรับบางภาษาเยอรมัน: "ß" พิมพ์ใหญ่เป็น "SS" ☦ แต่toupperสามารถส่งคืนหน่วยอักขระได้หนึ่งหน่วยเท่านั้น

ขั้นต่อไปwstring_convert/ wbuffer_convertและการแปลงรหัสมาตรฐานเป็นส่วน

wstring_convertจะใช้ในการแปลงระหว่างสตริงในการเข้ารหัสที่กำหนดให้เป็นสตริงในการเข้ารหัสที่กำหนดอื่น มีสองประเภทสตริงที่เกี่ยวข้องในการแปลงนี้ซึ่งมาตรฐานเรียกสตริงไบต์และสตริงกว้าง เนื่องจากข้อกำหนดเหล่านี้ทำให้เข้าใจผิดจริงๆฉันจึงต้องการใช้ "ต่อเนื่อง" และ "ดีซีเรียลไลซ์" ตามลำดับแทน†

การเข้ารหัสการแปลงระหว่างมีการตัดสินใจโดย codecvt (แง่โค้ด Conversion) wstring_convertผ่านเป็นอาร์กิวเมนต์ชนิดแม่แบบ

wbuffer_convertดำเนินการฟังก์ชั่นที่คล้ายกัน แต่เป็นบัฟเฟอร์กระแสกว้าง deserialized ที่ห่อบัฟเฟอร์กระแสไบต์อนุกรม I / O ใด ๆ จะดำเนินการผ่านบัฟเฟอร์กระแสไบต์พื้นฐานที่มีการแปลงไปและกลับจากการเข้ารหัสที่กำหนดโดยอาร์กิวเมนต์ codecvt การเขียนซีเรียลไลซ์ลงในบัฟเฟอร์นั้นจากนั้นเขียนจากมันและการอ่านจะอ่านลงในบัฟเฟอร์และจากนั้นทำการดีซีเรียลไลซ์

มาตรฐานการให้บางส่วนแม่แบบระดับ codecvt สำหรับใช้กับสิ่งอำนวยความสะดวกเหล่านี้: codecvt_utf8, codecvt_utf16, codecvt_utf8_utf16และบางส่วนcodecvtเฉพาะด้าน ร่วมกัน facets มาตรฐานเหล่านี้ให้การแปลงต่อไปนี้ทั้งหมด (หมายเหตุ: ในรายการต่อไปนี้การเข้ารหัสทางด้านซ้ายจะเป็นสตริง / streambuf ที่ต่อเนื่องกันเสมอและการเข้ารหัสทางด้านขวาจะเป็นสตริง / streambuf ที่ดีซีเรียลไลซ์เสมอซึ่งเป็นมาตรฐานที่อนุญาตการแปลงในทั้งสองทิศทาง)

  • UTF-8 ↔ UCS-2 ด้วยcodecvt_utf8<char16_t>, และcodecvt_utf8<wchar_t>ที่ไหนsizeof(wchar_t) == 2;
  • UTF-8 ↔ UTF-32 codecvt_utf8<char32_t>, codecvt<char32_t, char, mbstate_t>และcodecvt_utf8<wchar_t>ที่sizeof(wchar_t) == 4;
  • UTF-16 ↔ UCS-2 ด้วยcodecvt_utf16<char16_t>, และcodecvt_utf16<wchar_t>ที่ไหนsizeof(wchar_t) == 2;
  • UTF-16 ↔ UTF-32 ด้วยcodecvt_utf16<char32_t>, และcodecvt_utf16<wchar_t>ที่ไหนsizeof(wchar_t) == 4;
  • UTF-8 ↔ UTF-16 codecvt_utf8_utf16<char16_t>, codecvt<char16_t, char, mbstate_t>และcodecvt_utf8_utf16<wchar_t>ที่sizeof(wchar_t) == 2;
  • แคบ↔กว้างด้วย codecvt<wchar_t, char_t, mbstate_t>
  • ไม่มี-op codecvt<char, char, mbstate_t>กับ

หลายสิ่งเหล่านี้มีประโยชน์ แต่มีสิ่งที่น่าอึดอัดใจอยู่มากมายที่นี่

ก่อนอื่น - ตัวแทนระดับสูงศักดิ์สิทธิ์! รูปแบบการตั้งชื่อนั้นยุ่ง

จากนั้นมีการสนับสนุน UCS-2 มากมาย UCS-2 เป็นการเข้ารหัสจาก Unicode 1.0 ที่ถูกแทนที่ในปี 1996 เพราะรองรับเฉพาะเครื่องบินแบบหลายภาษาขั้นพื้นฐานเท่านั้น เหตุใดคณะกรรมการจึงคิดว่าเป็นที่น่าพอใจที่จะให้ความสำคัญกับการเข้ารหัสที่ถูกแทนที่เมื่อ 20 ปีก่อนฉันไม่รู้‡ มันไม่เหมือนกับการรองรับการเข้ารหัสเพิ่มเติมที่ไม่ดีหรืออะไรก็ตาม แต่ UCS-2 ปรากฏบ่อยเกินไปที่นี่

ฉันจะบอกว่าchar16_tมีความหมายชัดเจนสำหรับการจัดเก็บหน่วยรหัส UTF-16 อย่างไรก็ตามนี่เป็นส่วนหนึ่งของมาตรฐานที่คิดเป็นอย่างอื่น codecvt_utf8<char16_t>ไม่มีอะไรเกี่ยวข้องกับ UTF-16 ตัวอย่างเช่นwstring_convert<codecvt_utf8<char16_t>>().to_bytes(u"\U0001F34C")จะคอมไพล์ได้ดี แต่จะล้มเหลวโดยไม่มีเงื่อนไข: อินพุตจะถูกใช้เป็นสตริง UCS-2 u"\xD83C\xDF4C"ซึ่งไม่สามารถแปลงเป็น UTF-8 ได้เนื่องจาก UTF-8 ไม่สามารถเข้ารหัสค่าใด ๆ ในช่วง 0xD800-0xDFFF

ยังคงอยู่ที่ด้านหน้า UCS-2 ไม่มีวิธีการอ่านจากสตรีม UTF-16 ไบต์ไปยังสตริง UTF-16 ด้วย facets เหล่านี้ หากคุณมีลำดับ UTF-16 ไบต์คุณจะไม่สามารถทำการ deserialize ให้เป็นสตริงchar16_tได้ นี่เป็นเรื่องที่น่าแปลกใจเพราะมันเป็นการแปลงอัตลักษณ์ที่มากหรือน้อย แม้ว่าที่น่าแปลกใจมากขึ้นคือความจริงที่ว่ามีการสนับสนุนการดีซีเรียลไลซ์จากสตรีม UTF-16 ไปเป็นสตริง UCS-2 ด้วยcodecvt_utf16<char16_t>ซึ่งจริงๆแล้วเป็นการแปลงที่สูญเสียไป

การสนับสนุน UTF-16-as-bytes นั้นค่อนข้างดี แต่มันรองรับการตรวจจับ endianess จาก BOM หรือเลือกอย่างชัดเจนในโค้ด นอกจากนี้ยังรองรับการผลิตผลผลิตที่มีและไม่มี BOM

มีความเป็นไปได้ในการแปลงที่น่าสนใจอีกมากที่ขาดไป ไม่มีวิธีใดในการดีซีเรียลไลซ์จากสตรีมหรือสตริง UTF-16 ลงในสตริง UTF-8 เนื่องจาก UTF-8 ไม่ได้รับการสนับสนุนในรูปแบบที่ดีซีเรียลไลซ์

และที่นี่โลกแคบ / กว้างแยกจากโลก UTF / UCS อย่างสมบูรณ์ ไม่มีการแปลงระหว่างการเข้ารหัสแบบแคบ / กว้างแบบเก่ากับการเข้ารหัสแบบ Unicode

ไลบรารีอินพุต / เอาต์พุต

ไลบรารี I / O สามารถใช้เพื่ออ่านและเขียนข้อความในการเข้ารหัส Unicode โดยใช้wstring_convertและwbuffer_convertสิ่งอำนวยความสะดวกที่อธิบายไว้ข้างต้น ฉันไม่คิดว่าจะมีอะไรอีกมากมายที่จะต้องได้รับการสนับสนุนจากห้องสมุดมาตรฐานนี้

ไลบรารีนิพจน์ปกติ

ฉันได้อธิบายเกี่ยวกับปัญหากับC ++ regexes และ Unicodeใน Stack Overflow มาก่อน ฉันจะไม่ทำซ้ำจุดเหล่านี้ทั้งหมด แต่เพียงระบุว่า C ++ regexes ไม่มีการสนับสนุน Unicode ระดับ 1 ซึ่งเป็นขั้นต่ำที่เปลือยเปล่าเพื่อให้สามารถใช้งานได้โดยไม่ต้องใช้ UTF-32 ทุกที่

แค่นั้นแหละ?

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

U + 1F4A9 มีวิธีใดบ้างที่จะได้รับการสนับสนุน Unicode ที่ดีขึ้นใน C ++?

สงสัยปกติ: ห้องไอซียูและBoost.Locale


string สตริงไบต์ไม่น่าแปลกใจคือสตริงไบต์เช่นcharวัตถุ อย่างไรก็ตามแตกต่างจากตัวอักษรสตริงกว้างซึ่งมักจะเป็นอาร์เรย์ของwchar_tวัตถุ "สตริงกว้าง" ในบริบทนี้ไม่จำเป็นต้องเป็นสตริงของwchar_tวัตถุ ในความเป็นจริงมาตรฐานไม่ได้กำหนดอย่างชัดเจนว่า "wide string" หมายถึงอะไรดังนั้นเราจึงเหลือที่จะเดาความหมายจากการใช้งาน เนื่องจากคำศัพท์มาตรฐานนั้นเลอะเทอะและสับสนฉันจึงใช้ชื่อของฉันเองในความชัดเจน

การเข้ารหัสเช่น UTF-16 สามารถจัดเก็บเป็นลำดับของchar16_tซึ่งไม่มีความเอนเอียง หรือพวกเขาสามารถเก็บไว้เป็นลำดับของไบต์ซึ่งมี endianness (ไบต์คู่ต่อเนื่องแต่ละคู่สามารถแสดงchar16_tค่าที่แตกต่างกันขึ้นอยู่กับ endianness) มาตรฐานรองรับทั้งสองรูปแบบเหล่านี้ ลำดับของchar16_tมีประโยชน์มากสำหรับการจัดการภายในในโปรแกรม ลำดับของไบต์เป็นวิธีการแลกเปลี่ยนสตริงดังกล่าวกับโลกภายนอก คำที่ฉันจะใช้แทน "ไบต์" และ "กว้าง" จึงเป็น "อนุกรม" และ "ดีซีเรียลไลซ์"

‡หากคุณกำลังจะพูดว่า "แต่ใช้ Windows!" ถือของคุณ🐎🐎 Windows ทุกรุ่นตั้งแต่ Windows 2000 ใช้ UTF-16

☦ใช่ฉันรู้เกี่ยวกับgroßes Eszett (ẞ) แต่แม้ว่าคุณจะเปลี่ยนสถานที่เยอรมันทั้งหมดในชั่วข้ามคืนเพื่อรับßตัวพิมพ์ใหญ่เป็นẞยังมีอีกหลายกรณีที่สิ่งนี้จะล้มเหลว ลองใช้ตัวพิมพ์ใหญ่ U + FB00 ʟᴀᴛɪɴsᴍᴀʟʟʟɪɢᴀᴛᴜʀᴇғғ ไม่มีʟᴀᴛɪɴᴄᴀᴘɪᴛᴀʟʟɪɢᴀᴛᴜʀᴇғғ; มันเป็นตัวพิมพ์ใหญ่ถึงสอง Fs หรือ U + 01F0 ʟᴀᴛɪɴsᴍᴀʟʟʟᴇᴛᴛᴇʀᴊᴡɪᴛʜᴄᴀʀᴏɴ; ไม่มีทุน precomposed; มันเป็นตัวพิมพ์ใหญ่ถึงเมืองหลวง J และรอนรวมกัน


26
ยิ่งฉันอ่านเกี่ยวกับเรื่องนี้มากเท่าไหร่ฉันก็ยิ่งรู้สึกไม่เข้าใจเรื่องทั้งหมดนี้มากขึ้นเท่านั้น ฉันอ่านสิ่งนี้เกือบสองสามเดือนที่แล้วและยังรู้สึกเหมือนฉันค้นพบสิ่งทั้งหมดอีกครั้ง ... เพื่อให้สมองของฉันยากจนที่เรียบง่ายซึ่งตอนนี้เจ็บเล็กน้อยคำแนะนำเหล่านี้ทั้งหมดในutf8everywhereยังคงใช้ได้ ขวา? หากฉัน "เพียงแค่" ต้องการให้ผู้ใช้ของฉันสามารถเปิดและเขียนไฟล์ไม่ว่าการตั้งค่าระบบของพวกเขาฉันสามารถถามพวกเขาชื่อไฟล์เก็บไว้ใน std :: สตริงและทุกอย่างควรทำงานอย่างถูกต้องแม้ใน Windows? ขออภัยที่จะถามว่า (อีกครั้ง) ...
Uflex

5
@Uflex ทั้งหมดที่คุณสามารถจริงๆทำอย่างไรกับมาตรฐาน :: สตริงคือการรักษามันเป็นหยดไบนารี ในการใช้ Unicode ที่เหมาะสมทั้งภายใน (เพราะมันซ่อนอยู่ลึกลงไปในรายละเอียดการใช้งาน) หรือเรื่องการเข้ารหัสภายนอก (ดี, sorta, คุณยังต้องมีตัวเข้ารหัส / ตัวถอดรหัสที่พร้อมใช้งาน)
Cat Plus Plus

3
@ Uflex อาจจะ ฉันไม่รู้ว่าการทำตามคำแนะนำที่คุณไม่เข้าใจนั้นเป็นความคิดที่ดีหรือไม่
R. Martinho Fernandes

1
มีข้อเสนอสำหรับการสนับสนุน Unicode ใน C ++ 2014/17 อย่างไรก็ตามนั่นคือ 1 อาจจะอยู่ห่างออกไป 4 ปีและใช้งานเพียงเล็กน้อยในตอนนี้ open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3572.html
graham.reeds

20
@ graham.reeds ฮ่าฮ่าขอบคุณ แต่ฉันก็รู้ว่า ตรวจสอบส่วน "กิตติกรรมประกาศ";)
R. Martinho Fernandes

40

ไลบรารี่มาตรฐานไม่รองรับ Unicode (สำหรับความหมายที่สมเหตุสมผลตามสมควร)

std::stringไม่ดีกว่าstd::vector<char>: มันเป็นสมบูรณ์ลบเลือนไป Unicode (หรืออื่น ๆ การแสดง / การเข้ารหัส) และก็รักษาเนื้อหาที่เป็นหยดไบต์

หากคุณต้องการจัดเก็บและจัดการblobsเท่านั้นมันใช้งานได้ดี แต่ทันทีที่คุณต้องการฟังก์ชั่น Unicode (จำนวนคะแนนโค้ด , จำนวนภาพฯลฯ ) คุณจะโชคไม่ดี

เพียงห้องสมุดที่ครอบคลุมฉันรู้ว่านี้คือห้องไอซียู อินเทอร์เฟซ C ++ นั้นได้มาจาก Java หนึ่งดังนั้นจึงยังห่างไกลจากการใช้สำนวน


2
วิธีการเกี่ยวกับBoost.Locale ?
Uflex

11
@Uflex: จากหน้าเว็บที่คุณเชื่อมโยงเพื่อให้บรรลุเป้าหมายนี้ Boost.Locale ใช้ Unicode ที่ทันสมัยและห้องสมุด Localization: ICU - International Components for Unicode
Matthieu M.

1
Boost.Locale รองรับแบ็กเอนด์ที่ไม่ใช่ห้องไอซียูอื่น ๆ ดูที่นี่: boost.org/doc/libs/1_53_0/libs/locale/doc/html/ …
Superfly Jon

@ SuperflyJon: จริง แต่ตามหน้าเดียวกันนั้นการสนับสนุน Unicode ของแบ็กเอนด์ที่ไม่ใช่ ICU นั้น "จำกัด อย่างรุนแรง"
Matthieu M.

24

คุณสามารถเก็บ UTF-8 ได้อย่างปลอดภัยในstd::string(หรือในchar[]หรือchar*สำหรับเรื่องนั้น) เนื่องจากความจริงที่ว่า Unicode NUL (U + 0000) เป็นไบต์ว่างใน UTF-8 และนี่เป็นวิธีเดียวที่เป็นโมฆะ ไบต์สามารถเกิดขึ้นใน UTF-8 ดังนั้นสตริง UTF-8 ของคุณจะถูกยกเลิกอย่างถูกต้องตามฟังก์ชั่นสตริง C และ C ++ ทั้งหมดและคุณสามารถโยงมันด้วย C ++ iostreams (รวมถึงstd::coutและstd::cerrตราบใดที่โลแคลของคุณคือ UTF-8)

สิ่งที่คุณไม่สามารถทำได้std::stringสำหรับ UTF-8 นั้นคือความยาวในจุดโค้ด std::string::size()จะบอกความยาวสตริงเป็นไบต์ซึ่งเท่ากับจำนวนคะแนนโค้ดเฉพาะเมื่อคุณอยู่ในชุดย่อย ASCII ของ UTF-8

หากคุณต้องการใช้งานกับสตริง UTF-8 ที่ระดับรหัสจุด (เช่นไม่ใช่แค่จัดเก็บและพิมพ์) หรือถ้าคุณกำลังจัดการกับ UTF-16 ซึ่งมีแนวโน้มว่าจะมีไบต์ว่างภายในจำนวนมากคุณต้องพิจารณา ประเภทสตริงตัวกว้าง


3
std::stringสามารถโยนเข้าไปใน iostreams ด้วย nulls ฝังตัวได้ดี
R. Martinho Fernandes

3
มันตั้งใจทั้งหมด ไม่แตกc_str()เลยเพราะsize()ยังใช้งานได้ API ที่ใช้งานไม่ได้เท่านั้น (เช่นที่ไม่สามารถจัดการกับโมฆะแบบฝังตัวเช่นเดียวกับโลก C ส่วนใหญ่)
R. Martinho Fernandes

1
ตัวลบ nulls ที่ฝังอยู่c_str()เนื่องจากc_str()ควรส่งคืนข้อมูลเป็นสตริง C ที่สิ้นสุดด้วยค่า null ซึ่งเป็นไปไม่ได้เนื่องจากความจริงที่ว่าสตริง C ไม่สามารถมีค่า null ที่ฝังอยู่ได้
uckelman

4
ไม่อีกแล้ว. c_str()ตอนนี้เพียงแค่ส่งกลับเช่นเดียวกับdata()ทุกอย่าง API ที่มีขนาดสามารถบริโภคได้ API ที่ทำไม่ได้ไม่สามารถทำได้
R. Martinho Fernandes

6
ด้วยความแตกต่างเล็กน้อยที่c_str()ทำให้แน่ใจว่าผลลัพธ์ตามด้วยวัตถุที่คล้ายกับ NUL และฉันไม่คิดว่าdata()จะเป็นเช่นนั้น ไม่ดูเหมือนdata()ตอนนี้ก็ทำเช่นกัน (ของหลักสูตรนี้ไม่จำเป็นสำหรับ API ที่ใช้ขนาดแทนการอนุมานได้จากการค้นหาของเทอร์มิก)
เบนยต์

8

C ++ 11 มีสตริงตัวอักษรใหม่สองชนิดสำหรับ Unicode

น่าเสียดายที่การสนับสนุนในไลบรารีมาตรฐานสำหรับการเข้ารหัสที่ไม่สม่ำเสมอ (เช่น UTF-8) ยังคงไม่ดี ตัวอย่างเช่นไม่มีวิธีที่ดีในการรับความยาว (เป็นรหัสจุด) ของสตริง UTF-8


ดังนั้นเรายังจำเป็นต้องใช้ std :: wstring สำหรับชื่อไฟล์ถ้าเราต้องการสนับสนุนภาษาที่ไม่ใช่ภาษาละติน? เพราะตัวอักษรของสตริงใหม่ไม่ได้จริงๆช่วยที่นี่เป็นสตริงมักจะมาจากผู้ใช้ ...
Uflex

7
@Uflex std::stringสามารถเก็บสตริง UTF-8 ได้โดยไม่มีปัญหา แต่เช่นlengthวิธีการส่งคืนจำนวนไบต์ในสตริงและไม่ใช่จำนวนของรหัสจุด
โปรแกรมเมอร์บางคนเพื่อน

8
ความซื่อสัตย์การรับความยาวในจุดโค้ดของสตริงนั้นไม่มีประโยชน์อะไรมากมาย ความยาวเป็นไบต์สามารถใช้ในการจัดสรรบัฟเฟอร์ล่วงหน้าได้อย่างถูกต้อง
R. Martinho Fernandes

2
จำนวนจุดโค้ดในสตริง UTF-8 ไม่ใช่ตัวเลขที่น่าสนใจ: สามารถเขียนñเป็น 'LATIN SMALL LETTER N WITH TILDE' (U + 00F1) (ซึ่งเป็นจุดรหัสหนึ่ง) หรือ 'LATIN SMALL LETTER N' ( U + 006E) ตามด้วย 'COMBINING TILDE' (U + 0303) ซึ่งเป็นจุดรหัสสองจุด
Martin Bonner สนับสนุนโมนิก้า

ความคิดเห็นทั้งหมดเกี่ยวกับ "คุณไม่ต้องการสิ่งนี้และคุณไม่ต้องการสิ่งนั้น" เช่น "จำนวนรหัสคะแนนที่ไม่สำคัญ" ฯลฯ ฟังดูแปลกสำหรับฉัน เมื่อคุณเขียน parser ซึ่งควรจะแยกรหัสที่มา utf8 ของแปลก, มันขึ้นอยู่กับคุณสมบัติของตัวแยกวิเคราะห์ที่ว่าหรือไม่ก็พิจารณา==LATIN SMALL LETTER N' (U+006E) followed by 'COMBINING TILDE' (U+0303)
BitTickler

4

แต่มีเป็นห้องสมุดที่มีประโยชน์สวยที่เรียกว่าเล็ก ๆ -utf8ซึ่งเป็นพื้นดรอปแทนสำหรับ/std::string std::wstringมันมีจุดมุ่งหมายเพื่อเติมเต็มช่องว่างของคลาสคอนเทนเนอร์ utf8-string ที่หายไป

นี่อาจเป็นวิธีที่สะดวกสบายที่สุดในการ 'จัดการ' กับสตริง utf8 (นั่นคือไม่มีการทำให้เป็นมาตรฐานแบบ Unicode และสิ่งที่คล้ายกัน) คุณสบายทำงานบนcodepointsในขณะที่การเข้าพักสายของคุณเข้ารหัสในระยะยาวเข้ารหัสchars

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.