Loading...

Саптар

Саптар

 

JavaScript-те ар кандай текст маалыматтары сап болуп саналат. Бир катар башка тилдерде бар өзүнчө "мүнөзү" түрү жок.

Саптардын ички форматы ар дайым UTF-16 , беттин коддоосуна карабастан.

Кашалар

JavaScript'те цитаталардын ар кандай түрлөрү бар.

Сапты жалгыз, кош же арткы тырмакчаларды колдонуу менен түзсө болот:

@A@let single = 'single-quoted';
let double = "double-quoted";

let backticks = `backticks`;@A@

Жалгыз жана кош тырмакчалар негизинен бирдей иштешет жана эгер сиз артка тырмакчаларды колдонсоңуз, анда биз аларды ороп, мындай сапка каалаган туюнтмаларды киргизе алабыз ${…}:

@A@function sum(a, b) {
  return a + b;
}
alert(`1 + 2 = ${sum(1, 2)}.`); // 1 + 2 = 3.@A@

Backticks дагы бир артыкчылыгы, алар бирден ашык сызыктарды камтышы мүмкүн, мисалы:

@A@let guestList = `Guests:
 * John
 * Pete
 * Mary
`;
alert(guestList); // список гостей, состоящий из нескольких строк@A@

Абдан табигый көрүнөт, туурабы? Анан эмне? Бирок бир же кош тырмакчаны ошол эле жол менен колдонууга аракет кылсаңыз, ката аласыз:

@A@let guestList = "Guests: // Error: Unexpected token ILLEGAL
  * John";@A@

Жалгыз жана кош тырмакчалар тилде эзелтеден бери келе жатат: анда көп саптын зарылчылыгы эске алынган эмес. Арткы цитаталарга келсек, алар кийинчерээк пайда болгон, ошондуктан алар ийкемдүү.

Backquotes ошондой эле биринчи арткы цитатадан мурун "шаблон функциясын" көрсөтүүгө мүмкүндүк берет. Колдонулган синтаксис: func`string`. Автоматтык түрдө чакырылган функция funcага камтылган сапты жана туюнтмаларды кабыл алат жана аларды иштете алат. Бул тууралуу кененирээк документациядан окуй аласыз . Эгерде саптын алдында туюнтма бар болсо, анда шаблон сабы "тег шаблону" деп аталат. Бул саптар үчүн өзүңүздүн шаблонуңузду колдонууга мүмкүндүк берет, бирок иш жүзүндө тег үлгүлөрү сейрек колдонулат.

Атайын символдор

Көп сап саптары ошондой эле "жаңы сап белгиси" деп аталган бир жана кош тырмакчаларды колдонуу менен түзүлүшү мүмкүн, ал төмөнкүчө жазылат \n:

@A@let guestList = "Guests:\n * John\n * Pete\n * Mary";

alert(guestList); // список гостей, состоящий из нескольких строк@A@

Тактап айтканда, бул эки сап эквиваленттүү, жөн гана башкача жазылган:

@A@// перевод строки добавлен с помощью символа перевода строки
let str1 = "Hello\nWorld";
// многострочная строка, созданная с использованием обратных кавычек
let str2 = `Hello
World`;
alert(str1 == str2); // true@A@

Башка азыраак колдонулган атайын белгилер бар. Бул жерде тизме:

Символ Description
\n Саптык которуу
\r Windows текст файлдарында символдордун айкалышы линияларды берүү үчүн колдонулат \r\n, ал эми башка операциялык системаларда бул жөнөкөй \n. Бул тарыхый себептерден улам, Windows программасы адатта түшүнөт жана жөнөкөй \n.
\',\" Цитаталар
\\ Керти сызык
\t Өтмөк белгиси
\b.. \f_\v Backspace, Form Feed жана Vertical Tab - артка дал келүү үчүн солго коюлган, учурда колдонулбайт.

Көрүнүп тургандай, бардык өзгөчө каармандар \"качуучу каарман" деп аталган тескери сызык менен башталат.

Ал сапка цитата киргизгиңиз келгенде да колдонулат.

Мисалга:

@Aalert( 'I\'m the Walrus!' ); // I'm the Walrus!@A@

Бул жерде сиз тырмакчанын алдына тескери сызыкты кошушуңуз керек -  \'- антпесе ал саптын соңун көрсөтөт.

Албетте, качуу талабы сапты курчап турган тырмакчаларга гана тиешелүү. Ошентип, биз бул сап үчүн кош тырмакчаларды же арткы белгилерди колдонуу менен бир кыйла жарашыктуу чечимди колдоно алабыз:

@A@alert( `I'm the Walrus!` ); // I'm the Walrus!@A@

Эсиңизде болсун, арткы сызык \тилди котормочу тарабынан туура окуу үчүн гана кызмат кылат, бирок ал окугандан кийин сапка жазылбайт. Сап RAMга сакталганда, ага символ кошулбайт \alertМуну жогорудагы мисалдардын жыйынтыгынан ачык көрө аласыз .

Бирок саптын өзүнө тескери сызык кошуу керек болсочу \?

Сиз муну ... алдына дагы бир тескери сызык кошуу менен кыла аласыз!

@A@alert( `The backslash: \\` ); // The backslash: \

Сызыктын узундугу

length саптын узундугун камтыйт:

alert( `My\n`.length ); // 3

Бул бир өзгөчө белги экенин эске алыңыз \n, андыктан бул жерде баары туура: саптын узундугу 3.

length ...болуп саналат

Башка тилдерде практикасы бар адамдар кокусунан кашааларды кошуп, аны чакырып алганга аракет кылышат: алар str.length()ордуна жазышат str.length. Бул иштебейт.

Функция эмес, сандык касиет болгондуктан str.length, кашаа кошуунун кереги жок.

Символго кирүү

posСиз төрт бурчтуу кашаанын жардамы менен позицияны ээлеген символду ала аласыз : [pos]Сиз str.at(pos) ыкмасын да колдонсоңуз болот . Биринчи белги нөл позициясы:

@A@let str = `Hello`;
// получаем первый символ
alert( str[0] ); // H
alert( str.at(0) ); // H
// получаем последний символ
alert( str[str.length - 1] ); // o
alert( str.at(-1) ); // o@A@

Көрүнүп тургандай, ыкманын артыкчылыгы .at(pos)терс позицияга мүмкүндүк берет. Эгерде posтерс сан болсо, анда саноо саптын аягынан башталат.

Ошентип, .at(-1)акыркы белгини билдирет, жана .at(-2)анын алдындагы белгини билдирет ж.б.

Чарчы кашаалар ар дайым undefinedтерс көрсөткүчтөрдү кайтарат. Мисалы:

@A@let str = `Hello`;
alert( str[-2] ); // undefined
alert( str.at(-2) ); // l@A@

Сиз ошондой эле саптын символу боюнча итерациялай аласыз for..of:

@A@for (let char of "Hello") {
  alert(char); // H,e,l,l,o (char — сначала "H", потом "e", потом "l" и т.д.)
}@A@

Саптар өзгөрүлгүс

JavaScript саптын мазмунун өзгөртүү мүмкүн эмес. Ортодогу символду алып, аны алмаштырууга болбойт. Сап түзүлөөрү менен түбөлүккө ушундай болот.

Келгиле, муну сынап көрөлү жана ал иштебей калса, көрөлү:

@A@let str = 'Hi';
str[0] = 'h'; // ошибка
alert( str[0] ); // не работает@A@

Сиз жаңы сап түзүп, аны эскинин ордуна ошол эле өзгөрмөгө жазсаңыз болот.

Мисалы:

@A@let str = 'Hi';
str = 'h' + str[1]; // заменяем строку
alert( str ); // hi@A@

Биз кийинки бөлүмдөрдө көбүрөөк мисалдарды көрөбүз.

Ишти өзгөртүү

toLowerCase() жана toUpperCase() ыкмалары символдордун регистрлерин өзгөртөт:

@A@alert( 'Interface'.toUpperCase() ); // INTERFACE
alert( 'Interface'.toLowerCase() ); // interface@A@

Эгер биз белгилүү бир белгини кичирейтүүнү кааласак:

@A@alert( 'Interface'[0].toLowerCase() ); // 'i'@A@

Substring издөө

Субсапты издөөнүн бир нече жолу бар.

str.indexOf

Биринчи ыкма str.indexOf(substr, pos) .

substrАл саптан strпозициядан баштап субсапты издейт жана дал келген же дал келбеген posпозицияны кайтарат .-1

Мисалы:

@A@let str = 'Widget with id';

alert( str.indexOf('Widget') ); // 0, потому что подстрока 'Widget' найдена в начале
alert( str.indexOf('widget') ); // -1, совпадений нет, поиск чувствителен к регистру

alert( str.indexOf("id") ); // 1, подстрока "id" найдена на позиции 1 (..idget with id)@A@

Кошумча экинчи аргумент издөөнү белгилүү бир позициядан баштоого мүмкүндүк берет.

Мисалы, биринчи көрүнүш "id"позициясында 1. Төмөнкүлөрдү табуу үчүн издөөнү позициядан баштаңыз 2:

@A@let str = 'Widget with id';

alert( str.indexOf('id', 2) ) // 12@A@

Подряддын бардык көрүнүштөрүн табуу үчүн indexOfциклде иштешиңиз керек. Ар бир жолу, кийинки позицияны алгандан кийин, биз төмөндөгүлөр менен жаңы издөөнү баштайбыз:

@A@let str = 'Ослик Иа-Иа посмотрел на виадук';

let target = 'Иа'; // цель поиска

let pos = 0;
while (true) {
  let foundPos = str.indexOf(target, pos);
  if (foundPos == -1) break;

  alert( `Найдено тут: ${foundPos}` );
  pos = foundPos + 1; // продолжаем со следующей позиции
}@A@

Ошол эле алгоритм кыскараак түрдө жазылышы мүмкүн:

@A@let str = "Ослик Иа-Иа посмотрел на виадук";
let target = "Иа";
let pos = -1;
while ((pos = str.indexOf(target, pos + 1)) != -1) {
  alert( pos );
}@A@
str.lastIndexOf(substr, position)

Ушундай эле ыкма дагы бар str.lastIndexOf(substr, position) , ал саптын аягынан башына чейин издейт.

Ал эң акыркы учурду алуу керек болгондо колдонулат: саптын аягына чейин же белгилүү бир позицияга чейин (кошкондо).

indexOfАбалын текшергенде бир аз ыңгайсыздык бар if. Бул шарт иштебейт:

@A@let str = "Widget with id";

if (str.indexOf("Widget")) {
    alert("Совпадение есть"); // не работает
}@A@

Биз субсапты издеп жатабыз "Widget"жана ал ошол жерде, так позициясында 0. Бирок alertал көрсөтүлбөйт, анткени str.indexOf("Widget")ал кайтып келет 0жана ifсыноо өтпөй калды деп чечет.

Ошондуктан, сиз текшерүү керек -1:

@A@let str = "Widget with id";

if (str.indexOf("Widget") != -1) {
    alert("Совпадение есть"); // теперь работает
}@A@

Битвалдык ЭМЕС

Bitwise NOT операторун колдонгон эски трюк бар - ~. Ал санды кол коюлган 32 биттик бүтүн санга айлантат. Бөлчөк бөлүгү, эгерде бар болсо, жокко чыгарылат. Андан кийин сандын бардык биттери тескериленет.

Иш жүзүндө бул жөнөкөй нерсени билдирет: 32 биттик бүтүн сандар үчүн ~nмаани -(n+1).

Өзгөчө:

@A@alert( ~2 ); // -3, то же, что -(2+1)
alert( ~1 ); // -2, то же, что -(1+1)
alert( ~0 ); // -1, то же, что -(0+1)
alert( ~-1 ); // 0, то же, что -(-1+1)@A@

Ошентип, ~n0 ге гана барабар ( 32 биттик бүтүн сан болгон n == -1каалаган үчүн ).n

Демек, текшерүүдөн өтүү if ( ~str.indexOf("…") )натыйжадан indexOfайырмаланып -1, дал келүү бар дегенди билдирет.

Бул кээде чекти indexOfкомпакттуу кылуу үчүн колдонулат:

 
 
@A@let str = "Widget";

if (~str.indexOf("Widget")) {
  alert( 'Совпадение есть' ); // работает
}@A@

Жалпысынан тилдин өзгөчөлүктөрүн кандайдыр бир ачык-айкын эмес жол менен колдонуу сунушталбайт, бирок бул куулук эски коддо кеңири колдонулат, андыктан аны түшүнүү маанилүү.

Жөн гана эсиңизде болсун: if (~str.indexOf(…))"эгер табылса" дегенди билдирет.

Бирок, тагыраак айтканда, чоң сандар оператор тарабынан 32 битке чейин кыскартылгандыктан ~, натыйжасы боло турган башка сандар да бар 0, алардын эң кичинеси ~4294967295=0. Ошондуктан, мындай текшерүү кичине узундуктагы саптар үчүн гана туура иштейт.

Азыркы учурда, мындай куулук эски коддон гана тапса болот, анткени жаңысында бул жөн эле кереги жок: бир ыкма бар .includes(төмөндө караңыз).

камтыйт, startsWith, endsWith

Заманбап str.includes(substr, pos)true ыкмасы сапта strички сапты камтыса substrже falseал жок болсо кайтарат .

Бул туура тандоо, эгерде дал келүү бар-жогун текшерүү керек болсо, бирок бизге позициянын кереги жок:

@A@alert( "Widget with id".includes("Widget") ); // true
alert( "Hello".includes("Bye") ); // false@A@

Кошумча экинчи аргумент str.includesиздөөнү белгилүү бир позициядан баштоого мүмкүндүк берет:

@A@alert( "Midget".includes("id") ); // true
alert( "Midget".includes("id", 3) ); // false, поиск начат с позиции 3@A@

str.startsWith жана str.endsWith ыкмалары саптын белгилүү бир сап менен башталып, бүтөөрүн текшерет:

@A@alert( "Widget".startsWith("Wid") ); // true, "Wid" — начало "Widget"
alert( "Widget".endsWith("get") ); // true, "get" — окончание "Widget"@A@

Кошумча сап алуу

JavaScript субсапты алуунун 3 ыкмасына ээ: substringsubstrжана slice.

@A@str.slice(start [, end])@A@

Саптын чейинки бөлүгүн кайтарат start(кошпогондо) end.

Мисалы:

@A@let str = "stringify";
// 'strin', символы от 0 до 5 (не включая 5)
alert( str.slice(0, 5) );
// 's', от 0 до 1, не включая 1, т. е. только один символ на позиции 0
alert( str.slice(0, 1) );@A@

Эгерде аргумент жок болсо endsliceсаптын аягына чейинки символдорду кайтарат:

@A@let str = "stringify";
alert( str.slice(2) ); // ringify, с позиции 2 и до конца@A@

Сиз ошондой эле start/endүчүн терс маанилерди орното аласыз. Бул позиция саптын аягындагы белгилердин берилген саны катары аныкталат дегенди билдирет :

@A@let str = "stringify";
// начинаем с позиции 4 справа, а заканчиваем на позиции 1 справа
alert( str.slice(-4, -1) ); // gif

str.substring(start [, end])@A@

жана (кошпогон) ортосундагы саптын бөлүгүн кайтарат .startendend

Бул дээрлик бирдей, sliceбирок startдагы көптү көрсөтсө болот end.
Эгерде startандан чоңураак болсо end, анда ыкма substringаргументтер алмаштырылгандай иштейт.

Мисалы:

@A@let str = "stringify";
// для substring эти два примера — одинаковы
alert( str.substring(2, 6) ); // "ring"
alert( str.substring(6, 2) ); // "ring"
// …но не для slice:
alert( str.slice(2, 6) ); // "ring" (то же самое)
alert( str.slice(6, 2) ); // "" (пустая строка)@A@

Терс маанилер substring, айырмаланып sliceколдоого алынбайт, алар катары чечмеленет 0.

str.substr(start [, length])

startУзундуктан саптын бир бөлүгүн кайтарат length.

Мурунку ыкмалардан айырмаланып, бул акыркы позициянын ордуна узундукту көрсөтүүгө мүмкүндүк берет:

@A@let str = "stringify";
// ring, получаем 4 символа, начиная с позиции 2
alert( str.substr(2, 4) );@A@

Биринчи аргументтин мааниси терс болушу мүмкүн, бул учурда позиция аягында аныкталат:

@A@let str = "stringify";
// gi, получаем 2 символа, начиная с позиции 4 с конца строки
alert( str.substr(-4, 2) );@A@

Бул ыкма тил спецификациясынын В тиркемесинде келтирилген . Бул браузерге негизделген JavaScript кыймылдаткычтары гана колдоого алышы керек жана аны колдонуу сунушталбайт дегенди билдирет. Бирок иш жүзүндө бардык жерде колдоого алынат.

Чаташтырбоо үчүн бул ыкмалардын кандай иштээрин кыскача карап көрөлү:

ыкмасы тандайт... терс баалуулуктар
slice(start, end) чейин ( кошпогондо start)endend терс маанилерди өткөрө аласыз
substring(start, end) ортосунда startжанаend терс маанилер эквиваленттүү0
substr(start, length) lengthбаштап каармандарstart мааниси startтерс болушу мүмкүн
Кайсы ыкманы тандоо керек?

Бул ыкмалардын бардыгы тапшырманы натыйжалуу аткарат. Формалдуу түрдө методдун substrкичинекей кемчилиги бар: ал JavaScript спецификациясынын өзүндө сүрөттөлбөйт, бирок анын тиркемесинде - В тиркемесинде. Бул тиркемеде негизинен тарыхый себептерден улам бар браузерлерде колдонуу үчүн тилдин өзгөчөлүктөрү сүрөттөлөт. Ошентип, ал башка браузер эмес чөйрөлөрдө колдоого алынбашы мүмкүн. Бирок, иш жүзүндө бардык жерде иштейт.

Калган эки варианттын ичинен sliceал ийкемдүү, терс аргументтерди колдойт жана жазуу үчүн кыскараак. Ошентип, негизинен, сиз аны эстей аласыз.

Сапты салыштыруу

Салыштыруу операторлору бөлүмүндө белгилүү болгондой , саптар алфавиттик тартипте символ боюнча салыштырылат.

Бирок, кээ бир нюанстар бар.

  1. Кичи тамгалар чоң тамгадан чоңураак:

    @A@alert( 'a' > 'Z' ); // true@A@
  2. Диакритикалык белгилери бар тамгалар "тартиптен" чыгат:

    @A@alert( 'Österreich' > 'Zealand' ); // true@A@

    Бул өлкөнүн аталыштарын сорттоодо кызыктай натыйжаларга алып келиши мүмкүн: тизмеден Zealandкийинки нерсени күтүү кадимки көрүнүш.Österreich

Эмне болуп жатканын түшүнүү үчүн, келгиле, JavaScriptдеги саптардын ички көрүнүшүн карап көрөлү.

Саптар UTF-16да коддолгон . Ошентип, каалаган белги тиешелүү кодго ээ. Сиз анын коду жана тескерисинче, белгини алууга мүмкүндүк берген атайын ыкмалар бар.

str.codePointAt(pos)

Позициядагы символдун кодун кайтарат pos:

@A@// одна и та же буква в нижнем и верхнем регистре
// будет иметь разные коды
alert( "z".codePointAt(0) ); // 122
alert( "Z".codePointAt(0) ); // 90

String.fromCodePoint(code)@A@

Анын коду боюнча символ жарататcode

@A@alert( String.fromCodePoint(90) ); // Z@A@

65чейин коддору бар символдорду камтыган сап түзөлү 220- бул латын жана башка жалпы символдор:

 
 
@Alet str = '';

for (let i = 65; i <= 220; i++) {
  str += String.fromCodePoint(i);
}
alert( str );
// ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„
// ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜ@A@

Көрүнүп тургандай, биринчи баш тамгалар, андан кийин бир нече атайын белгилер, андан кийин кичине тамгалар жана Öчыгаруунун аягына чейин келет.

Эми эмне үчүн экени түшүнүктүү a > Z.

Каармандар алардын коддору менен салыштырылат. Чоңураак код = чоңураак символ. Код (97) коддон (90) aчоң .Z

  • Бардык кичине тамгалар чоң тамгалардан кийин келет, анткени алардын коддору чоңураак.
  • Кээ бир тамгалар, мисалы Ö, негизги алфавиттин сыртында. aБул каттын ар кандай тамгаларынан чоңураак код бар z.

Туура салыштыруу

"Туура" сапты салыштыруу алгоритми көрүнгөндөн да татаал, анткени ар кандай тилдер ар кандай алфавиттерди колдонушат.

Демек, браузер салыштыруу үчүн кайсы тилди колдонууну билиши керек.

Бактыга жараша, бардык заманбап браузерлер (IE10 - кошумча китепкана Intl.JS талап кылынат) ECMA 402 стандартын колдойт , ал ар кандай тилдердеги саптарды алардын эрежелерин эске алуу менен туура салыштырууну камсыз кылат.

Бул үчүн тиешелүү ыкма бар.

str.localeCompare (str2) чалуу тилдин эрежелерине ылайык кайсы сап чоңураак экенин көрсөткөн санды кайтарат:

  • strдан аз болсо, терс сан str2.
  • strЭгер андан чоң болсо , оң сан str2.
  • 0саптар бирдей болсо.

Мисалы:

@A@alert( 'Österreich'.localeCompare('Zealand') ); // -1@A@

Бул ыкманын эки кошумча аргументи бар, алар документтерде келтирилген . Биринчиси тилди көрсөтүүгө мүмкүндүк берет (демейки боюнча ал чөйрөдөн алынат) - тамгалардын тартиби ага көз каранды. Экинчиси, кошумча эрежелерди аныктоо, мисалы, регистрдин сезгичтиги жана ортосундагы айырмачылыктар "a"эске алынышы керекпи "á".

Бардыгы

  • Цитаталардын үч түрү бар. Артка тырмакчаларды колдонгон саптар коддун бирден ашык сабын камтышы мүмкүн ${…}.
  • JavaScript'теги саптар UTF-16да коддолгон.
  • Саптын үзүлүшү сыяктуу өзгөчө белгилер бар \n.
  • Белги алуу үчүн []же ыкмасын колдонуңуз at.
  • sliceже колдонуңуз substring.
  • Сапты кичине же чоң регистрге айландыруу үчүн колдонуңуз toLowerCase/toUpperCase.
  • Кошумча сапты издөө үчүн, indexOfже includes/startsWith/endsWithбир окуянын бар же жок экенин текшергиңиз келгенде гана колдонуңуз.
  • Саптарды тилдин эрежелерине ылайык салыштыруу үчүн колдонуңуз localeCompare.

Саптардын дагы башка пайдалуу ыкмалары бар:

  • str.trim()Саптын башындагы жана аягындагы боштуктарды жок кылат.
  • str.repeat(n)- сап nубакыттарын кайталайт.
  • …жана башкалардан таба аласыз .

Саптар туруктуу сөз айкаштарын колдонуу менен издөө жана алмаштыруу ыкмаларын камсыз кылат. Бирок бул өзүнчө чоң тема, андыктан ага Регулярдуу сөз айкаштары окуу китебинин өзүнчө бөлүмү арналган .

Ошондой эле, азыркы учурда, саптар Юникод коддоосуна негизделгенин билүү маанилүү, ошондуктан кээде салыштырууларда көйгөйлөр болушу мүмкүн. Юникод жөнүндө көбүрөөк билүү үчүн Юникод, Стринг ички бөлүмдөрүн караңыз .

Tasks

маанилүүлүгү: 5

Баш тамга менен жазылган ucFirst(str)сапты кайтаруучу функцияны жазыңыз . strМисалы:

ucFirst("вася") == "Вася";

Тапшырма үчүн тесттер менен кумкоргонду ачыңыз.

чечим
маанилүүлүгү: 5

Эгерде ал камтыса же болбосо checkSpam(str)кайтаруучу функцияны жазыңыз .truestr'viagra''XXX'false

Функция регистрге сезимсиз болушу керек:

checkSpam('buy ViAgRA now') == true
checkSpam('free xxxxx') == true
checkSpam("innocent rabbit") == false

Тапшырма үчүн тесттер менен кумкоргонду ачыңыз.

чечим
маанилүүлүгү: 5

truncate(str, maxlength)Саптын узундугун текшерген функцияны түзүңүз strжана ал чоң болсо maxlength, аягы strменен алмаштырып "…", анын узундугуна айланат maxlength.

Функциянын натыйжасы, эгерде кыскартуу талап кылынбаса, ошол эле сап болушу керек, керек болсо кыскартылган сап болушу керек.

Мисалы:

truncate("Вот, что мне хотелось бы сказать на эту тему:", 20) = "Вот, что мне хотело…"

truncate("Всем привет!", 20) = "Всем привет!"