JavaScript'te kelimeleri kesmeden dizeyi kısaltın


105

JavaScript'te dize manipülasyonu konusunda pek iyi değilim ve herhangi bir kelimeyi kesmeden bir dizeyi nasıl kısaltacağınızı merak ediyordum. Alt dizeyi nasıl kullanacağımı biliyorum, ancak indexOf veya herhangi bir şeyi gerçekten iyi bilmiyorum.

Aşağıdaki dizeye sahip olduğumu varsayalım:

text = "this is a long string I cant display"

10 karaktere indirmek istiyorum, ancak boşlukla bitmiyorsa kelimeyi bitirin. Dize değişkeninin böyle görünmesini istemiyorum:

"bu, ayıramadığım uzun bir dizi"

Bir boşluk oluşana kadar kelimeyi bitirmesini istiyorum.


Bir ipi kesmek mi demek istiyorsun? try" too many spaces ".trim()
Anurag

1
Bazı örnek girdiler ve beklenen çıktılar bu soruyu yanıtlamada çok yardımcı olacaktır.
deceze

peki pardon, dizeye sahip olduğumu söylüyorum text = "bu uzun bir dize gösteremiyorum" 10 karaktere kadar kısaltmak istiyorum ama bir boşlukla bitmezse kelime bitirin dize değişkeninin benzemesini istemiyorum Bu "bu uzun bir dize i can not dis olduğunu"
Josh Bedo

Yanıtlar:


181

Doğru anladıysam, bir dizgiyi belirli bir uzunluğa kısaltmak istiyorsunuz (örneğin "The quick brown fox jumps over the lazy dog", herhangi bir kelimeyi kesmeden 6 karakteri kısaltmak ).

Bu durumda, aşağıdaki gibi bir şey deneyebilirsiniz:

var yourString = "The quick brown fox jumps over the lazy dog"; //replace with your string.
var maxLength = 6 // maximum number of characters to extract

//Trim and re-trim only when necessary (prevent re-trim when string is shorted than maxLength, it causes last word cut) 
if(yourString.length > trimmedString.length){
    //trim the string to the maximum length
    var trimmedString = yourString.substr(0, maxLength);

    //re-trim if we are in the middle of a word and 
    trimmedString = trimmedString.substr(0, Math.min(trimmedString.length, trimmedString.lastIndexOf(" ")))
}

9
@josh ".replace" işlevinin "jQuery işlevlerinde" çalışmadığı kesinlikle doğru değil. "JQuery işlevi" diye bir şey bile yoktur.
Sivri

3
"maxLength + 1" olması gerekmiyor. Ve maxLength tüm cümle uzunluğundan büyük veya ona eşitse, son kelimeden daha fazla dahil edilmez. ama çözüm için teşekkürler.
Beytan Kurt

4
Bunu maxLength'den daha kısa bir dizede kullanırsanız, son kelime kesilir. Belki @AndrewJuniorHoward bunun için düzeltmeyi zaten belirtti ( maxLength + 1), ancak bu satırı en üste ekleyerek düzelttim:var yourString += " ";
tylerl

3
Maalesef, bir fox jumps over the lazy dogparçayı alırsanız , sonuç The quick brown olması gerektiği zaman olacaktır The quick brown fox.
Andrey Gordeev

2
Bu her zaman son sözü keser.
Chris Cinelli

114

Bunu yapmanın birçok yolu vardır, ancak normal ifade kullanışlı bir tek satırlık yöntemdir:

"this is a longish string of text".replace(/^(.{11}[^\s]*).*/, "$1"); 
//"this is a longish"

Bu ifade, ilk 11 (herhangi) karakteri ve ardından gelen boşluk olmayan karakterleri döndürür.

Örnek komut dosyası:

<pre>
<script>
var t = "this is a longish string of text";

document.write("1:   " + t.replace(/^(.{1}[^\s]*).*/, "$1") + "\n");
document.write("2:   " + t.replace(/^(.{2}[^\s]*).*/, "$1") + "\n");
document.write("5:   " + t.replace(/^(.{5}[^\s]*).*/, "$1") + "\n");
document.write("11:  " + t.replace(/^(.{11}[^\s]*).*/, "$1") + "\n");
document.write("20:  " + t.replace(/^(.{20}[^\s]*).*/, "$1") + "\n");
document.write("100: " + t.replace(/^(.{100}[^\s]*).*/, "$1") + "\n");
</script>

Çıktı:

1:   this
2:   this
5:   this is
11:  this is a longish
20:  this is a longish string
100: this is a longish string of text

Harika, kelimenin tam anlamıyla bu soruyu milyonlarca yoldan googledim ve sadece buna yakın ve döngüleri içeren php için çalışan bir sürüm bulabildim.
Josh Bedo

1
İlk (ve bu durumda yalnızca) alt ifade eşleşmesine atıfta bulunur - parantez içindeki maddeler. $ 0, tam eşleşmeye atıfta bulunur, bu durumda bu tüm dizedir.
Hamish

3
@josh Bir regexp nesnesi kullanarak maksimum uzunluğu bir değişken yapabilmelisiniz:t.replace(new RegExp("^(.{"+length+"}[^\s]*).*"), "$1")
rjmackay

1
@Hamish seçeneğiniz iyi çalışıyor, ancak uzunluk aşıldığında da son kelimeyi dahil ediyor. Maksimum kelime sınırı aşılıyorsa ancak işe yaramıyorsa son kelimeyi hariç tutmak için normal ifade ifadesini değiştirmeyi denedim. Bunu nasıl başarabiliriz?
Shashank Agrawal

1
Pekala, bu gerçekten doğru çalışmıyor, bazen maksimum değeri geçiyorum, örneğin son kelime zaten 30 karakter ise, uzunluğu zaten 60'tan fazla olacak! uzunluğu ayarlasa bile{30}
Mothafar

66

Bunun gibi basit bir problem için okunması zor çok sayıda cevap olmasına ve seçilen cevap dahil bazılarının çalışmamasına şaşırdım.

Genellikle sonuç dizesinin en fazla maxLen karakter olmasını isterim . URL'lerdeki sümüklü böcekleri kısaltmak için de aynı işlevi kullanıyorum.

str.lastIndexOf(searchValue[, fromIndex]) dizede geriye doğru aramaya başlanacak dizin olan ikinci bir parametre alır ve işleri verimli ve basit hale getirir.

// Shorten a string to less than maxLen characters without truncating words.
function shorten(str, maxLen, separator = ' ') {
  if (str.length <= maxLen) return str;
  return str.substr(0, str.lastIndexOf(separator, maxLen));
}

Bu bir örnek çıktı:

for (var i = 0; i < 50; i += 3) 
  console.log(i, shorten("The quick brown fox jumps over the lazy dog", i));

 0 ""
 3 "The"
 6 "The"
 9 "The quick"
12 "The quick"
15 "The quick brown"
18 "The quick brown"
21 "The quick brown fox"
24 "The quick brown fox"
27 "The quick brown fox jumps"
30 "The quick brown fox jumps over"
33 "The quick brown fox jumps over"
36 "The quick brown fox jumps over the"
39 "The quick brown fox jumps over the lazy"
42 "The quick brown fox jumps over the lazy"
45 "The quick brown fox jumps over the lazy dog"
48 "The quick brown fox jumps over the lazy dog"

Ve sümüklüböcek için:

for (var i = 0; i < 50; i += 10) 
  console.log(i, shorten("the-quick-brown-fox-jumps-over-the-lazy-dog", i, '-'));

 0 ""
10 "the-quick"
20 "the-quick-brown-fox"
30 "the-quick-brown-fox-jumps-over"
40 "the-quick-brown-fox-jumps-over-the-lazy"

1
LastIndexOf () 'u tamamen unuttum. İyi yakalama!
Tici

2
Bu, bazı nedenle eğer çöküyor strolduğunu undefined. Ben eklediif (!str || str.length <= maxLen) return str;
Silvain

bu, ayırıcının dizede bulunmadığı uç durumu işlemez
shrewquest

@shrewquest Çalışıyor. Ayırıcı dizede değilse, dizenin kendisini döndürür str.length <= maxLen. Aksi takdirde boş bir dize döndürür.
Chris Cinelli

22

Herkes, indexOf'un iki argüman aldığını unutmuş gibi görünüyor: eşleşecek dizge ve aramaya başlamak için karakter indeksi. Dizeyi 10 karakterden sonra ilk boşlukta kesebilirsiniz.

function cutString(s, n){
    var cut= s.indexOf(' ', n);
    if(cut== -1) return s;
    return s.substring(0, cut)
}
var s= "this is a long string i cant display";
cutString(s, 10)

/*  returned value: (String)
this is a long
*/

Sabit sınırlar gerekiyorsa indexOf'un lastIndexOf ile değiştirilebileceğini unutmayın.
Scheintod

14

Lodash'ın özellikle bunun için yazılmış bir işlevi vardır: _.truncate

const truncate = _.truncate
const str = 'The quick brown fox jumps over the lazy dog'

truncate(str, {
  length: 30, // maximum 30 characters
  separator: /,?\.* +/ // separate by spaces, including preceding commas and periods
})

// 'The quick brown fox jumps...'

7

Bazı köşe durumlarını ele almayan NT3RP cevabına dayanarak, bu kodu yaptım. Size> maxLength olayı olan bir metnin ...sonuna bir üç nokta eklenmiş olarak döndürülmemesini garanti eder .

Bu aynı zamanda tek bir kelimesi> maxLength olan bir metin gibi bazı köşe durumlarını da ele alır.

shorten: function(text,maxLength,options) {
    if ( text.length <= maxLength ) {
        return text;
    }
    if ( !options ) options = {};
    var defaultOptions = {
        // By default we add an ellipsis at the end
        suffix: true,
        suffixString: " ...",
        // By default we preserve word boundaries
        preserveWordBoundaries: true,
        wordSeparator: " "
    };
    $.extend(options, defaultOptions);
    // Compute suffix to use (eventually add an ellipsis)
    var suffix = "";
    if ( text.length > maxLength && options.suffix) {
        suffix = options.suffixString;
    }

    // Compute the index at which we have to cut the text
    var maxTextLength = maxLength - suffix.length;
    var cutIndex;
    if ( options.preserveWordBoundaries ) {
        // We use +1 because the extra char is either a space or will be cut anyway
        // This permits to avoid removing an extra word when there's a space at the maxTextLength index
        var lastWordSeparatorIndex = text.lastIndexOf(options.wordSeparator, maxTextLength+1);
        // We include 0 because if have a "very long first word" (size > maxLength), we still don't want to cut it
        // But just display "...". But in this case the user should probably use preserveWordBoundaries:false...
        cutIndex = lastWordSeparatorIndex > 0 ? lastWordSeparatorIndex : maxTextLength;
    } else {
        cutIndex = maxTextLength;
    }

    var newText = text.substr(0,cutIndex);
    return newText + suffix;
}

Sanırım bu sizi rahatsız ediyorsa jquery bağımlılığını kolayca kaldırabilirsiniz.


3
Bu çözümü beğendim, ancak aktarılan bağımsız değişkenlerin $.extendtersine çevrilmesi gerekmez mi?
JKesMc9tqIQe9M

7

İşte tek satırda bir çözüm.

text = "this is a long string I cant display"

function shorten(text,max) {
    return text && text.length > max ? text.slice(0,max).split(' ').slice(0, -1).join(' ') : text
}


console.log(shorten(text,10));


3

Partiye geç kaldım, ama işte bir miktar kelimeyi geri getirmek için bulduğum küçük ve kolay bir çözüm.

Karakter ihtiyacınızla doğrudan ilgili değildir , ancak peşinde olduğunuza inandığım sonucun aynısını sunar .

function truncateWords(sentence, amount, tail) {
  const words = sentence.split(' ');

  if (amount >= words.length) {
    return sentence;
  }

  const truncated = words.slice(0, amount);
  return `${truncated.join(' ')}${tail}`;
}

const sentence = 'Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.';

console.log(truncateWords(sentence, 10, '...'));

Burada çalışan örneğe bakın: https://jsfiddle.net/bx7rojgL/


Bir dizeyi birkaç kelimeye indirgeyen bir JS işlevi yazdınız. Soruyu tekrar okuyun.
ChristoKiwi

1
eeehm. Sanırım sorunun tek doğru cevabı bu. Kelimeyi kesmeden sordu.
Mike Aron

2

Bu, son kelimeyi eklemek yerine hariç tutar.

function smartTrim(str, length, delim, appendix) {
    if (str.length <= length) return str;

    var trimmedStr = str.substr(0, length+delim.length);

    var lastDelimIndex = trimmedStr.lastIndexOf(delim);
    if (lastDelimIndex >= 0) trimmedStr = trimmedStr.substr(0, lastDelimIndex);

    if (trimmedStr) trimmedStr += appendix;
    return trimmedStr;
}

Kullanım:

smartTrim(yourString, 11, ' ', ' ...')
"The quick ..."

2

Farklı bir yaklaşım izledim. Benzer bir sonuca ihtiyacım olsa da dönüş değerimi belirtilen uzunluktan daha az tutmak istedim.

function wordTrim(value, length, overflowSuffix) {
    value = value.trim();
    if (value.length <= length) return value;
    var strAry = value.split(' ');
    var retString = strAry[0];
    for (var i = 1; i < strAry.length; i++) {
        if (retString.length >= length || retString.length + strAry[i].length + 1 > length) break;
        retString += " " + strAry[i];
    }
    return retString + (overflowSuffix || '');
}

Düzenle Burada biraz yeniden düzenledim : JSFiddle Örneği . Birleştirme yerine orijinal diziye yeniden katılır.

function wordTrim(value, length, overflowSuffix) {
    if (value.length <= length) return value;
    var strAry = value.split(' ');
    var retLen = strAry[0].length;
    for (var i = 1; i < strAry.length; i++) {
        if(retLen == length || retLen + strAry[i].length + 1 > length) break;
        retLen+= strAry[i].length + 1
    }
    return strAry.slice(0,i).join(' ') + (overflowSuffix || '');
}

2
function shorten(str,n) {
  return (str.match(RegExp(".{"+n+"}\\S*"))||[str])[0];
}

shorten("Hello World", 3); // "Hello"


1

truncateAşağıdaki tek satırlık kullanabilirsiniz :

const text = "The string that I want to truncate!";

const truncate = (str, len) => str.substring(0, (str + ' ').lastIndexOf(' ', len));

console.log(truncate(text, 14));


1
shorten(str, maxLen, appendix, separator = ' ') {
if (str.length <= maxLen) return str;
let strNope = str.substr(0, str.lastIndexOf(separator, maxLen));
return (strNope += appendix);

}

var s = "bu uzun bir dizedir ve hepsini açıklayamıyorum"; kısaltmak (s, 10, '...')

/* "bu .." */


1

İşte noktalama işaretleri boyunca kesilen başka bir kod parçası (bunu arıyordu ve Google bu soruyu burada buldu). Kendi başıma bir çözüm bulmam gerekiyordu, bu yüzden 15 dakikada hack'ledim. Tüm oluşumlarını bulur. ! ? ve bunların herhangi bir konumunda keser <şundanlen

function pos(str, char) {
    let pos = 0
    const ret = []
    while ( (pos = str.indexOf(char, pos + 1)) != -1) {
        ret.push(pos)
    }
    return ret
}

function truncate(str, len) {
    if (str.length < len)
        return str

    const allPos = [  ...pos(str, '!'), ...pos(str, '.'), ...pos(str, '?')].sort( (a,b) => a-b )
    if (allPos.length === 0) {
        return str.substr(0, len)
    }

    for(let i = 0; i < allPos.length; i++) {
        if (allPos[i] > len) {
            return str.substr(0, allPos[i-1] + 1)
        }
    }
}

module.exports = truncate

1

Typcript ve elipslerle :)

export const sliceByWord = (phrase: string, length: number, skipEllipses?: boolean): string => {
  if (phrase.length < length) return phrase
  else {
    let trimmed = phrase.slice(0, length)
    trimmed = trimmed.slice(0, Math.min(trimmed.length, trimmed.lastIndexOf(' ')))
    return skipEllipses ? trimmed : trimmed + '…'
  }
}

1

'Domatesli ve ıspanaklı makarna'

kelimeyi ikiye bölmek istemiyorsan

ilk yineleme:

acc: 0 / acc + cur.length = 5 / newTitle = ['Pasta'];

ikinci yineleme:

acc: 5 / acc + cur.length = 9 / newTitle = ['Pasta', 'with'];

üçüncü yineleme:

acc: 9 / acc + cur.length = 15 / newTitle = ['Pasta', 'with', 'domates'];

dördüncü yineleme:

acc: 15 / acc + cur.length = 18 (sınıra bağlı) / newTitle = ['Pasta', 'with', 'domates'];

const limitRecipeTitle = (title, limit=17)=>{
    const newTitle = [];
    if(title.length>limit){
        title.split(' ').reduce((acc, cur)=>{
            if(acc+cur.length <= limit){
                newTitle.push(cur);
            }
            return acc+cur.length;
        },0);
    }

    return `${newTitle.join(' ')} ...`
}

çıktı: Domatesli makarna ...


Bu, dizeyi sınırdan daha uzun hale getirebilecek 'birleştirme (' ') karakterlerini hesaba katmaz. Azalt () 'ın işlevini (acc, cur, idx) ve if to (acc + cur.length <= limit - idx) olarak değiştirirseniz, sözcükler tekrar birleştirildiğinde fazladan boşlukları hesaba katacaktır. Kesinlikle sınır dahilinde olması gerekiyorsa.
PSaul

0

Ne olursa olsun, dizenin sonunda noktalama işareti veya boşluk bırakmadan kelime sınırını kesmek için bunu yazdım:

function truncateStringToWord(str, length, addEllipsis)
{
    if(str.length <= length)
    {
        // provided string already short enough
        return(str);
    }

    // cut string down but keep 1 extra character so we can check if a non-word character exists beyond the boundary
    str = str.substr(0, length+1);

    // cut any non-whitespace characters off the end of the string
    if (/[^\s]+$/.test(str))
    {
        str = str.replace(/[^\s]+$/, "");
    }

    // cut any remaining non-word characters
    str = str.replace(/[^\w]+$/, "");

    var ellipsis = addEllipsis && str.length > 0 ? '&hellip;' : '';

    return(str + ellipsis);
}

var testString = "hi stack overflow, how are you? Spare";
var i = testString.length;

document.write('<strong>Without ellipsis:</strong><br>');

while(i > 0)
{
  document.write(i+': "'+ truncateStringToWord(testString, i) +'"<br>');
  i--;
}

document.write('<strong>With ellipsis:</strong><br>');

i = testString.length;
while(i > 0)
{
  document.write(i+': "'+ truncateStringToWord(testString, i, true) +'"<br>');
  i--;
}


0

Oylanan çözümleri tatmin edici bulmadı. Bu yüzden, bir tür genel olan ve metninizin hem ilk hem de son kısmında işe yarayan bir şey yazdım (substr gibi ama kelimeler için). Ayrıca karakter sayımında boşlukların bırakılmasını isteyip istemediğinizi de ayarlayabilirsiniz.

    function chopTxtMinMax(txt, firstChar, lastChar=0){
        var wordsArr = txt.split(" ");
        var newWordsArr = [];

        var totalIteratedChars = 0;
        var inclSpacesCount = true;

        for(var wordIndx in wordsArr){
            totalIteratedChars += wordsArr[wordIndx].length + (inclSpacesCount ? 1 : 0);
            if(totalIteratedChars >= firstChar && (totalIteratedChars <= lastChar || lastChar==0)){
                newWordsArr.push(wordsArr[wordIndx]);
            }
        }

        txt = newWordsArr.join(" ");
        return txt;
    }

0

Bunun için geç geldim ancak bu işlevin OP'nin talep ettiği şeyi yaptığını düşünüyorum. Farklı sonuçlar için SENTENCE ve LIMIT değerlerini kolaylıkla değiştirebilirsiniz.

function breakSentence(word, limit) {
  const queue = word.split(' ');
  const list = [];

  while (queue.length) {
    const word = queue.shift();

    if (word.length >= limit) {
      list.push(word)
    }
    else {
      let words = word;

      while (true) {
        if (!queue.length ||
            words.length > limit ||
            words.length + queue[0].length + 1 > limit) {
          break;
        }

        words += ' ' + queue.shift();
      }

      list.push(words);
    }
  }

  return list;
}

const SENTENCE = 'the quick brown fox jumped over the lazy dog';
const LIMIT = 11;

// get result
const words = breakSentence(SENTENCE, LIMIT);

// transform the string so the result is easier to understand
const wordsWithLengths = words.map((item) => {
  return `[${item}] has a length of - ${item.length}`;
});

console.log(wordsWithLengths);

Bu pasajın çıktısı, LIMIT değerinin 11 olduğu yerdir:

[ '[the quick] has a length of - 9',
  '[brown fox] has a length of - 9',
  '[jumped over] has a length of - 11',
  '[the lazy] has a length of - 8',
  '[dog] has a length of - 3' ]

0

Boş cümle ve çok uzun ilk kelime gibi sınır koşulları ile. Ayrıca, dile özgü dizge api / kitaplığı kullanmaz.

function solution(message, k) {
    if(!message){
        return ""; //when message is empty
    }
    const messageWords = message.split(" ");
    let result = messageWords[0];
    if(result.length>k){
        return ""; //when length of first word itself is greater that k
    }
    for(let i = 1; i<messageWords.length; i++){
        let next = result + " " + messageWords[i];

        if(next.length<=k){
            result = next;
        }else{
            break;
        }
    }
    return result;
}

console.log(solution("this is a long string i cant display", 10));


0

Bunu, lodash'ın truncate fonksiyonunu kullanarak kolayca yapabiliriz

_.truncate('hi-diddly-ho there, neighborino');
// => 'hi-diddly-ho there, neighbo...'

_.truncate('hi-diddly-ho there, neighborino', {
  'length': 24,
  'separator': ' '
 });
// => 'hi-diddly-ho there,...'

daha fazla netlik için Lodash Belgelerine gidin.


-1

Boşlukları şununla kırpabilirsiniz:

var trimmedString = flabbyString.replace(/^\s*(.*)\s*$/, '$1');

-1

@ NT3RP'den güncellendi Eğer dize ilk kez etrafında bir boşluğa isabet ederse, dizinizi olabileceğinden bir kelime daha kısa yaparak bu kelimeyi silmeye başlayacağını keşfettim. Bu yüzden maxLength değerinin bir boşluğa düşmediğini kontrol etmek için bir if else ifadesini ekledim.

codepen.io

var yourString = "The quick brown fox jumps over the lazy dog"; //replace with your string.
var maxLength = 15 // maximum number of characters to extract

if (yourString[maxLength] !== " ") {

//trim the string to the maximum length
var trimmedString = yourString.substr(0, maxLength);

alert(trimmedString)

//re-trim if we are in the middle of a word
trimmedString = trimmedString.substr(0, Math.min(trimmedString.length, trimmedString.lastIndexOf(" ")))
}

else {
  var trimmedString = yourString.substr(0, maxLength);
}

alert(trimmedString)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.