我正在尝试编写一种编码/解码二进制数据的方法,使新行字符不是编码字符串的一部分。
这似乎是一个递归问题,但我似乎找不到解决方案。
e.g。一个天真的实现:
>>> original = 'binary\ndata'
>>> encoded = original.replace('\n', '=n')
'binary=ndata'
>>> decoded = original.replace('=n', '\n')
'binary\ndata'
如果原始字符串中已有=n
会怎样?
>>> original = 'binary\ndata=n'
>>> encoded = original.replace('\n', '=n')
'binary=ndata=n'
>>> decoded = original.replace('=n', '\n')
'binary\ndata\n' # wrong
尝试逃避现有的=n
,但如果已经有转义=n
,会发生什么?
>>> original = '++nbinary\ndata=n'
>>> encoded = original.replace('=n', '++n').replace('\n', '=n')
'++nbinary=ndata++n'
如何解决这个递归问题?
答案 0 :(得分:1)
编码可能包含“escape”字符的字符串的方法是转义转义字符。在python中,转义字符是反斜杠,但你可以使用你想要的任何东西。每次出现换行或转义时,您的费用都是一个字符。
为避免让您感到困惑,我会使用正斜杠:
# original
>>> print "slashes / and /newline/\nhere"
slashes / and /newline/
here
# encoding
>>> print "slashes / and /newline/\nhere".replace("/", "//").replace("\n", "/n")
slashes // and //newline///nhere
这种编码是明确的,因为所有真正的斜杠都加倍了;但它必须在一次通过中解码,因此您不能只使用两次连续调用replace()
:
# decoding
>>> def decode(c):
# Expand this into a real mapping if you have more substitutions
return '\n' if c == '/n' else c[0]
>>> print "".join( decode(c) for c in re.findall(r"(/.|.)",
"slashes // and //newline///nhere"))
slashes / and /newline/
here
请注意,输入中有一个实际的/n
(换行符之前有另一个斜杠):无论如何都能正常工作。
答案 1 :(得分:1)
解决方案
original = 'binary\ndata \\n'
# encoded = original.encode('string_escape') # escape many chr
encoded = original.replace('\\', '\\\\').replace('\n', '\\n') # escape \n and \\
decoded = encoded.decode('string_escape')
验证
>>> print encoded
binary\ndata \\n
>>> print decoded
binary
data \n
解决方案来自How do I un-escape a backslash-escaped string in python?
编辑:我也用你的特殊经济编码写了它。原始的“string_escape”编解码器转义反斜杠,撇号和chr(32)以及chr(126)以上的所有内容。两者的解码都是一样的。
答案 2 :(得分:0)
如果你系统地编码了整个字符串,你最终是否会逃脱它?对你做的每个角色(ord(char)+ 1)或者像这样的小事说什么呢?
答案 3 :(得分:0)
我对二进制数据没有太多经验,所以这可能完全不合理/效率低,但这会解决您的问题吗?
In [40]: original = 'binary\ndata\nmorestuff'
In [41]: nlines = [index for index, i in enumerate(original) if i == '\n']
In [42]: encoded = original.replace('\n', '')
In [43]: encoded
Out[43]: 'binarydatamorestuff'
In [44]: decoded = list(encoded)
In [45]: map(lambda x: decoded.insert(x, '\n'), nlines)
Out[45]: [None, None]
In [46]: decoded = ''.join(decoded)
In [47]: decoded
Out[47]: 'binary\ndata\nmorestuff'
同样,我确信有更好/更准确的方法 - 这只是从新手的角度来看。
答案 4 :(得分:0)
如果您将n个符号(例如ASCII)的字母编码为较小的m个符号集(例如除了换行符之外的ASCII),则必须允许编码的字符串比原始字符串长。
这样做的典型方法是将一个字符定义为“转义”字符; “escape”后面的字符表示编码字符。这种技术自20世纪40年代起就被用于电传打字机;这就是你在键盘上看到的“Esc”键的来源。
Python(和其他语言)已经在字符串中使用反斜杠字符。换行符编码为'\ n'(或'\ r \ n')。反斜杠会自行转义,因此文字字符串'\ r \ n'将被编码为'\\ r \\ n'。
请注意,仅包含转义字符的字符串的编码长度将是原始字符串的两倍。如果这是不可接受的,则必须使用使用较大字母表的编码来避免转义字符(可能比原始字符串长)或压缩它(也可能比原始字符串长)。
答案 5 :(得分:0)
怎么样:
In [8]: import urllib
In [9]: original = 'binary\ndata'
In [10]: encoded = urllib.quote(original)
In [11]: encoded
Out[11]: 'binary%0Adata'
In [12]: urllib.unquote(encoded)
Out[12]: 'binary\ndata'
答案 6 :(得分:0)
escapeless编码是专门为从二进制数据中修剪某些字符而设计的。如果仅删除\n
字符,则开销将小于0.4%。