Python ตัดสตริงที่มีความยาวออก


246

หนึ่งตัดสตริงถึง 75 ตัวอักษรใน Python อย่างไร

นี่คือวิธีที่มันทำใน JavaScript:

var data="saddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddsaddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddsadddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
var info = (data.length > 75) ? data.substring[0,75] + '..' : data;

คำตอบ:


427
info = (data[:75] + '..') if len(data) > 75 else data

58
ฉันจะเปลี่ยนเงื่อนไขบางทีเพื่อlen(data) > 77บัญชีจุดคู่ (มันไม่มีประโยชน์ที่จะตัดทอนเฉพาะตัวละครตัวสุดท้ายเท่านั้นเพื่อแทนที่ด้วยจุด)
Hasen

5
@hasenj: นั่นไม่สอดคล้องกับรหัสต้นฉบับ แต่เป็นคำแนะนำที่ดีที่ฉันควรจะชี้ให้เห็นในตอนแรก
Marcelo Cantos

2
โปรดทราบว่าการรวมคำอุปมานั้นเป็นทางเลือกแน่นอน
เทย์เลอร์เอ็ดมิสตัน

10
@TaylorEdmiston True แต่พวกเขาค่อนข้างมีประโยชน์สำหรับผู้ที่จำกฎสำคัญกว่าทั้งหมดในภาษาต่าง ๆ ที่พวกเขาใช้ในชีวิตประจำวัน
Marcelo Cantos

2
@Anthony a slice
Marcelo Cantos

126

สั้นกว่า:

info = data[:75] + (data[75:] and '..')

2
วิธีตลกที่จะทำ แม้ว่ามันจะยังคงเป็นคอมโพสิตหนึ่งซับ ^^
ไชโย

3
วิธีแก้ปัญหานี้ไม่มี 77 ตัวอักษรหากคุณใส่ '.. '
Mark Chackerian

นี่เป็นการดำเนินการสองชิ้นหรือไม่ ฉันสงสัยว่าสิ่งนี้มีประสิทธิภาพอย่างไรเมื่อเปรียบเทียบกับstackoverflow.com/a/52279347/1834057เมื่อประสิทธิภาพเป็นสิ่งสำคัญ
Nicholas Hamilton

1
แน่นอนว่าคำตอบดั้งเดิมที่ดี แต่คำตอบของ Marcelo นั้นดีกว่าเนื่องจากเป็นคำที่ชัดเจนกว่าและอ่านได้ง่าย (และ Pythonic)
sitnarf

114

รัดกุมยิ่งขึ้น:

data = data[:75]

ถ้ามันน้อยกว่า 75 ตัวอักษรจะไม่มีการเปลี่ยนแปลง


9
สมมุติว่าเขาต้องการเติมจุดไข่ปลาถ้าสตริงถูกตัดทอน
FogleBird

4
คุณพูดถูก - ฉันไม่เคยสังเกตว่า ฉันไม่สามารถคิดถึงวิธีที่ดีกว่าในการทำเช่นนั้นมากกว่าคำตอบอื่น ๆ
นีล

82

หากคุณใช้ Python 3.4+ คุณสามารถใช้textwrap.shortenจากไลบรารี่มาตรฐาน:

ยุบและตัดทอนข้อความที่กำหนดให้พอดีกับความกว้างที่กำหนด

ก่อนอื่นช่องว่างในข้อความจะถูกยุบ (ช่องว่างทั้งหมดจะถูกแทนที่ด้วยช่องว่างเดียว) ถ้าผลลัพธ์นั้นพอดีกับความกว้างมันจะถูกส่งคืน มิฉะนั้นมีคำที่พอจะถูกดร็อปจากท้ายเพื่อให้คำที่เหลือรวมกับตัวยึดพอดีภายในความกว้าง

>>> textwrap.shorten("Hello  world!", width=12)
'Hello world!'
>>> textwrap.shorten("Hello  world!", width=11)
'Hello [...]'
>>> textwrap.shorten("Hello world", width=10, placeholder="...")
'Hello...'

8
ดูเหมือนว่าจะอึกางเกงในสายยาวจริง ๆ (ไม่มีช่องว่าง) และส่งออกเฉพาะจุดไข่ปลา
elBradford

5
@elBradford (และคนอื่น ๆ ที่สนใจ): นั่นเป็นเพราะshorten()ตัดทอนคำไม่ใช่ตัวอักษรเดี่ยว ฉันค้นหา แต่ดูเหมือนจะไม่มีวิธีกำหนดค่าshorten()หรือTextWrapperอินสแตนซ์สำหรับคลิปตัวอักษรเดียวไม่ใช่คำ
Acsor

และมันก็มีผลข้างเคียงที่น่ารำคาญจากการลบตัวแบ่งบรรทัด
havlock

นี่ไม่ได้แก้คำถามของ OP มันตัดทอนคำและลบช่องว่างออก
Florian Wendelborn

32

สำหรับโซลูชัน Django (ซึ่งไม่ได้กล่าวถึงในคำถาม):

from django.utils.text import Truncator
value = Truncator(value).chars(75)

ดูที่ซอร์สโค้ดของ Truncator เพื่อชื่นชมปัญหา: https://github.com/django/django/blob/master/django/utils/text.py#L66

การตัดปลายด้วย Django: Django การตัด HTML


คู่ตรรกะในระดับต่ำถึง django นี้ไม่จำเป็น จะไม่แนะนำเลย
มนุษย์ถ้ำ


9

ด้วย regex:

re.sub(r'^(.{75}).*$', '\g<1>...', data)

สตริงยาวจะถูกตัดทอน:

>>> data="11111111112222222222333333333344444444445555555555666666666677777777778888888888"
>>> re.sub(r'^(.{75}).*$', '\g<1>...', data)
'111111111122222222223333333333444444444455555555556666666666777777777788888...'

สตริงที่สั้นกว่าไม่เคยถูกตัดทอน:

>>> data="11111111112222222222333333"
>>> re.sub(r'^(.{75}).*$', '\g<1>...', data)
'11111111112222222222333333'

ด้วยวิธีนี้คุณสามารถ "ตัด" ส่วนตรงกลางของสตริงได้ซึ่งดีกว่าในบางกรณี:

re.sub(r'^(.{5}).*(.{5})$', '\g<1>...\g<2>', data)

>>> data="11111111112222222222333333333344444444445555555555666666666677777777778888888888"
>>> re.sub(r'^(.{5}).*(.{5})$', '\g<1>...\g<2>', data)
'11111...88888'

ดีที่ไม่ได้ทำงานเมื่อคุณมีช่องว่างในสายของคุณ
Holms

ทำไมคุณจะใช้ regex สำหรับกรณีง่าย ๆ
Bora M. Alper

5

วิธีนี้จะไม่ใช้วิธีการใด ๆ ถ้า:

data[:75] + bool(data[75:]) * '..'


4
ฉันเขียนเพื่อแสดงว่าเป็นไปได้เท่านั้น มันขัดกับปรัชญาการอ่านของงูใหญ่ มันไม่มีความได้เปรียบด้านประสิทธิภาพใด ๆ เมื่อเปรียบเทียบกับวิธีการแบบ "ถ้า" อื่น ๆ ฉันไม่เคยใช้และไม่แนะนำให้คุณใช้ด้วย
Sassan

4
limit = 75
info = data[:limit] + '..' * (len(data) > limit)

1
นี่คือทางออกที่หรูหราที่สุด นอกจากนี้ฉันจะแยกขีด จำกัด ตัวอักษร (ในกรณีนี้75) เป็นตัวแปรเพื่อหลีกเลี่ยงความไม่สอดคล้องกัน limit = 75; info = data[:limit] + '..' * (len(data) > limit)
ekauffmann

3

อีกวิธีหนึ่ง ด้วยTrueและFalseคุณจะได้รับข้อเสนอแนะเล็กน้อยเกี่ยวกับการทดสอบในตอนท้าย

data = {True: data[:75] + '..', False: data}[len(data) > 75]

2

เพียงแค่นี้:

n = 8
s = '123'
print  s[:n-3] + (s[n-3:], '...')[len(s) > n]
s = '12345678'
print  s[:n-3] + (s[n-3:], '...')[len(s) > n]
s = '123456789'     
print  s[:n-3] + (s[n-3:], '...')[len(s) > n]
s = '123456789012345'
print  s[:n-3] + (s[n-3:], '...')[len(s) > n]

123
12345678
12345...
12345...

คำตอบก่อนหน้านี้ทั้งหมดละเลยที่จะพิจารณาสิ่งที่ OP ต้องการจริงๆ - สตริงเอาต์พุตมีความยาวไม่เกิน 75 อักขระ ความรุ่งโรจน์สำหรับการทำความเข้าใจกับ "ไม่ทำสิ่งที่ฉันพูดทำในสิ่งที่ฉันต้องการ" หลักการเขียนโปรแกรม เพื่อความสมบูรณ์คุณสามารถแก้ไขตัวพิมพ์เล็กของ n <3 ได้โดยต่อท้าย: ถ้า n> อีก 2 s [: n]
เดฟ

1
       >>> info = lambda data: len(data)>10 and data[:10]+'...' or data
       >>> info('sdfsdfsdfsdfsdfsdfsdfsdfsdfsdfsdf')
           'sdfsdfsdfs...'
       >>> info('sdfsdf')
           'sdfsdf'
       >>> 

1
กรุณาอธิบายคำตอบของคุณ?
Gwenc37

ตัวอย่างที่คล้ายกันของฟังก์ชั่นนี้ def info2 (data): ถ้า len (data)> 10: data return [: 10] + '... ' else: ส่งคืนข้อมูลคำสั่ง lambda ของการออกแบบนิรนามในรูปแบบการทำงาน ex = lambda x: x + 1 def (x): return x + 1
Spouk

1

คุณไม่สามารถ "ตัดทอน" สตริง Python จริง ๆ ได้เหมือนกับที่คุณทำสตริง C ที่จัดสรรแบบไดนามิก สายอักขระใน Python ไม่เปลี่ยนรูป สิ่งที่คุณสามารถทำได้คือฝานสตริงตามที่อธิบายไว้ในคำตอบอื่น ๆ ให้ผลสตริงใหม่ที่มีเฉพาะอักขระที่กำหนดโดย slice offsets และขั้นตอน ในบางกรณี (ไม่ใช่เชิงปฏิบัติ) สิ่งนี้อาจน่ารำคาญเล็กน้อยเช่นเมื่อคุณเลือก Python เป็นภาษาสัมภาษณ์ของคุณและผู้สัมภาษณ์ขอให้คุณลบอักขระที่ซ้ำกันออกจากสตริงในสถานที่ Doh


1
info = data[:min(len(data), 75)

คำตอบของรหัสเท่านั้นโดยทั่วไปถือว่ามีคุณภาพต่ำ คุณช่วยเพิ่มคำอธิบายลงในคำตอบของคุณได้ไหม
Lemon Kazi

0

ไม่จำเป็นต้องมีนิพจน์ทั่วไป แต่คุณต้องการใช้การจัดรูปแบบสตริงแทนที่การต่อสตริงในคำตอบที่ยอมรับ

นี่อาจเป็นวิธี Pythonic ที่เป็นที่ยอมรับมากที่สุดในการตัดสตริงdataที่ 75 อักขระ

>>> data = "saddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddsaddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddsadddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
>>> info = "{}..".format(data[:75]) if len(data) > 75 else data
>>> info
'111111111122222222223333333333444444444455555555556666666666777777777788888...'

ฉันพบว่ามันตลกว่าsaddddddd...สตริงของคุณจะเปลี่ยนเป็นอย่างไร111111...:) ฉันรู้ว่ามันเป็นตัวพิมพ์คัดลอกแปะและฉันก็เห็นด้วยกับคุณเกี่ยวกับการแสดงออกปกติ
akarilimano

0

นี่คือฟังก์ชั่นที่ฉันสร้างขึ้นเพื่อเป็นส่วนหนึ่งของคลาส String ใหม่ ... อนุญาตให้เพิ่มคำต่อท้าย (ถ้าสตริงมีขนาดหลังจากตัดแต่งและเพิ่มให้ยาวพอ - แม้ว่าคุณไม่จำเป็นต้องบังคับขนาดที่แน่นอน)

ฉันอยู่ในกระบวนการของการเปลี่ยนแปลงบางสิ่งรอบตัวดังนั้นจึงมีต้นทุนตรรกะที่ไร้ประโยชน์ (ถ้า _truncate ... เป็นต้น) ซึ่งไม่จำเป็นอีกต่อไปและมีผลตอบแทนที่ด้านบน ...

แต่ก็ยังคงเป็นฟังก์ชั่นที่ดีสำหรับการตัดทอนข้อมูล ...

##
## Truncate characters of a string after _len'nth char, if necessary... If _len is less than 0, don't truncate anything... Note: If you attach a suffix, and you enable absolute max length then the suffix length is subtracted from max length... Note: If the suffix length is longer than the output then no suffix is used...
##
## Usage: Where _text = 'Testing', _width = 4
##      _data = String.Truncate( _text, _width )                        == Test
##      _data = String.Truncate( _text, _width, '..', True )            == Te..
##
## Equivalent Alternates: Where _text = 'Testing', _width = 4
##      _data = String.SubStr( _text, 0, _width )                       == Test
##      _data = _text[  : _width ]                                      == Test
##      _data = ( _text )[  : _width ]                                  == Test
##
def Truncate( _text, _max_len = -1, _suffix = False, _absolute_max_len = True ):
    ## Length of the string we are considering for truncation
    _len            = len( _text )

    ## Whether or not we have to truncate
    _truncate       = ( False, True )[ _len > _max_len ]

    ## Note: If we don't need to truncate, there's no point in proceeding...
    if ( not _truncate ):
        return _text

    ## The suffix in string form
    _suffix_str     = ( '',  str( _suffix ) )[ _truncate and _suffix != False ]

    ## The suffix length
    _len_suffix     = len( _suffix_str )

    ## Whether or not we add the suffix
    _add_suffix     = ( False, True )[ _truncate and _suffix != False and _max_len > _len_suffix ]

    ## Suffix Offset
    _suffix_offset = _max_len - _len_suffix
    _suffix_offset  = ( _max_len, _suffix_offset )[ _add_suffix and _absolute_max_len != False and _suffix_offset > 0 ]

    ## The truncate point.... If not necessary, then length of string.. If necessary then the max length with or without subtracting the suffix length... Note: It may be easier ( less logic cost ) to simply add the suffix to the calculated point, then truncate - if point is negative then the suffix will be destroyed anyway.
    ## If we don't need to truncate, then the length is the length of the string.. If we do need to truncate, then the length depends on whether we add the suffix and offset the length of the suffix or not...
    _len_truncate   = ( _len, _max_len )[ _truncate ]
    _len_truncate   = ( _len_truncate, _max_len )[ _len_truncate <= _max_len ]

    ## If we add the suffix, add it... Suffix won't be added if the suffix is the same length as the text being output...
    if ( _add_suffix ):
        _text = _text[ 0 : _suffix_offset ] + _suffix_str + _text[ _suffix_offset: ]

    ## Return the text after truncating...
    return _text[ : _len_truncate ]

1
อะไรคือขีดล่างทั้งหมดในทุก ๆ อาร์กิวเมนต์และตัวแปร?
Nicholas Hamilton

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.