【问题标题】:How to use python_dateutil 1.5 'parse' function to work with unicode?如何使用 python_dateutil 1.5 'parse' 函数来处理 unicode?
【发布时间】:2012-02-12 08:10:02
【问题描述】:

我需要 Python_dateutil 1.5 parse() 使用 Unicode 月份名称。

如果使用fuzzy=True,它会跳过月份名称并产生月份= 1的结果

当我在没有模糊参数的情况下使用它时,我得到下一个异常:

from dateutil.parser import parserinfo, parser, parse

class myparserinfo(parserinfo):
    MONTHS = parserinfo.MONTHS[:]
    MONTHS[3] = (u"Foo", u"Foo", u"Июнь")


>>> test = unicode('8th of Июнь', 'utf-8')
>>> tester = parse(test, parserinfo=myparserinfo())
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "C:\Python27\lib\site-packages\python_dateutil-1.5-py2.7.egg\dateutil\parser.py", line 695, in parse
    return parser(parserinfo).parse(timestr, **kwargs)
  File "C:\Python27\lib\site-packages\python_dateutil-1.5-py2.7.egg\dateutil\parser.py", line 303, in parse
    raise ValueError, "unknown string format"
ValueError: unknown string format

【问题讨论】:

  • 尝试编码为 UTF-8。 test = test.encode("utf-8")
  • @S.Lott 谢谢,我已经修正了描述
  • RE:尝试编码为 UTF-8。 test = test.encode("utf-8") 没用
  • 我认为您在这个问题中使用“unicode”一词具有误导性。我认为您的意思是“俄罗斯”。我想你是在问如何 python-dateutil 1.5 能够解析用俄语写的日期。添加“国际化”标签将使您的问题更容易被知道的人看到。
  • 不是答案,但作为替代方案,您可以考虑使用 PyICU pyicu.osafoundation.org,它使用最新的 CLDR 数据。

标签: python datetime internationalization


【解决方案1】:

Rik Poggi 是对的,字符串 'Июнь' 不能是 python-dateutil 的月份。深入研究dateutil/parser.py,基本问题是该模块的国际化程度仅足以处理西欧拉丁脚本语言。它的设计目的不是为了能够处理使用非拉丁脚本(例如西里尔文)的语言,例如俄语。

最大的障碍在dateutil/parser.py:45-48,其中词法分析器class _timelex定义了可用于标记的字符,包括月份和日期名称:

class _timelex(object):
    def __init__(self, instream):
        # ... [some material omitted] ...
        self.wordchars = ('abcdfeghijklmnopqrstuvwxyz'
                          'ABCDEFGHIJKLMNOPQRSTUVWXYZ_'
                          'ßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ'
                          'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ')
        self.numchars = '0123456789'
        self.whitespace = ' \t\r\n'

因为wordchars 不包括西里尔字母,_timelex 将日期字符串中的每个字节作为单独的字符发出。这就是 Rik 观察到的。

另一个大障碍是dateutil 在内部使用 Python 字节字符串而不是 Unicode 字符串进行所有处理。这意味着,即使 _timelex 被扩展为接受西里尔字母,那么在处理字节和字符之间仍然会出现不匹配,以及调用者和python_dateutil 源代码之间的字符串编码差异导致的问题。

还有其他一些小问题,例如假设每个月的名称至少有 3 个字符长(对于日语来说不是这样),以及与公历有关的许多细节。从 parserinfo 中提取 wordchars 字段(如果存在)会很有帮助,这样 parserinfo 可以为其月和日名称定义正确的字符集。

python_dateutil v 2.0 已移植到 Python 3,但上述设计问题并没有显着改变。 2.0 和 1.5 的区别在于处理 Pyhon 语言的变化,而不是 dateutil 的设计和数据结构。

Oleg,您能够修改 parserinfo,我怀疑您成功了,因为您的测试代码没有使用 python_dateutilparser()(和 _timelex)。您实质上提供了自己的解析器和词法分析器。

纠正这个问题需要对python_dateutil 的文本处理进行相当大的改进。如果有人要为该更改制作补丁,并且包维护者能够合并它,那就太好了。

【讨论】:

    【解决方案2】:

    看了dateutil/parser.py的源码,基本发现'Июнь'这个字符串不能是dateutil的一个月

    当您的timestr 被拆分时,问题就开始了。

    在第 349 行,您有:

    l = _timelex.split(timestr)
    

    因为_timelex.split 的定义如下:

    def split(cls, s):      # at line 142
        return list(cls(s))
    

    你得到l 是:

    ['8', 'th', ' ', 'of', ' ', '\x18', '\x04', 'N', '\x04', '=', '\x04', 'L', '\x04']
    

    而不是(或多或少)人们所期望的:

    [u'8th', u'of', u'\u0418\u044e\u043d\u044c']
    

    因此,月份检查返回 None ,这会导致引发异常。

    # Check month name
    value = info.month(l[i])
    

    可能的解决方法:

    将所有内容翻译成英文,如果需要,再翻译回俄文。

    例子:

    dictionary = {u"Июнь": 'June', u'ноябрь': 'November'}
    
    for russian,english in dictionary.items():
        test = test.replace(russian,english)
    

    【讨论】:

    • 谢谢。我明白。但是如何解决它,以便我可以在解析函数中使用 unicode 月份名称?
    • @OlegDats:想到的更简单的解决方法是将所有内容翻译成英文,最后如果需要您可以返回俄文。我刚刚用一个简单的例子更新了我的答案。
    猜你喜欢
    • 2011-07-18
    • 1970-01-01
    • 2017-11-27
    • 2010-11-02
    • 2014-10-02
    • 1970-01-01
    • 1970-01-01
    • 2011-12-07
    • 1970-01-01
    相关资源
    最近更新 更多