การแยกสตริงที่คั่นด้วยอัฒภาคไปยังพจนานุกรมใน Python


86

ฉันมีสตริงที่มีลักษณะดังนี้:

"Name1=Value1;Name2=Value2;Name3=Value3"

มีคลาส / ฟังก์ชันในตัวใน Python หรือไม่ที่จะใช้สตริงนั้นและสร้างพจนานุกรมเหมือนกับที่ฉันทำสิ่งนี้:

dict = {
    "Name1": "Value1",
    "Name2": "Value2",
    "Name3": "Value3"
}

ฉันได้ตรวจสอบโมดูลต่างๆที่มี แต่ไม่พบสิ่งที่ตรงกับ


ขอบคุณฉันรู้วิธีสร้างโค้ดที่เกี่ยวข้องด้วยตัวเอง แต่เนื่องจากการแก้ปัญหาเล็ก ๆ น้อย ๆ เช่นนี้มักจะเป็นช่องของฉันที่รอให้เกิดขึ้น (เช่นมีคนเขียน: Name1 = 'Value1 = 2';) เป็นต้นดังนั้นฉันมักจะชอบ pre- ทดสอบฟังก์ชั่น

ฉันจะทำเอง


คำถามของคุณต้องการเพื่อรองรับการs = r'Name1='Value=2';Name2=Value2;Name3=Value3;Name4="Va\"lue;\n3"'ป้อนข้อมูลหรือไม่ (หมายเหตุ: อัฒภาคภายในสตริงที่ยกมา, อัญประกาศจะถูกใช้ Escape โดยใช้แบ็กสแลช, ใช้ Escape, \nใช้ทั้งอัญประกาศเดี่ยวและคู่)?
jfs

คำถามของฉันนี้มีอายุมากกว่า 6 ปีรหัสที่เกี่ยวข้องกับสิ่งนี้ถูกแทนที่มานานแล้ว :) และไม่มันไม่ต้องการการสนับสนุนสำหรับคำพูด ฉันแค่อยากมีฟังก์ชันที่สร้างไว้ล่วงหน้าแทนที่จะเขียนอะไรเอง อย่างไรก็ตามรหัสหายไปนาน
Lasse V.Karlsen

คำตอบ:


145

ไม่มีในตัว แต่คุณสามารถทำสิ่งนี้ให้สำเร็จได้ด้วยความเข้าใจของเครื่องกำเนิดไฟฟ้า:

s= "Name1=Value1;Name2=Value2;Name3=Value3"
dict(item.split("=") for item in s.split(";"))

[แก้ไข] จากการอัปเดตของคุณคุณระบุว่าคุณอาจต้องจัดการกับการเสนอราคา สิ่งนี้ทำให้สิ่งต่าง ๆ ซับซ้อนขึ้นอยู่กับรูปแบบที่แน่นอนที่คุณกำลังมองหาคืออะไร (ยอมรับตัวอักษรคำพูดอะไรอักขระหนี ฯลฯ ) คุณอาจต้องการดูโมดูล csv เพื่อดูว่าสามารถครอบคลุมรูปแบบของคุณได้หรือไม่ นี่คือตัวอย่าง: (โปรดทราบว่า API เป็นเพียงเล็กน้อยสำหรับตัวอย่างนี้เนื่องจาก CSV ได้รับการออกแบบมาให้วนซ้ำตามลำดับของระเบียนดังนั้นจึงเรียก. next () ที่ฉันทำเพื่อดูบรรทัดแรกเท่านั้นปรับเป็น เหมาะกับความต้องการของคุณ):

>>> s = "Name1='Value=2';Name2=Value2;Name3=Value3"

>>> dict(csv.reader([item], delimiter='=', quotechar="'").next() 
         for item in csv.reader([s], delimiter=';', quotechar="'").next())

{'Name2': 'Value2', 'Name3': 'Value3', 'Name1': 'Value1=2'}

อย่างไรก็ตามขึ้นอยู่กับโครงสร้างที่แน่นอนของรูปแบบของคุณคุณอาจต้องเขียนโปรแกรมแยกวิเคราะห์อย่างง่ายของคุณเอง


รหัสไม่รองรับการอ้างอิงลอง: s = "Name1='Value;2';Name2=Value2;Name3=Value3"(หมายเหตุ: อัฒภาคในName1ค่าที่ยกมา)
jfs

1
ฉันไม่รู้ว่าทำไมตัวอย่างที่สองAttributeError: '_csv.reader' object has no attribute 'next'ถึงทำให้ฉันรู้สึกแย่ import csvแน่นอนผมไม่ได้ทำ
ยองแจ

@ ไบรอันมีวิธีใดบ้างในการจัดเก็บค่าเป็นจำนวนเต็มแทนที่จะเป็นสตริง?
ChasedByDeath

จะย้อนกลับไปได้ยังไง @Brain
Jamil Noyda

6

สิ่งนี้ใกล้เคียงกับการทำสิ่งที่คุณต้องการ:

>>> import urlparse
>>> urlparse.parse_qs("Name1=Value1;Name2=Value2;Name3=Value3")
{'Name2': ['Value2'], 'Name3': ['Value3'], 'Name1': ['Value1']}

2
มันจะแตกถ้ามี&หรือ%ในอินพุต
jfs

@jfs แต่สตริงไม่มีอย่างใดอย่างหนึ่ง
Vishal Singh

@VishalSingh: ผู้เยี่ยมชม StackOverflow ส่วนใหญ่มาจาก google ดังนั้นคำตอบที่นี่ไม่ได้มีไว้สำหรับผู้โพสต์ต้นฉบับที่ถามคำถามเท่านั้น หากฉันมาที่นี่เพื่อค้นหาวิธีแยกวิเคราะห์ "สตริงที่คั่นด้วยอัฒภาคลงในพจนานุกรมใน Python" สตริงของฉันอาจมี&หรือ%- อย่างน้อยที่สุดก็ควรค่าแก่การกล่าวถึงว่าคำตอบใช้ไม่ได้กับสตริงดังกล่าว
jfs


1

สามารถทำได้ง่ายๆโดยการรวมสตริงและแสดงรายการเพื่อความเข้าใจ

",".join(["%s=%s" % x for x in d.items()])

>>d = {'a':1, 'b':2}
>>','.join(['%s=%s'%x for x in d.items()])
>>'a=1,b=2'

-2
easytiger $ cat test.out test.py | sed 's/^/    /'
p_easytiger_quoting:1.84563302994
{'Name2': 'Value2', 'Name3': 'Value3', 'Name1': 'Value1'}
p_brian:2.30507516861
{'Name2': 'Value2', 'Name3': "'Value3'", 'Name1': 'Value1'}
p_kyle:7.22536420822
{'Name2': ['Value2'], 'Name3': ["'Value3'"], 'Name1': ['Value1']}
import timeit
import urlparse

s = "Name1=Value1;Name2=Value2;Name3='Value3'"

def p_easytiger_quoting(s):
    d = {}
    s = s.replace("'", "")
    for x in s.split(';'):
        k, v = x.split('=')
        d[k] = v
    return d


def p_brian(s):
    return dict(item.split("=") for item in s.split(";"))

def p_kyle(s):
    return urlparse.parse_qs(s)



print "p_easytiger_quoting:" + str(timeit.timeit(lambda: p_easytiger_quoting(s)))
print p_easytiger_quoting(s)


print "p_brian:" + str(timeit.timeit(lambda: p_brian(s)))
print p_brian(s)

print "p_kyle:" + str(timeit.timeit(lambda: p_kyle(s)))
print p_kyle(s)

สิ่งนี้ไม่ตอบคำถามเพราะไม่ได้จัดการกับการอ้างอิง ลองs = "Name1='Value1=2';Name2=Value2" and csv` (เช่นเดียวกับคำตอบที่ยอมรับของ Brian) หรือparse_qs(เช่นเดียวกับ Kyle's) จะทำให้ถูกต้องในขณะที่ของคุณจะเพิ่ม a ValueError. OP กล่าวโดยเฉพาะว่า "โซลูชันขนาดเล็กเช่นนี้มักจะเป็นพื้นที่ของฉันที่รอให้เกิดขึ้น" ซึ่งเป็นเหตุผลว่าทำไมเขาถึงต้องการโซลูชันในตัวหรือที่ผ่านการทดสอบอย่างดีอื่น ๆ และเขาก็ยกตัวอย่างที่จะทำลายโค้ดของคุณ
ยกเลิก

ฉันไม่เห็นสิ่งนั้น ยัง. มันจะยังเร็วกว่าโซลูชันทั้งหมดของคุณในการเตรียมคำที่อยู่ในสตริงหลักก่อนที่จะเกิดการวนซ้ำและเรียกคืนฟังก์ชันการแทนที่หลายพันครั้ง ฉันจะอัปเดต
easytiger

ฉันไม่แน่ใจว่าคุณจะเตรียมการอย่างไร แต่แม้ว่าคุณจะทำเช่นนี้ดูเหมือนว่าสิ่งที่ OP กลัวในวิธีง่ายๆ แน่ใจหรือว่าไม่มีเหมืองอื่น ๆ อยู่ข้างหน้า? พิสูจน์ความพอใจของ OP ได้หรือไม่?
ยกเลิก

ตกลงตอนนี้ฉันเห็นการแก้ไขของคุณแล้ว ... อันดับแรกs.replaceไม่ได้ทำอะไรเลย มันจะส่งคืนสตริงใหม่ที่คุณเพิกเฉย ประการที่สองแม้ว่าคุณจะทำถูกต้อง ( s = s.replace…) แต่ก็ไม่สามารถแก้ไขปัญหาได้ แต่ก็เพิ่มอันใหม่ที่ด้านบน ลองใช้ทั้งตัวอย่างของฉันหรือ OP
ยกเลิก

Name='Value1=2';ข้อกำหนดอย่างชัดเจนรวมถึงการจัดการการป้อนข้อมูลตัวอย่างที่เขากล่าวถึงในคำถามของเขา และรหัสของคุณไม่สามารถจัดการได้ และฉันไม่แน่ใจว่าคุณจะล้างมันอย่างไรโดยไม่แยกวิเคราะห์ในบางวิธีซึ่งจะช้าพอ ๆ กับurlparseหรือcsvในตอนแรก
ยกเลิก

-2

ถ้าค่า 1 ของคุณ Value2 มีตัวยึดตำแหน่งเพียงสำหรับค่าที่แท้จริงนอกจากนี้คุณยังสามารถใช้ฟังก์ชั่นในการทำงานร่วมกับdict()eval()

>>> s= "Name1=1;Name2=2;Name3='string'"
>>> print eval('dict('+s.replace(';',',')+')')
{'Name2: 2, 'Name3': 'string', 'Name1': 1}

นี้เป็นเพราะว่าฟังก์ชั่นเข้าใจไวยากรณ์dict() dict(Name1=1, Name2=2,Name3='string')ช่องว่างในสตริง (เช่นหลังแต่ละอัฒภาค) จะถูกละเว้น แต่โปรดทราบว่าค่าสตริงจำเป็นต้องมีการอ้างอิง


ขอบคุณ upvote string.replace ทำงานได้ดี ไม่รู้ว่าทำไมฉันถึงแยกไม่ออก ฉันทำ i = textcontrol.GetValue () บนกล่อง tc แล้ว o = i.split (';') แต่ไม่ได้ส่งออกสตริงที่เพิ่งบ่นเกี่ยวกับรูปแบบซึ่งแตกต่างจากการแทนที่
Iancovici

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