Розумний спосіб обрізати довгі струни


187

Хтось має більш складне рішення / бібліотеку для обрізання рядків за допомогою JavaScript та встановлення еліпсису в кінці, ніж очевидний:

if (string.length > 25) {
  string = string.substring(0, 24) + "...";
}

5
Що ви маєте на увазі під "досконалішими"? Функції, що враховують межі слів?
Residuum

2
І не обрізання посеред тегів HTML.
Sz.

Відповіді:


366

По суті, ви перевіряєте довжину заданого рядка. Якщо вона довша заданої довжини n, відріжте її на довжину n( substrабо slice) та додайте html сутність …(…) до відсіченого рядка.

Такий спосіб виглядає так

function truncate(str, n){
  return (str.length > n) ? str.substr(0, n-1) + '…' : str;
};

Якщо під "більш досконалим" ви маєте на увазі обрізання на останній межі слова рядка, тоді вам потрібна додаткова перевірка. Спочатку ви обрізаєте рядок до потрібної довжини, потім обрізаєте результат цього межі останнього слова

function truncate( str, n, useWordBoundary ){
  if (str.length <= n) { return str; }
  const subString = str.substr(0, n-1); // the original check
  return (useWordBoundary 
    ? subString.substr(0, subString.lastIndexOf(" ")) 
    : subString) + "&hellip;";
};

Ви можете розширити власний Stringпрототип за допомогою своєї функції. У цьому випадку strпараметр слід видалити, а strв межах функції замінити на this:

String.prototype.truncate = String.prototype.truncate || 
function ( n, useWordBoundary ){
  if (this.length <= n) { return this; }
  const subString = this.substr(0, n-1); // the original check
  return (useWordBoundary 
    ? subString.substr(0, subString.lastIndexOf(" ")) 
    : subString) + "&hellip;";
};

Більш догматичні розробники можуть вас сильно капітулювати на цьому (" Не змінюйте об'єкти, якими ви не володієте ". Я б не проти).

Підхід без розширення Stringпрототипу полягає у створенні власного хелперного об'єкта, що містить (довгу) рядок, який ви надаєте, та вищевказаний метод для врізання його. Ось що робить фрагмент нижче.

Нарешті, ви можете використовувати css лише для обрізання довгих рядків у HTML-вузлах. Це дає менший контроль, але цілком може бути життєздатним рішенням.


5
Слід також врахувати наявність "жорстких" та "м'яких" меж, наприклад, якщо рядок довший 500 символів, усікає його до 400. Це може бути корисно, коли користувач хоче переглянути весь текст і клацне посилання для нього. Якщо, як результат, ви завантажите лише 1 або 2 символи більше, це буде виглядати по-справжньому потворно.
Максим Слойко

2
Другий параметр до substr- це довжина, тому слід substr(0,n)замість цього обмежувати його першими nсимволами.
JohnnyHK

10
Не змінюйте об'єкти, якими ви не володієте. nczonline.net/blog/2010/03/02/…
Чарлі Кіліан

5
Одне, що ви можете розглянути, - це замінити &hellip;фактичний еліпсис ( ...) у прикладі коду. Якщо ви намагаєтеся використовувати це для взаємодії з API, вам потрібна сутність, яка не є HTML.
AlbertEngelB

1
@RuneJeppesen ти маєш рацію. Налаштовані методи. На мій захист: відповідь датується 7 років тому;)
KooiInc

62

Зауважте, що це потрібно зробити лише для Firefox.

Усі інші браузери підтримують рішення CSS (див. Таблицю підтримки ):

p {
    white-space: nowrap;
    width: 100%;                   /* IE6 needs any width */
    overflow: hidden;              /* "overflow" value must be different from  visible"*/ 
    -o-text-overflow: ellipsis;    /* Opera < 11*/
    text-overflow:    ellipsis;    /* IE, Safari (WebKit), Opera >= 11, FF > 6 */
}

Іронія в тому, що я отримав цей фрагмент коду від Mozilla MDC.


1
mattsnider.com/css/css-string-truncation-with-ellipsis, щоб він працював і з FF.
Ніл

Ого, це ідеальне рішення для мобільних Safari. Дякую!
samvermette

9
Дуже хороший CSS-підхід. Можливо, зауважимо, що це працює лише з одним рядком тексту (як задумано white-space: nowrap;). Якщо мова йде про більше ніж один рядок, ви застрягли в JavaScript.
insertusernamehere

Він також працює лише для всього елемента. Якщо ви хочете обрізати частину рядка, не загортаючи біт, який ви хочете врізати в проліт або інший html-елемент, це не спрацює, наприклад:Your picture ('some very long picture filename truncated...') has been uploaded.
Кріс

1
ОП запитували спеціально для рішення Javascript
vsync

25

Є поважні причини, які люди можуть захотіти зробити це в JavaScript замість CSS.

Щоб скоротити до 8 символів (включаючи еліпсис) у JavaScript:

short = long.replace(/(.{7})..+/, "$1&hellip;");

або

short = long.replace(/(.{7})..+/, "$1…");

1
Якщо порахувати еліпсис, це буде 9 символів. Якщо вам потрібно, щоб після усікання було 8, скористайтеся .replace(/^(.{7}).{2,}/, "$1…");натомість
Окку

longі shortзарезервовано як майбутні ключові слова за старими специфікаціями ECMAScript (ECMAScript 1 до 3). Дивіться MDN: Майбутні зарезервовані ключові слова у старих стандартах
Рікардо


9
('long text to be truncated').replace(/(.{250})..+/, "$1…");

Якось вище код не працював для якоїсь копії, вставленої чи написаної тексту в додатку vuejs. Тож я використав трибун lodash і його зараз добре працює.

_.truncate('long text to be truncated', { 'length': 250, 'separator': ' '});

приємна сучасна відповідь!
ykonda

Мені було б цікаво дізнатися, що це за текст. Це використовували нелатинські символи?
Адам

Це був просто lorem ipsum
Афраз Ахмад

7

Ось моє рішення, яке має кілька удосконалень порівняно з іншими пропозиціями:

String.prototype.truncate = function(){
    var re = this.match(/^.{0,25}[\S]*/);
    var l = re[0].length;
    var re = re[0].replace(/\s$/,'');
    if(l < this.length)
        re = re + "&hellip;";
    return re;
}

// "This is a short string".truncate();
"This is a short string"

// "Thisstringismuchlongerthan25characters".truncate();
"Thisstringismuchlongerthan25characters"

// "This string is much longer than 25 characters and has spaces".truncate();
"This string is much longer&hellip;"

Це:

  • Скорочується на першому пробілі після 25 символів
  • Розширює об’єкт JavaScript String, тому його можна використовувати на (і прикувати до) будь-який рядок.
  • Обріже рядок, якщо обрізання призведе до пробілу;
  • Додасть суть унікоду Hellip (еліпсис), якщо усічена рядок довше 25 символів

7

Найкраща функція, яку я знайшов. Заслуга тексту-еліпсису .

function textEllipsis(str, maxLength, { side = "end", ellipsis = "..." } = {}) {
  if (str.length > maxLength) {
    switch (side) {
      case "start":
        return ellipsis + str.slice(-(maxLength - ellipsis.length));
      case "end":
      default:
        return str.slice(0, maxLength - ellipsis.length) + ellipsis;
    }
  }
  return str;
}

Приклади :

var short = textEllipsis('a very long text', 10);
console.log(short);
// "a very ..."

var short = textEllipsis('a very long text', 10, { side: 'start' });
console.log(short);
// "...ng text"

var short = textEllipsis('a very long text', 10, { textEllipsis: ' END' });
console.log(short);
// "a very END"

5

Усі сучасні браузери тепер підтримують просте рішення CSS для автоматичного додавання еліпсису, якщо рядок тексту перевищує доступну ширину:

p {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

(Зверніть увагу, що для отримання будь-якого ефекту потрібно обмежити ширину елемента.)

На основі https://css-tricks.com/snippets/css/truncate-string-with-ellipsis/ .

Слід зазначити, що такий підхід не обмежується, виходячи з кількості символів. Це також не працює, якщо вам потрібно дозволити кілька рядків тексту.


2
Це корисно лише для однорядкових пропозицій, немає способу (поки що я знаю) зробити багаторядковий приклад через CSS.
Hooman Askari

Чи є випадковий спосіб змусити це зробити еліпсис зліва замість правої?
GreenAsJade

1
@GreenAsJade Я вважаю, що ви можете досягти цього за допомогою text-direction: rtlі text-align: left. Дивіться davidwalsh.name/css-ellipsis-left
Sean the Bean

4

Більшість сучасних фреймворків ( JQuery , Prototype , і т.д ...) мають функцію корисності прикріпив на рядок , яка обробляє це.

Ось приклад у прототипі:

'Some random text'.truncate(10);
// -> 'Some ra...'

Це здається однією з тих функцій, з якою ви хочете, щоб хтось інший займався / підтримував. Я б дозволив рамці впоратися з цим, а не писати більше коду.


8
Я не думаю, що у jQuery нічого для цього немає.
alex

2
Underscore.js does - _ ('Hello world'). Truncate (5) => 'Hello ...' _ ('Hello'). Truncate (10) => 'Hello'
JayCrossler

3
У чистого підкреслення, схоже, немає truncate()- вам може знадобитися розширення, таке як underscore.string .
мартін

2
Це абсолютно правильна відповідь. Я не знаю про підкреслення, але лодаш має те, _.truncщо робить саме це.
leftclickben

2
Я думаю, що правильною відповіддю є використання lodash.trunc або underscore.string.truncate.
ooolala

2

Можливо, я пропустив приклад того, коли хтось обробляє нулі, але 3 ТОП відповіді не спрацювали для мене, коли у мене були нулі (Звичайно, я розумію, що поводження з помилками і мільйони інших речей - НЕ відповідальність людини, відповідаючи на питання, але оскільки Я використовував існуючу функцію разом із однією з відмінних відповідей на еліпсис усікання, я думав, що надаю її іншим.

напр

javascript:

news.comments

за допомогою функції усічення

news.comments.trunc(20, true);

Однак, на news.comments будучи нуль це буде «зламати»

Фінал

checkNull(news.comments).trunc(20, true) 

функція обрізки люб’язно надана KooiInc

String.prototype.trunc =
 function (n, useWordBoundary) {
     console.log(this);
     var isTooLong = this.length > n,
         s_ = isTooLong ? this.substr(0, n - 1) : this;
     s_ = (useWordBoundary && isTooLong) ? s_.substr(0, s_.lastIndexOf(' ')) : s_;
     return isTooLong ? s_ + '&hellip;' : s_;
 };

Моя проста нульова перевірка (також перевіряє буквальну річ "null" (ця фіксація не визначена, "", null, "null" тощо).

  function checkNull(val) {
      if (val) {
          if (val === "null") {
              return "";
          } else {
              return val;
          }
      } else {
          return "";
      }
  }

Ось модифікована версія - уникає використання прототипу, включає функцію перевірки нуля у функції та має деяке використання тесту / демонстрації. codepen.io/mahemoff/pen/LGEdzy
mahemoff

Чи вважаєте ви прототип проблематичним? Просто цікаво
Том Стікель

Причина моєї окремої функції нульової перевірки полягає в тому, що вона насправді перевірятиме на предмет null, undefined, NaN, порожній рядок (""), 0, false та "null", але загалом мені подобається ваш fx
Том Стікель

1
Так, це питання думки та контексту використання, але прототип стає некрасивим, коли ви працюєте з іншими бібліотеками, оскільки вони також можуть перекрити те саме. (Або в рідкісних випадках функція однойменної функції може бути введена пізніше як стандартна функція мови.)
mahemoff

Так, я згоден з вами
Том Стікель

2

Іноді імена файлів нумеруються, де індекс може бути на початку або в кінці. Тому я хотів скоротити від центру струни:

function stringTruncateFromCenter(str, maxLength) {
    const midChar = "…";      // character to insert into the center of the result
    var left, right;

    if (str.length <= maxLength) return str;

    // length of beginning part      
    left = Math.ceil(maxLength / 2);

    // start index of ending part   
    right = str.length - Math.floor(maxLength / 2) + 1;   

    return str.substr(0, left) + midChar + str.substring(right);
}

Зверніть увагу, що я тут використав символ заповнення з більш ніж 1 байтом у UTF-8.



1

Я підтримав рішення Kooilnc. Дійсно приємне компактне рішення. Є один невеликий крайній випадок, який я хотів би вирішити. Якщо хтось із будь-якої причини вводить дійсно довгу послідовність символів, вона не буде усічена:

function truncate(str, n, useWordBoundary) {
    var singular, tooLong = str.length > n;
    useWordBoundary = useWordBoundary || true;

    // Edge case where someone enters a ridiculously long string.
    str = tooLong ? str.substr(0, n-1) : str;

    singular = (str.search(/\s/) === -1) ? true : false;
    if(!singular) {
      str = useWordBoundary && tooLong ? str.substr(0, str.lastIndexOf(' ')) : str;
    }

    return  tooLong ? str + '&hellip;' : str;
}

1

Швидкий гуглінг я виявив це ... Це працює для вас?

/**
 * Truncate a string to the given length, breaking at word boundaries and adding an elipsis
 * @param string str String to be truncated
 * @param integer limit Max length of the string
 * @return string
 */
var truncate = function (str, limit) {
    var bits, i;
    if (STR !== typeof str) {
        return '';
    }
    bits = str.split('');
    if (bits.length > limit) {
        for (i = bits.length - 1; i > -1; --i) {
            if (i > limit) {
                bits.length = i;
            }
            else if (' ' === bits[i]) {
                bits.length = i;
                break;
            }
        }
        bits.push('...');
    }
    return bits.join('');
};
// END: truncate

1

Переповнення тексту: еліпсис - це властивість, яка вам потрібна. З цим і переповнення: приховано певну ширину, все перевершує те, що отримає ефект три періоду в кінці ... Не забудьте додати пробіл: nowrap або текст буде розміщений у кілька рядків.

.wrap{
  text-overflow: ellipsis
  white-space: nowrap;
  overflow: hidden;
  width:"your desired width";
}
<p class="wrap">The string to be cut</p>

1
Стислість прийнятна, але повніші пояснення краще.
Армалі

mwilcox та Sean the Bean вже розмістили це рішення.
Ендрю Майєрс

1
Можна використовувати лише для
однорядного

Переповнення тексту: еліпсис ідеально !!
zardilior

0

Відповідь c_harm на мою думку найкраща. Зверніть увагу, що якщо ви хочете використовувати

"My string".truncate(n)

вам доведеться використовувати конструктор об'єктів regexp, а не буквальний. Також вам доведеться уникнути цього \Sпри перетворенні.

String.prototype.truncate =
    function(n){
        var p  = new RegExp("^.{0," + n + "}[\\S]*", 'g');
        var re = this.match(p);
        var l  = re[0].length;
        var re = re[0].replace(/\s$/,'');

        if (l < this.length) return re + '&hellip;';
    };

Кожен почув про коментування та правильне називання змінної?
велосипед

@bicycle код копіюється та змінюється з іншої відповіді вище, не потрібно бути таким грубим і химерним.
Метт Флетчер

0

Використовуйте наступний код

 function trancateTitle (title) {
    var length = 10;
    if (title.length > length) {
       title = title.substring(0, length)+'...';
    }
    return title;
}

0

Виправлення рішення Kooilnc:

String.prototype.trunc = String.prototype.trunc ||
  function(n){
      return this.length>n ? this.substr(0,n-1)+'&hellip;' : this.toString();
  };

Це повертає значення рядка замість об'єкта String, якщо його не потрібно обрізати.


Це не дає відповіді на запитання. Щоб критикувати або вимагати роз'яснення у автора, залиште коментар під їх публікацією - ви завжди можете коментувати свої власні публікації, і коли ви матимете достатню репутацію, ви зможете коментувати будь-яку публікацію .
Спенсер Вєчерек

Ах, я зараз бачу відмінність. Дякую за довідку. Я хотів залишити коментар з надією, що @Kooilnc його побачить, і, можливо, відредагував би прийняту відповідь, якщо він чи вона погодиться, але не мав репутації.
qwales1

0

Нещодавно мені довелося це зробити і закінчилося:

/**
 * Truncate a string over a given length and add ellipsis if necessary
 * @param {string} str - string to be truncated
 * @param {integer} limit - max length of the string before truncating
 * @return {string} truncated string
 */
function truncate(str, limit) {
    return (str.length < limit) ? str : str.substring(0, limit).replace(/\w{3}$/gi, '...');
}

Мені добре і чисто :)


1
Це може зробити результуючу рядок на 3 символи довшою, ніж межа.
Хоук

0

Мені подобається використовувати .slice () Перший аргумент - це початковий індекс, а другий - індекс закінчення. Все, що знаходиться між ними, - це те, що ти повернеш.

var long = "hello there! Good day to ya."
// hello there! Good day to ya.

var short  = long.slice(0, 5)
// hello

0

Десь розумно: D

//My Huge Huge String
    let tooHugeToHandle = `It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).`
    
//Trim Max Length
 const maxValue = 50
// The barber.
 const TrimMyString = (string, maxLength, start = 0) => {
//Note - `start` is if I want to start after some point of the string
    	if (string.length > maxLength) {
    	let trimmedString = string.substr(start, maxLength)
    	 return (
    	   trimmedString.substr(
    	   start,
    	   Math.min(trimmedString.length,   trimmedString.lastIndexOf(' '))
           ) + ' ...'
         )
       }
    return string
}

console.log(TrimMyString(tooHugeToHandle, maxValue))


-1

Ця функція виконує також урізання простору та частин слова. (Напр .: Мати в міль ...)

String.prototype.truc= function (length) {
        return this.length>length ? this.substring(0, length) + '&hellip;' : this;
};

використання:

"this is long length text".trunc(10);
"1234567890".trunc(5);

вихід:

це ось ...

12345 ...

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.