如何在python中转义整个字符串?

时间:2014-05-23 02:41:29

标签: python

file=r'D:\tdx\vipdoc\szf10\300383.Txt'
text=open(file,"r").read()

可以读取文件,但最初我将file写为:

file='D:\tdx\vipdoc\szf10\300383.Txt'

我无法将其读作text=open(file,"r").read()

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: [Errno 22] Invalid argument: 'D:\tdx\x0bipdoc\\szf10\xc0383.Txt'

如果不使用file=r'D:\tdx\vipdoc\szf10\300383.Txt',我该怎么办?

也许我必须用某种方法逃避file的整个字符串?

问题是:文件是在开始时定义的,file是一个包含字符串的变量,我只能在程序中调用它,如何在程序中修复它。

  • 方法1:file=r'D:\tdx\vipdoc\szf10\300383.Txt'无法使用。
  • 方法2:file='D:\\tdx\\vipdoc\\szf10\\300383.Txt'也不能使用。

当程序已经运行时,给定file是一个字符串变量,我现在该如何修复它?

file不是字符串文字但是从代码的另一部分传递给我的代码,我无法修复使用正确的格式但仍希望能够使用文件名。

为什么我无法将'D:\tdx\vipdoc\szf10\300383.Txt'替换为'D:\\tdx\\vipdoc\\szf10\\300383.Txt' simply with file.replace(&#34; \&#34;,&#34; \\&#34;)`?< / p>

>>> file="D:\tdx\vipdoc\shf10\300383.Txt"
>>> file.replace("\x5c","\x5c\x5c")  #can't work 
'D:\tdx\x0bipdoc\\\\shf10\xc0383.Txt'

我想把它分成两部分,失败。

>>> filename = 'D:\tdx\vipdoc\szf10\300383.Txt'
>>> re.search('(.*?)(\d+\.Txt)',filename).group(1)
'D:\tdx\x0bipdoc\\szf10\xc0'
>>> re.search('(.*?)(\d+\.Txt)',filename).group(2)
'383.Txt'

在Martijn Pieters的帮助下,我解决了在映射中添加'\300':r'\300'的问题。

mapping = {'\a': r'\a', '\b': r'\b', '\f': r'\f', '\n': r'\n',
       '\r': r'\r', '\t': r'\t', '\v': r'\v','\300':r'\300'}
filename = 'D:\tdx\vipdoc\szf10\300383.Txt'
for char, escaped in mapping.items():
    filename = filename.replace(char, escaped)

5 个答案:

答案 0 :(得分:7)

因为你被打破了&#39;文件名实际上并不包含\个字符,您也无法替换这些字符。您有一个ASCII 9 TAB字符,两个单独的字符\t

>>> len('\t')
1
>>> '\' in '\t'
False

您必须尝试修复&#39;断弦;这是将是万无一失的,但您可以创建一个替换表来处理常见的转义序列。对于通常不处理回车符,制表符或换页符 的文件名,这是完全可行的。

Python字符串文字仅支持有限数量的单字母\转义序列;请参阅Python string literal documentation

\a  ASCII Bell (BEL)     
\b  ASCII Backspace (BS)     
\f  ASCII Formfeed (FF)  
\n  ASCII Linefeed (LF)  
\r  ASCII Carriage Return (CR)   
\t  ASCII Horizontal Tab (TAB)   
\v  ASCII Vertical Tab (VT)

我省略了多字符序列,因为这些在定义文字时往往会出错。只需使用转义序列替换这些字符:

mapping = {'\a': r'\a', '\b': r'\b', '\f': r'\f', '\n': r'\n',
           '\r': r'\r', '\t': r'\t', '\v': r'\v'}

for char, escaped in mapping.items():
    filename = filename.replace(char, escaped)

或者,我们可以使用'string_escape'编解码器

映射这些字符
>>> '\t'.encode('string_escape')
'\\t'

你不能将它应用于整个字符串,因为这会使任何正确转义的反斜杠加倍。此外,对于上面的许多转义码,它将使用\xhh转义序列而不是

>>> '\a'.encode('string_escape')
'\\x07'

所以这种方法并不适合您的需要。

对于使用\xhh编码的字符,这些更难要修复。例如,Windows文件系统支持Unicode代码点就好了。如果你做出假设而不是只使用ASCII码点,那么它就变得容易了。您可以使用正则表达式将这些替换为“逃脱”&#39;版本:

import re

filename = re.sub(r'[\x80-\xff]', lambda m: m.group().encode('string_escape'), filename)

这会将ASCII范围之外的任何字节更改为转义序列:

>>> import re
>>> re.sub(r'[\x80-\xff]', lambda m: m.group().encode('string_escape'), '\xc0')
'\\xc0'

使用精心挑选的字符范围,上述内容也可应用于所有不可打印的ASCII字符,并使用一个表达式修复大多数此类损坏的文件名,前提是我们首先应用上述映射替换'string_escape'未正确处理的代码:

def repair_filename(filename):
    mapping = {'\a': r'\a', '\b': r'\b', '\f': r'\f', '\v': r'\v'}
    for char, escaped in mapping.items():
        filename = filename.replace(char, escaped)
    filename = re.sub(r'[\x00-\x1f\x7f-\xff]', 
                      lambda m: m.group().encode('string_escape'),
                      filename)
    return filename

示例输入演示:

>>> def repair_filename(filename):
...     mapping = {'\a': r'\a', '\b': r'\b', '\f': r'\f', '\v': r'\v'}
...     for char, escaped in mapping.items():
...         filename = filename.replace(char, escaped)
...     filename = re.sub(r'[\x00-\x1f\x7f-\xff]', 
...                       lambda m: m.group().encode('string_escape'),
...                       filename)
...     return filename
... 
>>> filename = 'D:\tdx\vipdoc\szf10\300383.Txt'
>>> repair_filename(filename)
'D:\\tdx\\vipdoc\\szf10\\xc0383.Txt'

这应该为您修复大多数这样的损坏文件名。例如,它不会修复\x09,因为它也被\\t取代。

它也无法检测八进制转义码,也无法修复它们。请注意,\300已修复为\xc0。这将需要试运行,尝试所有可能的组合,或对输入做出假设。您可以假设\xhh永远不会发生,但\ooo会发生,例如。

在这种情况下,表达式变为:

filename = re.sub(r'[\x00-\x1f\x7f-\xff]', lambda m: '\\{:o}'.format(ord(m.group())), filename)

演示:

>>> def repair_filename(filename):
...     mapping = {'\a': r'\a', '\b': r'\b', '\f': r'\f', '\v': r'\v'}
...     for char, escaped in mapping.items():
...         filename = filename.replace(char, escaped)
...     filename = re.sub(r'[\x00-\x1f\x7f-\xff]', 
...                       lambda m: '\\{:o}'.format(ord(m.group())),
...                       filename)
...     return filename
... 
>>> repair_filename(filename)
'D:\\11dx\\vipdoc\\szf10\\300383.Txt'

什么有效,并且不取决于您期望的文件名类型。如果您知道文件名的最后部分总是以6位数字结尾,则可以执行更多操作。

但是,最好的办法是避免完全破坏文件名。

答案 1 :(得分:2)

如果您使用''而不是r'',则需要手动转义字符串文字中的每个反斜杠:

filename = 'D:\\tdx\\vipdoc\\szf10\\300383.Txt'

使用r''更简单,因为它禁止将\解释为转义字符,因此\本身不需要转义,只需将其作为转义字符字面斜线。

答案 2 :(得分:0)

您通常不能,因为例如'D:\tdx'\t被解释为制表符。但是,您可以尝试将转义的字符转换为类似于原始字符串的字符,但这比首先正确编写该文件名更有效。

答案 3 :(得分:0)

我认为,如果您最初使用非转义版本编写它,则文件名中会有一些特殊字符。它也将位于脚本最初运行的目录中。

\t将作为制表符,\ v作为垂直制表符,\ s正常,\ 300为高ascii字符。

我建议你在python中运行以下命令:

import shutil
shutil.move('D:\tdx\vipdoc\szf10\300383.Txt',r'D:\tdx\vipdoc\szf10\300383.Txt')

确保在最初运行脚本的同一目录中运行它。这应该放在您期望的位置,并带有您期望的文件名。

从那时起,您可以使用正确的版本。

答案 4 :(得分:0)

你不需要做任何复杂的事情,Python有内置的工具来处理这类问题,特别是os.path.normpath。有关实施细节,请参阅this article