【问题标题】:Shorten string without cutting words in JavaScript在 JavaScript 中缩短字符串而不剪切单词
【发布时间】:2011-07-24 04:16:46
【问题描述】:

我不太擅长 JavaScript 中的字符串操作,我想知道如何在不截断任何单词的情况下缩短字符串。我知道如何使用子字符串,但不知道 indexOf 或任何非常好的东西。

假设我有以下字符串:

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

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

"这是一个长字符串,我无法解散"

我希望它完成单词直到出现空格。

【问题讨论】:

  • 你的意思是修剪一个字符串?试试" too many spaces ".trim()
  • 一些示例输入和预期输出将有助于回答这个问题。
  • 好吧,对不起,我有字符串 text = “这是一个我无法显示的长字符串”,我想将其缩减为 10 个字符,但如果它不以空格结尾,则完成单词我不'不希望字符串变量看起来像这样“这是一个长字符串,我无法解散”

标签: javascript string substring


【解决方案1】:

如果我理解正确,您想将字符串缩短到一定长度(例如,将 "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 the string to the maximum length
var trimmedString = yourString.substr(0, maxLength);

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

【讨论】:

  • @josh “.replace”在“jQuery 函数”中不起作用绝对不是真的。甚至没有“jQuery 函数”之类的东西。
  • 不应该是“maxLength + 1”。如果 maxLength 大于或等于完整的句子长度,则不包括最后一个单词。但感谢您的解决方案。
  • 如果在短于 maxLength 的字符串上使用它,最后一个单词会被截断。也许@AndrewJuniorHoward 已经说明了这个问题的修复(maxLength + 1),但我通过简单地在顶部添加这行来修复它:var yourString += " ";
  • 不幸的是,如果你去掉fox jumps over the lazy dog部分,结果将是The quick brown ,而它应该是The quick brown fox
  • 这总是删掉最后一个字。
【解决方案2】:

有很多方法可以做到,但正则表达式是一种有用的单行方法:

"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 没有接近这个并且涉及循环。
  • 它指的是第一个(在这种情况下也是唯一的)子表达式匹配 - 括号中的内容。 $0 将引用整个匹配项,在这种情况下是整个字符串。
  • @josh 您应该能够使用正则表达式对象将最大长度设为变量:t.replace(new RegExp("^(.{"+length+"}[^\s]*).*"), "$1")
  • @Hamish 您的选项效果很好,但如果长度超过,它也包括最后一个词。如果最大字数限制超出但没有使其正常工作,我尝试更改正则表达式以排除最后一个字。我们怎样才能做到这一点?
  • 嗯,这并不能正常工作,有时我会传递最大值,例如,如果最后一个单词已经是 30 个字符,那么它的长度已经超过 60!即使将长度设置为{30}
【解决方案3】:

我有点惊讶,对于这样一个简单的问题,有这么多难以阅读的答案,而且有些答案,包括选择的答案,都不起作用。

我通常希望结果字符串最多 maxLen 个字符。 我也使用相同的函数来缩短 URL 中的 slug。

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"

【讨论】:

  • 我完全忘记了 lastIndexOf()。好收获!
  • 如果由于某种原因strundefined,则会崩溃。我加了if (!str || str.length &lt;= maxLen) return str;
  • 这不处理字符串中没有出现分隔符的边缘情况
  • @shrewquest 它有效。如果分隔符不在字符串中,则在str.length &lt;= maxLen 时返回字符串本身。否则返回一个空字符串。
  • 如果 str>maxLen 返回空字符串。通过添加解决它 if(str.split(separator)[0].length>maxLen) return str.split(separator)[0].substr(0,maxLen-2)+"...";
【解决方案4】:

似乎每个人都忘记了 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
*/

【讨论】:

  • 请注意,如果需要硬边界,可以将 indexOf 替换为 lastIndexOf。
【解决方案5】:

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

【讨论】:

    【解决方案6】:

    这是一个解决方案。

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

    【讨论】:

      【解决方案7】:

      基于不处理某些极端情况的 NT3RP 答案,我编写了此代码。 它保证不返回大小 > 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 依赖项。

      【讨论】:

      • 我喜欢这个解决方案,但是传递给$.extend 的参数不应该颠倒吗?
      【解决方案8】:

      我参加聚会迟到了,但我想出了一个小而简单的解决方案来返回大量单词。

      这与您对字符的要求没有直接关系,但它与我相信您所追求的结果相同。

      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 函数,将字符串截断为多个单词。再次阅读问题。
      • eeehm。我认为这是对这个问题的唯一正确答案。他不说话就问。
      【解决方案9】:

      我采取了不同的方法。虽然我需要一个类似的结果,但我想保持我的返回值小于指定的长度。

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

      【讨论】:

        【解决方案10】:
        function shorten(str,n) {
          return (str.match(RegExp(".{"+n+"}\\S*"))||[str])[0];
        }
        
        shorten("Hello World", 3); // "Hello"
        

        // SHORTEN STRING TO WHOLE WORDS
        function shorten(s,l) {
          return (s.match(new RegExp(".{"+l+"}\\S*"))||[s])[0];
        }
        
        console.log( shorten("The quick brown fox jumps over the lazy dog", 6) ); // "The quick"

        【讨论】:

          【解决方案11】:

          这会排除最后一个单词而不是包含它。

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

          【讨论】:

            【解决方案12】:

            您可以在下面使用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));

            【讨论】:

              【解决方案13】:

              这是一个包含一些有用属性的单行版本:

              1. 处理与\s 正则表达式匹配的任何形式的空间
              2. 独立于输入长度执行(不扫描超过最大长度的任何内容)
              3. 独立于输出长度执行(从最大长度向后扫描并且不拆分/加入字符串)
              s.length > maxLen ? s.substring(0, s.substring(0, maxLen + 1).search(/\s+\S*$/)) : s
              

              【讨论】:

                【解决方案14】:

                为了它的价值,我写了这个来截断到单词边界,而不在字符串的末尾留下标点符号或空格:

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

                【讨论】:

                  【解决方案15】:
                  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, '...')

                  /* "这是.." */

                  【讨论】:

                    【解决方案16】:

                    这里还有一段截断标点符号的代码(正在寻找这个,谷歌在这里发现了这个问题)。必须自己想出一个解决方案,所以这是我在 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
                    

                    【讨论】:

                      【解决方案17】:

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

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

                      【讨论】:

                        【解决方案18】:

                        “番茄菠菜意大利面”

                        如果你不想把单词切成两半

                        第一次迭代:

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

                        第二次迭代:

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

                        第三次迭代:

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

                        第四次迭代:

                        acc:15 / acc + cur.length = 18(limit bound) / 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(' ')} ...`
                        }
                        

                        输出:番茄意大利面...

                        【讨论】:

                        • 这不考虑 'join(' ') 字符,这会使字符串长度超过限制。如果将 reduce() 的函数更改为 (acc, cur, idx) 并将 if 更改为 (acc + cur.length
                        【解决方案19】:

                        如果您(已经)使用lodash 库,则有一个名为truncate 的函数可用于修剪字符串。

                        基于文档页面上的示例

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

                        【讨论】:

                          【解决方案20】:

                          没有找到令人满意的投票解决方案。所以我写了一些通用的东西,并且适用于文本的第一部分和最后一部分(类似于 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;
                              }
                          

                          【讨论】:

                            【解决方案21】:

                            我为此迟到了,但我认为这个功能完全符合 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);

                            这个 sn-p 的输出是 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' ]
                            

                            【讨论】:

                              【解决方案22】:

                              具有空句和很长的第一个单词等边界条件。此外,它不使用特定于语言的字符串 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));

                              【讨论】:

                                【解决方案23】:

                                我们可以使用 lodash 的 truncate 函数轻松做到这一点

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

                                继续阅读 Lodash 文档以获得更清晰的信息。

                                【讨论】:

                                  【解决方案24】:
                                  const title = "Hello world is not the way to go"    
                                  const trimmedTitle = title.split(" ").slice(0, 4).join(" ");
                                  

                                  // 输出:“Hello world is not”

                                  【讨论】:

                                    【解决方案25】:

                                    接吻回答

                                    'this is a string'.split(' ').reduce((a, b) => (a+b).length < 10 ? a+' '+b : a);
                                    

                                    【讨论】:

                                      【解决方案26】:

                                      从@NT3RP 更新,我发现如果字符串第一次碰到空格,它最终会删除那个单词,使你的字符串比它可以短一个单词。所以我只是添加了一个 if else 语句来检查 maxLength 没有落在空格上。

                                      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)
                                      

                                      【讨论】:

                                        【解决方案27】:

                                        您可以使用名为 substring 的 JavaScript 方法:

                                        var content = "ABCD";
                                        content.substring(0, 2);
                                        console.log(content);
                                        

                                        预期的输出是 "D"
                                        "ABC" 被修剪,所以可用的内容是 "D"

                                        【讨论】:

                                        • 这可能会截断单词的一部分。
                                        猜你喜欢
                                        • 1970-01-01
                                        • 2019-07-30
                                        • 1970-01-01
                                        • 1970-01-01
                                        • 1970-01-01
                                        • 1970-01-01
                                        • 2022-08-17
                                        • 2016-09-28
                                        • 2013-08-17
                                        相关资源
                                        最近更新 更多