如何使用python_dateutil 1.5的'parse'函数处理unicode?
我需要让 Python_dateutil 1.5 的 parse() 函数能够处理 Unicode 格式的月份名称。
如果我使用 fuzzy=True,它会跳过月份名称,结果就会把月份设为 1。
当我不使用 fuzzy 参数时,我遇到了以下错误:
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
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)
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个字符(这对日语来说不成立),以及与公历相关的许多细节。如果wordchars
字段能够从parserinfo
中获取(如果存在的话),那么parserinfo
就可以为其月份和日期名称定义正确的字符集,这样会更好。
python_dateutil
的版本2.0已经移植到Python 3,但上述设计问题并没有显著改变。2.0和1.5之间的区别主要是为了处理Python语言的变化,而不是dateutil
的设计和数据结构。
Oleg,你能够修改parserinfo
,我怀疑你成功的原因是你的测试代码没有使用python_dateutil
的parser()
(和_timelex
)。实际上,你提供了自己的解析器和词法分析器。
要解决这个问题,需要对python_dateutil
的文本处理进行相当大的改进。如果有人能做出这样的补丁,并且包的维护者能够将其合并,那就太好了。