[英]Get str repr with double quotes Python
我正在使用一個小的Python腳本來生成一些將在C頭中使用的二進制數據。
這個數據應該聲明為char[]
,如果它可以被編碼為一個字符串(當它們不在ASCII可打印字符范圍內時具有相關的轉義序列)以保持標題比使用它更緊湊,那將是很好的。十進制或十六進制數組編碼。
問題是,當我打印Python字符串的repr
時,它由單引號分隔,而C不喜歡它。 天真的解決方案是:
'"%s"'%repr(data)[1:-1]
但是當數據中的一個字節恰好是雙引號時,這不起作用,所以我也需要它們進行轉義。
我認為一個簡單的replace('"', '\\\\"')
可以完成這項工作,但也許有一個更好,更pythonic的解決方案。
額外點 :
將數據拆分成大約80個字符的行也很方便,但是再次將大小為80的塊中的源字符串拆分的簡單方法將不起作用,因為每個不可打印的字符在轉義序列中需要2或3個字符。 在獲得repr 之后將列表拆分為80塊也無濟於事,因為它可以划分轉義序列。
有什么建議?
最好不要破解repr()
但從一開始就使用正確的編碼。 您可以使用編碼string_escape
直接獲取repr的編碼
>>> "naïveté".encode("string_escape")
'na\\xc3\\xafvet\\xc3\\xa9'
>>> print _
na\xc3\xafvet\xc3\xa9
為了逃避“-quotes我認為在轉義后使用簡單的替換編碼字符串是一個完全明確的過程:
>>> '"%s"' % 'data:\x00\x01 "like this"'.encode("string_escape").replace('"', r'\"')
'"data:\\x00\\x01 \\"like this\\""'
>>> print _
"data:\x00\x01 \"like this\""
如果你要求python str
為它的repr
,我不認為引用的類型是真的可配置。 從python 2.6.4源代碼樹中的PyString_Repr
函數:
/* figure out which quote to use; single is preferred */
quote = '\'';
if (smartquotes &&
memchr(op->ob_sval, '\'', Py_SIZE(op)) &&
!memchr(op->ob_sval, '"', Py_SIZE(op)))
quote = '"';
所以,如果字符串中有單引號,我想使用雙引號,但如果字符串中有雙引號則不要。
我會嘗試編寫自己的類來包含字符串數據而不是使用內置字符串來執行此操作。 一種選擇是從str
派生一個類並編寫自己的repr
:
class MyString(str):
__slots__ = []
def __repr__(self):
return '"%s"' % self.replace('"', r'\"')
print repr(MyString(r'foo"bar'))
或者,根本不要使用repr
:
def ready_string(string):
return '"%s"' % string.replace('"', r'\"')
print ready_string(r'foo"bar')
如果字符串中已經存在轉義引號,那么這種簡單的引用可能不會做“正確”的事情。
你可以嘗試json.dumps
:
>>> import json
>>> print(json.dumps("hello world"))
"hello world"
>>> print(json.dumps('hëllo "world"!'))
"h\u00ebllo \"world\"!"
我不確定json字符串是否與C兼容,但至少它們有一個非常大的公共子集,並且保證與javascript兼容;)。
repr()不是你想要的。 存在一個基本問題:repr()可以使用可以作為Python求值的字符串的任何表示來生成字符串。 從理論上講,這意味着它可能決定使用任何在C中無效的其他結構,例如“”“long strings”“”。
這段代碼可能是正確的方向。 我使用140的默認包裝,這對於2009年來說是一個合理的值,但是如果你真的想要將你的代碼包裝到80列,那就改變它吧。
如果unicode = True,它會輸出一個L“寬”字符串,它可以有意義地存儲Unicode轉義符。 或者,您可能希望將Unicode字符轉換為UTF-8並將其轉義為轉義,具體取決於您使用它們的程序。
def string_to_c(s, max_length = 140, unicode=False):
ret = []
# Try to split on whitespace, not in the middle of a word.
split_at_space_pos = max_length - 10
if split_at_space_pos < 10:
split_at_space_pos = None
position = 0
if unicode:
position += 1
ret.append('L')
ret.append('"')
position += 1
for c in s:
newline = False
if c == "\n":
to_add = "\\\n"
newline = True
elif ord(c) < 32 or 0x80 <= ord(c) <= 0xff:
to_add = "\\x%02x" % ord(c)
elif ord(c) > 0xff:
if not unicode:
raise ValueError, "string contains unicode character but unicode=False"
to_add = "\\u%04x" % ord(c)
elif "\\\"".find(c) != -1:
to_add = "\\%c" % c
else:
to_add = c
ret.append(to_add)
position += len(to_add)
if newline:
position = 0
if split_at_space_pos is not None and position >= split_at_space_pos and " \t".find(c) != -1:
ret.append("\\\n")
position = 0
elif position >= max_length:
ret.append("\\\n")
position = 0
ret.append('"')
return "".join(ret)
print string_to_c("testing testing testing testing testing testing testing testing testing testing testing testing testing testing testing testing testing", max_length = 20)
print string_to_c("Escapes: \"quote\" \\backslash\\ \x00 \x1f testing \x80 \xff")
print string_to_c(u"Unicode: \u1234", unicode=True)
print string_to_c("""New
lines""")
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.