వెడల్పు తనిఖీ (Width Check) స్ట్రింగ్ను కత్తిరించడం సురక్షితమని చెప్పింది. కానీ అది ఒక కాంజీని (Kanji) సగంలో విడగొట్టింది.
ఒక పేరు టెర్మినల్ టేబుల్లోకి ప్రవేశించింది మరియు విచ్ఛిన్నమై బయటకు వచ్చింది. ఆ ఇంటిపేరు 𠮷田.
మొదటి అక్షరం సాధారణ 吉 కాదు. అది 𠮷 (U+20BB7). ఇది నిజమైన జపనీస్ కుటుంబ పేర్లలో ఉపయోగించే ఒక అరుదైన రూపం. కాలమ్కు సరిపోయేలా టేబుల్ ఆ సెల్ను కత్తిరించింది (truncated). దీనివల్ల ఒక విచ్ఛిన్నమైన అక్షరం మిగిలిపోయింది.
ఈ బగ్ కేవలం ఒకే ఒక కోడ్ లైన్లో ఉంది. ఇండెక్స్ ఆధారంగా స్ట్రింగ్ను కత్తిరించడం సురక్షితమని నిర్ణయించే ఒక ఆప్టిమైజేషన్ (optimization) వల్ల ఇది జరిగింది.
ఒక JavaScript స్ట్రింగ్కు మూడు రకాల పొడవులు (lengths) ఉంటాయి: • కోడ్ యూనిట్లు (Code units) (.length): "𠮷".length అనేది 2. • కోడ్ పాయింట్లు (Code points): [..."𠮷"].length అనేది 1. • డిస్ప్లే వెడల్పు (Display width): 𠮷 అనేది 2 కాలమ్స్ ఆక్రమిస్తుంది.
సాధారణ ఇంగ్లీష్ టెక్స్ట్కు, ఈ నంబర్లు అన్నీ ఒకేలా ఉంటాయి. ఈ యాదృచ్ఛికత వల్ల కోడ్ సురక్షితంగా ఉన్నట్లు కనిపిస్తుంది.
𠮷 అనే అక్షరం ఈ నియమాన్ని ఉల్లంఘిస్తుంది. ఇది ఒక 'సరోగట్ పెయిర్' (surrogate pair) కాబట్టి దీనికి 2 కోడ్ యూనిట్లు ఉంటాయి. ఇది ఒక వెడల్పాటి అక్షరం (wide character) కాబట్టి 2 కాలమ్స్ ఆక్రమిస్తుంది. నంబర్లు సరిపోతాయి (2 = 2), కానీ వేర్వేరు కారణాల వల్ల.
cli-table3 లైబ్రరీ ఒక 'ఫాస్ట్ పాత్' (fast path) ఉపయోగించింది: కోడ్ యూనిట్ పొడవు, డిస్ప్లే వెడల్పుతో సమానంగా ఉంటే, స్ట్రింగ్ను ఇండెక్స్ ద్వారా కత్తిరించు.
ఇది సంవత్సరాల తరబడి పని చేసింది, ఎందుకంటే 漢 వంటి సాధారణ జపనీస్ అక్షరాలకు పొడవు 1 మరియు వెడల్పు 2 ఉంటుంది. అవి ఎప్పుడూ ఈ ఫాస్ట్ పాత్లోకి రావు.
ఫాస్ట్ పాత్ కేవలం 𠮷 లేదా ఎమోజీల వంటి అరుదైన అక్షరాల కోసం మాత్రమే పనిచేస్తుంది. ఈ అక్షరాలకు పొడవు 2 మరియు వెడల్పు 2 ఉంటుంది. కోడ్ వీటిని సాధారణ ఒక యూనిట్ అక్షరాలుగా భావిస్తుంది. ఇది వాటిని ఇండెక్స్ ద్వారా సగంలో కత్తిరిస్తుంది. దీనివల్ల ఒక ఒంటరి సరోగట్ (surrogate) మిగిలిపోతుంది. అందుకే టెర్మినల్లో విచ్ఛిన్నమైన బాక్స్ కనిపిస్తుంది.
దీనిని సరిచేయడానికి, మీరు:
- సరోగట్ పెయిర్లను మినహాయించడానికి ఫాస్ట్ పాత్ను రక్షించాలి (Guard).
- కోడ్ యూనిట్ల కంటే కోడ్ పాయింట్ల ద్వారా ట్రిమ్ (Trim) చేయాలి.
Array.from(str) ఉపయోగించడం వల్ల సహాయపడుతుంది, ఎందుకంటే ఇది కోడ్ పాయింట్ ద్వారా ఇటరేట్ (iterate) చేస్తుంది. దీనివల్ల మీరు అక్షరాన్ని సగంలో కత్తిరించకుండా ఉండవచ్చు.
పాఠం సరళమైనది: ఒక యూనిట్తో కొలిచి, మరొక యూనిట్తో కత్తిరించకండి. మీరు డిస్ప్లే వెడల్పు లేదా కోడ్ పాయింట్లను కొలిస్తే, అదే యూనిట్లను ఉపయోగించి కత్తిరించాలి.
మీ కోడ్ను CJK Extension B అక్షరం లేదా ఎమోజీతో పరీక్షించండి. ASCII ఈ బగ్ను ఎప్పటికీ బయటపెట్టదు.
Optional learning community: https://greymoth-jp.github.io/cjk-failure-corpus/
