एका विड्थ चेकमुळे (Width Check) एक कांजी (Kanji) तुटली
एका टर्मिनल टेबलमध्ये एक नाव टाकले आणि ते तुटलेल्या स्वरूपात बाहेर आले. ते आडनाव 𠮷田 होते.
पहिले अक्षर सामान्य 吉 नाही. ते 𠮷 (U+20BB7) आहे. हे जपानी आडनावांमध्ये वापरले जाणारे एक दुर्मिळ रूप आहे. कॉलममध्ये बसवण्यासाठी टेबलने सेल ट्रंकेट (truncate) केला. नावाऐवजी, तिथे एक तुटलेले अक्षर छापले गेले. कांजी अर्धी विभागली गेली होती.
हा बग एका ओळीच्या शॉर्टकटमध्ये होता. प्रत्यक्षात ट्रंकेट करण्यापूर्वी, कोडने इंडेक्सद्वारे स्ट्रिंग कापण्यास सुरक्षित आहे असे ठरवले. JavaScript स्ट्रिंग्स हाताळण्याच्या पद्धतीमुळे हे लॉजिक अयशस्वी ठरले.
JavaScript स्ट्रिंगची तीन वेगवेगळ्या प्रकारची लांबी असते:
- कोड युनिट लांबी (Code unit length):
"𠮷".lengthहे 2 आहे. हे UTF-16 युनिट्स मोजते. - कोड पॉइंट काउंट (Code point count):
[..."𠮷"].lengthहे 1 आहे. हे प्रत्यक्ष अक्षरे मोजते. - डिस्प्ले विड्थ (Display width): टर्मिनलमध्ये ते किती कॉलम घेते, ते म्हणजे 2.
साध्या इंग्रजी मजकुरासाठी, हे आकडे सारखेच असतात. "abc" मध्ये 3 युनिट्स, 3 पॉइंट्स आणि 3 कॉलम्स असतात. बहुतेक कोडमध्ये हा योगायोग एक नियम आहे असे मानले जाते.
𠮷 हे अक्षर तो नियम मोडते. त्याला 2 कोड युनिट्स आणि 2 कॉलम्स आहेत. आकडे जुळतात, पण वेगवेगळ्या कारणांमुळे. कोडने 2 बरोबर 2 पाहिले आणि इंडेक्सद्वारे स्ट्रिंग कापण्यासाठी 'फास्ट पाथ' (fast path) वापरला.
जेव्हा त्याने इंडेक्स 3 वर स्ट्रिंग कापली, तेव्हा त्याने पहिले पूर्ण अक्षर आणि दुसऱ्याचे फक्त अर्धे अक्षर घेतले. यामुळे एक एकटा 'सरोगेट' (surrogate) मागे राहिला. टर्मिनलमध्ये हे एका तुटलेल्या बॉक्ससारखे दिसते.
漢 सारखी सामान्य जपानी अक्षरे सुरक्षित आहेत. त्यांना 1 कोड युनिट आणि 2 कॉलम्स आहेत. 1 हे 2 च्या बरोबर नसल्यामुळे, कोड तो चुकीचा शॉर्टकट टाळतो. हा बग फक्त दुर्मिळ अक्षरे आणि इमोजीमध्ये आढळतो.
हे सुधारण्यासाठी, तुम्हाला खालील गोष्टी कराव्या लागतील:
- हाय सरोगेट्स (high surrogates) असलेल्या स्ट्रिंग्स नाकारण्यासाठी फास्ट पाथ सुरक्षित करा.
- कोड युनिट्सऐवजी पूर्ण कोड पॉइंट्सनुसार ट्रिम करा.
Array.from(str) वापरल्याने हे सुटते कारण ते कोड पॉइंटनुसार इटरेशन (iterate) करते. ते अक्षराला एक पूर्ण युनिट मानते.
धडा साधा आहे: कधीही एका युनिटने मोजू नका आणि दुसऱ्याने कापून टाकू नका. जर तुम्ही डिस्प्ले विड्थ मोजली पण कोड युनिट इंडेक्सने कापले, तर तुम्ही वापरकर्त्यांचा डेटा खराब कराल.
तुमच्या कोडची चाचणी एखाद्या दुर्मिळ CJK अक्षराने किंवा इमोजीने करा. ASCII मध्ये तुम्हाला या त्रुटी दिसणार नाहीत. ज्या इनपुटची तुमच्या कोडला भीती वाटते, तेच तुम्हाला द्यावे लागेल.
पर्यायी लर्निंग कम्युनिटी: https://greymoth-jp.github.io/cjk-failure-corpus/
