เหตุใดสตริงว่างจึงถูกส่งคืนในผลลัพธ์ Split ()


121

จุด'/segment/segment/'.split('/')กลับรถ['', 'segment', 'segment', '']คืออะไร?

สังเกตองค์ประกอบที่ว่างเปล่า หากคุณกำลังแยกตัวคั่นที่อยู่ในตำแหน่งที่หนึ่งและอยู่ท้ายสุดของสตริงค่าพิเศษใดที่ให้ค่าสตริงว่างที่ส่งคืนจากปลายแต่ละด้าน


1
ฉันมีคำถามเดียวกันและค้นหามานานแล้ว ตอนนี้ฉันเข้าใจแล้วว่าผลลัพธ์ที่ว่างเปล่านั้นสำคัญมาก ขอบคุณสำหรับคำถามของคุณ
emeraldhieu

3
วิธีแก้ปัญหาคือใช้strip()เพื่อตัดอักขระแยกที่นำหน้าและต่อท้ายออกจากสตริงก่อนที่จะแยก:'/segment/segment/'.strip('/').split('/')
pkamb

คำตอบ:


181

str.splitเติมเต็มstr.joinดังนั้น

"/".join(['', 'segment', 'segment', ''])

ทำให้คุณกลับมาใช้สตริงเดิม

หากไม่มีสตริงว่างตัวแรกและตัวสุดท้าย'/'จะหายไปหลังjoin()


11
เรียบง่าย แต่ตอบคำถามได้ครบถ้วน
orokusaki

ฉันตกใจมากที่พบว่าเครื่องหมายคำพูดแบบหยิกใช้ได้จริงใน Python ... แต่ แต่ ... อย่างไร เอกสารดูเหมือนจะไม่พูดถึงเรื่องนี้
Tim Pietzcker

@ ทิมฉันไม่รู้ว่าคำพูดเหล่านั้นไปอยู่ที่นั่นได้อย่างไร: /
John La Rooy

7
คุณไม่ได้ใช้ Microsoft Word เป็น Python IDE แล้วใช่ไหม :)
Tim Pietzcker

1
@ aaa90210 ใครบอกว่าคำตอบง่ายๆไม่ดีที่สุด? เป็นความคิดเห็น (ประการแรกเมื่อ 5 ปีที่แล้ว) เกี่ยวกับคำตอบที่ง่าย แต่ตอบคำถามได้ครบถ้วน การใช้ "but" ในประโยคไม่ได้หมายความถึงสิ่งที่ไม่ดี คำตอบที่ไม่ง่ายอาจเป็นคำตอบที่สมบูรณ์กว่า (เช่นรวมถึงการตัดสินใจที่เกี่ยวข้องหรือ PEP ที่เกี่ยวข้องกับฟังก์ชันที่ระบุไว้)
orokusaki

89

โดยทั่วไปในการลบสตริงว่างที่ส่งคืนsplit()ผลลัพธ์คุณอาจต้องการดูที่filterฟังก์ชัน

ตัวอย่าง:

filter(None, '/segment/segment/'.split('/'))

ผลตอบแทน

['segment', 'segment']

3
ขอบคุณสำหรับสิ่งนี้ฉันไม่รู้ว่าทำไมคำตอบนี้ถึงได้รับความสนใจมากนักทุกอย่างเป็นพื้นฐาน
ลิ่ม

6
list(...)ถ้ามันต้องการที่จะเก็บผลในรายการแทนการได้รับวัตถุกรองเป็นผลผลิตวางโครงสร้างกรองทั้งใน
Tim Visée

29

มีสองประเด็นหลักที่ควรพิจารณาที่นี่:

  • การคาดหวังว่าผลลัพธ์'/segment/segment/'.split('/')จะเท่ากับ['segment', 'segment']นั้นสมเหตุสมผล แต่ก็ทำให้สูญเสียข้อมูลไป ถ้าsplit()ได้ผลในแบบที่คุณต้องการถ้าฉันบอกคุณa.split('/') == ['segment', 'segment']คุณก็ไม่สามารถบอกฉันได้ว่าaคืออะไร
  • ผลของ'a//b'.split()be คืออะไร? ['a', 'b']?, หรือ['a', '', 'b']? เช่นควรsplit()ผสานตัวคั่นที่อยู่ติดกัน? หากควรจะเป็นเรื่องยากมากที่จะแยกวิเคราะห์ข้อมูลที่คั่นด้วยอักขระและบางฟิลด์อาจว่างเปล่า ผมค่อนข้างแน่ใจว่ามีหลายคนที่ทำต้องการค่าว่างในผลการกรณีข้างต้น!

ในท้ายที่สุดมันก็เดือดเป็นสองอย่าง:

ความสอดคล้อง: ถ้าฉันมีnตัวคั่นaฉันจะได้รับn+1ค่ากลับมาหลังจากsplit().

มันควรจะเป็นไปได้ที่จะทำสิ่งที่ซับซ้อนและทำสิ่งง่ายๆง่ายๆ: หากคุณต้องการละเว้นสตริงว่างอันเป็นผลมาจากสิ่งเหล่าsplit()นี้คุณสามารถทำได้เสมอ:

def mysplit(s, delim=None):
    return [x for x in s.split(delim) if x]

แต่ถ้าใครไม่ต้องการละเว้นค่าว่างก็ควรจะทำได้

ภาษาต้องเลือกหนึ่งคำจำกัดความของsplit()- มีกรณีการใช้งานที่แตกต่างกันมากเกินไปเพื่อตอบสนองความต้องการของทุกคนเป็นค่าเริ่มต้น ฉันคิดว่าตัวเลือกของ Python นั้นดีและมีเหตุผลมากที่สุด (นอกจากเหตุผลหนึ่งที่ฉันไม่ชอบ C strtok()ก็เพราะมันรวมตัวคั่นที่อยู่ติดกันทำให้ยากมากที่จะแยกวิเคราะห์ / โทเค็นอย่างจริงจังด้วย)

มีข้อยกเว้นอย่างหนึ่ง: การa.split()ไม่มีอาร์กิวเมนต์จะบีบพื้นที่สีขาวติดต่อกัน แต่เราสามารถโต้แย้งได้ว่านี่เป็นสิ่งที่ถูกต้องที่จะทำในกรณีนั้น a.split(' ')หากคุณไม่ต้องการพฤติกรรมที่คุณสามารถเสมอ


สำหรับผู้ที่สงสัยว่าจะเร็วกว่าที่จะทำ nuke ช่องว่างซ้ำจากนั้นแยกหรือแยกและใช้เฉพาะสตริงที่ไม่ว่างเปล่านี่คือสิ่งที่ฉันได้รับ: python3 -m timeit "import re ; re.sub(' +', ' foo bar baz ', '').split(' ')"-> 875 nsec ต่อลูป python3 -m timeit "[token for token in ' foo bar baz '.split(' ') if token]"-> 616 nsec ต่อวง
s3cur3

8

การx.split(y)ส่งคืนรายการเสมอ1 + x.count(y)ถือเป็นความสม่ำเสมอที่มีค่า - เนื่องจาก @ gnibbler ได้ชี้ให้เห็นแล้วว่ามีการสร้างsplitและการjoinผกผันที่แน่นอนของกันและกัน (ตามที่ควรจะเป็น) นอกจากนี้ยังจับคู่ความหมายของระเบียนที่รวมตัวคั่นทุกชนิดได้อย่างแม่นยำ ( เช่นcsvบรรทัดไฟล์ [[net of quoting issue]], บรรทัดจาก/etc/groupใน Unix และอื่น ๆ ) จะช่วยให้ (ตามที่ @ Roman กล่าวถึง) ตรวจสอบได้ง่าย (เช่น) พา ธ สัมบูรณ์เทียบกับพา ธ สัมพัทธ์ (ในพา ธ ไฟล์และ URL) และอื่น ๆ

อีกวิธีหนึ่งในการตรวจสอบก็คือคุณไม่ควรโยนข้อมูลออกไปนอกหน้าต่างโดยไม่หวังผลประโยชน์ สิ่งที่จะได้รับจากการx.split(y)เทียบเท่าx.strip(y).split(y)? ไม่มีอะไรแน่นอน - มันเป็นเรื่องง่ายที่จะใช้รูปแบบที่สองเมื่อที่คุณหมายถึงอะไร แต่ถ้ารูปแบบครั้งแรกก็ถือว่าพลจะหมายถึงคนที่สองคุณจะมีจำนวนมากของงานที่ต้องทำเมื่อคุณไม่ต้องการเป็นคนแรก ( ซึ่งห่างไกลจากความหายากตามที่ย่อหน้าก่อนหน้านี้ชี้ให้เห็น)

แต่จริงๆแล้วการคิดในแง่ของความสม่ำเสมอทางคณิตศาสตร์เป็นวิธีที่ง่ายที่สุดและทั่วไปที่สุดที่คุณสามารถสอนตัวเองให้ออกแบบ API ที่ผ่านได้ ในการใช้ตัวอย่างที่แตกต่างกันสิ่งสำคัญอย่างยิ่งคือสำหรับสิ่งที่ถูกต้องxและy x == x[:y] + x[y:]- ซึ่งจะระบุทันทีว่าเหตุใดจึงควรยกเว้นการแบ่งส่วนแบบสุดโต่ง ยิ่งการยืนยันค่าคงที่ที่ง่ายกว่าที่คุณสามารถกำหนดได้ก็คือความหมายที่เกิดขึ้นคือสิ่งที่คุณต้องการในชีวิตจริงซึ่งเป็นส่วนหนึ่งของความจริงที่ลึกลับที่คณิตศาสตร์มีประโยชน์มากในการจัดการกับจักรวาล

ลองกำหนดค่าคงที่สำหรับsplitภาษาถิ่นซึ่งตัวคั่นที่นำหน้าและต่อท้ายเป็นตัวกำหนดพิเศษ ... ตัวอย่างตัวนับ: วิธีการสตริงเช่นisspaceไม่ง่ายที่สุด - x.isspace()เทียบเท่ากับx and all(c in string.whitespace for c in x)- การนำทางที่ไร้สาระx andเป็นสาเหตุที่คุณมักพบว่าตัวเองกำลังเขียนnot x or x.isspace()เพื่อกลับไปสู่ความเรียบง่ายซึ่งควรได้รับการออกแบบมาในis...วิธีการสตริง (โดยที่สตริงว่าง "คือ" อะไรก็ได้ที่คุณต้องการ - ตรงกันข้ามกับความรู้สึกของคนในท้องถนนอาจจะ [[เซตว่างเช่นศูนย์ & c ทำให้คนส่วนใหญ่สับสนอยู่เสมอ ;-)]] แต่ก็สอดคล้องกับสามัญสำนึกทางคณิตศาสตร์ที่ได้รับการขัดเกลาอย่างดี! -)


5

ฉันไม่แน่ใจว่าคุณกำลังมองหาคำตอบแบบไหน? คุณได้สามรายการที่ตรงกันเนื่องจากคุณมีตัวคั่นสามตัว หากคุณไม่ต้องการสิ่งที่ว่างเปล่าเพียงใช้:

'/segment/segment/'.strip('/').split('/')

4
-1 เพราะคุณได้รับการแข่งขันสี่ครั้งไม่ใช่สามครั้งและนี่ก็ไม่ได้ตอบคำถามจริงๆ
โรมัน

1
+1 เพื่อต่อต้านการปฏิเสธ .. เขาไม่ได้บอกว่าคุณจะได้รับสามผลลัพธ์กลับมา เขาพูดว่า "จับคู่สามตัว" สำหรับ "ตัวคั่นสามตัว" ซึ่งฟังดูมีเหตุผลสำหรับฉัน อย่างไรก็ตามคุณไม่ได้รับ "สี่นัด" จากสิ่งใดเลย คุณจะได้รับ "สี่องค์ประกอบ" กลับมาในผลลัพธ์ของคุณ นอกจากนี้ยังไม่ตอบโจทย์โดยตรงว่า "ทำไม" แต่มันมีวิธีง่ายๆในการได้รับสิ่งที่เขาต้องการจริงๆ ... ซึ่งฉันไม่คิดว่าสมควรได้รับการโหวตลดลง หากคุณกำลังจะไนท์พิคใครสักคน (ด้วยการโหวตลดก็ไม่น้อย) โปรดระวังให้มากขึ้น! ไชโย! 8 ^)
kodybrown

@wasatchwizard ขอบคุณสำหรับคำชี้แจง ขอขอบคุณสำหรับการแก้ไขและคำแนะนำ ขออภัยตอนนี้การโหวตของฉันถูกล็อคและไม่สามารถเปลี่ยนแปลงได้
Roman

ฉันชอบวิธีแก้ปัญหาของคุณ - แล้วแยกออกเพื่อลบผลลัพธ์ที่ว่างเปล่า
Nam G VU

5

มันทำให้คุณรู้ว่ามีตัวคั่นอยู่ตรงนั้น ดังนั้นการเห็นผลลัพธ์ 4 รายการทำให้คุณรู้ว่าคุณมีตัวคั่น 3 ตัว สิ่งนี้ทำให้คุณมีอำนาจในการทำอะไรก็ได้ที่คุณต้องการด้วยข้อมูลนี้แทนที่จะปล่อยให้ Python ปล่อยองค์ประกอบที่ว่างเปล่าจากนั้นให้คุณตรวจสอบตัวคั่นเริ่มต้นหรือสิ้นสุดด้วยตนเองหากคุณต้องการทราบ

ตัวอย่างง่ายๆ: สมมติว่าคุณต้องการตรวจสอบชื่อไฟล์แบบสัมบูรณ์และแบบสัมพัทธ์ ด้วยวิธีนี้คุณสามารถทำได้ทั้งหมดด้วยการแยกโดยไม่ต้องตรวจสอบว่าอักขระตัวแรกของชื่อไฟล์ของคุณคืออะไร


2

ลองพิจารณาตัวอย่างเล็กน้อยนี้:

>>> '/'.split('/')
['', '']

splitต้องระบุสิ่งที่อยู่ก่อนและหลังตัวคั่น'/'แต่ไม่มีอักขระอื่น ดังนั้นจึงมีเพื่อให้คุณสตริงที่ว่างเปล่าซึ่งในทางเทคนิคนำหน้าและตามมาเพราะ'/''' + '/' + '' == '/'

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