我正在寻找一种在Python中截断字符串的方法,它不会在一个单词的中间切断字符串。
例如:
Original: "This is really awesome." "Dumb" truncate: "This is real..." "Smart" truncate: "This is really..."
我正在寻找一种从上面完成“智能”截断的方法。
答案 0 :(得分:60)
我实际上是在我最近的一个项目中为此写了一个解决方案。我把它的大部分压缩到了一点点。
def smart_truncate(content, length=100, suffix='...'):
if len(content) <= length:
return content
else:
return ' '.join(content[:length+1].split(' ')[0:-1]) + suffix
if-statement会检查您的内容是否已低于截止点。如果不是,它会截断到所需的长度,在空格上分割,删除最后一个元素(这样你就不会切断一个单词),然后将它连接在一起(同时加上'...')
答案 1 :(得分:44)
这是Adam解决方案中最后一行的稍微好一点的版本:
return content[:length].rsplit(' ', 1)[0]+suffix
(这稍微有点效率,如果字符串前面没有空格,则会返回更明智的结果。)
答案 2 :(得分:11)
有一些细微之处可能会或可能不会给您带来麻烦,例如处理标签(例如,如果您将它们显示为8个空格,但在内部将它们视为1个字符),处理各种破坏风格和不破坏的空格,或允许打破连字符等。如果需要这些,你可能需要看一下textwrap模块。例如:
def truncate(text, max_size):
if len(text) <= max_size:
return text
return textwrap.wrap(text, max_size-3)[0] + "..."
大于max_size的单词的默认行为是打破它们(使max_size成为硬限制)。您可以通过将break_long_words = False传递给wrap()来更改为此处某些其他解决方案使用的软限制,在这种情况下,它将返回整个单词。如果您想要此行为,请将最后一行更改为:
lines = textwrap.wrap(text, max_size-3, break_long_words=False)
return lines[0] + ("..." if len(lines)>1 else "")
根据您想要的确切行为,还有一些其他选项,例如expand_tabs可能会引起您的兴趣。
答案 3 :(得分:7)
def smart_truncate1(text, max_length=100, suffix='...'):
"""Returns a string of at most `max_length` characters, cutting
only at word-boundaries. If the string was truncated, `suffix`
will be appended.
"""
if len(text) > max_length:
pattern = r'^(.{0,%d}\S)\s.*' % (max_length-len(suffix)-1)
return re.sub(pattern, r'\1' + suffix, text)
else:
return text
OR
def smart_truncate2(text, min_length=100, suffix='...'):
"""If the `text` is more than `min_length` characters long,
it will be cut at the next word-boundary and `suffix`will
be appended.
"""
pattern = r'^(.{%d,}?\S)\s.*' % (min_length-1)
return re.sub(pattern, r'\1' + suffix, text)
OR
def smart_truncate3(text, length=100, suffix='...'):
"""Truncates `text`, on a word boundary, as close to
the target length it can come.
"""
slen = len(suffix)
pattern = r'^(.{0,%d}\S)\s+\S+' % (length-slen-1)
if len(text) > length:
match = re.match(pattern, text)
if match:
length0 = match.end(0)
length1 = match.end(1)
if abs(length0+slen-length) < abs(length1+slen-length):
return match.group(0) + suffix
else:
return match.group(1) + suffix
return text
答案 4 :(得分:6)
>>> import textwrap
>>> textwrap.wrap('The quick brown fox jumps over the lazy dog', 12)
['The quick', 'brown fox', 'jumps over', 'the lazy dog']
你只需要拿出第一个元素就可以了......
答案 5 :(得分:3)
def smart_truncate(s, width):
if s[width].isspace():
return s[0:width];
else:
return s[0:width].rsplit(None, 1)[0]
测试它:
>>> smart_truncate('The quick brown fox jumped over the lazy dog.', 23) + "..."
'The quick brown fox...'
答案 6 :(得分:1)
从Python 3.4+开始,您可以使用textwrap.shorten。使用OP示例:
>>> import textwrap
>>> original = "This is really awesome."
>>> textwrap.shorten(original, width=20, placeholder="...")
'This is really...'
textwrap.shorten(text,width,** kwargs)
折叠并截断给定文本以适合给定的宽度。
首先,文本中的空格被折叠(所有空格都被单个空格替换)。如果结果适合宽度,则为 回。否则,从末尾删除足够的单词,以便 剩余的单词加上占位符适合宽度:
答案 7 :(得分:0)
对于Python 3.4+,我将使用textwrap.shorten。
对于旧版本:
def truncate(description, max_len=140, suffix='…'):
description = description.strip()
if len(description) <= max_len:
return description
new_description = ''
for word in description.split(' '):
tmp_description = new_description + word
if len(tmp_description) <= max_len-len(suffix):
new_description = tmp_description + ' '
else:
new_description = new_description.strip() + suffix
break
return new_description
答案 8 :(得分:0)
如果您实际上可能更喜欢按完整句子而不是按单词截断,请从以下开始:
def smart_truncate_by_sentence(content, length=100, suffix='...',):
if not isinstance(content,str): return content
if len(content) <= length:
return content
else:
sentences=content.split('.')
cs=np.cumsum([len(s) for s in sentences])
n = max(1, len(cs[cs<length]) )
return '.'.join(sentences[:n])+ '. ...'*(n<len(sentences))