মূল অংশে যান

একটি অক্ষর বলতে কী গোনা হয়?

চারটি আলাদা ব্যবস্থা একই লেখা চারভাবে গোনে। ইংরেজি লেখায় সবগুলো একই ফল দেয়, আর এ কারণেই সমস্যাটি চোখের আড়ালে থাকে — যেদিন ফল মেলে না, সেদিন পর্যন্ত।

সর্বশেষ পর্যালোচনা:

একটি ইমোজি, চারটি উত্তর

স্কিন টোনসহ একটি থাম্বস-আপ, বা একটি পরিবারের ইমোজি নিন। চারভাবে গুনুন, চারটি সংখ্যা পাবেন, আর কোনোটিই ভুল নয়।

পাঠক দেখেন একটি অক্ষর। একটি জিনিস, মুছতে ব্যাকস্পেসে একবার চাপ।

একটি রেগুলার এক্সপ্রেশন হয়তো দেখে সাতটি। এটি অদৃশ্য সংযোজক দিয়ে জোড়া কয়েকটি কোড পয়েন্টে গড়া — একটি মূল ইমোজি, একটি মডিফায়ার, একটি জয়নার, আরেকটি ইমোজি, এভাবে।

JavaScript বলে এগারোটি। এটি লেখা রাখে ১৬-বিট ইউনিটে, আর মৌলিক পরিসরের বাইরের যেকোনো কিছু দুটি ইউনিট নেয়, তাই ওই কোড পয়েন্টগুলোর প্রতিটি দুবার গোনা হতে পারে।

একটি ডেটাবেস কলাম দেখে পঁচিশটি বাইট। সংরক্ষণের জন্য UTF-8-এ এনকোড করলে প্রতিটি কোড পয়েন্ট চার বাইট পর্যন্ত জায়গা নেয়।

সাধারণ ইংরেজি লেখায় চারটি সংখ্যাই হুবহু এক। ঠিক এ কারণেই সমস্যাটি অদৃশ্য থাকে, যতক্ষণ না কেউ অ্যাকসেন্টযুক্ত একটি নাম, জাপানি একটি বাক্য বা একটিমাত্র ইমোজি লেখেন — আর তিন বছর ধরে ঠিকঠাক চলা একটি ফিল্ড ডেটা কেটে ফেলতে শুরু করে।

আপনার সীমা কোন সংখ্যাটি বোঝায়

কাজের প্রশ্নটি কখনোই “এই লেখা কত লম্বা” নয়। প্রশ্ন হলো “সীমাটা কে বেঁধে দিচ্ছে”, আর এর চারটি সাধারণ উত্তর আছে।

VARCHAR হিসেবে ঘোষিত একটি ডেটাবেস কলাম বেশিরভাগ ইঞ্জিনে বাইট গোনে। এ কারণেই যে ফিল্ড অনায়াসে ২৫৫টি ইংরেজি অক্ষর নেয়, তা অনেক কম জাপানি অক্ষর নেয় — প্রতিটি তিন বাইট — আর এ কারণেই অ্যাকসেন্টযুক্ত একটি নাম মাঝে মাঝে আঁটে না, যেখানে তার সাধারণ রূপটি আঁটত।

একটি SMS নিজস্ব সাত-বিট বর্ণমালায় ১৬০ অক্ষরের, আর একটি অক্ষরও এর বাইরে পড়লে সঙ্গে সঙ্গে নেমে আসে প্রতি মেসেজে ৭০-এ। ওয়ার্ড প্রসেসর থেকে পেস্ট করা একটি বাঁকা উদ্ধৃতিচিহ্ন, বা একটি ইমোজি, এক অংশের মেসেজকে তিন অংশে পরিণত করে খরচ তিনগুণ করে দিতে পারে।

JavaScript-এ লেখা একটি ফর্ম ভ্যালিডেটর প্রায় সবসময় UTF-16 ইউনিট গোনে, আর এ কারণেই যে ফিল্ডে ২৮০ অক্ষর লেখা আছে, তা ইমোজিতে ভরা এমন একটি লেখাও ফিরিয়ে দিতে পারে, যা দেখতে অনেক ছোট।

একজন মানুষ গোনেন যা তিনি দেখতে পান, আর শিরোনাম, টাইটেল ট্যাগ বা দৃশ্যমান জায়গার সীমা আছে এমন যেকোনো কিছুর জন্য এটিই একমাত্র গুরুত্বপূর্ণ সংজ্ঞা।

কোথায় গণনা আলাদা হয়ে যায়

কোন ইনপুট সমস্যা তৈরি করে, তা জানা তত্ত্ব জানার চেয়ে বেশি কাজের, কারণ সেই ইনপুটগুলো আগে থেকে অনুমান করা যায়।

ইমোজি, বিশেষ করে জোড়া লাগানোগুলো — স্কিন টোন, পরিবার, পতাকা, পেশা। একটি পতাকা হলো দুটি রিজিওনাল-ইন্ডিকেটর অক্ষর; একটি পেশা সাধারণত একজন মানুষ, একটি জয়নার আর একটি বস্তু।

অ্যাকসেন্টযুক্ত ও সংযুক্ত (কম্বাইনিং) অক্ষর। একটি é লেখা যায় একটি কোড পয়েন্ট হিসেবে, অথবা একটি e আর তার পরে একটি কম্বাইনিং অ্যাকিউট অ্যাকসেন্ট হিসেবে। দেখতে হুবহু এক, কিন্তু সাজানো হয় আলাদাভাবে, তুলনায় অসমান দাঁড়ায়, আর গোনাও হয় আলাদাভাবে — আর দুটি রূপই আসল ডেটায় থাকে, প্রায়ই একই কলামে।

লাতিন নয় এমন লিপি। চীনা, জাপানি ও কোরিয়ান অক্ষর UTF-8-এ প্রতিটি তিন বাইট। হিন্দি, থাই, তামিল ও আরবি এমন গুচ্ছ তৈরি করে, যা পাঠকের কাছে একক মনে হয়, অথচ কয়েকটি কোড পয়েন্ট লম্বা।

গাণিতিক ও সংগীতের চিহ্ন, যেগুলো মৌলিক পরিসরের বাইরে থাকে, আর তাই UTF-16-এ দুবার গোনা হয়।

এ নিয়ে কী করবেন

আপনার সীমা যা গোনে, সেটিই গুনুন। চারটি সংখ্যাই দেখায় এমন একটি কাউন্টার সরাসরি প্রশ্নের উত্তর দেয়, যা মাথা খাটিয়ে বের করার চেয়ে দ্রুত। কোডে মানানসই ফাংশন ব্যবহার করুন: JavaScript-এ Intl.Segmenter পাঠক যা দেখেন তা গোনে, Python-এ len(s.encode("utf-8")) বাইট গোনে, PHP-তে strlen নয়, mb_strlen।

ফর্ম নয়, কলাম ঠিক করুন। সীমাটা যদি ডেটাবেস ফিল্ডের হয়, স্থায়ী সমাধান গোড়ায়: MySQL-এ utf8mb4, বা PostgreSQL-এ text হিসেবে ঘোষণা করুন। MySQL-এর পুরোনো “utf8” কুখ্যাতভাবে প্রতি অক্ষরে মাত্র তিন বাইট, আর এতে একটি ইমোজিও রাখা যায় না — দীর্ঘদিনের এই ফাঁদে প্রচুর আসল ডেটা চুপচাপ কাটা পড়েছে। ফর্মে সাবধানে গোনা আসলে এমন একটি কলামের জন্য জোড়াতালি, যা অন্যভাবে ঘোষণা করা উচিত ছিল।

ঢোকার মুখেই নর্মালাইজ করুন। এন্ট্রির সময়ই লেখাকে একটি নির্দিষ্ট নর্মাল ফর্মে রূপান্তর করলে é-এর দুই রকম বানান এক হয়ে যায়, আর তুলনা, সাজানো ও গণনা সব একমত হতে শুরু করে। প্রতিটি ভাষায় এর একটি ফাংশন আছে, আর সব জায়গায় দুটি রূপ সামলানোর চেয়ে সীমানায় একবার এটি করা অনেক সহজ।

সম্পর্কিত ক্ষেত্র: base64

উল্লেখ করার মতো, কারণ এটিও একই ধরনের চমক দেয়। ডেটাকে base64-এ এনকোড করা একবারে তিন বাইট নিয়ে সেগুলো চারটি অক্ষর হিসেবে লেখে, তাই ফল প্রায় এক-তৃতীয়াংশ বড় হয় — এটি অঙ্কের হিসাব, অদক্ষতা নয়। ৬ MB-এর একটি অ্যাটাচমেন্ট মোটামুটি ৮ MB টেক্সট হয়ে যায়, আর এ কারণেই সাইজ-সীমার বেশ নিচে থাকা একটি ফাইলও পাঠানোর জন্য এনকোড করার পরে প্রত্যাখ্যাত হতে পারে।

একই হিসাব ব্যাখ্যা করে, ইমেইলের অ্যাটাচমেন্ট কেন দেখতে সীমার মধ্যে থেকেও ফেরত আসে। কোনো সীমার সঙ্গে সাইজ মেলাতে হলে এনকোড করা রূপটির সাইজ মেলান।

সাধারণ প্রশ্নোত্তর

আমার ২৫৫ অক্ষরের ফিল্ড কেন ছোট লেখাও নেয় না?

প্রায় নিশ্চিতভাবেই কারণ এটি অক্ষর নয়, বাইট গোনে। UTF-8-এ অ্যাকসেন্টযুক্ত অক্ষর দুই বাইট আর CJK অক্ষর তিন বাইট নেয়, তাই ২৫৫ বাইট মানে হয়তো ৮৫টি জাপানি অক্ষর। কলামটি utf8mb4 বা text হিসেবে ঘোষণা করলে ঠিকভাবে সমাধান হয়।

একটি ইমোজিতে কি সত্যিই তিনটি SMS-এর খরচ হয়?

হতে পারে। শুধু GSM বর্ণমালার অক্ষর থাকা মেসেজ প্রতি অংশে ১৬০ অক্ষর পায়; এর বাইরের একটি অক্ষরও পুরো মেসেজকে ৭০ অক্ষরের এনকোডিংয়ে পাঠিয়ে দেয়। তাই একটি ইমোজিসহ ১৫০ অক্ষরের মেসেজ এক অংশের বদলে তিন অংশ হয়ে যায়।

টাইটেল ট্যাগের জন্য কোন গণনা ব্যবহার করব?

কোনোটিই পুরোপুরি নয় — সার্চ ইঞ্জিন অক্ষরের সংখ্যা নয়, পিক্সেলের প্রস্থ ধরে কাটে, তাই চওড়া বড় হাতের অক্ষরের টাইটেল সরু ছোট হাতের অক্ষরের চেয়ে আগে কাটা পড়ে। প্রায় ৬০ অক্ষর সাধারণ হিসাব, আর এটি সীমা নয়, একটি নির্দেশনা।

দেখতে হুবহু এক দুটি লেখা কেন মেলে না?

সাধারণত কারণ একটি অ্যাকসেন্টযুক্ত অক্ষর দুইভাবে লেখা হয়েছে — একটিতে একক কোড পয়েন্ট হিসেবে, অন্যটিতে মূল অক্ষর আর একটি কম্বাইনিং চিহ্ন হিসেবে। তুলনার আগে দুটিকে একই রূপে নর্মালাইজ করলে মিলে যায়, আর ডেটা আপনার সিস্টেমে ঢোকার মুখেই এটি করা সার্থক।

শব্দ গণনা কি অক্ষর গণনার চেয়ে বেশি স্থির?

ইংরেজিতে, মোটামুটি হ্যাঁ। সব ভাষায় নয়: চীনা ও জাপানি ভাষায় শব্দের মাঝে স্পেস থাকে না, থাইতেও না, তাই ওই লিপিতে শব্দ গুনতে সেগমেন্টেশন লাগে, আর ভিন্ন টুল ভিন্ন উত্তর দেয়।