Sprytny sposób na obcinanie długich sznurków


187

Czy ktoś ma bardziej wyrafinowane rozwiązanie / bibliotekę do obcinania ciągów za pomocą JavaScript i umieszczania wielokropka na końcu, niż to oczywiste:

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

5
Co masz na myśli mówiąc „bardziej wyrafinowany”? Funkcje uwzględniające granice słów?
Residuum,

2
I bez obcinania w środku tagów HTML.
Sz.

Odpowiedzi:


366

Zasadniczo sprawdzasz długość danego ciągu. Jeśli jest dłuższy niż podana długość n, przytnij go do długości n( substrlub slice) i dodaj encję html …(…) do obciętego ciągu.

Taka metoda wygląda

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

Jeśli przez „bardziej wyrafinowany” masz na myśli obcinanie ostatniej granicy słowa w ciągu, potrzebujesz dodatkowej kontroli. Najpierw przycinasz ciąg do żądanej długości, a następnie przycinasz wynik do granicy ostatniego słowa

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;";
};

Możesz rozszerzyć natywny Stringprototyp za pomocą swojej funkcji. W takim przypadku strparametr należy usunąć iw strramach funkcji zamienić na 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;";
};

Bardziej dogmatyczni programiści mogą cię mocno skapitulować na tym („ Nie modyfikuj obiektów, których nie jesteś właścicielem ”. Nie miałbym nic przeciwko).

Podejściem bez rozszerzania Stringprototypu jest utworzenie własnego obiektu pomocniczego, zawierającego (długi) napis, który podasz i wspomnianą wcześniej metodę obcinania go. To właśnie robi poniższy fragment.

Wreszcie, możesz używać CSS tylko do obcinania długich ciągów w węzłach HTML. Zapewnia mniejszą kontrolę, ale może być dobrym rozwiązaniem.


5
Należy również rozważyć zastosowanie „twardych” i „miękkich” limitów, na przykład, jeśli ciąg jest dłuższy niż 500 znaków, skróć go do 400. Może to być przydatne, gdy użytkownik chce zobaczyć cały tekst i kliknie link dla tego. Jeśli w rezultacie załadujesz tylko 1 lub 2 znaki więcej, będzie to wyglądać naprawdę brzydko.
Maxim Sloyko

2
Drugi parametr substrto długość, więc substr(0,n)zamiast tego należy ograniczyć go do pierwszych nznaków.
JohnnyHK,

10
Nie modyfikuj obiektów, których nie jesteś właścicielem. nczonline.net/blog/2010/03/02/…
Charlie Kilian

5
Jedną rzeczą, którą możesz rozważyć, jest zastąpienie &hellip;rzeczywistej elipsy ( ...) w przykładowym kodzie. Jeśli próbujesz użyć tego do interakcji z interfejsami API, będziesz potrzebować encji innej niż HTML.
AlbertEngelB

1
@RuneJeppesen masz rację. Dostosowano metody. Na moją obronę: odpowiedź pochodzi sprzed 7 lat;)
KooiInc

62

Pamiętaj, że trzeba to zrobić tylko w przypadku przeglądarki Firefox.

Wszystkie inne przeglądarki obsługują rozwiązanie CSS (zobacz tabelę wsparcia ):

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 */
}

Jak na ironię, mam ten fragment kodu z Mozilla MDC.



Wow, to idealne rozwiązanie dla mobilnego Safari. Dziękuję Ci!
samvermette

9
Bardzo dobre podejście do CSS. Może być uwaga, że ​​działa to tylko z pojedynczym wierszem tekstu (zgodnie z zamierzeniami white-space: nowrap;). Jeśli chodzi o więcej niż jedną linię, utkniesz w JavaScript.
insertusernamehere

Działa również tylko dla całego elementu. Jeśli chcesz obciąć część ciągu, bez zawijania bitu, który chcesz obciąć, w zakres lub inny element html, to nie zadziała, np .:Your picture ('some very long picture filename truncated...') has been uploaded.
Chris

1
OP poprosił specjalnie o rozwiązanie javascript
vsync

25

Istnieją ważne powody, dla których ludzie mogą chcieć to zrobić w JavaScript zamiast CSS.

Aby skrócić do 8 znaków (w tym wielokropka) w JavaScript:

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

lub

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

1
Jeśli policzysz wielokropek, będzie to 9 znaków. Jeśli chcesz, aby po obcięciu było 8, użyj .replace(/^(.{7}).{2,}/, "$1…");zamiast tego
Okku

longi shortsą zarezerwowane jako przyszłe słowa kluczowe przez starsze specyfikacje ECMAScript (ECMAScript 1 do 3). Zobacz MDN: Przyszłe zastrzeżone słowa kluczowe w starszych standardach
Ricardo


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

Jakoś powyższy kod nie działał dla jakiejś kopii wklejonego lub napisanego tekstu w aplikacji vuejs. Więc użyłem lodash truncate i teraz działa dobrze.

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

ładna, nowoczesna odpowiedź!
ykonda

Byłbym ciekawy, co to za tekst. Czy używał znaków spoza alfabetu łacińskiego?
Adam Leggett

To było tylko lorem ipsum
Afraz Ahmad,

7

Oto moje rozwiązanie, które ma kilka ulepszeń w stosunku do innych sugestii:

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;"

To:

  • Obcina pierwszą spację po 25 znakach
  • Rozszerza obiekt String JavaScript, dzięki czemu można go używać na dowolnym łańcuchu (i łączyć z nim).
  • Obetnie ciąg, jeśli obcięcie skutkuje końcową spacją;
  • Dodaje jednostkę hellip Unicode (wielokropek), jeśli obcięty ciąg jest dłuższy niż 25 znaków

7

Najlepsza funkcja, jaką znalazłem. Kredyt dla tekstu-wielokropka .

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;
}

Przykłady :

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

Wszystkie nowoczesne przeglądarki obsługują teraz proste rozwiązanie CSS do automatycznego dodawania wielokropka, jeśli wiersz tekstu przekracza dostępną szerokość:

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

(Zwróć uwagę, że wymaga to ograniczenia szerokości elementu w jakiś sposób, aby uzyskać jakikolwiek efekt).

Na podstawie https://css-tricks.com/snippets/css/truncate-string-with-ellipsis/ .

Należy zauważyć, że to podejście nie ogranicza liczby znaków. To też ma nie działać, jeśli trzeba, aby umożliwić wielu wierszy tekstu.


2
Jest to przydatne tylko dla zdań jednowierszowych, nie ma sposobu (o ile wiem), aby zrobić przykład wielowierszowy za pomocą CSS.
Hooman Askari

Czy jest jakaś szansa, aby zrobić to za pomocą wielokropka po lewej stronie zamiast po prawej?
GreenAsJade

1
@GreenAsJade Wierzę, że możesz to osiągnąć za pomocą text-direction: rtli text-align: left. Zobacz davidwalsh.name/css-ellipsis-left
Sean the Bean

4

Większość nowoczesnych ram JavaScript ( JQuery , Prototype , etc ...) posiadają funkcję użytkową dołączona na ciąg znaków, który obsługuje to.

Oto przykład w Prototype:

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

Wygląda na to, że jest to jedna z tych funkcji, którymi powinien zajmować się / utrzymywać ktoś inny. Pozwoliłbym, aby framework to obsłużył, zamiast pisać więcej kodu.


8
Nie sądzę, by jQuery miało coś do tego.
Alex

2
Underscore.js robi - _ ('Hello world'). Truncate (5) => 'Hello ...' _ ('Hello').
Truncate

3
Wydaje się, że Pure Underscore też nie ma truncate()- możesz potrzebować rozszerzenia, takiego jak podkreślenie.string .
martin

2
To jest całkowicie poprawna odpowiedź. Nie wiem o podkreśleniu, ale lodash ma, _.truncktóry dokładnie to robi.
leftclickben

2
Myślę, że właściwą odpowiedzią jest użycie lodash.trunc lub underscore.string.truncate.
ooolala

2

Być może przegapiłem przykład, w którym ktoś obsługuje wartości zerowe, ale 3 TOP odpowiedzi nie zadziałały dla mnie, gdy miałem wartości zerowe (Jasne, zdaję sobie sprawę, że obsługa błędów jest i milion innych rzeczy NIE jest obowiązkiem osoby odpowiadającej na pytanie, ale ponieważ Skorzystałem z istniejącej funkcji wraz z jedną z doskonałych odpowiedzi z elipsami, które według mnie były przydatne dla innych.

na przykład

javascript:

news.comments

za pomocą funkcji obcięcia

news.comments.trunc(20, true);

Jednak w wiadomościach. Comments są zerowe spowoduje to „przerwanie”

Finał

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

funkcja obcinania dzięki uprzejmości 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_;
 };

Mój prosty moduł sprawdzający wartość null (sprawdza również literał „null” (to łapie undefined, „”, null, „null” itp.)

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

Oto zmodyfikowana wersja - unika używania prototypu, zawiera funkcję sprawdzania wartości null i ma pewne zastosowania testowe / demonstracyjne. codepen.io/mahemoff/pen/LGEdzy
mahemoff

Czy uważasz, że prototyp jest problematyczny? Po prostu ciekawy
Tom Stickel

Powodem mojej oddzielnej funkcji sprawdzania wartości null jest to, że faktycznie będzie sprawdzać pod kątem wartości null, undefined, NaN, pustego ciągu (""), 0, false i "null". Ale ogólnie podoba mi się twój
efekt

1
Tak, to kwestia opinii i kontekstu użycia, ale prototyp robi się brzydki, gdy pracujesz z innymi bibliotekami, ponieważ mogą one również przesłonić to samo. (Lub w rzadkich przypadkach funkcja o tej samej nazwie może zostać później wprowadzona jako standardowa funkcja języka.)
mahemoff

Tak, zgadzam się z tobą
Tom Stickel

2

Czasami nazwy plików są numerowane, gdzie indeks może znajdować się na początku lub na końcu. Chciałem więc skrócić od środka struny:

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);
}

Należy pamiętać, że użyłem tutaj znaku wypełnienia z więcej niż 1 bajtem w UTF-8.



1

Głosowałem za rozwiązaniem Kooilnc. Naprawdę ładne kompaktowe rozwiązanie. Jest jeden mały, skrajny przypadek, którym chciałbym się zająć. Jeśli z jakiegoś powodu ktoś wprowadzi naprawdę długą sekwencję znaków, nie zostanie ona obcięta:

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

Dzięki szybkiemu wyszukiwaniu w Google znalazłem to ... Czy to działa dla Ciebie?

/**
 * 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

Przepełnienie tekstu: wielokropek to właściwość, której potrzebujesz. Z tym i przepełnieniem: ukryte z określoną szerokością, wszystko wykraczające poza to, co daje efekt trzech kropek na końcu ... Nie zapomnij dodać spacji: nowrap lub tekst zostanie umieszczony w wielu wierszach.

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

1
Zwięzłość jest akceptowalna, ale pełniejsze wyjaśnienia są lepsze.
Armali

mwilcox i Sean the Bean już opublikowali to rozwiązanie.
Andrew Myers

1
Może być używany tylko do
jednowierszowego

Przepełnienie tekstu: wielokropek jest doskonały!
zardilior

0

Odpowiedź c_harm jest moim zdaniem najlepsza. Pamiętaj, że jeśli chcesz użyć

"My string".truncate(n)

będziesz musiał użyć konstruktora obiektów regexp zamiast literału. Będziesz także musiał uciec przed \Skonwersją.

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;';
    };

Czy słyszałeś o komentowaniu i odpowiednim nazewnictwie zmiennych?
rower

@bicycle kod jest kopiowany i modyfikowany z innej odpowiedzi powyżej, nie ma potrzeby być tak niegrzeczny i wredny.
Matt Fletcher

0

Użyj następującego kodu

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

0

Poprawianie rozwiązania Kooilnc:

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

Zwraca wartość ciągu zamiast obiektu String, jeśli nie trzeba go obcinać.


To nie daje odpowiedzi na pytanie. Aby skrytykować lub poprosić autora o wyjaśnienie, zostaw komentarz pod jego postem - zawsze możesz komentować własne posty, a gdy zdobędziesz wystarczającą reputację , będziesz mógł komentować każdy post .
Spencer Wieczorek

Ach, teraz widzę różnicę. Dzięki za referencje. Chciałem zostawić komentarz z nadzieją, że @Kooilnc go zobaczy i prawdopodobnie zmodyfikuje zaakceptowaną odpowiedź, jeśli się zgodzi, ale nie ma reputacji.
qwales1

0

Niedawno musiałem to zrobić i skończyło się na:

/**
 * 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, '...');
}

Czuję się miło i czysto :)


1
Może to spowodować, że wynikowy łańcuch o 3 znaki będzie dłuższy niż limit.
Hauke

0

Lubię używać .slice () Pierwszy argument to indeks początkowy, a drugi to indeks końcowy. Otrzymujesz wszystko pomiędzy.

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

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

0

Somewhere Smart: 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

Ta funkcja wykonuje również obcięcie spacji i części słów. (Np. Matka w Ćmę ...)

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

stosowanie:

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

wynik:

to jest lo ...

12345 ...

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.