Learn JavaScript

lesson ১ / ৯ · string আর template literal

Module ৩ · string আর template literal

string মানে code unit-এর একটা সারি: পুরো ছবিটা

Freeপড়া

এই lesson-এ যা শিখবে

  • একটা string-কে নম্বর দেওয়া বাক্সের সারি হিসেবে কল্পনা করতে পারবে, আর s[i] বা s.at(i) দিয়ে যেকোনো বাক্স পড়তে পারবে।
  • s[0] = "x" কেন কিছুই বদলায় না, আর প্রতিটা string method কেন নতুন একটা string ফেরত দেয়, বুঝিয়ে বলতে পারবে।
  • বাংলা text আর emoji-র বেলায় length কখন পাঠকের চোখে দেখা অক্ষরের সংখ্যা না, আগে থেকেই বলে দিতে পারবে।

Maria-র স্কুলে নামের badge print হয়। Printer প্রতিটা character-এর জন্য একটা করে ছোট বাক্স দেয়, আর কয়টা বাক্স লাগবে সেটা program-কে জিজ্ঞেস করে: name.length। "Maria" পায় 5টা বাক্স, ঠিকই আছে। ওর বান্ধবী Mahi লেখে "মাহি", আর পায় 4টা বাক্স, অথচ চোখে পড়ে দুটো অক্ষর। Zara নামের পাশে একটা smiley বসায়, আর পায় একটা বাক্স বেশি। Printer নষ্ট না। ও কিছু একটা গোনে, আর এই lesson-এ আমরা ঠিক সেটাই খুঁজে বের করব।

String জিনিসটা কী

string হলো এমন একটা value যার ভেতরে text থাকে: একটা নাম, একটা message, input-এর একটা লাইন। Module 1-এ এটাকে সাতটা primitive type-এর একটা হিসেবে দেখেছ। Engine-এর ভেতরে একটা string হলো পরপর সাজানো ছোট ছোট বাক্সের একটা সারি।

প্রতিটা বাক্সে থাকে একটা code unit: 0 থেকে 65535-এর মধ্যে একটা সংখ্যা, যেটা text-এর এক টুকরোকে বোঝায়। বাক্সগুলোর নম্বর শুরু হয় 0 থেকে, আর একটা বাক্সের নম্বরকে বলে তার index। বাক্স মোট কয়টা, সেটাই string-এর length।

English অক্ষর, অঙ্ক আর রোজকার বেশিরভাগ character-এর বেলায় এক character মানে এক বাক্স। তিনটা নাম নিয়ে badge printer-এর প্রশ্নটাই করে দেখা যাক।

console.log("Maria".length);
console.log("মাহি".length);
console.log("Zara 😀".length);
5
4
7

"Maria" পাঁচটা বাক্স। বাকি দুটো উত্তর হলো badge printer-এর সেই চমক, আর এই lesson-এর শেষ অংশ দুটোরই কারণ দেখাবে। তাহলে length বাক্স গোনে, আর সাধারণ English text-এ একটা বাক্স মানে একটা অক্ষর।

String লেখার তিনটা উপায়

Code-এ একটা string লেখা হয় quote-এর ভেতরে। JavaScript-এ quote তিন রকম, আর তিনটাই একই type-এর value বানায়।

const name = "Amara";
console.log("She said \"hi\"");
console.log('She said "hi"');
console.log(`Hello, ${name}! You have ${2 + 3} new messages.`);
console.log(`Line one
Line two`);
console.log(typeof `x`);
She said "hi"
She said "hi"
Hello, Amara! You have 5 new messages.
Line one
Line two
string

Double quote আর single quote একইভাবে কাজ করে। Double quote-এর ভেতরে একটা double quote বসাতে লেখো \"; backslash দিয়ে শুরু হয় একটা escape, মানে দুটো character মিলে একটার কাজ করে। \n হলো নতুন লাইন, আর \\ হলো একটা backslash।

Backtick দিয়ে হয় template literal। এর ভেতরে ${...} যেকোনো expression চালায়, আর তার value-টা text-এর ভেতরে বসিয়ে দেয়। Code-এ লাইন ভাঙলে string-এও লাইন ভাঙে। Template literal পুরোটা শেখাবে lesson 02।

এই track double quote লেখে, আর text-এর ভেতরে কোনো value বসাতে হলে backtick। তাহলে তিন রকম quote একই type-এর তিনটা বানান, আর text যেটায় সবচেয়ে সহজে পড়া যায়, সেটাই বেছে নাও।

একটা string, তার length আর তার বাক্সগুলো

"text"   'text'   `text with ${expression}`

s.length        বাক্সের সংখ্যা (code unit)
s[i]            index i-এর বাক্স, length 1-এর একটা string হিসেবে
s.at(i)         একই জিনিস, আর i negative হলে শেষ থেকে গোনে
s.method(...)   নতুন একটা string (বা number, boolean, array); s নিজে কখনো বদলায় না
  • Quote-গুলো দেখায় text কোথায় শুরু আর কোথায় শেষ। এরা string-এর অংশ না।
  • length একটা property, তাই এর পরে কোনো বন্ধনী নেই।
  • i হলো 0 থেকে s.length - 1 পর্যন্ত একটা index। এর বাইরে গেলে উত্তর আসে undefined।
  • Method হলো একটা value-র নিজের function, dot দিয়ে call করা হয়। প্রতিটা string method একটা একটা করে দেখাবে lesson 02।

বাক্সগুলো আর তাদের নম্বর

"Amara" string-টাকে বাক্সে এঁকে ফেলো। প্রতিটা বাক্সের ওপরে তার index, 0 থেকে 4। প্রথম বাক্স যেহেতু বাক্স 0, শেষ বাক্স সবসময় length - 1, এখানে 4।

"Amara" string-টা পাঁচটা নম্বর দেওয়া বাক্সে const s = "Amara"; s.length হলো 5 s[i] 0 1 2 3 4 5 A m a r a undefined s.at(i) -5 -4 -3 -2 -1 প্রথম বাক্স index 0, তাই শেষ বাক্স index length - 1, এখানে 4। at(-1) শেষ বাক্স, at(-2) তার আগেরটা। s[-1] তা না: ওটা দেয় undefined। Dashed বাক্সটা আসলে নেই। Index 5 পড়লে আসে undefined, কোনো error না।

বাক্সগুলোর নিচের সারিটা গোনার দ্বিতীয় একটা উপায়, শেষ থেকে। এটা চলে s.at(i) দিয়ে, square bracket দিয়ে না। এবার দেখো, একই string নিয়ে ছয়টা প্রশ্নের উত্তর engine কীভাবে দেয়।

"Amara" string-টা পাঁচটা বাক্স, 0 থেকে 4 নম্বর। s[i] আর s.at(i) একটা বাক্স পড়ে, s.at(-1) গোনে শেষ থেকে, শেষ বাক্সের পরের নম্বর দিলে আসে undefined, আর slice(1, 4) বাক্স 1, 2 আর 3 copy করে।

index01234
code unitAmara
hex0041006D006100720061
Expressionফলকী হলো
s.length5পাঁচটা বাক্স, তাই length 5। Index চলে 0 থেকে 4।
s[0]"A"Index 0 মানে প্রথম বাক্স।
s[4]"a"Index 4 শেষ বাক্স: length - 1।
s.at(-1)"a"at() শেষ থেকেও গুনতে পারে: -1 মানে শেষ বাক্স।
s[5]undefinedবাক্স 5 বলে কিছু নেই। শেষের পরে পড়তে গেলে আসে undefined, কোনো error না।
s.slice(1, 4)"mar"slice বাক্স 1, 2 আর 3 নতুন একটা string-এ copy করে। বাক্স 4-এ এসে থামে, ওটা বাদ যায়।

শেষ ধাপে slice-এর একটা ঝলক দেখলে, যেটা এক সারি বাক্স copy করে নতুন একটা string বানায়। বাকি সব method-এর সাথে এটাও শেখাবে lesson 02।

একটা বাক্স পড়া: s[i] আর s.at(i)

String-এর পরে square bracket দিলে একটা বাক্স পড়া যায়: s[0] হলো প্রথমটা। উত্তরটা নিজেও একটা string, এক বাক্স লম্বা। s.at(i)-ও একই কাজ করে, আর negative index-ও নেয়, তাই s.at(-1) মানে শেষ বাক্স।

const s = "Amara";
console.log(s[0], s[1], s[4]);
console.log(s[s.length - 1], s.at(-1), s.at(-2));
console.log(s[5], s[-1], s.at(5));
console.log(typeof s[0], s[0].length);
A m a
a a r
undefined undefined undefined
string 1

লাইন 2 শেষ বাক্সটা দুবার পড়ে: একবার index হিসাব করে, একবার at(-1) দিয়ে। লাইন 3 এমন বাক্স চায় যেগুলো নেই। কোনো error আসে না, আসে শুধু undefined, যাকে Module 1 বলেছিল "এখনো কোনো value নেই"।

s[-1]-টা খেয়াল করো: square bracket শেষ থেকে গোনে না। ও "-1" নামের একটা বাক্স খোঁজে, পায় না, আর দেয় undefined। তাই শেষ বাক্সের জন্য s.at(-1), আর index আগে থেকে জানা থাকলে s[i]।

String কখনো বদলায় না

বাক্স পড়া যায়, কিন্তু বদলানো যায় না। String immutable: একবার বানানো হলে যেমন আছে তেমনই থাকে। সাধারণ একটা program-এ বাক্সে লিখতে গেলে error হয় না। কিছুই হয় না, ব্যস।

let word = "kenji";
word[0] = "K";
console.log(word);

const upper = word.toUpperCase();
console.log(word, upper);

word = "K" + word.slice(1);
console.log(word);
kenji
kenji KENJI
Kenji

লাইন 2 বাক্স 0 বদলাতে চেয়েছিল, string সেটা পাত্তাই দেয়নি। toUpperCase()-ও word-কে বদলায়নি। ও নতুন একটা string বানিয়েছে, "KENJI", সেটা ফেরত দিয়েছে, আর program সেটা রেখেছে upper-এ।

শেষ পরিবর্তনটা কাজ করেছে, কারণ ওটা নতুন একটা string বানিয়ে word-এ রেখেছে। এটা চলে: word একটা let, তাই অন্য string রাখতে পারে। পুরোনো "kenji"-তে কেউ হাতই দেয়নি। তাহলে একটা নাম নতুন value-র দিকে তাকাতে পারবে কি না, সেটা ঠিক করে let আর const, আর immutable মানে string নিজে কখনো বদলায় না।

প্রতিটা string method এভাবেই কাজ করে: নতুন একটা value ফেরত দেয়, আসলটাকে যেমন ছিল তেমন রেখে দেয়। Strict mode হলো ভাষার একটু কড়া একটা setting, আর Module 11-এর module-গুলো এটা চালু করে দেয়। Strict mode-এ লাইন 2-এর ওই লেখাটা একটা TypeError দিয়ে program থামিয়ে দেয়, message-টা দেখাবে lesson 06।

যখন length মানে অক্ষরের সংখ্যা না

আবার badge printer-এ ফিরি। একটা বাক্সে থাকে 0 থেকে 65535-এর একটা সংখ্যা, আর দুনিয়ার বেশিরভাগ অক্ষর এক বাক্সেই এঁটে যায়। দুটো জিনিস পাঠক যেভাবে ভাবে সেভাবে চলে না।

  • বাংলা কার-চিহ্ন নিজেই একটা বাক্স। মা মানে অক্ষর ম, তারপর আ-কার া। Unicode, যে standard দুনিয়ার প্রতিটা character-কে একটা নম্বর দেয়, কার-চিহ্নকে আলাদা character হিসেবে রাখে। পাঠক দেখে একটা অক্ষর, string-এ থাকে দুটো বাক্স।
  • একটা emoji-র প্রায়ই দুটো বাক্স লাগে। Unicode এখন এত character-কে নম্বর দেয় যে 65535-এ আর কুলায় না। ওই সীমার ওপারের character, যেমন 😀, রাখা হয় দুটো বাক্সে, যাদের বলে surrogate pair। প্রতিটা অর্ধেক একা কোনো মানে বহন করে না।

JavaScript এই বাক্সগুলোতে text যে নিয়মে রাখে, তার নাম UTF-16। নিচের widget "মাহি 😀"-কে বাক্স ধরে ধরে দেখায়, আর তার নিচে আঁকা থাকে পাঠক কী দেখে।

"মাহি 😀" string-টা সাতটা code unit: মাহি-র চারটা (দুটো অক্ষর আর দুটো কার-চিহ্ন), একটা space, আর emoji-র দুটো। পাঠক দেখে চারটা character, তাই length গোনে বাক্স, অক্ষর না।

index0123456
code unitমাহিspace0xD83D0xDE00
hex09AE09BE09B909BF0020D83DDE00
চোখে দেখা character0 থেকে 12 থেকে 345 থেকে 6
Expressionফলকী হলো
s.length7সাতটা বাক্স। পাঠক দেখে চারটা character: মা, হি, একটা space আর emoji-টা।
s[0]"ম"বাক্স 0-তে অক্ষর ম।
s[1]"া"বাক্স 1-এ শুধু আ-কারের চিহ্নটা। Unicode-এ এটা নিজেই একটা character, আগের অক্ষরের গায়ে বসে।
s.slice(0, 2)"মা"বাক্স 0 আর 1 মিলে মা, পাঠকের চোখে একটাই অক্ষর।
s[5]"\ud83d"Emoji-টার লাগে দুটো বাক্স। বাক্স 5 শুধু তার প্রথম অর্ধেক, একা print করলে কাজের কিছু আসে না।
s.slice(5, 7)"😀"বাক্স 5 আর 6 মিলে পুরো emoji।
[...s].length6String-টা spread করলে গোনা হয় code point, তাই emoji-র দুই অর্ধেক একবার গোনা হয়: 6। কার-চিহ্নগুলো তবু আলাদা গোনা হয়।
[...new Intl.Segmenter().segment(s)].length4পাঠক যা দেখে তা গুনতে লাগে Intl.Segmenter: 4। Lesson 05 এটা খুলে দেখাবে।

প্রতিটা character-এর একটা Unicode নম্বর আছে, তার code point। Emoji-টা একটা code point, রাখা আছে দুটো বাক্সে। [...s] একটা string-কে তার code point-গুলোর একটা list-এ ছড়িয়ে দেয়, আর list-এর এই spread লেখার ধরনটা শেখাবে Module 7। তাই [...s].length emoji-টাকে একবারই গোনে।

const s = "মাহি 😀";
console.log(s.length);
console.log([...s].length);
console.log(JSON.stringify(s[5]), JSON.stringify(s.slice(5)));
7
6
"\ud83d" "😀"

JSON.stringify একটা value-কে code হিসেবে লেখে, তাই একা অর্ধেকটা ভাঙা চিহ্নের বদলে দেখা যায় তার নম্বর হিসেবে, \ud83d। তিন রকম গোনা, তিনটা উত্তর: 7টা বাক্স, 6টা code point, পাঠকের চোখে 4টা character।

এই track-এর problem-গুলোতে statement আলাদা কিছু না বললে length-এর গোনাটাই ধরা হয়। পাঠক যা দেখে তা গুনতে lesson 05-এর একটা tool লাগে। তাই string-এ বাংলা বা emoji থাকতে পারলে length-কে কখনো "অক্ষরের সংখ্যা" বলবে না।

Example 1: একটা শব্দের বাক্সগুলো

এই lesson-এর সবচেয়ে ছোট program। এটা বাক্স পড়ে সামনে থেকে, পেছন থেকে, আর শেষের পরে গিয়েও।

const word = "Zara";
console.log(word.length);
console.log(word[0], word[3]);
console.log(word.at(-1), word.at(-4));
console.log(word[4]);
4
Z a
a Z
undefined

চারটা বাক্স, তাই index 0 থেকে 3, আর word[4] শেষের পরে। at(-4) শেষ থেকে চার ঘর গুনে গিয়ে পড়ে প্রথম বাক্সে।

Run in Compiler
Example 2: Amara-র name card

Amara-র program fixed starter দিয়ে একটা নাম পড়ে, আর সেটা নিয়ে ছোট্ট একটা card print করে। Template literal প্রতিটা value তার লাইনে বসিয়ে দেয়।

const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];

const name = next();
out.push(`Name:   ${name}`);
out.push(`Boxes:  ${name.length}`);
out.push(`First:  ${name[0]}`);
out.push(`Last:   ${name.at(-1)}`);
out.push(`Loud:   ${name.toUpperCase()}`);
out.push(`Still:  ${name}`);

console.log(out.join("\n"));
Name:   Amara
Boxes:  5
First:  A
Last:   a
Loud:   AMARA
Still:  Amara

এই output input Amara-এর জন্য। শেষ লাইনটাই immutability-র প্রমাণ: toUpperCase() তার আগের লাইনের জন্য "AMARA" বানিয়েছে, আর name এখনো "Amara"।

Run in Compiler
Example 3: badge printer, এবার সৎভাবে

Maria badge printer-এর check-টা নতুন করে লেখে। এটা n-টা নাম পড়ে, আর প্রতিটার জন্য print করে length কয়টা বাক্স গোনে আর [...name] কয়টা code point গোনে। দুটো না মিললে বুঝতে হবে emoji আছে, তাই badge-টা একবার দেখে নিতে হবে।

const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];

const n = nextInt();
for (let i = 0; i < n; i++) {
  const name = next();
  const boxes = name.length;
  const points = [...name].length;
  let line = `${name}: ${boxes} boxes, ${points} code points`;
  if (boxes !== points) {
    line += ", check the badge";
  }
  out.push(line);
}

console.log(out.join("\n"));
Maria: 5 boxes, 5 code points
মাহি: 4 boxes, 4 code points
Zara😀: 6 boxes, 5 code points, check the badge
Kenji: 5 boxes, 5 code points

এই output input 4, তারপর Maria মাহি Zara😀 Kenji-এর জন্য। for loop আর if হলো Module 1-এ যেগুলো দেখেছ সেগুলোই; ঠিকঠাক শেখাবে Module 4। += line-এর শেষে text জুড়ে দেয়, আর প্রতিবার নতুন একটা string বানায়।

Check-টা emoji ধরে ফেলে, কিন্তু মাহি ধরে না: চারটা code point, অথচ পাঠকের চোখে দুটো অক্ষর। ওগুলো যে tool গোনে, Intl.Segmenter, সেটা দেখাবে lesson 05।

Run in Compiler

এটা কোথায় কাজে লাগে

  • Web form-এর সীমা। HTML standard একটা text field-এর maxlength আর minlength মাপে UTF-16 code unit দিয়ে, মানে length যা গোনে সেটাই। maxlength="10" দেওয়া field-এ দশটা Latin অক্ষর ধরে, কিন্তু 😀 ধরে মাত্র পাঁচটা।
  • Database। MySQL-এ utf8mb4 character set-এর একটা VARCHAR(10) column দশটা character রাখে, আর সেখানে 😀 গোনা হয় একটা হিসেবে। JavaScript-এর length দিয়ে check করলে ওটা দুটো, তাই একই নাম নিয়ে form আর database দ্বিমত করতে পারে।
  • X-এ post-এর দৈর্ঘ্য। X-এর open-source twitter-text library post গুনতে length ব্যবহার করে না। ও প্রতিটা character-কে একটা ওজন দেয়, আর একটা emoji যত code unit-ই নিক, গোনা হয় একইভাবে।

যে ভুলগুলো সবাই করে

১. শেষ বাক্সটা index length-এ পড়তে যাওয়া।

const name = "Bob";
console.log(name[name.length]);
console.log(name[name.length - 1]);
undefined
b

কোনো error নেই, যেখানে একটা অক্ষর থাকার কথা সেখানে শুধু undefined। বাক্স চলে 0 থেকে length - 1, তাই শেষটা name[name.length - 1], বা name.at(-1)। এই ভুলটা হবে, কারণ তুমি "3 নম্বর বাক্স" গোনো 1 থেকে, আর index গোনে 0 থেকে।

২. ভাবা যে বাক্সে লিখলেই string বদলাবে।

let title = "hello";
title[0] = "H";
console.log(title);
hello

Program চলে, hello print করে, কোনো message-ই দেয় না। নতুন একটা string বানিয়ে রেখে দাও: title = "H" + title.slice(1);। এই লেখাটা লিখতে যাবে, কারণ square bracket দিয়ে বাক্স পড়া যায়, আর লেখাটাও দেখতে ঠিক একই রকম।

৩. Method call করে তার উত্তর ফেলে দেওয়া।

let city = "dhaka";
city.toUpperCase();
console.log(city);
dhaka

Method-টা "DHAKA" বানিয়েছিল, কেউ সেটা রাখেনি। উত্তরটা রেখে দাও: city = city.toUpperCase();। এটা লিখবে, কারণ নামটা শুনতে string-কে দেওয়া একটা হুকুমের মতো, আর string কারো হুকুম শোনে না।

৪. Square bracket দিয়ে শেষ থেকে গোনা।

const code = "BD-1207";
console.log(code[-1]);
console.log(code.at(-1));
undefined
7

code[-1] "-1" নামের বাক্স খোঁজে, পায় না। at(-1) লেখো। Python জানা থাকলে [-1] লিখে ফেলবে, কারণ ওখানে এটা চলে।

মাথা খাটাও

Bob নিশ্চিত, তিনটা লাইনই নামটার শেষ অক্ষর print করবে।

console.log("Zara"[4]);
console.log("Zara".at(-5));
console.log("Zara".length - 1);

প্রতিটা লাইন আসলে কী print করে, আর Bob যা চেয়েছিল তার সবচেয়ে কাছে কোনটা?

"Zara"-র বাক্সগুলো গোনো 0 থেকে, তারপর -1 থেকে পেছনের দিকে। তিন নম্বর লাইন কোনো বাক্সই পড়ে না।

অনুশীলন ১সহজ

Kenji যেকোনো শব্দে এক নজর দিতে চায়: প্রথম বাক্স, শেষ বাক্স, আর মোট কয়টা বাক্স।

Input. ASCII অক্ষরের একটা শব্দ।

Output. তিনটা লাইন: প্রথম অক্ষর, শেষ অক্ষর, আর length।

Constraints. শব্দে 1 থেকে 50টা অক্ষর।

Sample. Input Kenji দিলে তিন লাইনে আসে K, i আর 5।

const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];

// your code: read with next() and nextInt(), push every line of output to out

console.log(out.join("\n"));

এটা আলাদা করে grade হয় না। Zara-র প্রথম test এক অক্ষরের একটা শব্দ: তার প্রথম আর শেষ বাক্স কোনগুলো?

Run in Compiler
অনুশীলন ২মাঝারি

Bob একটা game board-এ প্রতিটা শব্দের মাঝখানটা print করে। বিজোড় length-এর শব্দে মাঝের অক্ষর একটা। জোড় length-এ দুটো, আর ও দুটোই চায়।

Input. n, তারপর ASCII অক্ষরের n-টা শব্দ।

Output. প্রতি শব্দে একটা লাইন: তার মাঝের অক্ষর, বা মাঝের দুটো অক্ষর।

Constraints. 1 <= n <= 1000। প্রতিটা শব্দে 1 থেকে 50টা অক্ষর।

Sample. Input 3 আর Amara Zara a দিলে তিন লাইনে আসে a, ar আর a।

const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];

// your code: read with next() and nextInt(), push every line of output to out

console.log(out.join("\n"));

এটা আলাদা করে grade হয় না। Math.floor(word.length / 2) হলো মাঝখানের ঠিক ডান দিকের index। জোড়ের হিসাবটা আগে "Zara" দিয়ে হাতে করে দেখো।

Run in Compiler
অনুশীলন ৩মাঝারি

Zara-র chat app প্রতিটা message কত লম্বা দেখায়, আর বাংলা আর emoji-তে ভুল করেছে। ও প্রতিটা message-এর দুটো গোনাই পাশাপাশি চায়।

Input. এই problem starter-এর lines variant ব্যবহার করে। লাইন 1-এ n। তারপর UTF-8-এ n-টা text লাইন। Input-এর শেষ লাইন কখনো খালি না।

Output. প্রতিটা text লাইনের জন্য একটা লাইন: UTF-16 code unit-এ তার length, একটা space, আর তার code point-এর সংখ্যা।

Constraints. 1 <= n <= 10000। প্রতিটা লাইনে 0 থেকে 1000টা code point, কোনো carriage return নেই, কোনো একা surrogate নেই।

Sample. চার লাইনে input 3, Maria, মাহি 😀 আর 👋🏽 hi দিলে আসে 5 5, 7 6 আর 7 5।

const input = require("fs").readFileSync(0, "utf8");
const lines = input.split("\n");
let at = 0;
const next = () => lines[at++];
const nextInt = () => Number(next());
const out = [];

// your code: read with next() and nextInt(), push every line of output to out
// Read n, then n lines. Per line: code units, then code points.

console.log(out.join("\n"));

true-length নামে grade হয়। Lines variant space আর খালি লাইন রেখে দেয়, তাই next() পুরো একটা লাইন ফেরত দেয়। Hidden test-এ খালি লাইন, পতাকা আর skin tone দেওয়া emoji-ও আছে।

Run in Compiler
অনুশীলন ৪কঠিন

Zara-র game প্রতিটা player-এর নামের শেষ character একটা tile-এ দেখায়। কিছু নাম শেষ হয় emoji দিয়ে, আর at(-1) tile-এ বসিয়ে দেয় আধখানা emoji।

Input. n, তারপর n-টা নাম। একটা নাম ASCII অক্ষর, পরে হয়তো একটা emoji, যেমন 😀 বা 🐱 (প্রতিটা একটা code point)। কোনো নামে space নেই।

Output. প্রতিটা নামের জন্য একটা লাইন: তার শেষ code point, মানে নাম emoji দিয়ে শেষ হলে পুরো emoji-টা।

Constraints. 1 <= n <= 1000। প্রতিটা নামে 1 থেকে 30টা code point।

Sample. Input 3 আর Zara😀 Kenji Bob🐱 দিলে তিন লাইনে আসে 😀, i আর 🐱।

const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];

// your code: read with next() and nextInt(), push every line of output to out

console.log(out.join("\n"));

এটা আলাদা করে grade হয় না। Lesson-এ idea-টার ইঙ্গিত দেওয়া আছে: [...name] হলো code point-এর একটা list, আর list-এরও at() আছে।

Run in Compiler

সচরাচর যে প্রশ্নগুলো আসে

  • JavaScript অক্ষর না গুনে code unit গোনে কেন?

    1995 সালে JavaScript যখন বানানো হয়, তখন Unicode-এর প্রতিটা character 16 bit-এ এঁটে যেত, তাই এক বাক্স মানে ছিল এক character। 1996-এ Unicode সেই সীমা ছাড়িয়ে যায়, আর JavaScript, Java-র মতোই, বাক্সগুলো রেখে নতুন character-গুলো জোড়ায় জোড়ায় রাখা শুরু করে। এখন length বদলালে পুরোনো program ভেঙে যাবে। তাই length বাক্স গোনে, আর বাকিটা গোনে নতুন tool-গুলো।

  • String কি একটা array?

    না, যদিও দেখতে অনেকটা সেরকম: এর একটা length আছে, আর নম্বর দেওয়া বাক্স আছে যেগুলো square bracket দিয়ে পড়া যায়। String একটা primitive value, কখনো বদলায় না; array একটা object, বদলানো যায়, শেখাবে Module 7। একটাকে আরেকটায় বদলাবে প্রায়ই, lesson 02-এর split আর join দিয়ে।

  • Single না double quote, এতে কিছু আসে যায়?

    Engine-এর কাছে না: দুটোই একই string বানায়। Team-গুলো একটা বেছে নেয়, আর একটা formatter সেটা সব জায়গায় একরকম রাখে; Prettier-এর default double quote, এই track-এরও তাই। অন্যটা নাও শুধু escape এড়াতে, যেমন 'She said "hi"'।

  • String যদি কখনো না বদলায়, তাহলে program সারাদিন text edit করে কীভাবে?

    পুরোনো string-এর টুকরো দিয়ে নতুন একটা string বানিয়ে একই নামে রেখে দেয়। ওপরের "K" + word.slice(1) এই ধরনটাই। টুকরো কাটার সব method দেবে lesson 02, আর নতুন string বানানো শুনতে যত খরচের মনে হয় আসলে তত না কেন, দেখাবে lesson 05।

  • const দিলেই কি string আর বদলানো যায় না?

    String এমনিতেই বদলায় না, let হোক বা const। const শুধু নামটাকে পরে অন্য value-র দিকে তাকাতে দেয় না। তাই const word = "hi"; word = "ho"; আটকায় const-এর কারণে, আর word[0] = "H" কিছুই করে না string-এর কারণে।

মূল কথা

  • একটা string হলো বাক্সের (code unit) একটা সারি, index 0 থেকে length - 1; s[i] আর s.at(i) একটা বাক্স পড়ে।
  • s.at(-1) শেষ বাক্স; s[-1] আর শেষের পরের যেকোনো index দেয় undefined, error না।
  • String immutable: বাক্সে লিখলে কিছু হয় না, আর প্রতিটা method নতুন একটা value ফেরত দেয়।
  • String লেখা যায় double quote, single quote বা backtick দিয়ে; backtick বানায় template literal, যাতে থাকে ${...} আর সত্যিকারের লাইন ভাঙা।
  • length গোনে UTF-16 code unit: বাংলা কার-চিহ্ন নিজেই একটা বাক্স, আর emoji প্রায়ই দুটো।
  • আরও গভীরে: Under the Hood, immutability, rope আর UTF-16 (Pro)।

এরপর lesson 02 প্রতিটা string method একটা একটা করে নেবে, তার output আর খরচসহ, আর দেখাবে character code-এর পুরো table।

lesson ১ শেষ

শেষ হলে চিহ্ন দিন, অগ্রগতি আপনার সাথে থাকবে।

পরেরটা: প্রতিটা string method, একটা একটা করে

string মানে code unit-এর একটা সারি: পুরো ছবিটা | Learn JavaScript | Progsity