for*_*ran 13 c python escaping
我正在使用一个小的Python脚本来生成一些将在C头中使用的二进制数据.
这个数据应该声明为a char[],如果它可以被编码为一个字符串(当它们不在ASCII可打印字符范围内时具有相关的转义序列)以保持标题比使用小数或十六进制数组编码.
问题是,当我打印reprPython字符串时,它由单引号分隔,而C不喜欢它.天真的解决方案是:
'"%s"'%repr(data)[1:-1]
Run Code Online (Sandbox Code Playgroud)
但是当数据中的一个字节恰好是双引号时,这不起作用,所以我也需要它们进行转义.
我认为简单replace('"', '\\"')可以完成这项工作,但也许有一个更好,更pythonic的解决方案.
额外点:
将数据拆分成大约80个字符的行也很方便,但是再次将大小为80的块中的源字符串拆分的简单方法将不起作用,因为每个不可打印的字符在转义序列中需要2或3个字符.在获得repr 之后将列表拆分为80块也无济于事,因为它可以划分转义序列.
有什么建议?
最好不要破解,repr()但从一开始就使用正确的编码.您可以直接使用编码获取repr的编码string_escape
>>> "naïveté".encode("string_escape")
'na\\xc3\\xafvet\\xc3\\xa9'
>>> print _
na\xc3\xafvet\xc3\xa9
Run Code Online (Sandbox Code Playgroud)
为了逃避"-quotes我认为在转义后使用简单的替换编码字符串是一个完全明确的过程:
>>> '"%s"' % 'data:\x00\x01 "like this"'.encode("string_escape").replace('"', r'\"')
'"data:\\x00\\x01 \\"like this\\""'
>>> print _
"data:\x00\x01 \"like this\""
Run Code Online (Sandbox Code Playgroud)
如果你问一个python str其repr,我不认为引用的类型真的是可配置的.从PyString_Reprpython 2.6.4源代码树中的函数:
/* 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 = '"';
Run Code Online (Sandbox Code Playgroud)
所以,如果字符串中有单引号,我想使用双引号,但如果字符串中有双引号则不要.
我会尝试编写自己的类来包含字符串数据而不是使用内置字符串来执行此操作.一种选择是从str自己编写一个类并编写自己的类repr:
class MyString(str):
__slots__ = []
def __repr__(self):
return '"%s"' % self.replace('"', r'\"')
print repr(MyString(r'foo"bar'))
Run Code Online (Sandbox Code Playgroud)
或者,根本不要使用repr:
def ready_string(string):
return '"%s"' % string.replace('"', r'\"')
print ready_string(r'foo"bar')
Run Code Online (Sandbox Code Playgroud)
如果字符串中已经存在转义引号,那么这种简单的引用可能不会做"正确"的事情.
您可以尝试json.dumps:
>>> import json
>>> print(json.dumps("hello world"))
"hello world"
>>> print(json.dumps('hëllo "world"!'))
"h\u00ebllo \"world\"!"
Run Code Online (Sandbox Code Playgroud)
我不确定json字符串是否与C兼容,但至少它们具有相当大的通用子集,并保证与javascript兼容;)。
repr() 不是你想要的。有一个基本问题:repr() 可以使用任何可以作为 Python 计算的字符串表示形式来生成字符串。这意味着,从理论上讲,它可能会决定使用任意数量的其他在 C 中无效的结构,例如“”“长字符串”“”。
这段代码可能是正确的方向。我使用的默认值是 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""")
Run Code Online (Sandbox Code Playgroud)