2014-02-13 145 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