22

anyone have a handy method to truncate a string in the middle? Something like:

truncate ('abcdefghi', 8);

would result in

'abc...hi'

UPDATE:

to be a bit more complete

  • if the string is <= maxLength, return the string
  • otherwise, return a version of the string that is maxLength, with a chunk taken out of the middle, and replaced with "...".
  • count the three characters of "..." in the total, so if maxLength is 8, you'll only see 5 characters from the original string
3
  • 1
    What specific trouble are you having trying to write it yourself? Commented Apr 19, 2011 at 21:52
  • oh, off by one errors, I suppose. I'm sure I can get it, but it seems like it's probably a solved problem somewhere, so I thought I'd ask. Commented Apr 19, 2011 at 21:54
  • Just as a side note, if you'd use the Unicode ellipsis character ('…') instead of three periods, you can save a couple of characters... Commented Aug 12, 2015 at 11:24

9 Answers 9

40

Here's one way to do it chopping up the string with substr:

var truncate = function (fullStr, strLen, separator) {
    if (fullStr.length <= strLen) return fullStr;

    separator = separator || '...';

    var sepLen = separator.length,
        charsToShow = strLen - sepLen,
        frontChars = Math.ceil(charsToShow/2),
        backChars = Math.floor(charsToShow/2);

    return fullStr.substr(0, frontChars) + 
           separator + 
           fullStr.substr(fullStr.length - backChars);
};

See example →

Sign up to request clarification or add additional context in comments.

3 Comments

Is it possible to create a pipe for angular 2 with the same behavior?
@AlexZahorodnyk I found a bunch of content when I did a web search for "angular 2 create custom pipe", I don't know much about Angular 2 but if you search you'll probably be able to figure it out.
Yeah, I created one yesterday. There is bunch of information about pipes on Angular. Thanks
2

Here is how I did it:

function truncate(
  fullStr,
  strLen = 8,
  separator = "...",
  frontChars = 3,
  backChars = 4
) {
  if (fullStr.length <= strLen) return fullStr;

  return (
    fullStr.substr(0, frontChars) +
    separator +
    fullStr.substr(fullStr.length - backChars)
  );
}

Comments

2

I personally found this approach to be nice and easy to use.

    export function truncate(str: string, maxLength: number, location = 'middle') {
      if (str.length <= maxLength) {
        return str;
      }
    
      let partLength = Math.ceil((maxLength - 3) / 2);
      let startStr, endStr;
    
      switch (location) {
        case 'start':
          endStr = str.substring(str.length - maxLength + 3);
          return '...' + endStr;
        case 'end':
          startStr = str.substring(0, maxLength - 3);
          return startStr + '...';
        case 'middle':
        default:
          startStr = str.substring(0, partLength);
          endStr = str.substring(str.length - partLength);
          return startStr + '...' + endStr;
      }
    }
console.log(truncate('abcdefghi', 8, 'start')); // Output: '...defghi'
console.log(truncate('abcdefghi', 8, 'end')); // Output: 'abcdef...'
console.log(truncate('abcdefghi', 8)); // Output: 'abc...hi'

Comments

1

Something like this...

function truncate(text, startChars, endChars, maxLength) {
    if (text.length > maxLength) {
        var start = text.substring(0, startChars);
        var end = text.substring(text.length - endChars, text.length);
        while ((start.length + end.length) < maxLength)
        {
            start = start + '.';
        }
        return start + end;
    }
    return text;
}
alert(truncate('abcdefghi',2,2,8));

Or to limit to true ellipsis:

function truncate(text, startChars, endChars, maxLength) {
    if (text.length > maxLength) {
        var start = text.substring(0, startChars);
        var end = text.substring(text.length - endChars, text.length);
        return start + '...' + end;
    }
    return text;
}
alert(truncate('abcdefghi',2,2,8));

jsFiddle

2 Comments

Just wanted to point out that your solution writes out n dots, rather than exactly 3, which would emulate an ellipsis.
I know, that is what I had as a space filler. Easily removed, just putting up what I had. I will update with alternative.
1
function truncateString(str, maxLength) {
  if (str.length <= maxLength) {
    return str;
  }

  var ellipsis = '...';
  var truncatedLength = maxLength - ellipsis.length;

  var leftLength = Math.ceil(truncatedLength / 2);
  var rightLength = Math.floor(truncatedLength / 2);

  var leftSubstring = str.substring(0, leftLength);
  var rightSubstring = str.substring(str.length - rightLength);

  return leftSubstring + ellipsis + rightSubstring;
}

EXPLAINED:

The truncateString function takes two parameters: str, which is the original string to be truncated, and maxLength, which is the maximum length of the truncated string (including the ellipsis). If the length of the original string is less than or equal to the maxLength, the function simply returns the original string.

If the length of the original string is greater than the maxLength, the function calculates the lengths of the left and right substrings to be included in the truncated string. The lengths are calculated to be roughly equal, with the left substring potentially having one extra character if the truncatedLength is an odd number.

The function then uses the substring method to extract the appropriate substrings from the original string, and concatenates them with the ellipsis in the middle.

Finally, the truncated string is returned.

Comments

0

This may be a bit 'heavy' for what you're looking for but there's a jQuery plugin that does this sort of thing.

The "Three Dots" plugin

Comments

0

By relying on the @mvChr solution, I propose to use a @pipe with Typescript.
First, You need to create a @pipe helper where you will described the function of truncate.

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'truncateString',
})
export class TreeHelperPipe implements PipeTransform {
  transform(fullStr: string, strLen: number, separator: string): any {
    if (fullStr.length < strLen) {
      return fullStr;
    }

    separator = separator || '...';

    const sepLen = separator.length,
      charsToShow = strLen - sepLen,
      frontChars = Math.ceil(charsToShow / 2),
      backChars = Math.floor(charsToShow / 2);

    return (
      fullStr.substr(0, frontChars) +
      separator +
      fullStr.substr(fullStr.length - backChars)
    );
  }
}

After that, you will be able to use your @pipe helper on your template like that :

<span
  class="item-name"
  [text]="item.name | truncateString: 60"
  [title]="item.name"
></span>

I only apply the @pipe to the text and not the title attribute (which displays the text in a flyover window).

Comments

-1

CoffeeScript version based on mVChr's answer:

truncate = (str, length, separator = '...') ->
  return '' if str is null
  return str if str.length <= length

  pad = Math.round (length - separator.length) / 2
  start = str.substr(0, pad)
  end = str.substr(str.length - pad)

  [start, separator, end].join('')

Comments

-5

If you are playing in PHP you can call this, works fine and could be adjusted to JS well I assume.

function middle_dots($crumb, $max=30){
  if(strlen($crumb) > $max)
  $crumb = substr_replace($crumb, '...', $max/2, round(-$max/2));
  return $crumb;
}

echo middle_dots('Some long text here would if longer than 30 chars get some ...');

Enjoy

Steve

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.