2014-02-13 95 views
0

我需要根据自定义替换集替换unicode。自定义替换由其他人的API定义,我基本上只需要处理它。就目前而言,我已经将所有必需的替换提取到一个csv文件中。这里有一个例子:Python - 读取unicode替换的csv文件

\u0020, 
\u0021,! 
\u0023,# 
\u0024,$ 
\u0025,% 
\u0026,& 
\u0028,(
\u0029,) 
\u002a,* 
\u002b,+ 
\u002c,"," 
\u002d,- 
\u002e,. 
\u002f,/ 
\u03ba,kappa 
... 

我产生这个在MS Excel通过黑客攻击了Java程序的API所有者使用自己时,他们需要做的转换(没有...他们不会只运行转换器时,该API接收输入...)。有约1500个替代定义。

当我生成输出(从我的Django应用程序)发送到他们的API作为输入,我想处理替换。下面是我如何一直在努力做到这一点:

class UTF8Converter(object): 
    def __init__(self): 
     #create replacement mapper 
     full_file_path = os.path.join(os.path.dirname(__file__), 
             CONVERSION_FILE) 
     with open(full_file_path) as csvfile: 
      reader = csv.reader(csvfile) 
      mapping = [] 
      for row in reader: 
       #remove escape-y slash 
       mapping.append((row[0], row[1])) # here's the problem 
     self.mapping = mapping 

    def replace_UTF8(self, string): 
     for old, new in self.mapping: 
      print new 
      string.replace(old, new) 
     return string 

的问题是,在CSV文件unicode的代码出现,例如,self.mapping[example][0] = '\\u00e0'。好的,那是错的,所以我们试试:

mapping.append((row[0].decode("string_escape"), row[1])) 

没有变化。如何:

mapping.append((row[0].decode("unicode_escape"), row[1])) 

好的,现在self.mapping[example][0] = u'\xe0'。所以是的,这是我需要替换的字符...但是我需要调用replace_UTF8()函数的字符串看起来像u'\u00e0'

我也试过row[0].decode("utf-8"),row[0].encode("utf-8"),unicode(row[0], "utf-8")

我也试过this但我没有unicode字符在csv文件中,我有unicode代码点(不知道这是否是正确的术语或什么)。

那么,如何将我从csv文件中读取的字符串转换为可与mythingthatneedsconverted.replace(...)一起使用的unicode字符串?

还是...我需要用csv文件做其他事情才能使用更明智的方法吗?

+0

作为一个侧面说明,为什么您使用翻译的列表,并走在整个列表来调用'每个replace',而不是只建立一个表['unicode.translate'使用](http://docs.python.org/2.7/library/stdtypes.html#str.translate)? – abarnert

+0

另外,'string.replace(old,new)'只是返回一个新的字符串,它不会以任何方式改变'string'。另外,你不能在Unicode字符串中搜索UTF-8数据,你必须将它解码为Unicode,然后在那里完成这项工作。 – abarnert

回答

1

我不认为你的问题确实存在:

好了,现在self.mapping [示例] [0] = U '\ xe0'。所以是的,这是我需要替换的字符...但是我需要调用replace_UTF8()函数的字符串看起来像u'\ u00e0'。

这些只是完全相同的字符串的不同表示。你可以自己测试一下:

>>> u'\xe0' == u'\u00e0' 
True 

实际的问题是,你没有做任何更换。在此代码:

def replace_UTF8(self, string): 
    for old, new in self.mapping: 
     print new 
     string.replace(old, new) 
    return string 

你只是打电话string.replace一遍又一遍,它返回一个新的字符串,但没有采取任何措施string本身。 (它不能做任何事情string本身;字符串是不可变的。)你想要的是:

​​

但是,如果string真的是UTF-8编码的str,作为函数名称所暗示的,这仍然是行不通的。当你使用UTF-8编码u'\u00e0'时,你得到的是'\xce\xa0'。没有\u00e0在那里被替换。所以,你真正需要做的是解码它,做替换,然后重新编码。就像这样:

def replace_UTF8(self, string): 
    u = string.decode('utf-8') 
    for old, new in self.mapping: 
     print new 
     u = u.replace(old, new) 
    return u.encode('utf-8') 

,或者甚至更好,让事情作为unicode,而不是除了在非常边缘编码str整个程序,所以你不必担心这些东西。


最后,这是应该做的更换非常缓慢和复杂的方式,当字符串(包括strunicode)有一个内置的translate方法做的正是你想要的。

而是构建表作为对Unicode字符串列表,把它做成一个字典映射序到序数:

mapping = {} 
for row in reader: 
    mapping[ord(row[0].decode("unicode_escape"))] = ord(row[1]) 

而现在,整个事情是一个一行,即使你编码混乱:

def replace_UTF8(self, string): 
    return string.decode('utf-8').translate(self.mapping).encode('utf-8') 
+0

如果我明白'正确翻译它是1-1字符替换。有时我需要用多个字符替换单个字符。请参阅csv示例中的编辑。我正在尝试其他解决方案。 – andy

+0

>我不认为你的问题确实存在 - 是的,我认为这是其中一种问题! :)“字符串”实际上是一个unicode字符串,所以工作的方法是没有包含decode()/ encode()的方法。整个问题是弦的不变性。咄。谢谢。 – andy

+0

@andy:正如链接文档所说,翻译表“必须是Unicode序号到Unicode序号,Unicode字符串或None的映射”。例如:'u'abc'.translate({97:u'xxx'})'将返回'u'xxxbc''。 – abarnert