เหตุใดอักขระภาษาอังกฤษจึงต้องใช้จำนวนไบต์น้อยกว่าในการแสดงแทนตัวอักษรอื่น


31

เมื่อฉันใส่ 'a' ลงในไฟล์ข้อความมันทำให้มีขนาด 2 ไบต์ แต่เมื่อฉันใส่สมมุติว่า 'ա' ซึ่งเป็นตัวอักษรจากตัวอักษรอาร์เมเนีย

ความแตกต่างระหว่างตัวอักษรสำหรับคอมพิวเตอร์คืออะไร?
ทำไมภาษาอังกฤษถึงใช้พื้นที่น้อย


22
คุณควรอ่านบทความนี้โดยผู้ก่อตั้ง StackExchange: joelonsoftware.com/articles/Unicode.html
Eric Lippert

22
ฉันไม่คิดว่าจะมีบางอย่างเช่น "ตัวอักษรภาษาอังกฤษ" พวกเขาเป็นชาวโรมัน
Raphael

5
@ ราฟาเอลทุกคนรู้ว่าสิ่งที่เขาหมายถึงแม้ว่า แต่เพิ่มดี
Mathias Lykkegaard Lorenzen

1
@Raphael จริงๆแล้วมีตัวอักษรโรมันจำนวนมากที่ไม่ได้ใช้ในภาษาอังกฤษและดังนั้นจึงไม่รวมอยู่ในชุดอักขระ ASCII ส่วนใหญ่ของพวกเขารวมถึงการปรับเปลี่ยน แต่พวกเขายังคงต้องการที่จะแสดงข้อความอย่างถูกต้องในภาษาละตินต่างๆที่มาจากภาษาละตินอื่นที่ไม่ใช่ภาษาอังกฤษ
Wutaz

7
@ ราฟาเอลฉันไม่คิดว่าจะมีสิ่งใดที่เหมือน "ตัวอักษรโรมัน" พวกเขาเป็นภาษาละติน
แบล็กไลท์ส่องแสง

คำตอบ:


41

หนึ่งในรูปแบบการเข้ารหัสแรกที่ได้รับการพัฒนาเพื่อใช้ในคอมพิวเตอร์กระแสหลักคือมาตรฐานASCII ( รหัสมาตรฐานอเมริกันสำหรับการแลกเปลี่ยนข้อมูล ) มันได้รับการพัฒนาในปี 1960 ในประเทศสหรัฐอเมริกา

ตัวอักษรภาษาอังกฤษใช้ส่วนหนึ่งของตัวอักษรละติน (เช่นมีคำที่เน้นเสียงภาษาอังกฤษเล็กน้อย) ในจดหมายนั้นมี 26 ตัวอักษรแต่ละตัวไม่พิจารณาตัวพิมพ์ และจะต้องมีหมายเลขบุคคลและเครื่องหมายวรรคตอนในรูปแบบใด ๆ ที่อ้างว่าเข้ารหัสตัวอักษรภาษาอังกฤษ

ปี 1960 เป็นช่วงเวลาที่คอมพิวเตอร์ไม่มีหน่วยความจำหรือพื้นที่ดิสก์ที่เรามีอยู่ตอนนี้ ASCII ได้รับการพัฒนาให้เป็นตัวแทนมาตรฐานของตัวอักษรที่ใช้งานได้ในคอมพิวเตอร์ทุกเครื่องในสหรัฐอเมริกา ในขณะนั้นการตัดสินใจที่จะทำให้อักขระ ASCII ทุกตัวมีความยาว 8 บิต (1 ไบต์) เกิดขึ้นเนื่องจากรายละเอียดทางเทคนิคของเวลา ในความเป็นจริงชุดรูปแบบ ASCII ดั้งเดิมสามารถส่งโดยใช้ 7 บิตแปดสามารถใช้สำหรับการตรวจสอบพาริตี การพัฒนาภายหลังได้ขยายรูปแบบ ASCII ดั้งเดิมเพื่อรวมอักขระเน้นเสียงคณิตศาสตร์และเทอร์มินัลหลายตัว

ด้วยการเพิ่มขึ้นของการใช้คอมพิวเตอร์เมื่อเร็ว ๆ นี้ทั่วโลกทำให้ผู้คนจากภาษาต่าง ๆ จำนวนมากขึ้นสามารถเข้าถึงคอมพิวเตอร์ได้ นั่นหมายความว่าสำหรับแต่ละภาษาต้องมีการพัฒนารูปแบบการเข้ารหัสใหม่โดยไม่ขึ้นกับรูปแบบอื่น ๆ ซึ่งจะขัดแย้งกันหากอ่านจากเทอร์มินัลภาษาที่แตกต่างกัน

Unicodeมาเป็นวิธีแก้ปัญหาการมีอยู่ของเทอร์มินัลต่าง ๆ โดยการรวมอักขระที่มีความหมายที่เป็นไปได้ทั้งหมดไว้ในชุดอักขระนามธรรมเดียว

UTF-8เป็นวิธีหนึ่งในการเข้ารหัสชุดอักขระ Unicode มันคือการเข้ารหัสความกว้างแปรผัน (เช่นตัวอักษรที่แตกต่างกันสามารถมีขนาดแตกต่างกัน) และมันถูกออกแบบมาสำหรับการทำงานร่วมกันได้ย้อนหลังกับรูปแบบ ASCII เดิม ดังนั้นชุดอักขระ ASCII จะยังคงมีขนาดใหญ่หนึ่งไบต์ในขณะที่อักขระอื่น ๆ มีขนาดใหญ่สองไบต์ขึ้นไป UTF-16 เป็นอีกวิธีในการเข้ารหัสชุดอักขระ Unicode เมื่อเปรียบเทียบกับ UTF-8 อักขระจะถูกเข้ารหัสเป็นชุดของหน่วยรหัส 16 บิตหนึ่งหรือสองชุด

ตามที่ระบุไว้ในความคิดเห็นอักขระ 'a' ใช้หนึ่งไบต์ในขณะที่ '\' ใช้สองไบต์แสดงถึงการเข้ารหัส UTF-8 ไบต์พิเศษในคำถามของคุณเกิดจากการมีอักขระขึ้นบรรทัดใหม่ในตอนท้าย (ซึ่ง OP พบเกี่ยวกับ)


26
ไม่มีไบต์สุดท้ายที่รหัสจุดสิ้นสุดของไฟล์ในการเข้ารหัสปกติหรือรูปแบบไฟล์ใด ๆ เมื่อโปรแกรมอ่านไฟล์จุดสิ้นสุดของไฟล์อาจถูกส่งสัญญาณโดยระบบปฏิบัติการด้วยวิธีพิเศษ แต่นั่นเป็นปัญหาที่แตกต่างกัน
Jukka K. Korpela

2
อักขระ้อคือ 2 ไบต์ (0xD5A1) ใน Unicode รุ่น UTF-8 อักขระพิเศษ (อะไรก็ตามที่มี) มีอยู่ในไฟล์ทั้งสอง marathon-studios.com/unicode/U0561/Armenian_Small_Letter_Ayb
Dan Neely

6
@khajvah หากคุณecho 'ա' > file.txtเป็นหรือแก้ไขไฟล์โดยใช้เครื่องมือแก้ไขบางตัวพวกเขาจะเพิ่มบรรทัดใหม่หลังจากนั้นโดยอัตโนมัติ หากคุณเรียกใช้xxd file.txtไบต์สุดท้ายอาจเป็น0aฟีดหรือบรรทัด
Daniel Beck

7
@DoktoroReichard: โปรดชี้แจงในคำตอบว่า Unicode ไม่ใช่การเข้ารหัส; ค่อนข้างจะเป็นชุดอักขระที่เป็นนามธรรมและ UTF-16 และ UTF-8 เป็นเครื่องเข้ารหัสของ Unicode codepoints ย่อหน้าสุดท้ายของคำตอบของคุณส่วนใหญ่พูดถึง UTF-8 แต่ถ้าไฟล์ใช้ UTF-16 ดังนั้น codepoint ใด ๆ แม้แต่อันสำหรับaจะใช้สองไบต์ (หรือหลายเท่าของสอง)
grawity

6
มันอาจจะคุ้มค่าที่จะเน้นว่าชุดอักขระ "ASCII แบบขยาย" นั้นจริงแล้วไม่ใช่ ASCII เลยและวิธีการใช้จำนวนบิตที่แตกต่างกันจำนวนแปดทำให้ทุกอย่างยุ่งเหยิง เพียงใช้ UTF-8 แทน
ntoskrnl

17

1 ไบต์คือ 8 บิตและสามารถแทนค่าต่างกันสูงสุด 256 (2 ^ 8)

สำหรับภาษาที่ต้องการความเป็นไปได้มากกว่านี้การแมปแบบ 1 ต่อ 1 ไม่สามารถทำได้ดังนั้นจึงจำเป็นต้องมีข้อมูลเพิ่มเติมในการจัดเก็บอักขระ

โปรดทราบว่าโดยทั่วไปการเข้ารหัสส่วนใหญ่ใช้เป็นครั้งแรก 7 บิต (128 ค่า) สำหรับASCIIตัวอักษร นั่นทำให้บิตที่ 8 หรือ 128 มีค่ามากขึ้นสำหรับตัวละครมากขึ้น . . เพิ่มอักขระที่เน้นเสียงภาษาเอเชียซิริลลิก ฯลฯ และคุณสามารถเห็นได้อย่างง่ายดายว่าทำไม 1 ไบต์ไม่เพียงพอสำหรับการรักษาอักขระทั้งหมด


ดังนั้นนี่เป็นคำตอบเดียวที่อธิบายว่าทำไมมีการใช้พื้นที่มากขึ้น
Félix Gagnon-Grenier

10

ใน UTF-8 อักขระ ASCIIใช้หนึ่งไบต์อักขระอื่นใช้สองไบต์สามหรือสี่ไบต์


1
คุณช่วยอธิบายได้ไหมว่าเพราะเหตุใด การสังเกตวิธีการเข้ารหัสสองวิธีไม่ตอบคำถาม
MaQleod

@MaQleod Unicode ถูกสร้างขึ้นเพื่อแทนที่ ASCII เพื่อความเข้ากันได้ย้อนหลังอักขระ 128 ตัวแรกจะเหมือนกัน 128 อักขระเหล่านี้สามารถแสดงด้วยหนึ่งไบต์ มีการเพิ่มไบต์เพิ่มเติมสำหรับอักขระเพิ่มเติม
Jason

ฉันรู้ แต่นี่เป็นส่วนหนึ่งของคำตอบสำหรับคำถามที่ทำให้อักขระ ASCII แตกต่างกัน มันควรจะอธิบายให้ OP
MaQleod

@MaQleod นอกจากนี้ยังอาจกล่าวได้ว่า Unicode Consortium ส่วนใหญ่ประกอบด้วย บริษัท อเมริกันและมีอคติต่อตัวอักษรภาษาอังกฤษ ฉันคิดว่าคำตอบง่าย ๆ ดีกว่าคำตอบแบบอัตนัย
Jason

15
ไม่ใช่ "in Unicode" ใน UTF8 - ซึ่งเป็นเพียงหนึ่งในการเข้ารหัสของชุดอักขระ Unicode
Sebastian Negraszus

3

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

ในการเข้ารหัสการถ่ายโอน UTF-8 สำหรับ Unicode อักขระต้องมีจำนวนไบต์ที่แตกต่างกัน ในนั้น“ a” ใช้เวลาเพียงหนึ่งไบต์ (ความคิดเกี่ยวกับสองไบต์คือความสับสน),“ á” ใช้สองไบต์และตัวอักษรอาร์เมเนีย ayb“ ա” ก็ใช้สองไบต์เช่นกัน สามไบต์ต้องเป็นความสับสน ในทางตรงกันข้ามเช่นอักษรเบงกาลีตัวอักษร“ অ” ใช้เวลาสามไบต์ใน UTF-8

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

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


ขอบคุณสำหรับคำตอบ ไบต์เพิ่มเติมเป็นเพราะโปรแกรมที่ฉันใช้เพิ่มอักขระบรรทัดใหม่โดยอัตโนมัติไปยังจุดสิ้นสุด
khajvah

1
ฉันไม่คิดว่า UTF-8 ได้รับการออกแบบมากสำหรับประสิทธิภาพกับข้อมูล ASCII สำหรับการทำงานร่วมกัน UTF-8 มีคุณสมบัติที่ดีมากที่เนื้อหา ASCII 7 บิต (ที่ตั้งค่าบิตสูงเป็นศูนย์) จะเหมือนกับเนื้อหาเดียวกันที่เข้ารหัสเป็น UTF-8 ดังนั้นสำหรับเครื่องมือที่ปกติจัดการกับ ASCII มันเป็นการแทนที่แบบดรอปอิน . ไม่มีรูปแบบการเข้ารหัส Unicode อื่น ๆ ที่มีคุณสมบัติที่ให้ความรู้ของฉัน UTF-8 ยังเป็นเหตุผลที่มีขนาดกะทัดรัดสำหรับข้อมูลมากที่สุดโดยเฉพาะอย่างยิ่งถ้าคุณอยู่ภายในขอบเขตของUnicode BMP
CVn

1
@ MichaelKjörlingฉันได้เพิ่มการอ้างอิงถึงคุณลักษณะนั้น อย่างไรก็ตามการคัดค้านที่สำคัญของ Unicode ในช่วงแรกคือความไร้ประสิทธิภาพและ UTF-16 จะเพิ่มขนาดของข้อมูลที่มีขนาดใหญ่กว่า Ascii เป็นสองเท่า UTF-8 หมายถึงเช่นสำหรับข้อความภาษาอังกฤษที่คุณ“ จ่าย” สำหรับอักขระที่ไม่ใช่แอสทูที่คุณใช้เท่านั้น
Jukka K. Korpela

3

รหัสอักขระในปี 1960 (และนานกว่านั้น) เป็นเครื่องเฉพาะ ในช่วงปี 1980 ฉันใช้เครื่อง DEC 2020 ชั่วครู่ซึ่งมี 36 บิตคำและ 5, 6 และ 8 ( IIRC ) บิตต่อการเข้ารหัสอักขระ ก่อนหน้านั้นฉันใช้ IBM 370 series กับ EBCDIC ASCII ที่มี 7 บิตนำคำสั่งซื้อมาใช้ แต่มันก็ยุ่งกับ IBM PC "codepages" ที่ใช้ทั้ง 8 บิตเพื่อเป็นตัวแทนของอักขระพิเศษเช่นกล่องวาดรูปทุกประเภทเพื่อระบายสีเมนูดั้งเดิมและต่อมา ASCII เช่นละติน -1 (8 บิต การเข้ารหัสด้วย 7 บิตแรกเช่น ASCII และอีกครึ่งหนึ่งสำหรับ "ตัวละครแห่งชาติ" เหมือนñ, Çหรืออื่น ๆ . น่าจะเป็นที่นิยมมากที่สุดคือ Latin-1 เหมาะกับภาษาอังกฤษและภาษาในยุโรปส่วนใหญ่ใช้อักขระภาษาละติน (และสำเนียงและสายพันธุ์)

การเขียนข้อความที่ผสมกันเช่นภาษาอังกฤษและสเปนก็ใช้ได้ (เพียงแค่ใช้ Latin-1, superset ของทั้งคู่) แต่การผสมสิ่งที่ใช้การเข้ารหัสที่แตกต่างกัน (เช่นใส่ตัวอย่างของกรีกหรือรัสเซียไม่ต้องพูดถึงภาษาเอเชียเช่นญี่ปุ่น) ฝันร้ายที่แท้จริง ที่แย่ที่สุดคือรัสเซียและญี่ปุ่นและจีนโดยเฉพาะมีการเข้ารหัสที่นิยมและเข้ากันไม่ได้อย่างสมบูรณ์

วันนี้เราใช้ Unicode ซึ่งเป็นรูปแบบการเข้ารหัสที่มีประสิทธิภาพเช่น UTF-8 ที่ให้ตัวอักษรภาษาอังกฤษ (น่าประหลาดใจการเข้ารหัสสำหรับตัวอักษรภาษาอังกฤษจึงเกิดขึ้นเพื่อให้สอดคล้องกับ ASCII) ทำให้ตัวละครที่ไม่ใช่ภาษาอังกฤษจำนวนมากใช้การเข้ารหัสนานกว่า


2

ไฟล์ Windows 8.1 US / English ที่บันทึกด้วย 'a' เพียงแผ่นเดียวพร้อมแผ่นจดบันทึก

  • บันทึก AS ANSI 1 ไบต์
  • บันทึก AS Unicode 4 ไบต์
  • บันทึก AS UTF-8 4 ไบต์

ไฟล์ที่มี 'ա' บันทึกด้วย Notepad

  • ไม่สามารถบันทึก AS ANSI ได้
  • บันทึก AS Unicode 4 ไบต์
  • บันทึก AS UTF-8 5 ไบต์

หนึ่ง 'a' ถูกเข้ารหัสเป็นไบต์เดียวใน ANSI ใน Unicode อักขระแต่ละตัวมักจะ 2 ไบต์นอกจากนี้ยังมี BOM 2 ไบต์ (Byte Order Marker) ที่จุดเริ่มต้นของไฟล์ UTF-8 มี BOM 3 ไบต์และอักขระไบต์เดียว

สำหรับ 'ա' ตัวละครนั้นไม่มีอยู่ในชุดอักขระ ANSI และไม่สามารถบันทึกลงในเครื่องของฉันได้ ไฟล์ Unicode เหมือนกันกับก่อนหน้านี้และไฟล์ UTF-8 มีขนาดใหญ่กว่า 1 ไบต์เนื่องจากอักขระนั้นใช้เวลา 2 ไบต์

หากเครื่องของคุณมาจากภูมิภาคอื่นคุณอาจติดตั้งโค้ดเพจ OEM ที่แตกต่างกันซึ่งมี glyphs ต่างกันสำหรับ 255 อักขระที่เป็นไปได้ในช่วง ASCII ตามที่ @ntoskrnl พูดถึงเพจรหัส OEM สำหรับเครื่องของฉันจะเป็น Windows-1252 ซึ่งเป็นค่าเริ่มต้นสำหรับภาษาอังกฤษแบบสหรัฐอเมริกา


4
Notepad (และ Windows โดยทั่วไป) ใช้คำศัพท์ที่สับสนที่นี่ "ANSI" เป็นการเข้ารหัสไบต์เดียวแบบโลแคล (Windows-1252 สำหรับเวอร์ชันภาษาอังกฤษ) และ "Unicode" คือ UTF-16
ntoskrnl

@ntoskrnl ถูกต้อง แต่ถ้าคุณกำลังมองหาในกล่องดรอปสำหรับการเข้ารหัสมันบอกว่า ANSI ซึ่งเป็นสาเหตุที่ฉันพูดถึงถ้าคุณมีรหัสเพจ OEM ที่แตกต่างกันคุณอาจได้รับผลลัพธ์ที่แตกต่างกัน
Darryl Braaten

2

หากคุณสนใจว่าจะจัดเก็บอักขระอย่างไรคุณสามารถไปที่ www.unicode.org และดูรอบ ๆ ที่ด้านบนของหน้าหลักคือลิงค์ "Code Charts" ที่แสดงรหัสอักขระทั้งหมดที่มีอยู่ใน Unicode

โดยสรุปแล้วมีรหัสมากกว่าหนึ่งล้านรหัสที่มีอยู่ใน Unicode (ไม่ใช่รหัสทั้งหมดที่ใช้) หนึ่งไบต์สามารถเก็บค่า 256 ที่แตกต่างกันดังนั้นคุณจะต้องสามไบต์ถ้าคุณต้องการที่จะเก็บทุกรหัส Unicode ที่เป็นไปได้

โดยปกติแล้ว Unicode จะถูกเก็บไว้ในการเข้ารหัส "UTF-8" ซึ่งใช้จำนวนไบต์น้อยลงสำหรับอักขระบางตัวและอื่น ๆ รหัส 128 ค่าแรกจะถูกเก็บไว้ในไบต์เดียวสูงสุด 2048 ค่ารหัสจะถูกเก็บไว้ในสองไบต์สูงสุด 65536 จะถูกเก็บไว้ในสามไบต์และส่วนที่เหลือใช้เวลาสี่ไบต์ สิ่งนี้ได้รับการจัดเรียงเพื่อให้ค่ารหัสที่ใช้บ่อยกว่าจะใช้พื้นที่น้อยลง AZ, az, 0-9 และ! @ $% ^ & * () - [} {}; ': "|,. / <>? และบางอย่างที่ฉันลืมใช้เวลาหนึ่งไบต์ภาษาอังกฤษเกือบทั้งหมด 98% ของ เยอรมันและฝรั่งเศส (เพียงแค่คาดเดา) สามารถจัดเก็บในหนึ่งไบต์ต่อตัวอักษรและนี่คืออักขระที่ใช้มากที่สุด Cyrillic, กรีก, ฮิบรู, อาหรับและอื่น ๆ ใช้สองไบต์ต่อตัวอักษรภาษาอินเดียส่วนใหญ่ของจีนญี่ปุ่น สัญลักษณ์ทางคณิตศาสตร์, เกาหลี, ไทย, ตัน สามารถเขียนได้สามไบต์ต่อตัวอักษร สิ่งที่หายาก (ถ้าคุณต้องการเขียนข้อความเป็น Linear A หรือ Linear B, Emojis) ใช้เวลาสี่ไบต์

การเข้ารหัสอื่นคือ UTF-16 ทุกอย่างที่ใช้ 1, 2 หรือ 3 ไบต์ใน UTF-8 ใช้สองไบต์ใน UTF-16 นั่นเป็นข้อได้เปรียบถ้าคุณมีข้อความภาษาจีนหรือญี่ปุ่นที่มีตัวอักษรละตินน้อยมาก

เกี่ยวกับเหตุผลของการออกแบบ UTF-8: มันมีข้อดีหลายประการมากกว่าการออกแบบอื่น ๆ พวกเขาเป็น:

ความเข้ากันได้กับอักขระ US-ASCII

ความกะทัดรัดที่สมเหตุสมผล

การซิงโครไนซ์ด้วยตนเอง: ซึ่งหมายความว่าหากคุณได้รับส่วนหนึ่งของลำดับไบต์ซึ่งเป็นอักขระในการเข้ารหัส UTF-8 คุณจะพบว่าตัวอักษรเริ่มต้นที่ใด ในการเข้ารหัสบางส่วนทั้ง xy และ yx อาจเป็นการเข้ารหัสอักขระที่ถูกต้องดังนั้นหากคุณได้รับส่วนหนึ่งของลำดับ ... xyxyxyxyxyxy ... คุณไม่สามารถรู้ได้ว่าคุณมีอักขระอะไร

การเรียงลำดับความถูกต้อง: หากคุณเรียงลำดับสตริงที่มีอักขระที่เข้ารหัส UTF-8 ด้วยค่าไบต์พวกเขาจะถูกจัดเรียงอย่างถูกต้องโดยอัตโนมัติตามค่า Unicode

เข้ากันได้กับรหัสไบต์เดียว: รหัสส่วนใหญ่ที่ถือว่าค่าไบต์เดียวทำงานอย่างถูกต้องโดยอัตโนมัติด้วยอักขระที่เข้ารหัส UTF-8

รวมทั้งเหตุผลที่ฉันลืม

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