sprintf เหมือนกับการทำงานใน Python


131

ฉันต้องการสร้างบัฟเฟอร์สตริงเพื่อทำการประมวลผลรูปแบบและสุดท้ายเขียนบัฟเฟอร์ในไฟล์ข้อความโดยใช้sprintfฟังก์ชันC-style ใน Python เนื่องจากข้อความที่มีเงื่อนไขฉันไม่สามารถเขียนลงในไฟล์ได้โดยตรง

เช่นรหัสหลอก:

sprintf(buf,"A = %d\n , B= %s\n",A,B)
/* some processing */
sprint(buf,"C=%d\n",c)
....
...
fprintf(file,buf)

ดังนั้นในไฟล์เอาต์พุตเรามี o / p ประเภทนี้:

A= foo B= bar
C= ded
etc...

แก้ไขเพื่อชี้แจงคำถามของฉัน:
bufบัฟเฟอร์ขนาดใหญ่มีสตริงเหล่านี้ทั้งหมดซึ่งจัดรูปแบบโดยใช้ sprintf ตามตัวอย่างของคุณbufจะมีเฉพาะค่าปัจจุบันไม่ใช่ค่าที่เก่ากว่า เช่นแรกในที่bufฉันเขียนในA= something ,B= somethingภายหลังC= somethingถูกต่อท้ายbufด้วยคำตอบเดียวกันแต่ในคำตอบ Python ของคุณbufมีเพียงค่าสุดท้ายซึ่งไม่ใช่ฉันต้องการ - ฉันต้องการbufให้มีสิ่งที่printfฉันทำทั้งหมดตั้งแต่เริ่มต้นเช่นในC.


1
นั่นไม่ใช่วิธีที่ sprintf () ทำงานใน C. (มันเขียนเนื้อหาที่จุดเริ่มต้นbufไม่ใช่ตอนท้าย) มันน่าจะดีที่สุดที่จะใช้อาร์เรย์ของสตริงจากนั้นรวมเข้าด้วยกันก่อนที่คุณจะเขียนลงไฟล์
yam655

@dividebyzero นี่ไม่ใช่เรื่องเล็กน้อยใน Python เนื่องจากเป็นภาษาโปรแกรมทั่วไปหรือไม่? ตัวอย่างเช่นดูวิธีแก้ปัญหาของ Michael J. Barber (โพสต์หลังความคิดเห็นของคุณ) def sprintf(buf, fmt, *args): ...
jdk1.0

@ jdk1.0 ฉันไม่รู้ว่าฉันหมายถึงอะไรฉันยังเด็กและไร้เดียงสาโปรแกรมเมอร์ Python ... คำถามนี้แปลกจริง ๆ เพราะสิ่งที่นำมาใช้ใหม่บัฟเฟอร์ไม่ง่ายอย่างนั้นคุณต้องเพิ่มตัวชี้ด้วยผลลัพธ์ของ sprintf แต่ละครั้งและสิ่งนี้ไม่ใช่สิ่งที่คุณควรกังวลหากคุณกำลังทำ Python อย่างไรก็ตามฉันดีใจที่ได้ย้ายไปที่ Scala และตอนนี้ Julia!
Dividebyzero

คำตอบ:


170

Python มีตัว%ดำเนินการสำหรับสิ่งนี้

>>> a = 5
>>> b = "hello"
>>> buf = "A = %d\n , B = %s\n" % (a, b)
>>> print buf
A = 5
 , B = hello

>>> c = 10
>>> buf = "C = %d\n" % c
>>> print buf
C = 10

ดูข้อมูลอ้างอิงนี้สำหรับตัวระบุรูปแบบที่รองรับทั้งหมด

คุณสามารถใช้format:

>>> print "This is the {}th tome of {}".format(5, "knowledge")
This is the 5th tome of knowledge

40

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

ตัวอย่างโง่ ๆ สำหรับ python 2.7 ขึ้นไป:

>>> print "{} ...\r\n {}!".format("Hello", "world")
Hello ...
 world!

สำหรับ python เวอร์ชันก่อนหน้า: (ทดสอบด้วย 2.6.2)

>>> print "{0} ...\r\n {1}!".format("Hello", "world")
Hello ...
 world!

4
คุณควรทราบว่าเวอร์ชันนั้นใช้งานได้เฉพาะใน Python 3 เท่านั้นใน Python 2.6 คุณต้องทำ:"{0} ...\r\n {1}!".format("Hello", "world")
Mark Longair

1
การแก้ไขคำตอบของฉันเพื่อรวมสิ่งนั้น อย่าว่ามันใช้ได้กับ python 2.7 ด้วย!
Nicolas Lefebvre

20

ฉันไม่แน่ใจอย่างสมบูรณ์ว่าฉันเข้าใจเป้าหมายของคุณ แต่คุณสามารถใช้StringIOอินสแตนซ์เป็นบัฟเฟอร์ได้:

>>> import StringIO 
>>> buf = StringIO.StringIO()
>>> buf.write("A = %d, B = %s\n" % (3, "bar"))
>>> buf.write("C=%d\n" % 5)
>>> print(buf.getvalue())
A = 3, B = bar
C=5

ไม่เหมือนsprintfคุณเพียงแค่ส่งสตริงไปbuf.writeจัดรูปแบบด้วยตัว%ดำเนินการหรือformatวิธีการของสตริง

คุณสามารถกำหนดฟังก์ชันเพื่อรับsprintfอินเทอร์เฟซที่คุณต้องการได้:

def sprintf(buf, fmt, *args):
    buf.write(fmt % args)

ซึ่งจะใช้ในลักษณะนี้:

>>> buf = StringIO.StringIO()
>>> sprintf(buf, "A = %d, B = %s\n", 3, "foo")
>>> sprintf(buf, "C = %d\n", 5)
>>> print(buf.getvalue())
A = 3, B = foo
C = 5

2
+1 สำหรับแสดงวิธีใช้ * args กับตัวดำเนินการจัดรูปแบบสตริง (%)
Curtis Yallop

สำหรับ Python3 ให้ใช้io.StringIO()แทน
Wolf


11

คุณสามารถใช้การจัดรูปแบบสตริง:

>>> a=42
>>> b="bar"
>>> "The number is %d and the word is %s" % (a,b)
'The number is 42 and the word is bar'

แต่สิ่งนี้ถูกลบออกใน Python 3 คุณควรใช้ "str.format ()":

>>> a=42
>>> b="bar"
>>> "The number is {0} and the word is {1}".format(a,b)
'The number is 42 and the word is bar'

4
ผิดมันไม่ถูกลบใน Python 3 Python 3.0 บอกว่าจะเลิกใช้ใน 3.1 แต่ฉันเชื่อว่าไม่เคยเกิดขึ้น การใช้format()อาจดีกว่า แต่%การจัดรูปแบบยังคงมีอยู่ (ดูmail.python.org/pipermail/python-dev/2009-September/092399.htmlสำหรับเหตุผลบางประการที่ไม่เลิกใช้งาน)
Duncan

1
@Duncan; ขอบคุณฉันไม่รู้เรื่องนั้น ฉันอ่านที่ไหนสักแห่งที่เลิกใช้แล้วและไม่เคยลองอีกเลย :)
utdemir

7

หากต้องการแทรกลงในสตริงที่ยาวมากคุณควรใช้ชื่อสำหรับอาร์กิวเมนต์ที่แตกต่างกันแทนที่จะหวังว่าจะอยู่ในตำแหน่งที่ถูกต้อง นอกจากนี้ยังทำให้ง่ายต่อการแทนที่การเกิดซ้ำหลายครั้ง

>>> 'Coordinates: {latitude}, {longitude}'.format(latitude='37.24N', longitude='-115.81W')
'Coordinates: 37.24N, -115.81W'

นำมาจากตัวอย่างรูปแบบซึ่งFormatจะแสดงคำตอบอื่น ๆที่เกี่ยวข้องทั้งหมดด้วย


3

นี่อาจเป็นการแปลที่ใกล้เคียงที่สุดจากรหัส C ของคุณเป็นรหัส Python

A = 1
B = "hello"
buf = "A = %d\n , B= %s\n" % (A, B)

c = 2
buf += "C=%d\n" % c

f = open('output.txt', 'w')
print >> f, c
f.close()

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

แทนที่จะทำให้ทำ+=สิ่งนี้:

import cStringIO
buf = cStringIO.StringIO()

...

print >> buf, "A = %d\n , B= %s\n" % (A, B)

...

print >> buf, "C=%d\n" % c

...

print >> f, buf.getvalue()

3

หากคุณต้องการบางอย่างเช่นฟังก์ชันการพิมพ์ python3 แต่เป็นสตริง:

def sprint(*args, **kwargs):
    sio = io.StringIO()
    print(*args, **kwargs, file=sio)
    return sio.getvalue()
>>> x = sprint('abc', 10, ['one', 'two'], {'a': 1, 'b': 2}, {1, 2, 3})
>>> x
"abc 10 ['one', 'two'] {'a': 1, 'b': 2} {1, 2, 3}\n"

หรือไม่มี'\n'ตอนท้าย:

def sprint(*args, end='', **kwargs):
    sio = io.StringIO()
    print(*args, **kwargs, end=end, file=sio)
    return sio.getvalue()
>>> x = sprint('abc', 10, ['one', 'two'], {'a': 1, 'b': 2}, {1, 2, 3})
>>> x
"abc 10 ['one', 'two'] {'a': 1, 'b': 2} {1, 2, 3}"

1

สิ่งที่ต้องการ...

greetings = 'Hello {name}'.format(name = 'John')

Hello John

สิ่งนี้จะพิมพ์สตริงไปยังคอนโซลไม่ใช่สตริงซึ่งเป็นสิ่งที่ OP ต้องการ
Teemu Leisti

นอกจากนี้ยังพิมพ์% s ไปที่หน้าจอซึ่งไม่คาดคิด แต่ฉันชอบที่ฉันสามารถเพิ่มตัวแปรหลายตัวโดยใช้ลูกน้ำ


0

สองวิธีคือการเขียนลงในบัฟเฟอร์สตริงหรือเขียนบรรทัดลงในรายการและเข้าร่วมในภายหลัง ฉันคิดว่าStringIOวิธีนี้เป็นแบบ pythonic มากกว่า แต่ไม่ได้ผลก่อน Python 2.6

from io import StringIO

with StringIO() as s:
   print("Hello", file=s)
   print("Goodbye", file=s)
   # And later...
   with open('myfile', 'w') as f:
       f.write(s.getvalue())

คุณยังสามารถใช้สิ่งเหล่านี้ได้โดยไม่ต้องใช้ContextMananger( s = StringIO()) ตอนนี้ฉันใช้คลาสตัวจัดการบริบทพร้อมprintฟังก์ชัน ส่วนนี้อาจเป็นประโยชน์ในการแทรกข้อกำหนดการดีบักหรือการเพจแปลก ๆ :

class Report:
    ... usual init/enter/exit
    def print(self, *args, **kwargs):
        with StringIO() as s:
            print(*args, **kwargs, file=s)
            out = s.getvalue()
        ... stuff with out

with Report() as r:
   r.print(f"This is {datetime.date.today()}!", 'Yikes!', end=':')
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.