แยกด้วยเครื่องหมายจุลภาคและตัดช่องว่างใน Python


346

ฉันมีรหัสหลามที่แยกบนเครื่องหมายจุลภาค แต่ไม่ได้ตัดช่องว่าง:

>>> string = "blah, lots  ,  of ,  spaces, here "
>>> mylist = string.split(',')
>>> print mylist
['blah', ' lots  ', '  of ', '  spaces', ' here ']

ฉันต้องการที่จะลบช่องว่างออกเช่นนี้:

['blah', 'lots', 'of', 'spaces', 'here']

ฉันรู้ว่าฉันสามารถวนรอบรายการและสตริป () แต่ละรายการ แต่เนื่องจากนี่คือ Python ฉันเดาว่ามีวิธีที่เร็วกว่าง่ายกว่าและสง่างามกว่าในการทำมัน

คำตอบ:


595

ใช้ list comprehension - ง่ายขึ้นและอ่านง่ายเหมือนforวนซ้ำ

my_string = "blah, lots  ,  of ,  spaces, here "
result = [x.strip() for x in my_string.split(',')]
# result is ["blah", "lots", "of", "spaces", "here"]

ดู: Python docs จาก List Comprehension
คำอธิบายที่ดี 2 วินาทีของ list comprehension


1
ดีมาก! ฉันเพิ่มหนึ่งรายการดังนี้เพื่อกำจัดรายการว่างเปล่า > text = [x.strip () สำหรับ x in text.split ('.') ถ้า x! = '']
RandallShanePhD

@Sean: รหัสหลามไม่ถูกต้อง / ไม่สมบูรณ์ "เจตนาดั้งเดิมของการโพสต์" ของคุณหรือไม่ ตาม wankers ทบทวนมันเป็น: stackoverflow.com/review/suggested-edits/21504253 คุณช่วยบอกพวกเขาเป็นอย่างอื่นได้ไหมโดยการแก้ไขหากพวกเขาผิด (อีกครั้ง)?
อาหาร

เดิมได้รับการคัดลอกวางจาก REPL (ถ้าผมจำไม่ผิด) และเป้าหมายได้รับความเข้าใจในแนวคิดพื้นฐาน (โดยใช้ความเข้าใจในรายชื่อที่จะทำการดำเนินการ) - แต่คุณขวามันทำให้รู้สึกมากขึ้นถ้าคุณดูรายการเข้าใจว่า สร้างรายการใหม่
Sean Vieira

24

แยกโดยใช้นิพจน์ทั่วไป หมายเหตุฉันสร้างเคสให้กว้างขึ้นด้วยช่องว่างนำหน้า รายการความเข้าใจคือการลบสตริง null ที่ด้านหน้าและด้านหลัง

>>> import re
>>> string = "  blah, lots  ,  of ,  spaces, here "
>>> pattern = re.compile("^\s+|\s*,\s*|\s+$")
>>> print([x for x in pattern.split(string) if x])
['blah', 'lots', 'of', 'spaces', 'here']

สิ่งนี้ใช้ได้แม้ว่า^\s+จะไม่ตรงกัน:

>>> string = "foo,   bar  "
>>> print([x for x in pattern.split(string) if x])
['foo', 'bar']
>>>

นี่คือเหตุผลที่คุณต้องการ ^ \ s +:

>>> pattern = re.compile("\s*,\s*|\s+$")
>>> print([x for x in pattern.split(string) if x])
['  blah', 'lots', 'of', 'spaces', 'here']

ดูช่องว่างชั้นนำใน blah?

การชี้แจง: ด้านบนใช้ตัวแปล Python 3 แต่ผลลัพธ์จะเหมือนกันใน Python 2


8
ฉันเชื่อว่า[x.strip() for x in my_string.split(',')]เป็น pythonic เพิ่มเติมสำหรับคำถามที่ถาม อาจมีหลายกรณีที่จำเป็นต้องแก้ปัญหาของฉัน ฉันจะอัปเดตเนื้อหานี้หากฉันพบเจอ
tbc0

ทำไมถึง^\s+จำเป็น? ฉันทดสอบโค้ดของคุณโดยที่ไม่มีรหัสและมันใช้งานไม่ได้ แต่ไม่รู้ว่าทำไม
laike9m

หากฉันใช้ผลเป็นre.compile("^\s*,\s*$") [' blah, lots , of , spaces, here ']
laike9m

@ laike9m ฉันได้อัปเดตคำตอบเพื่อแสดงความแตกต่าง ^\s+ยี่ห้อ อย่างที่คุณเห็นด้วยตัวคุณเอง^\s*,\s*$อย่าส่งผลลัพธ์ที่ต้องการเช่นกัน ดังนั้นหากคุณต้องการแยกกับ regexp ^\s+|\s*,\s*|\s+$ใช้
tbc0

การจับคู่ครั้งแรกว่างเปล่าหากรูปแบบการนำหน้า (^ \ s +) ไม่ตรงกันดังนั้นคุณจะได้รับบางสิ่งเช่น ['', 'foo', 'bar'] สำหรับสตริง "foo, bar"
Steeve McCauley

21

ฉันมาเพื่อเพิ่ม:

map(str.strip, string.split(','))

แต่เห็นว่ามันได้รับการกล่าวถึงโดยเจสัน Orendorff ในความคิดเห็น

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

ดังนั้นการทดสอบที่รวดเร็ว (อาจมีข้อบกพร่อง) ในกล่องของฉันโดยใช้ทั้งสามวิธีในการวนซ้ำที่เปิดเผย:

[word.strip() for word in string.split(',')]
$ time ./list_comprehension.py 
real    0m22.876s

map(lambda s: s.strip(), string.split(','))
$ time ./map_with_lambda.py 
real    0m25.736s

map(str.strip, string.split(','))
$ time ./map_with_str.strip.py 
real    0m19.428s

ทำให้map(str.strip, string.split(','))ผู้ชนะแม้ว่าจะดูเหมือนว่าพวกเขาทั้งหมดอยู่ใน ballpark เดียวกัน

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

แก้ไข:

Python 2.6.5 บน Ubuntu 10.04


15

เพียงแค่ลบช่องว่างออกจากสตริงก่อนที่จะแยก

mylist = my_string.replace(' ','').split(',')

10
"you just, broke this"ชนิดของปัญหาถ้ารายการที่คั่นด้วยเครื่องหมายจุลภาคมีช่องว่างที่ฝังตัวเช่น
Robert Rossney

1
Geeze, a-1 สำหรับเรื่องนี้ พวกคุณแข็งแกร่งมาก มันแก้ปัญหาของเขาได้โดยการให้ข้อมูลตัวอย่างเป็นเพียงคำเดียวและไม่มีข้อกำหนดว่าข้อมูลจะเป็นวลี แต่ด้วยฉันคิดว่านั่นเป็นวิธีที่พวกคุณกลิ้งไปมาที่นี่
user489041

ขอขอบคุณผู้ใช้ เพื่อความเป็นธรรมแม้ว่าฉันจะขอแยกและแยก () และดึงเอาช่องว่างชั้นนำและต่อท้ายและไม่ได้สัมผัสอะไรในระหว่าง การเปลี่ยนแปลงเล็กน้อยและคำตอบของคุณจะทำงานได้อย่างสมบูรณ์แบบ: mylist = mystring.strip (). split (',') แม้ว่าฉันจะไม่รู้ว่าสิ่งนี้มีประสิทธิภาพเป็นพิเศษหรือไม่
Mr_Chimp

12

ฉันรู้ว่าคำตอบนี้ได้รับการตอบแล้ว แต่ถ้าคุณจบการทำสิ่งนี้มากการแสดงออกปกติอาจเป็นวิธีที่ดีกว่าในการไป:

>>> import re
>>> re.sub(r'\s', '', string).split(',')
['blah', 'lots', 'of', 'spaces', 'here']

\sตรงกับตัวอักษรช่องว่างใด ๆ ''และเราก็แทนที่ด้วยสตริงที่ว่างเปล่า คุณสามารถหาข้อมูลเพิ่มเติมได้ที่นี่: http://docs.python.org/library/re.html#re.sub


3
ตัวอย่างของคุณจะไม่ทำงานกับสตริงที่มีช่องว่าง "สำหรับตัวอย่างนี้หนึ่ง" จะกลายเป็น "สำหรับ", "ตัวอย่างนี้", "หนึ่ง" ไม่ได้บอกว่ามันเป็นทางออกที่ไม่ดี (มันทำงานได้อย่างสมบูรณ์ในตัวอย่างของฉัน) มันขึ้นอยู่กับงานในมือ!
Mr_Chimp

ใช่มันถูกต้องมาก! คุณอาจปรับ regexp เพื่อให้สามารถจัดการกับสตริงด้วยช่องว่าง แต่ถ้ารายการความเข้าใจในการทำงานฉันจะบอกว่าติดกับมัน;)
แบรดเมอรี


2

re (เหมือนในนิพจน์ทั่วไป) อนุญาตให้แยกหลายตัวพร้อมกัน:

$ string = "blah, lots  ,  of ,  spaces, here "
$ re.split(', ',string)
['blah', 'lots  ', ' of ', ' spaces', 'here ']

สิ่งนี้ใช้งานไม่ได้กับสตริงตัวอย่างของคุณ แต่ใช้ได้ดีสำหรับรายการที่คั่นด้วยเครื่องหมายจุลภาค สำหรับสตริงตัวอย่างของคุณคุณสามารถรวมกำลัง re.split เพื่อแยกในรูปแบบ regexเพื่อรับเอฟเฟกต์ "แบบแยกบนนี้หรือแบบนั้น"

$ re.split('[, ]',string)
['blah',
 '',
 'lots',
 '',
 '',
 '',
 '',
 'of',
 '',
 '',
 '',
 'spaces',
 '',
 'here',
 '']

น่าเสียดายที่น่าเกลียด แต่filterจะทำเคล็ดลับ:

$ filter(None, re.split('[, ]',string))
['blah', 'lots', 'of', 'spaces', 'here']

Voila!


2
ทำไมไม่เพียงre.split(' *, *', string)?
พอลทอมบลิน

4
@ พอลทอมบลินความคิดที่ดี ท่านสามารถทำสิ่งนี้ได้เช่นกันre.split('[, ]*',string)สำหรับเอฟเฟกต์เดียวกัน
Dannid

Dannid ฉันรู้หลังจากเขียนว่ามันไม่ได้ตัดช่องว่างที่จุดเริ่มต้นและจุดจบเหมือนคำตอบของ @ tbc0
พอล

@PaulTomblinheh และการโต้แย้งของฉัน[, ]*ปล่อยสตริงว่างไว้ท้ายรายการ ฉันคิดว่าตัวกรองยังคงเป็นสิ่งที่ดีที่จะเข้าไปข้างในหรือยึดติดกับรายการความเข้าใจเช่นเดียวกับคำตอบอันดับต้น ๆ
Dannid

1

map(lambda s: s.strip(), mylist)จะดีกว่าการวนซ้ำเล็กน้อยอย่างชัดเจน หรือสำหรับสิ่งทั้งหมดในครั้งเดียว:map(lambda s:s.strip(), string.split(','))


10
เคล็ดลับ: เมื่อใดก็ตามที่คุณพบว่าตัวเองกำลังใช้mapงานโดยเฉพาะอย่างยิ่งหากคุณกำลังใช้งานอยู่lambdaให้ตรวจสอบอีกครั้งเพื่อดูว่าคุณควรใช้ความเข้าใจในรายการหรือไม่
Glenn Maynard

11
map(str.strip, s.split(','))คุณสามารถหลีกเลี่ยงแลมบ์ดาด้วย
Jason Orendorff


1
import re
mylist = [x for x in re.compile('\s*[,|\s+]\s*').split(string)]

เพียงใช้เครื่องหมายจุลภาคหรือช่องว่างสีขาวอย่างน้อยหนึ่งช่องที่มี / ไม่มีช่องว่างก่อนหน้า / หลัง

โปรดลอง!


0

map(lambda s: s.strip(), mylist)จะดีกว่าการวนซ้ำเล็กน้อยอย่างชัดเจน
หรือสำหรับสิ่งทั้งหมดในครั้งเดียว:

map(lambda s:s.strip(), string.split(','))

นั่นคือทุกสิ่งที่คุณต้องการ

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