【问题标题】:Python - read csv file of unicode substitutionsPython - 读取 unicode 替换的 csv 文件
【发布时间】:2014-02-13 23:18:20
【问题描述】:

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

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

我通过破解 API 所有者在需要进行转换时为自己使用的 java 程序在 MS Excel 中生成了这个(不......当 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,但我在 csv 文件中没有 unicode 字符,我有 unicode 代码点(不确定这是否是正确的术语或什么)。

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

或者...我是否需要对 csv 文件执行其他操作才能使用更明智的方法?

【问题讨论】:

  • 附带说明一下,您为什么要使用翻译列表并遍历整个列表来调用replace,而不是仅仅构建一个表以与unicode.translate 一起使用?
  • 另外,string.replace(old, new) 只是返回一个新字符串,它不会以任何方式改变string。此外,您无法在 UTF-8 数据中搜索 Unicode 字符串,您必须将其解码为 Unicode,然后在那里进行工作。

标签: python csv unicode


【解决方案1】:

我认为您的问题实际上并不存在:

好的,现在 self.mapping[example][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 本身做任何事情;字符串是不可变的。)你想要的是:

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

但是,如果 string 真的是 UTF-8 编码的 str,正如函数名所暗示的那样,这仍然行不通。当你对u'\u00e0'进行UTF-8编码时,你得到的是'\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 字符串对的列表,不如将其构建为将序数映射到序数的 dict:

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')

【讨论】:

  • 如果我理解 translate 正确,它是用于 1-1 字符替换。有时我需要用多个字符替换单个字符。请参阅 csv 示例中的编辑。我现在正在尝试其他解决方案。
  • >我认为您的问题实际上并不存在 - 是的,我认为这是其中一种问题! :) “字符串”实际上是一个 unicode 字符串,因此有效的方法是不包含 decode()/encode() 的方法。整个问题是字符串的不变性。呃。谢谢。
  • @andy:正如链接文档所说,翻译表“必须是 Unicode 序数到 Unicode 序数、Unicode 字符串或无的映射”。例如:u'abc'.translate({97: u'xxx'}) 将返回 u'xxxbc'
  • @andy:另外,如果字符串是unicode,你可能不应该给函数起一个误导性的名字,比如replace_UTF8
猜你喜欢
  • 2023-03-17
  • 2016-12-30
  • 2017-12-23
  • 2013-06-30
  • 1970-01-01
  • 2013-08-08
  • 1970-01-01
  • 1970-01-01
  • 2019-11-10
相关资源
最近更新 更多