缩短字符串而无需在JavaScript中切词


102

我对JavaScript中的字符串操作不太满意,我想知道如何在不删节的情况下缩短字符串。我知道如何使用子字符串,但不知道indexOf或其他任何真正好的方法。

说我有以下字符串:

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

我想将其缩减为10个字符,但是如果它不以空格结尾,请完成该单词。我不希望字符串变量看起来像这样:

“这是我不能忍受的长字符串”

我希望它在出现空格之前将单词结束。


你是说修剪一根绳子?尝试" too many spaces ".trim()
阿努拉格

1
一些示例输入和预期输出将有助于回答这个问题。
deceze

好吧,对不起,我有字符串text =“这是一个无法显示的长字符串”,我想将其缩减为10个字符,但是如果它不以空格结尾,则表示该单词我不希望字符串变量看起来像这个“这是我不能
diss

Answers:


180

如果我理解正确,则希望将字符串缩短为一定的长度(例如,缩短"The quick brown fox jumps over the lazy dog"为6个字符而不切断任何单词)。

在这种情况下,您可以尝试以下操作:

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”在“ jQuery函数”中不起作用是绝对不正确的。甚至没有“ jQuery函数”之类的东西。
尖尖的

3
不是应该是“ maxLength + 1”。并且如果maxLength大于或等于完整句子的长度,则不包括最后一个单词。但感谢您的解决方案。
Beytan Kurt 2014年

4
如果在小于maxLength的字符串上使用此字符串,则会截断最后一个单词。也许@AndrewJuniorHoward已经说明了此(maxLength + 1)的修复方法,但我通过在顶部添加以下代码来解决了该问题:var yourString += " ";
tylerl 2014年

3
不幸的是,如果您删除fox jumps over the lazy dog一部分,结果将是The quick brown 应该的The quick brown fox
Andrey Gordeev

2
这总是刻板的。
克里斯·辛纳利

108

有很多方法可以执行此操作,但是正则表达式是一种有用的单行方法:

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

此表达式返回前11个(任意)字符以及任何后续的非空格字符。

示例脚本:

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

输出:

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

太棒了,我从字面上用百万种方法搜索了这个问题,并且只能找到适用于php的工作版本,而与此版本并没有涉及循环。
2011年

1
它指的是第一个(也是唯一的,在这种情况下)子表达式匹配-方括号中的内容。$ 0表示整个匹配项,在这种情况下为整个字符串。
Hamish

3
@josh您应该能够通过使用正则表达式对象来使最大长度成为变量:t.replace(new RegExp("^(.{"+length+"}[^\s]*).*"), "$1")
rjmackay 2013年

1
@Hamish您的选择效果很好,但是如果长度超过,它也会包含最后一个单词。如果最大字数限制超过了上限,但我尝试更改正则表达式以排除最后一个字,但无法正常工作。我们如何实现这一目标?
Shashank Agrawal,2015年

1
好吧,这实际上并不能正常工作,有时我会传递最大值,例如,如果最后一个单词已经是30个字符,则长度已经超过60个!即使将长度设置为{30}
Al-Mothafar '17

65

对于像这样的简单问题,有如此之多的答案难以理解,有些答案(包括所选的答案)不起作用,我感到很惊讶。

我通常希望结果字符串最多为 maxLen字符。我还使用相同的功能来缩短URL中的段。

str.lastIndexOf(searchValue[, fromIndex]) 接受第二个参数,该参数是开始向后搜索字符串的索引,使事情变得高效而简单。

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

这是一个示例输出:

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"

对于子弹:

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()。接得好!
迪契

2
如果由于某种原因str而崩溃undefined。我添加了if (!str || str.length <= maxLen) return str;
Silvain

这不能处理字符串中不出现分隔符的
极端

@shrewquest它有效。如果分隔符不在字符串中,则返回字符串本身str.length <= maxLen。否则,它将返回一个空字符串。
克里斯·辛纳利

20

每个人似乎都忘记了indexOf接受两个参数-要匹配的字符串,以及要从中查找的字符索引。您可以在10个字符后的第一个空格处中断字符串。

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

注意,如果需要硬边界,可以用lastIndexOf代替indexOf。
Scheintod 2014年

14

Lodash具有专门为此编写的功能: _.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

基于无法处理某些极端情况的NT3RP答案,我编写了此代码。它保证不返回size> maxLength事件的文本,该事件...的末尾添加了省略号。

这也可以处理一些极端情况,例如文本,其中一个单词> 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;
}

我想如果这困扰您,您可以轻松删除jquery依赖项。


3
我喜欢这种解决方案,但是传递给args的参数不$.extend应该反向吗?
JKesMc9tqIQe9M 2015年


3

我参加聚会很晚,但这是我想出一个简单的解决方案,可以返回一些单词。

它与您对字符的要求没有直接关系,但它的效果与我认为的相同。

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

参见此处的工作示例:https : //jsfiddle.net/bx7rojgL/


您编写了一个JS函数,该函数将字符串截断为多个单词。再次阅读问题。
ChristoKiwi

1
嗯 我认为这是对该问题的唯一正确答案。他不加言语地问。
Mike Aron

2

这排除了最后一个单词,而不是包括它。

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

用法:

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

2

我采取了不同的方法。当我需要类似的结果时,我想使返回值小于指定的长度。

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

编辑我在这里重构了一下: JSFiddle Example。它重新加入原始数组,而不是连接在一起。

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

您可以truncate在下面使用单线:

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 =“这是一个很长的字符串,我无法全部解释”;缩短(s,10,'...')

/* “这是 ..” */


1

这是另一段沿标点符号截断的代码(一直在寻找,而Google在这里找到了这个问题)。必须自己提出一个解决方案,所以这是我在15分钟内破解的内容。查找所有出现的。!?并在<len

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

打字稿,并带有省略号:)

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

值得的是,我将其编写为截断到单词边界,而在字符串末尾没有标点或空格:

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

投票解决方案未令人满意。因此,我写的多数民众赞成在某种程度上通用并且可以在文本的第一部分和最后一部分工作(类似于substr,但适用于单词)。您还可以设置是否要在字符计数中保留空格。

    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

为此,我来晚了,但我认为此功能完全可以满足OP的要求。您可以轻松更改SENTENCE和LIMIT值以获得不同的结果。

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

此代码段的输出是LIMIT为11的位置:

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

具有边界条件,例如空句子和很长的第一个单词。另外,它不使用语言特定的字符串api / library。

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

意大利面配番茄和菠菜

如果你不想把这个词切成两半

第一次迭代:

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

第二次迭代:

acc:5 / acc +长度= 9 / newTitle = ['Pasta','with'];

第三次迭代:

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

第四次迭代:

acc:15 / acc + cur.length = 18(界限)/ newTitle = ['Pasta','with','tomato'];

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

输出:番茄意面...


-1

您可以使用以下方法修剪空间:

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

-1

从@ NT3RP更新,我发现如果字符串碰巧第一次碰到一个空格,它将最终删除该单词,使您的字符串短一个单词。所以我只用了if if语句来检查maxLength是否不落在一个空格上。

代码库

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)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.