Rút ngắn chuỗi mà không cắt từ trong JavaScript


102

Tôi không giỏi thao tác chuỗi trong JavaScript và tôi đã tự hỏi bạn sẽ làm thế nào để rút ngắn một chuỗi mà không cắt bỏ bất kỳ từ nào. Tôi biết cách sử dụng chuỗi con, nhưng không phải indexOf hoặc bất cứ thứ gì thực sự tốt.

Giả sử tôi có chuỗi sau:

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

Tôi muốn cắt nó xuống còn 10 ký tự, nhưng nếu nó không kết thúc bằng dấu cách, hãy kết thúc từ. Tôi không muốn biến chuỗi trông như thế này:

"đây là một chuỗi dài tôi không thể bỏ qua"

Tôi muốn nó kết thúc từ cho đến khi xuất hiện khoảng trắng.


ý bạn là cắt một chuỗi? thử" too many spaces ".trim()
Anurag

1
Một số ví dụ đầu vào và đầu ra dự kiến ​​sẽ giúp ích rất nhiều trong việc trả lời câu hỏi này.
lừa dối

được rồi, xin lỗi nói rằng tôi có chuỗi văn bản = "đây là một chuỗi dài tôi không thể hiển thị" tôi muốn cắt nó xuống còn 10 ký tự nhưng nếu nó không kết thúc bằng dấu cách thì kết thúc từ đó tôi không muốn biến chuỗi trông như thế nào này "đây là một chuỗi dài tôi không thể dis"
Josh Bedo

Câu trả lời:


180

Nếu tôi hiểu chính xác, bạn muốn rút ngắn một chuỗi đến một độ dài nhất định (ví dụ: rút ngắn "The quick brown fox jumps over the lazy dog"thành, chẳng hạn, 6 ký tự mà không cắt bỏ bất kỳ từ nào).

Nếu đúng như vậy, bạn có thể thử một số cách như sau:

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, hoàn toàn không đúng khi ".replace" không hoạt động trong "các hàm jQuery". Thậm chí không có bất kỳ thứ gì gọi là "hàm jQuery".
Pointy

3
đó không phải là "maxLength + 1". Và nếu maxLength lớn hơn hoặc bằng độ dài câu hoàn chỉnh, thì từ cuối cùng sẽ không được bao gồm. nhưng cảm ơn vì giải pháp.
Beytan Kurt

4
Nếu sử dụng điều này trên một chuỗi ngắn hơn maxLength, từ cuối cùng sẽ bị cắt. Có lẽ @AndrewJuniorHoward đã tuyên bố việc sửa chữa cho điều này ( maxLength + 1), nhưng tôi cố định nó bằng cách thêm dòng này lên hàng đầu:var yourString += " ";
tylerl

3
Thật không may, nếu bạn bỏ đi fox jumps over the lazy dogmột phần, kết quả sẽ là The quick brown , khi nó nên có The quick brown fox.
Andrey Gordeev

2
Điều này luôn luôn cắt từ cuối cùng.
Chris Cinelli

108

Có rất nhiều cách để làm điều đó, nhưng một biểu thức chính quy là một phương pháp một dòng hữu ích:

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

Biểu thức này trả về 11 ký tự (bất kỳ) đầu tiên cộng với bất kỳ ký tự không phải khoảng trắng nào tiếp theo.

Tập lệnh mẫu:

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

Đầu ra:

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

Tuyệt vời, tôi thực sự đã tìm kiếm câu hỏi này hàng triệu cách và chỉ có thể tìm thấy một phiên bản làm việc cho php không có gì gần với điều này và liên quan đến các vòng lặp.
Josh Bedo

1
Nó đề cập đến đối sánh biểu thức phụ đầu tiên (và duy nhất, trong trường hợp này) - nội dung trong dấu ngoặc. $ 0 sẽ tham chiếu đến toàn bộ kết hợp, trong trường hợp này là toàn bộ chuỗi.
Hamish

3
@josh Bạn sẽ có thể đặt độ dài tối đa thành một biến bằng cách sử dụng đối tượng regexp:t.replace(new RegExp("^(.{"+length+"}[^\s]*).*"), "$1")
rjmackay

1
@Hamish tùy chọn của bạn hoạt động tốt, nhưng nó cũng bao gồm từ cuối cùng nếu độ dài vượt quá. Tôi đã thử thay đổi biểu thức regex để loại trừ từ cuối cùng nếu giới hạn từ tối đa vượt quá nhưng không hoạt động. Làm thế nào chúng ta có thể đạt được điều đó?
Shashank Agrawal

1
Chà, điều này không thực sự hoạt động chính xác, đôi khi tôi vượt qua giá trị tối đa, ví dụ như nếu từ cuối cùng đã có 30 ký tự thì nó sẽ có độ dài hơn 60 rồi! thậm chí nếu nó thiết lập chiều dài tới{30}
Al-Mothafar

65

Tôi hơi ngạc nhiên là đối với một bài toán đơn giản như thế này có rất nhiều câu trả lời rất khó đọc và một số, bao gồm cả câu đã chọn, không hoạt động.

Tôi thường muốn chuỗi kết quả có nhiều nhất là maxLen ký tự. Tôi cũng sử dụng chức năng tương tự này để rút ngắn các slugs trong URL.

str.lastIndexOf(searchValue[, fromIndex]) nhận tham số thứ hai là chỉ mục để bắt đầu tìm kiếm ngược trong chuỗi làm cho mọi thứ trở nên hiệu quả và đơn giản.

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

Đây là đầu ra mẫu:

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"

Và đối với sên:

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
Tôi đã hoàn toàn quên về lastIndexOf (). Nắm bắt tốt!
Tici

2
Đây crashes, nếu vì một lý do strundefined. Tôi đã thêmif (!str || str.length <= maxLen) return str;
Silvain

điều này không xử lý trường hợp cạnh trong đó dấu phân tách không xảy ra trong chuỗi
khôn ngoan

@shrewquest Nó hoạt động. Nếu dấu phân tách không có trong chuỗi, nó sẽ trả về chính chuỗi nếu str.length <= maxLen. Nếu không, nó trả về một chuỗi trống.
Chris Cinelli

20

Mọi người dường như quên rằng indexOf nhận hai đối số - chuỗi để khớp và chỉ mục ký tự để bắt đầu tìm kiếm. Bạn có thể ngắt chuỗi ở khoảng trắng đầu tiên sau 10 ký tự.

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

Lưu ý rằng indexOf có thể được thay thế bằng lastIndexOf nếu cần các ranh giới cứng.
Scheintod

14

Lodash có một chức năng được viết riêng cho điều này: _.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

Dựa trên câu trả lời NT3RP không xử lý một số trường hợp góc, tôi đã tạo mã này. Nó đảm bảo không trả về văn bản có sự kiện size> maxLength, dấu chấm lửng ...đã được thêm vào cuối.

Điều này cũng xử lý một số trường hợp ở góc như văn bản có một từ duy nhất là> maxLength

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

Tôi đoán bạn có thể dễ dàng loại bỏ sự phụ thuộc jquery nếu điều này làm phiền bạn.


3
Tôi thích giải pháp này, nhưng không phải các args đã được thông qua để $.extendđược đảo ngược?
JKesMc9tqIQe9M

6

Đây là một giải pháp trong một dòng.

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

Tôi đến bữa tiệc muộn, nhưng đây là một giải pháp nhỏ và dễ dàng mà tôi nghĩ ra để trả lại một lượng lời.

Nó không liên quan trực tiếp đến yêu cầu của bạn về các nhân vật , nhưng nó phục vụ cùng một kết quả mà tôi tin rằng bạn đang theo đuổi.

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

Xem ví dụ làm việc tại đây: https://jsfiddle.net/bx7rojgL/


Bạn đã viết một hàm JS cắt ngắn một chuỗi thành một số từ. Đọc lại câu hỏi.
ChristoKiwi

1
eeehm. tôi nghĩ đây là câu trả lời đúng duy nhất cho câu hỏi. Anh hỏi mà không cắt lời.
Mike Aron,

2

Điều này loại trừ từ cuối cùng thay vì bao gồm nó.

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

Sử dụng:

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

2

Tôi đã có một cách tiếp cận khác. Trong khi tôi cần một kết quả tương tự, tôi muốn giữ giá trị trả về của mình nhỏ hơn độ dài được chỉ định.

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

Chỉnh sửa Tôi đã cấu trúc lại nó một chút ở đây: Ví dụ JSFiddle . Nó nối lại mảng ban đầu thay vì nối.

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

Bạn có thể sử dụng truncatemột lớp lót bên dưới:

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 = "đây là một chuỗi dài và tôi không thể giải thích tất cả"; rút ngắn (s, 10, '...')

/* "đây là .." */


1

Đây là một đoạn mã khác được cắt theo dấu chấm câu (đang tìm kiếm điều này và Google đã tìm thấy câu hỏi này ở đây). Phải tự mình đưa ra giải pháp, vì vậy đây là những gì tôi đã hack được trong 15 phút. Tìm tất cả các lần xuất hiện của. ! ? và cắt bớt ở bất kỳ vị trí nào trong số này <thanlen

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

Chữ viết và dấu chấm lửng :)

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

0

Vì những gì đáng giá, tôi đã viết điều này để cắt ngắn đến ranh giới từ mà không để lại dấu chấm câu hoặc khoảng trắng ở cuối chuỗi:

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

Không tìm thấy các giải pháp được bình chọn thỏa đáng. Vì vậy, tôi đã viết một cái gì đó là loại chung chung và hoạt động cả phần đầu và phần cuối của văn bản của bạn (một cái gì đó giống như substr nhưng cho các từ). Ngoài ra, bạn có thể đặt nếu bạn muốn các khoảng trống bị bỏ trống trong số ký tự.

    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

Tôi đã đến muộn vì điều này nhưng tôi nghĩ rằng chức năng này thực hiện chính xác những gì OP yêu cầu. Bạn có thể dễ dàng thay đổi các giá trị SENTENCE và LIMIT cho các kết quả khác nhau.

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

Đầu ra của đoạn mã này có LIMIT là 11 là:

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

Với các điều kiện biên như câu trống và từ đầu tiên rất dài. Ngoài ra, nó không sử dụng api / thư viện chuỗi ngôn ngữ cụ thể.

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

'Pasta với cà chua và rau bina'

nếu bạn không muốn cắt từ một nửa

lần lặp đầu tiên:

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

lần lặp thứ hai:

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

lần lặp thứ ba:

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

lần lặp thứ tư:

acc: 15 / acc + cur.length = 18 (giới hạn ràng buộc) / newTitle = ['Pasta', 'with', 'cà chua'];

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

đầu ra: Pasta với cà chua ...


-1

Bạn có thể cắt khoảng trống bằng cách này:

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

-1

Cập nhật từ @ NT3RP Tôi thấy rằng nếu chuỗi xảy ra chạm vào khoảng trắng lần đầu tiên xung quanh nó sẽ kết thúc việc xóa từ đó khiến chuỗi của bạn ngắn hơn một từ có thể. Vì vậy, tôi chỉ cần đưa vào một câu lệnh if else để kiểm tra xem maxLength không nằm trên một khoảng trắng.

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)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.