对二进制数据进行编码,以便转义\ n

时间:2012-11-22 23:24:50

标签: python string encoding recursion

我正在尝试编写一种编码/解码二进制数据的方法,使新行字符不是编码字符串的一部分。

这似乎是一个递归问题,但我似乎找不到解决方案。

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'

如何解决这个递归问题?

7 个答案:

答案 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%。