அகலச் சரிபார்ப்பு அந்தச் சரத்தை (string) வெட்டுவது பாதுகாப்பானது என்று கூறியது. ஆனால் அது ஒரு கஞ்சியை (Kanji) பாதியாகப் பிரித்தது.
ஒரு பெயர் டெர்மினல் அட்டவணையில் (terminal table) உள்ளிடப்பட்டது, ஆனால் அது சிதைந்த நிலையில் வெளிவந்தது. அந்தப் பெயர் 𠮷田.
முதல் எழுத்து பொதுவான 吉 அல்ல. அது 𠮷 (U+20BB7). இது உண்மையான ஜப்பானிய குடும்பப் பெயர்களில் பயன்படுத்தப்படும் ஒரு அரிய வடிவம். அட்டவணை ஒரு நெடுவரிசைக்கு (column) ஏற்ப அந்தச் செல்லின் (cell) அளவைக் குறைத்தது (truncate). இதனால் ஒரு சிதைந்த எழுத்து எஞ்சியது.
அந்தப் பிழை (bug) ஒரு வரியிலான குறியீட்டில் (code) இருந்தது. ஒரு சரத்தை (string) குறியீட்டின் (index) அடிப்படையில் வெட்டுவது பாதுகாப்பானது என்று தீர்மானித்த ஒரு மேம்படுத்தல் (optimization) அதுவாகும்.
ஒரு JavaScript சரத்திற்கு மூன்று வெவ்வேறு நீளங்கள் உள்ளன: • Code units (.length): "𠮷".length என்பது 2. • Code points: [..."𠮷"].length என்பது 1. • Display width: 𠮷 என்பது 2 நெடுவரிசைகளை எடுத்துக்கொள்கிறது.
சாதாரண ஆங்கில உரையைப் பொறுத்தவரை, இந்த எண்கள் அனைத்தும் சமமாக இருக்கும். இந்தத் தற்செயலான ஒற்றுமை, குறியீடு பாதுகாப்பானது போலத் தோன்றச் செய்கிறது.
𠮷 என்ற எழுத்து இந்த விதியைப் பாதிக்கிறது. இது ஒரு surrogate pair என்பதால் இதற்கு 2 code units உள்ளன. இது ஒரு அகலமான எழுத்து (wide character) என்பதால் 2 நெடுவரிசைகளை எடுத்துக்கொள்கிறது. எண்கள் ஒத்துப்போகின்றன (2 = 2), ஆனால் வெவ்வேறு காரணங்களுக்காக.
cli-table3 என்ற library ஒரு வேகமான பாதையைப் (fast path) பயன்படுத்தியது: If code unit length equals display width, then cut the string by index.
இது பல ஆண்டுகளாகச் சரியாகச் செயல்பட்டது, ஏனெனில் 漢 போன்ற பொதுவான ஜப்பானிய எழுத்துக்களுக்கு நீளம் 1 மற்றும் அகலம் 2 ஆக இருக்கும். அவை ஒருபோதும் அந்த வேகமான பாதையை (fast path) அடையவில்லை.
அந்த வேகமான பாதை 𠮷 அல்லது emojis போன்ற அரிய எழுத்துக்களுக்கு மட்டுமே செயல்படும். இந்த எழுத்துக்களுக்கு நீளம் 2 மற்றும் அகலம் 2 ஆக இருக்கும். குறியீடு அவற்றைச் சாதாரண ஒரு-அலகு (one-unit) எழுத்துக்களாக நினைக்கிறது. அது அவற்றை index மூலம் பாதியாக வெட்டுகிறது. இது ஒரு தனித்த surrogate-ஐ மட்டும் எஞ்சிய வைக்கிறது. இதனால்தான் டெர்மினலில் ஒரு சிதைந்த பெட்டி (broken box) காட்டப்படுகிறது.
இதைச் சரிசெய்ய, நீங்கள்:
- surrogate pairs-களைத் தவிர்க்க வேகமான பாதையைப் (fast path) பாதுகாக்கவும்.
- code units-க்கு பதிலாக code points மூலம் வெட்டவும் (trim).
Array.from(str) பயன்படுத்துவது உதவும், ஏனெனில் அது code point மூலம் சுழற்சி (iterate) செய்கிறது. இது நீங்கள் ஒரு எழுத்தை ஒருபோதும் பாதியாக வெட்டாமல் இருப்பதை உறுதி செய்கிறது.
பாடம் எளிமையானது: ஒரு அலகைக் கொண்டு அளவிட்டு, மற்றொரு அலகைக் கொண்டு வெட்டாதீர்கள். நீங்கள் display width அல்லது code points-ஐ அளவிடுகிறீர்கள் என்றால், அதே அலகுகளைப் பயன்படுத்தி வெட்ட வேண்டும்.
உங்கள் குறியீட்டை ஒரு CJK Extension B எழுத்து அல்லது emoji மூலம் சோதிக்கவும். ASCII இந்தப் பிழையை ஒருபோதும் வெளிப்படுத்தாது.
Optional learning community: https://greymoth-jp.github.io/cjk-failure-corpus/
