【问题标题】:Smart way to truncate long strings截断长字符串的聪明方法
【发布时间】:2010-11-15 00:31:43
【问题描述】:

有没有人有比显而易见的解决方案/库更复杂的解决方案/库,用于使用 JavaScript 截断字符串并在末尾添加省略号:

if (string.length > 25) {
  string = string.substring(0, 24) + "...";
}

【问题讨论】:

  • “更复杂”是什么意思?考虑单词边界的函数?
  • 而不是在 HTML 标签中间截断。

标签: javascript string truncation


【解决方案1】:

本质上,您检查给定字符串的长度。如果它比给定长度 n 长,则将其剪辑为长度 nsubstrslice)并将 html 实体 … (...) 添加到剪辑的字符串中。

这样的方法看起来像

function truncate(str, n){
  return (str.length > n) ? str.substr(0, n-1) + '…' : str;
};

如果“更复杂”是指在字符串的最后一个单词边界处截断,则需要进行额外检查。 首先将字符串剪辑到所需的长度,然后将结果剪辑到最后一个单词的边界

function truncate( str, n, useWordBoundary ){
  if (str.length <= n) { return str; }
  const subString = str.substr(0, n-1); // the original check
  return (useWordBoundary 
    ? subString.substr(0, subString.lastIndexOf(" ")) 
    : subString) + "&hellip;";
};

您可以使用您的函数扩展原生 String 原型。在这种情况下,应删除str 参数,并将函数内的str 替换为this

String.prototype.truncate = String.prototype.truncate || 
function ( n, useWordBoundary ){
  if (this.length <= n) { return this; }
  const subString = this.substr(0, n-1); // the original check
  return (useWordBoundary 
    ? subString.substr(0, subString.lastIndexOf(" ")) 
    : subString) + "&hellip;";
};

更多教条的开发者可能会为此强烈谴责你(“不要修改你不拥有的对象”。不过我不介意)。

不扩展 String 原型的方法是创建 您自己的辅助对象,包含您提供的(长)字符串 以及前面提到的截断它的方法。这就是sn-p 下面是。

const LongstringHelper = str => {
  const sliceBoundary = str => str.substr(0, str.lastIndexOf(" "));
  const truncate = (n, useWordBoundary) => 
        str.length <= n ? str : `${ useWordBoundary 
          ? sliceBoundary(str.slice(0, n - 1))
          : str.substr(0, n - 1)}&hellip;`;
  return { full: str,  truncate };
}; 
const longStr = LongstringHelper(`Lorem ipsum dolor sit amet, consectetur 
adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore 
magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation 
ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute 
irure dolor in reprehenderit in voluptate velit esse cillum dolore 
eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non 
proident, sunt in culpa qui officia deserunt mollit anim id est laborum`);

const plain = document.querySelector("#resultTruncatedPlain");
const lastWord = document.querySelector("#resultTruncatedBoundary");
plain.innerHTML = 
  longStr.truncate(+plain.dataset.truncateat, !!+plain.dataset.onword);
lastWord.innerHTML = 
  longStr.truncate(+lastWord.dataset.truncateat, !!+lastWord.dataset.onword);
document.querySelector("#resultFull").innerHTML = longStr.full;
body {
  font: normal 12px/15px verdana, arial;
}

p {
  width: 450px;
}

#resultTruncatedPlain:before {
  content: 'Truncated (plain) n='attr(data-truncateat)': ';
  color: green;
}

#resultTruncatedBoundary:before {
  content: 'Truncated (last whole word) n='attr(data-truncateat)': ';
  color: green;
}

#resultFull:before {
  content: 'Full: ';
  color: green;
}
<p id="resultTruncatedPlain" data-truncateat="120" data-onword="0"></p>
<p id="resultTruncatedBoundary" data-truncateat="120" data-onword="1"></p>
<p id="resultFull"></p>

最后,您只能使用 css 来截断 HTML 节点中的长字符串。它使您的控制更少,但很可能是可行的解决方案。

body {
  font: normal 12px/15px verdana, arial;
  margin: 2rem;
}

.truncate {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  width: 30vw;
}

.truncate:before{
  content: attr(data-longstring);
}

.truncate:hover::before {
  content: attr(data-longstring);
  width: auto;
  height: auto;
  overflow: initial;
  text-overflow: initial;
  white-space: initial;
  background-color: white;
  display: inline-block;
}
&lt;div class="truncate" data-longstring="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."&gt;&lt;/div&gt;

【讨论】:

  • 还应考虑具有“硬”和“软”限制,例如,如果字符串长度超过 500 个字符,则将其截断为 400。当用户想要查看全文并单击一些链接。结果,如果您只加载了 1 或 2 个字符,它看起来会非常难看。
  • substr 的第二个参数是一个长度,所以它应该是 substr(0,n) 而不是限制为第一个 n 字符。
  • 不要修改不属于您的对象。 nczonline.net/blog/2010/03/02/…
  • 您可能会考虑将代码示例中的 &amp;hellip; 替换为实际的省略号 (...)。如果您尝试使用它与 API 交互,您将需要非 HTML 实体。
  • @RuneJeppesen 你是对的。调整了方法。为我辩护:答案可以追溯到 7 年前 ;)
【解决方案2】:

请注意,这只需要为 Firefox 完成。

所有其他浏览器都支持CSS解决方案(见support table):

p {
    white-space: nowrap;
    width: 100%;                   /* IE6 needs any width */
    overflow: hidden;              /* "overflow" value must be different from  visible"*/ 
    -o-text-overflow: ellipsis;    /* Opera < 11*/
    text-overflow:    ellipsis;    /* IE, Safari (WebKit), Opera >= 11, FF > 6 */
}

具有讽刺意味的是,我从 Mozilla MDC 获得了代码 sn-p。

【讨论】:

  • 哇,这是移动 Safari 的完美解决方案。谢谢!
  • 非常好的 CSS 方法。可能有一个注释,这仅适用于单行文本(如white-space: nowrap; 所期望的那样)。当涉及到多行时,您会被 JavaScript 卡住。
  • 它也只适用于整个元素。如果您想截断字符串的一部分,而不将要截断的位包装在 span 或其他 html 元素中,这将不起作用,例如:Your picture ('some very long picture filename truncated...') has been uploaded.
  • OP 专门要求提供 javascript 解决方案
【解决方案3】:

人们可能希望在 JavaScript 而不是 CSS 中执行此操作是有正当理由的。

在 JavaScript 中截断为 8 个字符(包括省略号):

short = long.replace(/(.{7})..+/, "$1&hellip;");

short = long.replace(/(.{7})..+/, "$1…");

【讨论】:

  • 如果算上省略号,则为 9 个字符。如果需要截断后为 8,请改用.replace(/^(.{7}).{2,}/, "$1…");
  • longshort 被旧的 ECMAScript 规范(ECMAScript 1 到 3)保留为未来的关键字。见MDN: Future reserved keywords in older standards
【解决方案4】:

使用lodash's truncate

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

underscore.string's truncate

_('Hello world').truncate(5); => 'Hello...'

【讨论】:

    【解决方案5】:
    ('long text to be truncated').replace(/(.{250})..+/, "$1…");
    

    不知何故,上面的代码不适用于 vuejs 应用程序中的某种复制粘贴或写入的文本。所以我使用了lodash truncate,它现在工作正常。

    _.truncate('long text to be truncated', { 'length': 250, 'separator': ' '});
    

    【讨论】:

    • 不错的现代答案!
    • 我很想知道文本是什么。是否使用了非拉丁字符?
    • 这只是一个 lorem ipsum
    【解决方案6】:

    我发现的最佳功能。感谢 text-ellipsis

    function textEllipsis(str, maxLength, { side = "end", ellipsis = "..." } = {}) {
      if (str.length > maxLength) {
        switch (side) {
          case "start":
            return ellipsis + str.slice(-(maxLength - ellipsis.length));
          case "end":
          default:
            return str.slice(0, maxLength - ellipsis.length) + ellipsis;
        }
      }
      return str;
    }
    

    示例

    var short = textEllipsis('a very long text', 10);
    console.log(short);
    // "a very ..."
    
    var short = textEllipsis('a very long text', 10, { side: 'start' });
    console.log(short);
    // "...ng text"
    
    var short = textEllipsis('a very long text', 10, { textEllipsis: ' END' });
    console.log(short);
    // "a very END"
    

    【讨论】:

      【解决方案7】:

      All modern browsers 现在支持简单的 CSS 解决方案,如果一行文本超出可用宽度,则自动添加省略号:

      p {
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;
      }
      

      (请注意,这需要以某种方式限制元素的宽度才能产生任何效果。)

      基于https://css-tricks.com/snippets/css/truncate-string-with-ellipsis/

      需要注意的是,这种方式根据字符数进行限制。如果您需要允许多行文本,它也不起作用

      【讨论】:

      • 这仅对单行句子有用,没有办法(据我所知)通过 CSS 做一个多行示例。
      • 有没有办法让它在左边而不是右边做省略号?
      • @GreenAsJade 我相信您可以通过使用text-direction: rtltext-align: left 来实现这一点。见davidwalsh.name/css-ellipsis-left
      【解决方案8】:

      这是我的解决方案,与其他建议相比有一些改进:

      String.prototype.truncate = function(){
          var re = this.match(/^.{0,25}[\S]*/);
          var l = re[0].length;
          var re = re[0].replace(/\s$/,'');
          if(l < this.length)
              re = re + "&hellip;";
          return re;
      }
      
      // "This is a short string".truncate();
      "This is a short string"
      
      // "Thisstringismuchlongerthan25characters".truncate();
      "Thisstringismuchlongerthan25characters"
      
      // "This string is much longer than 25 characters and has spaces".truncate();
      "This string is much longer&hellip;"
      

      它:

      • 在 25 之后的第一个空格处截断 字符
      • 扩展 JavaScript 字符串对象, 所以它可以用于(并链接到) 任何字符串。
      • 如果被截断,将修剪字符串 导致尾随空格;
      • 将添加 unicode hellip 实体 (省略号)如果截断的字符串超过 25 个字符

      【讨论】:

        【解决方案9】:

        大多数现代 Javascript 框架(JQueryPrototypeetc...)都有一个附加到 String 的实用函数来处理这个问题。

        这是 Prototype 中的一个示例:

        'Some random text'.truncate(10);
        // -> 'Some ra...'
        

        这似乎是您希望其他人处理/维护的功能之一。我会让框架处理它,而不是编写更多代码。

        【讨论】:

        • 我认为 jQuery 对此没有任何帮助。
        • Underscore.js 确实 - _('Hello world').truncate(5) => 'Hello...' _('Hello').truncate(10) => 'Hello'
        • 纯下划线似乎也没有 truncate() - 您可能需要一个扩展名,例如 underscore.string
        • 这完全是正确的答案。我不知道下划线,但 lodash 有 _.trunc 正是这样做的。
        • 我认为正确的答案是使用 lodash.trunc 或 underscore.string.truncate。
        【解决方案10】:

        我喜欢使用 .slice() 第一个参数是起始索引,第二个是结束索引。两者之间的一切都是你得到的。

        var long = "hello there! Good day to ya."
        // hello there! Good day to ya.
        
        var short  = long.slice(0, 5)
        // hello
        

        【讨论】:

        • 最简单的答案,不需要过于复杂的答案。
        【解决方案11】:

        文本溢出:省略号是您需要的属性。有了这个和一个溢出:以特定宽度隐藏,所有超过它的东西都会在最后得到三个句点效果......不要忘记添加空格:nowrap,否则文本将被放在多行中。

        .wrap{
          text-overflow: ellipsis
          white-space: nowrap;
          overflow: hidden;
          width:"your desired width";
        }
        <p class="wrap">The string to be cut</p>
        

        【讨论】:

        • 简洁是可以接受的,但更全面的解释更好。
        • mwilcoxSean the Bean 已发布此解决方案。
        • 只能用于单行文字
        • 文本溢出:省略号是完美的!!
        【解决方案12】:

        我总是使用cuttr.js library to truncate strings 并添加自定义省略号:

        new Cuttr('.container', {
          //options here
          truncate: 'words',
          length: 8,
          ending: '... ►'
        });
        <script src="https://unpkg.com/cuttr@1.1.1/dist/cuttr.min.js"></script>
        <p class="container">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. </p>

        这是迄今为止最简单的方法(并且没有任何依赖项)我知道用 JS 剪切字符串,它也可用作 jQuery 插件。

        【讨论】:

          【解决方案13】:

          也许我错过了有人处理空值的示例,但是当我有空值时,3 TOP 答案对我不起作用(当然,我意识到错误处理和其他数百万件事不是回答问题的人的责任,但由于我使用了现有函数以及出色的截断省略号答案之一,我想我会为其他人提供它。

          例如

          javascript:

          news.comments
          

          使用截断函数

          news.comments.trunc(20, true);
          

          但是,如果 news.cmets 为 null,这将“中断”

          决赛

          checkNull(news.comments).trunc(20, true) 
          

          trunc 函数由 KooiInc

          提供
          String.prototype.trunc =
           function (n, useWordBoundary) {
               console.log(this);
               var isTooLong = this.length > n,
                   s_ = isTooLong ? this.substr(0, n - 1) : this;
               s_ = (useWordBoundary && isTooLong) ? s_.substr(0, s_.lastIndexOf(' ')) : s_;
               return isTooLong ? s_ + '&hellip;' : s_;
           };
          

          我的简单空检查器(也检查文字“空”的东西 (这会捕获 undefined、""、null、"null" 等。)

            function checkNull(val) {
                if (val) {
                    if (val === "null") {
                        return "";
                    } else {
                        return val;
                    }
                } else {
                    return "";
                }
            }
          

          【讨论】:

          • 这是一个修改版本 - 避免使用原型,在函数中加入空值检查,并有一些测试/演示用法。 codepen.io/mahemoff/pen/LGEdzy
          • 你觉得原型有问题吗?只是好奇
          • 我使用单独的空值检查函数的原因是它实际上会检查空值、未定义、NaN、空字符串 ("")、0、false 和 "null" 但总的来说我喜欢你的 fx
          • 是的,这是意见和使用上下文的问题,但是当您使用其他库时,原型会变得很难看,因为它们也可能会覆盖相同的东西。 (或者在极少数情况下,稍后可能会引入同名函数作为标准语言特性。)
          • 是的,我同意你的看法
          【解决方案14】:

          有时文件名是编号的,索引可能在开头或结尾。所以我想从字符串的中心缩短:

          function stringTruncateFromCenter(str, maxLength) {
              const midChar = "…";      // character to insert into the center of the result
              var left, right;
          
              if (str.length <= maxLength) return str;
          
              // length of beginning part      
              left = Math.ceil(maxLength / 2);
          
              // start index of ending part   
              right = str.length - Math.floor(maxLength / 2) + 1;   
          
              return str.substr(0, left) + midChar + str.substring(right);
          }
          

          请注意,我在此处使用了 UTF-8 中超过 1 个字节的填充字符。

          【讨论】:

            【解决方案15】:

            如果你使用 Ext.js,你可以使用Ext.util.Format.ellipsis 函数。

            【讨论】:

              【解决方案16】:

              我赞成 Kooilnc 的解决方案。非常好的紧凑型解决方案。我想解决一个小的边缘案例。如果有人出于某种原因输入了一个非常长的字符序列,它不会被截断:

              function truncate(str, n, useWordBoundary) {
                  var singular, tooLong = str.length > n;
                  useWordBoundary = useWordBoundary || true;
              
                  // Edge case where someone enters a ridiculously long string.
                  str = tooLong ? str.substr(0, n-1) : str;
              
                  singular = (str.search(/\s/) === -1) ? true : false;
                  if(!singular) {
                    str = useWordBoundary && tooLong ? str.substr(0, str.lastIndexOf(' ')) : str;
                  }
              
                  return  tooLong ? str + '&hellip;' : str;
              }
              

              【讨论】:

                【解决方案17】:

                通过快速谷歌搜索,我找到了this...这对你有用吗?

                /**
                 * Truncate a string to the given length, breaking at word boundaries and adding an elipsis
                 * @param string str String to be truncated
                 * @param integer limit Max length of the string
                 * @return string
                 */
                var truncate = function (str, limit) {
                    var bits, i;
                    if (STR !== typeof str) {
                        return '';
                    }
                    bits = str.split('');
                    if (bits.length > limit) {
                        for (i = bits.length - 1; i > -1; --i) {
                            if (i > limit) {
                                bits.length = i;
                            }
                            else if (' ' === bits[i]) {
                                bits.length = i;
                                break;
                            }
                        }
                        bits.push('...');
                    }
                    return bits.join('');
                };
                // END: truncate
                

                【讨论】:

                • 什么是STR?这是在哪里定义的??
                【解决方案18】:

                c_harm 的答案在我看来是最好的。请注意,如果您想使用

                "My string".truncate(n)
                

                您将不得不使用正则表达式对象构造函数而不是文字。此外,您必须在转换时转义 \S

                String.prototype.truncate =
                    function(n){
                        var p  = new RegExp("^.{0," + n + "}[\\S]*", 'g');
                        var re = this.match(p);
                        var l  = re[0].length;
                        var re = re[0].replace(/\s$/,'');
                
                        if (l < this.length) return re + '&hellip;';
                    };
                

                【讨论】:

                • 听说过注释和正确的变量命名吗?
                • @bicycle 代码是从上面的另一个答案中复制和修改的,没必要这么粗鲁和刻薄。
                【解决方案19】:

                使用以下代码

                 function trancateTitle (title) {
                    var length = 10;
                    if (title.length > length) {
                       title = title.substring(0, length)+'...';
                    }
                    return title;
                }
                

                【讨论】:

                  【解决方案20】:

                  纠正 Kooilnc 的解决方案:

                  String.prototype.trunc = String.prototype.trunc ||
                    function(n){
                        return this.length>n ? this.substr(0,n-1)+'&hellip;' : this.toString();
                    };
                  

                  如果不需要截断,这将返回字符串值而不是 String 对象。

                  【讨论】:

                  • 这没有提供问题的答案。要批评或要求作者澄清,请在他们的帖子下方发表评论 - 您可以随时评论自己的帖子,一旦您有足够的reputation,您就可以comment on any post
                  • 啊,我现在看到了区别。感谢您的参考。我确实想发表评论,希望@Kooilnc 能看到它,如果他或她同意,可能会编辑接受的答案,但没有声誉。
                  【解决方案21】:

                  我最近不得不这样做,结果是:

                  /**
                   * Truncate a string over a given length and add ellipsis if necessary
                   * @param {string} str - string to be truncated
                   * @param {integer} limit - max length of the string before truncating
                   * @return {string} truncated string
                   */
                  function truncate(str, limit) {
                      return (str.length < limit) ? str : str.substring(0, limit).replace(/\w{3}$/gi, '...');
                  }
                  

                  对我来说感觉又好又干净:)

                  【讨论】:

                  • 这可能会使生成的字符串比限制长 3 个字符。
                  【解决方案22】:

                  聪明的地方:D

                  //My Huge Huge String
                      let tooHugeToHandle = `It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).`
                      
                  //Trim Max Length
                   const maxValue = 50
                  // The barber.
                   const TrimMyString = (string, maxLength, start = 0) => {
                  //Note - `start` is if I want to start after some point of the string
                      	if (string.length > maxLength) {
                      	let trimmedString = string.substr(start, maxLength)
                      	 return (
                      	   trimmedString.substr(
                      	   start,
                      	   Math.min(trimmedString.length,   trimmedString.lastIndexOf(' '))
                             ) + ' ...'
                           )
                         }
                      return string
                  }
                  
                  console.log(TrimMyString(tooHugeToHandle, maxValue))

                  【讨论】:

                    【解决方案23】:

                    这是我的单词边界解决方案。

                    let s = "At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."
                    let s_split = s.split(/\s+/);
                    let word_count = 0;
                    let result = "";
                    //1
                    for(let i = 0; word_count < 100; i++){
                      word_count += s_split[i].length+1;
                      result += (s_split[i] + " ");
                    }
                    console.log(result);
                    // 2
                    word_count = 0;
                    result = s_split.reduce((x,y)=>{
                      word_count+=(y.length+1);
                      if(word_count>=100) return x;
                      else return x+" "+y;}, "").substring(1);
                    console.log(result);

                    【讨论】:

                      【解决方案24】:

                      如果你想用 css 而不是 JavaScript;

                      .textShortDesc { /*Here we have determined the max number of lines.*/
                          display: block; /* or inline-block */
                          -o-text-overflow: ellipsis; /* Opera < 11*/
                          text-overflow: ellipsis; /* IE, Safari (WebKit), Opera >= 11, FF > 6 */
                          word-wrap: break-word;
                          overflow: hidden;
                          max-height: 2em; /*max-height/line-height=rowCount */
                          line-height: 1em;
                      }
                      

                      【讨论】:

                        【解决方案25】:

                        此函数还可以截断空格和单词部分。(例如:Mother into Moth...)

                        String.prototype.truc= function (length) {
                                return this.length>length ? this.substring(0, length) + '&hellip;' : this;
                        };
                        

                        用法:

                        "this is long length text".trunc(10);
                        "1234567890".trunc(5);
                        

                        输出:

                        这是...

                        12345...

                        【讨论】:

                          猜你喜欢
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2015-03-12
                          • 2015-07-08
                          • 2012-09-03
                          相关资源
                          最近更新 更多