如何使用JavaScript将字符串截断为指定长度?
将字符串拆分为单词并不容易,找到一个好的地方来截断字符串也不容易。问题的一部分在于识别单词边界和单词本身。更高级的用例甚至可能需要考虑区域设置。让我们从最简单的情况逐步构建到最高级的情况。
截断字符串
最简单的截断字符串的方法是使用String.prototype.slice()
。你只需要将String.prototype.length
与所需长度进行比较,并返回截断到所需长度的字符串。如果字符串长度小于所需长度,则返回原字符串。
const truncateString = (str, num) =>
str.length > num ? str.slice(0, num) : str;
truncateString('boomerang', 6); // 'boomer'
截断字符串,并添加省略号
这样做是可以的,但结果并没有提示字符串已被截断的事实。让我们在字符串末尾添加省略号,以表示字符串已被截断。如果字符串已被截断,我们需要将'...'
附加到字符串末尾。我们还需要考虑省略号的长度,因此需要从所需长度中减去省略号的长度。
const truncateString = (str, lim) =>
str.length > lim ? str.slice(0, lim > 3 ? lim - 3 : lim) + '...' : str;
truncateString('boomerang', 7); // 'boom...'
在空格处截断字符串
到目前为止,我们一直在指定的长度处截断字符串,无论它是否在单词中间。但是您可能需要尊重单词边界,并在空格字符处截断字符串。
我们可以使用String.prototype.lastIndexOf()
来找到所需长度下最后一个空格的索引。然后,我们可以使用String.prototype.slice()
根据最后一个空格的索引适当地截断字符串,尽可能地保留空格,并在末尾添加'...'
。
const truncateStringAtWhitespace = (str, lim, ending = '...') => {
if (str.length <= lim) return str;
const lastSpace = str.slice(0, lim - ending.length + 1).lastIndexOf(' ');
return str.slice(0, lastSpace > 0 ? lastSpace : lim - ending.length) + ending;
};
truncateStringAtWhitespace('short', 10); // 'short'
truncateStringAtWhitespace('not so short', 10); // 'not so...'
truncateStringAtWhitespace('trying a thing', 10); // 'trying...'
truncateStringAtWhitespace('javascripting', 10); // 'javascr...'
区域敏感的字符串截断
最后,我们来到了最复杂的问题 - 区域敏感的字符串截断。这是一个难以解决的问题,这就是为什么JavaScript友好地添加了Intl.Segmenter
对象。
Intl.Segmenter
允许您指定区域设置和granularity
选项来指定如何分段字符串。granularity
选项可以设置为'grapheme'
、'word'
或'sentence'
,根据需要进行设置。在字符串上使用Intl.Segmenter.prototype.segment()
将返回一个可迭代的Segments
对象。然后可以使用它来找到正确的索引来分割字符串,而不会在单词或句子中间。
const truncateStringAtWord = (str, lim, locale = 'en-US', ending = '...') => {
const segmenter = new Intl.Segmenter(locale, { granularity: 'word' });
let lastWordBreak = -1;
for (let word of segmenter.segment(str)) {
if (word.isWordLike) continue;
if (word.index >= lim) break;
lastWordBreak = word.index;
}
```javascript
const truncateStringAtWord = (str, lim, ending = '...') => {
let lastWordBreak = -1;
for (let i = 0; i < str.length; i++) {
if (str[i] === ' ') {
if (i >= lim) break;
lastWordBreak = i;
}
}
if (lastWordBreak === -1) return str;
return str.slice(0, lastWordBreak) + ending;
};
const truncateStringAtSentence = (
str,
lim,
locale = 'en-US',
ending = '...'
) => {
const segmenter = new Intl.Segmenter(locale, { granularity: 'sentence' });
let lastSentenceBreak = -1;
for (let sentence of segmenter.segment(str)) {
if (
lastSentenceBreak !== -1 &&
sentence.index + sentence.segment.length >= lim
)
break;
lastSentenceBreak = sentence.index + sentence.segment.length;
}
return str.slice(0, lastSentenceBreak).trim().slice(0, -1) + ending;
};
const str =
'The quick brown fox jumps over the lazy dog. The jay, pig, fox, zebra and my wolves quack!';
const lim = 50;
truncateStringAtWord(str, lim);
// 'The quick brown fox jumps over the lazy dog. The...'
truncateStringAtSentence(str, lim);
// 'The quick brown fox jumps over the lazy dog...'
[!NOTE]
Intl.Segmenter
对象在现代浏览器和 Node.js(自 v16.0.0 起)中可用。请确保检查目标环境的兼容性。