Kürzen Sie die Zeichenfolge, ohne Wörter in JavaScript zu schneiden

102

Ich bin nicht sehr gut mit der Manipulation von Zeichenfolgen in JavaScript und habe mich gefragt, wie Sie eine Zeichenfolge kürzen könnten, ohne ein Wort abzuschneiden. Ich weiß, wie man Teilzeichenfolgen verwendet, aber nicht indexOf oder irgendetwas wirklich gut.

Angenommen, ich hätte die folgende Zeichenfolge:

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

Ich möchte es auf 10 Zeichen reduzieren, aber wenn es nicht mit einem Leerzeichen endet, beenden Sie das Wort. Ich möchte nicht, dass die Zeichenfolgenvariable so aussieht:

"Dies ist eine lange Saite, die ich nicht dis"

Ich möchte, dass das Wort beendet wird, bis ein Leerzeichen auftritt.

Josh Bedo
quelle
du meinst eine Schnur schneiden? versuchen" too many spaces ".trim()
Anurag
1
Einige Beispieleingaben und erwartete Ausgaben würden bei der Beantwortung dieser Frage sehr hilfreich sein.
Täuschung
Okay, tut mir leid, ich hatte den String-Text = "Dies ist ein langer String, den ich nicht anzeigen kann." Ich möchte ihn auf 10 Zeichen reduzieren, aber wenn er nicht mit einem Leerzeichen endet, beenden Sie das Wort. Ich möchte nicht, dass die String-Variable so aussieht dies "das ist eine lange Saite, die ich nicht dis" kann
Josh Bedo

Antworten:

180

Wenn ich das richtig verstehe, möchten Sie eine Zeichenfolge auf eine bestimmte Länge kürzen (z. B. "The quick brown fox jumps over the lazy dog"auf beispielsweise 6 Zeichen kürzen , ohne ein Wort abzuschneiden).

In diesem Fall können Sie Folgendes versuchen:

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(" ")))
}
NT3RP
quelle
9
@josh es ist absolut nicht wahr, dass ".replace" in "jQuery-Funktionen" nicht funktioniert. Es gibt nicht einmal eine "jQuery-Funktion".
Pointy
3
sollte das nicht "maxLength + 1" sein? Und wenn maxLength größer oder gleich der vollständigen Satzlänge ist, ist das letzte Wort nicht enthalten. aber danke für die lösung.
Beytan Kurt
4
Wenn Sie dies für eine Zeichenfolge verwenden, die kürzer als die maximale Länge ist, wird das letzte Wort abgeschnitten. Vielleicht hat @AndrewJuniorHoward das Update für this ( maxLength + 1) bereits angegeben , aber ich habe es behoben, indem ich einfach diese Zeile oben hinzugefügt habe:var yourString += " ";
tylerl
3
Wenn Sie einen fox jumps over the lazy dogTeil wegnehmen , wird das Ergebnis leider sein The quick brown , wann es sein sollte The quick brown fox.
Andrey Gordeev
2
Dies schneidet immer das letzte Wort.
Chris Cinelli
108

Es gibt viele Möglichkeiten, dies zu tun, aber ein regulärer Ausdruck ist eine nützliche einzeilige Methode:

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

Dieser Ausdruck gibt die ersten 11 (beliebigen) Zeichen sowie alle nachfolgenden Nicht-Leerzeichen zurück.

Beispielskript:

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

Ausgabe:

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
Hamish
quelle
Genial, ich habe diese Frage buchstäblich millionenfach gegoogelt und konnte nur eine funktionierende Version für PHP finden, die nichts in der Nähe davon hat und Schleifen beinhaltet.
Josh Bedo
1
Es bezieht sich auf die erste (und in diesem Fall einzige) Übereinstimmung des Unterausdrucks - das Zeug in den Klammern. $ 0 würde sich auf die gesamte Übereinstimmung beziehen, in diesem Fall auf die gesamte Zeichenfolge.
Hamish
3
@ Josh Sie sollten in der Lage sein, maximale Länge eine Variable zu machen, indem Sie ein Regexp-Objekt verwenden:t.replace(new RegExp("^(.{"+length+"}[^\s]*).*"), "$1")
rjmackay
1
@Hamish Ihre Option funktioniert gut, aber es enthält das letzte Wort auch, wenn die Länge überschreitet. Ich habe versucht, den regulären Ausdruck zu ändern, um das letzte Wort auszuschließen, wenn das maximale Wortlimit überschritten wird, aber es hat nicht funktioniert. Wie können wir das erreichen?
Shashank Agrawal
1
Nun, das funktioniert nicht wirklich richtig, manchmal übergebe ich den Maximalwert, zum Beispiel wenn das letzte Wort bereits 30 Zeichen war, wird es bereits eine Länge von mehr als 60 haben! auch wenn es Länge auf{30}
Al-Mothafar
65

Ich bin ein bisschen überrascht, dass es für ein einfaches Problem wie dieses so viele Antworten gibt, die schwer zu lesen sind und einige, einschließlich der ausgewählten, nicht funktionieren.

Normalerweise möchte ich, dass die Ergebniszeichenfolge höchstens aus maxLen Zeichen besteht. Ich benutze dieselbe Funktion auch, um die Slugs in URLs zu verkürzen.

str.lastIndexOf(searchValue[, fromIndex]) Nimmt einen zweiten Parameter, der der Index ist, an dem die Suche in der Zeichenfolge rückwärts gestartet wird, um die Dinge effizient und einfach zu gestalten.

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

Dies ist eine Beispielausgabe:

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"

Und für die Schnecke:

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"
Chris Cinelli
quelle
1
Ich habe das lastIndexOf () komplett vergessen. Guter Fang!
Tici
2
Dieser stürzt ab , wenn aus irgendeinem Grund strist undefined. Ich fügte hinzuif (!str || str.length <= maxLen) return str;
Silvain
Dies behandelt nicht den
Randfall,
@shrewquest Es funktioniert. Wenn sich das Trennzeichen nicht in der Zeichenfolge befindet, wird die Zeichenfolge selbst zurückgegeben, wenn str.length <= maxLen. Andernfalls wird eine leere Zeichenfolge zurückgegeben.
Chris Cinelli
20

Jeder scheint zu vergessen, dass indexOf zwei Argumente benötigt - die übereinstimmende Zeichenfolge und den zu zeigenden Zeichenindex. Sie können die Zeichenfolge am ersten Leerzeichen nach 10 Zeichen brechen.

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
*/
kennebec
quelle
Beachten Sie, dass indexOf durch lastIndexOf ersetzt werden kann, wenn harte Grenzen erforderlich sind.
Scheintod
14

Lodash hat eine speziell dafür geschriebene Funktion: _.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...'
Leon Li
quelle
7

Basierend auf der NT3RP-Antwort, die einige Eckfälle nicht behandelt, habe ich diesen Code erstellt. Es wird garantiert, dass kein Text mit einem Ereignis der Größe> maxLength zurückgegeben wird, ...bei dem am Ende Auslassungspunkte hinzugefügt wurden.

Dies behandelt auch einige Eckfälle wie einen Text, bei dem ein einzelnes Wort> maxLength ist

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

Ich denke, Sie können die JQuery-Abhängigkeit leicht entfernen, wenn Sie dies stört.

Sebastien Lorber
quelle
3
Ich mag diese Lösung, aber sollten die Argumente $.extendnicht umgekehrt werden?
JKesMc9tqIQe9M
5

Hier ist eine Lösung in einer Zeile.

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

Joakim Poromaa Helger
quelle
3

Ich bin zu spät zur Party, aber hier ist eine kleine und einfache Lösung, die ich mir ausgedacht habe, um eine Menge Worte zurückzugeben.

Es hängt nicht direkt mit Ihrer Anforderung an Charaktere zusammen , aber es dient dem gleichen Ergebnis , nach dem Sie meiner Meinung nach gesucht haben.

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

Das Arbeitsbeispiel finden Sie hier: https://jsfiddle.net/bx7rojgL/

Michael Giovanni Pumo
quelle
Sie haben eine JS-Funktion geschrieben, die eine Zeichenfolge auf mehrere Wörter abschneidet. Lesen Sie die Frage noch einmal.
ChristoKiwi
1
eeehm. Ich denke, dies ist die einzig richtige Antwort auf die Frage. Fragte er ohne das Wort zu schneiden.
Mike Aron
2

Dies schließt das letzte Wort aus, anstatt es einzuschließen.

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

Verwendung:

smartTrim(yourString, 11, ' ', ' ...')
"The quick ..."
Klima
quelle
2

Ich habe einen anderen Ansatz gewählt. Obwohl ich ein ähnliches Ergebnis benötigte, wollte ich meinen Rückgabewert unter der angegebenen Länge halten.

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

Bearbeiten Ich habe es hier ein wenig überarbeitet : JSFiddle-Beispiel . Es wird wieder mit dem ursprünglichen Array verbunden, anstatt es zu verketten.

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 || '');
}
Pete
quelle
2
function shorten(str,n) {
  return (str.match(RegExp(".{"+n+"}\\S*"))||[str])[0];
}

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

Roko C. Buljan
quelle
1

Sie können truncateunten einen Einzeiler verwenden:

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

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

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

Viktor Vlasenko
quelle
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 = "Dies ist eine lange Zeichenfolge und ich kann nicht alles erklären"; verkürzen (s, 10, '...')

/* "das ist .." */

vivi margaretha
quelle
1

Hier ist noch ein weiterer Code, der entlang von Satzzeichen abgeschnitten wird (suchte danach und Google hat diese Frage hier gefunden). Musste selbst eine Lösung finden, also habe ich das in 15 Minuten gehackt. Findet alle Vorkommen von. ! ? und schneidet an jeder Position von diesen ab, die <alslen

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
Stefan
quelle
1

Typoskript und mit Ellipsen :)

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 + '…'
  }
}
Doublejosh
quelle
0

Für das, was es wert ist, habe ich dies geschrieben, um bis zur Wortgrenze abzuschneiden, ohne Interpunktion oder Leerzeichen am Ende der Zeichenfolge zu hinterlassen:

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

bbeckford
quelle
0

Fanden die gewählten Lösungen nicht zufriedenstellend. Also habe ich etwas geschrieben, das generisch ist und sowohl im ersten als auch im letzten Teil Ihres Textes funktioniert (so etwas wie substr, aber für Wörter). Sie können auch festlegen, ob die Leerzeichen in der Zeichenanzahl weggelassen werden sollen.

    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;
    }
Vasili Paspalas
quelle
0

Ich bin zu spät gekommen, aber ich denke, diese Funktion macht genau das, was OP verlangt. Sie können die SENTENCE- und die LIMIT-Werte leicht für verschiedene Ergebnisse ändern.

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

Die Ausgabe dieses Snippets ist dort, wo das LIMIT 11 ist:

[ '[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' ]
Ian Calderon
quelle
0

Mit Randbedingungen wie leerem Satz und sehr langem ersten Wort. Außerdem wird keine sprachspezifische String-API / Bibliothek verwendet.

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

Shishir Arora
quelle
0

"Pasta mit Tomaten und Spinat"

wenn Sie das Wort nicht halbieren möchten

erste Iteration:

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

zweite Iteration:

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

dritte Iteration:

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

vierte Iteration:

acc: 15 / acc + cur.length = 18 (Limit gebunden) / newTitle = ['Pasta', 'with','omato '];

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(' ')} ...`
}

Ausgabe: Pasta mit Tomate ...

Herr
quelle
-1

Sie können Leerzeichen damit zuschneiden:

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

Von @ NT3RP aktualisiert Ich habe festgestellt, dass, wenn die Zeichenfolge beim ersten Mal ein Leerzeichen trifft, dieses Wort gelöscht wird, wodurch Ihre Zeichenfolge ein Wort kürzer wird, als es sein kann. Also habe ich einfach eine if else-Anweisung eingegeben, um zu überprüfen, ob die maxLength nicht auf ein Leerzeichen fällt.

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)
Landon Anruf
quelle