ಅಗಲದ ಪರಿಶೀಲನೆಯು ಒಂದು ಕಾಂಜಿ ಅಕ್ಷರವನ್ನು ಮುರಿದುಹಾಕಿತು

ಒಂದು ಹೆಸರು ಟರ್ಮಿನಲ್ ಟೇಬಲ್‌ಗೆ (terminal table) ಸೇರಿಸಲ್ಪಟ್ಟಿತು ಮತ್ತು ಅದು ಹಾನಿಗೊಳಗಾದ ಸ್ಥಿತಿಯಲ್ಲಿ ಹೊರಬಂದಿತು. ಆ ಉಪನಾಮ 𠮷田 ಆಗಿತ್ತು.

ಮೊದಲ ಅಕ್ಷರವು ಸಾಮಾನ್ಯ 吉 ಅಲ್ಲ. ಅದು 𠮷 (U+20BB7). ಇದು ನೈಜ ಜಪಾನೀಸ್ ಕುಟುಂಬದ ಹೆಸರುಗಳಲ್ಲಿ ಬಳಸಲಾಗುವ ಒಂದು ಅಪರೂಪದ ರೂಪವಾಗಿದೆ. ಕಾಲಂಗೆ ಹೊಂದಿಸಲು ಟೇಬಲ್ ಸೆಲ್ ಅನ್ನು ಟ್ರಂಕೇಟ್ (truncate) ಮಾಡಿತು. ಹೆಸರಿನ ಬದಲಿಗೆ, ಅದು ಒಂದು ಮುರಿದ ಅಕ್ಷರವನ್ನು ಪ್ರಿಂಟ್ ಮಾಡಿತು. ಆ ಕಾಂಜಿ ಅಕ್ಷರವು ಅರ್ಧಕ್ಕೆ ಸೀಳಲ್ಪಟ್ಟಿತು.

ಈ ಬಗ್ (bug) ಒಂದು ಸಾಲಿನ ಶಾರ್ಟ್‌ಕಟ್‌ನಲ್ಲಿ ಅಡಗಿತ್ತು. ಸ್ಟ್ರಿಂಗ್ ಅನ್ನು ವಾಸ್ತವವಾಗಿ ಟ್ರಂಕೇಟ್ ಮಾಡುವ ಮೊದಲು, ಅದನ್ನು ಇಂಡೆಕ್ಸ್ ಮೂಲಕ ಕತ್ತರಿಸುವುದು ಸುರಕ್ಷಿತ ಎಂದು ಕೋಡ್ ನಿರ್ಧರಿಸಿತು. ಜಾವಾಸ್ಕ್ರಿಪ್ಟ್ (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) ಹೊಂದಿರುವ ಸ್ಟ್ರಿಂಗ್‌ಗಳನ್ನು ತಿರಸ್ಕರಿಸಲು ಫಾಸ್ಟ್ ಪಾತ್ ಅನ್ನು ರಕ್ಷಿಸಿ (Guard).
  • ಕೋಡ್ ಯೂನಿಟ್‌ಗಳ ಬದಲಿಗೆ ಪೂರ್ಣ ಕೋಡ್ ಪಾಯಿಂಟ್‌ಗಳ ಮೂಲಕ ಟ್ರಿಮ್ (Trim) ಮಾಡಿ.

Array.from(str) ಬಳಸುವುದು ಇದನ್ನು ಸರಿಪಡಿಸುತ್ತದೆ ಏಕೆಂದರೆ ಇದು ಕೋಡ್ ಪಾಯಿಂಟ್ ಮೂಲಕ ಇಟರೇಟ್ (iterate) ಮಾಡುತ್ತದೆ. ಇದು ಅಕ್ಷರವನ್ನು ಒಂದು ಪೂರ್ಣ ಯೂನಿಟ್ ಎಂದು ಪರಿಗಣಿಸುತ್ತದೆ.

ಪಾಠ ಸರಳವಾಗಿದೆ: ಎಂದಿಗೂ ಒಂದು ಯೂನಿಟ್‌ನಿಂದ ಅಳೆದು ಮತ್ತೊಂದು ಯೂನಿಟ್‌ನಿಂದ ಕತ್ತರಿಸಬೇಡಿ. ನೀವು ಡಿಸ್‌ಪ್ಲೇ ಅಗಲವನ್ನು ಅಳೆದು, ಕೋಡ್ ಯೂನಿಟ್ ಇಂಡೆಕ್ಸ್ ಮೂಲಕ ಕತ್ತರಿಸಿದರೆ, ನಿಮ್ಮ ಬಳಕೆದಾರರ ಡೇಟಾವನ್ನು ನೀವು ಹಾಳುಮಾಡುತ್ತೀರಿ.

ನಿಮ್ಮ ಕೋಡ್ ಅನ್ನು ಅಪರೂಪದ CJK ಅಕ್ಷರ ಅಥವಾ ಎಮೋಜಿಯೊಂದಿಗೆ ಪರೀಕ್ಷಿಸಿ. ASCII ಈ ದೋಷಗಳನ್ನು ತೋರಿಸುವುದಿಲ್ಲ. ನಿಮ್ಮ ಕೋಡ್ ಯಾವುದಕ್ಕೆ ಹೆದರುತ್ತದೆಯೋ ಅಂತಹ ಇನ್‌ಪುಟ್ ಅನ್ನು ನೀವು ನೀಡಲೇಬೇಕು.

Source: https://dev.to/greymothjp/a-width-check-said-the-string-was-safe-to-cut-it-split-a-kanji-in-half-4hjk

Optional learning community: https://greymoth-jp.github.io/cjk-failure-corpus/