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@
Ошентип, ~n
0 ге гана барабар ( 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 ыкмасына ээ: substring
, substr
жана 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@
Эгерде аргумент жок болсо end
, slice
саптын аягына чейинки символдорду кайтарат:
@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@
жана (кошпогон) ортосундагы саптын бөлүгүн кайтарат .start
end
end
Бул дээрлик бирдей, 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 )end end |
терс маанилерди өткөрө аласыз |
substring(start, end) |
ортосунда start жанаend |
терс маанилер эквиваленттүү0 |
substr(start, length) |
length баштап каармандарstart |
мааниси start терс болушу мүмкүн |
Бул ыкмалардын бардыгы тапшырманы натыйжалуу аткарат. Формалдуу түрдө методдун substr
кичинекей кемчилиги бар: ал JavaScript спецификациясынын өзүндө сүрөттөлбөйт, бирок анын тиркемесинде - В тиркемесинде. Бул тиркемеде негизинен тарыхый себептерден улам бар браузерлерде колдонуу үчүн тилдин өзгөчөлүктөрү сүрөттөлөт. Ошентип, ал башка браузер эмес чөйрөлөрдө колдоого алынбашы мүмкүн. Бирок, иш жүзүндө бардык жерде иштейт.
Калган эки варианттын ичинен slice
ал ийкемдүү, терс аргументтерди колдойт жана жазуу үчүн кыскараак. Ошентип, негизинен, сиз аны эстей аласыз.
Сапты салыштыруу
Салыштыруу операторлору бөлүмүндө белгилүү болгондой , саптар алфавиттик тартипте символ боюнча салыштырылат.
Бирок, кээ бир нюанстар бар.
-
Кичи тамгалар чоң тамгадан чоңураак:
@A@alert( 'a' > 'Z' ); // true@A@
-
Диакритикалык белгилери бар тамгалар "тартиптен" чыгат:
@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
Баш тамга менен жазылган ucFirst(str)
сапты кайтаруучу функцияны жазыңыз . str
Мисалы:
ucFirst("вася") == "Вася";
Эгерде ал камтыса же болбосо checkSpam(str)
кайтаруучу функцияны жазыңыз .true
str
'viagra'
'XXX'
false
Функция регистрге сезимсиз болушу керек:
checkSpam('buy ViAgRA now') == true
checkSpam('free xxxxx') == true
checkSpam("innocent rabbit") == false
truncate(str, maxlength)
Саптын узундугун текшерген функцияны түзүңүз str
жана ал чоң болсо maxlength
, аягы str
менен алмаштырып "…"
, анын узундугуна айланат maxlength
.
Функциянын натыйжасы, эгерде кыскартуу талап кылынбаса, ошол эле сап болушу керек, керек болсо кыскартылган сап болушу керек.
Мисалы:
truncate("Вот, что мне хотелось бы сказать на эту тему:", 20) = "Вот, что мне хотело…"
truncate("Всем привет!", 20) = "Всем привет!"