Kivy: Windows 上“utf-8”kv 文件的编码问题

创建于 2016-02-16  ·  24评论  ·  资料来源: kivy/kivy

我正在为 Linux 和 Windows 7 开发一个多平台应用程序。我所有的文件都是首先在 Linux 上编写并编码为utf-8 ,但是当我在 Windows 上打开同一个项目时, kv文件使用cp1252编码读取。 我的.py文件似乎没有发生同样的事情,可能是因为我使用的是 python3。

因此,写入kv文件的 Unicode 字符将无法在 Kivy 应用程序上正确呈现。 字符串'Título'将显示为TÃ-tulo

我的设置是:Kivy=1.9.1、Python=3.4.4、Windows 7 x64 Home Premium。

我的 python 也是使用 Anaconda 安装的,但这可能无关。

要重现问题:

编写一个用utf-8编码的kv文件:

# test.kv
<myButton@Button>:
    text: 'Título'

在 python 解释器或.py脚本上:

import kivy
from kivy.lang import Builder
from kivy.uix.button import Button

Builder.load_file('test.kv')
class myButton(Button):
    pass

print( myButton().text == 'Título' ) # False
print( myButton().text.encode('cp1252').decode() == 'Título' ) # True

我发现的多平台解决方法是这样的:

# test.kv
<myButton@Button>:
    text: str(b'T\xc3\xadtulo'.decode())

最有用的评论

是的@ChristianTremblay ,这只是一个 Windows 错误。 这实际上是因为 windows 默认编码是 cp1252,导致 Kivy 读取 .kv 文件就好像以这种方式编码一样。 也许@KeyWeeUsr提出的解决方案确实有帮助,我还没有尝试过,但可能比提出的其他解决方法更干净。

我同意,一个好的解决方案是允许在 .kv 文件上进行编码规范,就像我们在 python 中所做的那样:

# -*- coding: utf-8 -*-
<MyWidget>:
    # ...

所有24条评论

仅供参考 - 解决此问题的一种稍微简单的方法是使用 Unicode 文字:

<MyButton@Button>:
    text: u'T\u00edtulo'

谢谢,我会用的=)

对于使用此解决方法的其他人,如果您想为您的 Unicode 字符找到 Unicode 转义序列,您可能会发现它是这样的:

>> hex( ord('ã') )
0xe3
>> u'\u00e3'
'ã'

你不认为应该有更好的方法吗? (听赫廷格说话……)

一个 # 标头会告诉如何处理 unicode 字符?

即使这个技巧有效……当有很多 unicode 字符时,它会使文本很难阅读……

这只是一个Windows错误吗?

好吧,这不是处理编码的推荐方式,但您可以使用它。 它在 py2.7 和 kivy 1.8.0 中对我有用,但它甚至可以在 py3 上工作。 文件保存为utf-8\u...符号直接用作u'ä'

    import sys
    reload(sys)
    sys.setdefaultencoding("utf-8")

是的@ChristianTremblay ,这只是一个 Windows 错误。 这实际上是因为 windows 默认编码是 cp1252,导致 Kivy 读取 .kv 文件就好像以这种方式编码一样。 也许@KeyWeeUsr提出的解决方案确实有帮助,我还没有尝试过,但可能比提出的其他解决方法更干净。

我同意,一个好的解决方案是允许在 .kv 文件上进行编码规范,就像我们在 python 中所做的那样:

# -*- coding: utf-8 -*-
<MyWidget>:
    # ...

如果 utf-8 对 kv 文件是强制性的怎么办?

    def load_file(self, filename, **kwargs):
        '''Insert a file into the language builder and return the root widget
        (if defined) of the kv file.

        :parameters:
            `rulesonly`: bool, defaults to False
                If True, the Builder will raise an exception if you have a root
                widget inside the definition.
        '''
        filename = resource_find(filename) or filename
        if __debug__:
            trace('Builder: load file %s' % filename)
        with open(filename, 'r', encoding='utf-8') as fd:
            kwargs['filename'] = filename
            data = fd.read()

            # remove bom ?
            if PY2:
                if data.startswith((codecs.BOM_UTF16_LE, codecs.BOM_UTF16_BE)):
                    raise ValueError('Unsupported UTF16 for kv files.')
                if data.startswith((codecs.BOM_UTF32_LE, codecs.BOM_UTF32_BE)):
                    raise ValueError('Unsupported UTF32 for kv files.')
                if data.startswith(codecs.BOM_UTF8):
                    data = data[len(codecs.BOM_UTF8):]

            return self.load_string(data, **kwargs)

这可以在 kivy/lang/builder.py 第 275 行及以上找到

@ChristianTremblay ,我认为这不是最好的。 一些用户可能仍然使用默认编码不同于“utf-8”的文本编辑器,例如默认的 Windows 编码“cp1252”。 我们必须为两者提供解决方案。

最好的方法可能是模仿 python 行为:

  • 期望程序员在第一行指定编码。
  • 或者使用python默认编码(在python3上我认为它总是'utf8')。

在 Android 上遇到问题:

An unanticipated UnicodeDecodeError occurred: 'ascii' codec can't decode byte 0xef in position 564: ordinal not in range(128)
Traceback (most recent call last):  
  File "./pages.py", line 21, in <module>
    Builder.load_file('pages.kv')
  File "/data/data/.../files/app/crystax_python/site-packages/kivy/lang/builder.py", line 290, in load_file
    data = fd.read()
  File "/data/data/.../files/app/crystax_python/stdlib.zip/encodings/ascii.py", line 26, in decode
    return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xef in position 564: ordinal not in range(128)

((boggle)) 不过似乎在我的 Linux 机器上工作。

默认值绝对应该是 utf-8,尽管不是强制的。

mixmastamyk 我遇到了完全相同的问题。
我的应用程序运行良好,但是当我构建 APK 并在我的 android 手机上运行它时,我得到:
UnicodeDecodeError:“ascii”编解码器无法解码位置 352 中的字节 0xc3:序号不在范围内(128)
这是因为我的文件中有几个“É”。 太糟糕了,我在 python3 中编码以避免这些烦人的事情。

对。 看起来Builder.load_file()应该默认为 utf8 和/或具有编码参数。 与此同时,我这样做了:

 with open(filename, encoding='utf8') as f:
     Builder.load_string(f.read())

确保禁用 kv 文件的自动加载,否则仍会抛出错误并使其看起来不起作用。 '\u2026' 形式也可以工作,如果它只有一个或两个字符。

聪明的想法。谢谢!
我会试试这个。

此问题已自动标记为陈旧,因为它最近没有活动。 如果没有进一步的活动发生,它将被关闭。 感谢你的贡献。

多么方便,忽略错误并让它们自行关闭。

实际上我们一直在挖掘旧问题来对它们进行分类,不会关闭任何有效且可操作的问题。 尽管这种态度无助于将我们的下午奉献给该项目所需的动力。

不是因为缺乏工作而生气,而是一个关闭被忽略问题的机器人。 这可能需要一两行代码来向 load_file 添加编码参数。 本来可以自己做的,但是有 70 个未完成的拉取请求。

人力稀缺的项目不应该有这种类型的机器人。

我仍然鼓励你提出拉取请求。 如果它是一个干净且简单的修复,它很有可能被合并。

我在 kivy 1.10 上有同样的问题,我的应用程序在 linux 上运行完美,使用 python3 (python3 main.py) 但是当我在我的 android 手机上调试部署时,应用程序崩溃:/如果你想做一些有质量的事情,那就太烦人了

Windows 10 上的 kivy 1.10.1 和 python 3.6.6 仍然存在此问题。当前的解决方法不是自动加载 .kv 文件。 将其重命名为默认不加载的内容,使用 utf8 编码保存并按照 #5154 所示执行

from kivy.lang import Builder
with open('MyApp.renamed.kv', encoding='utf8') as f: 
    Builder.load_string(f.read())

@carasuca解决方案对我不起作用

kivy 1.10.1 蟒蛇 3.5.3 视窗 7
Windows 10 和 python 3.6.5 上的相同行为

相同的代码在 osx 和 linux 上完美运行

编辑:问题出在#:include kv 语言指令中
@carasuca解决方案当且仅当您有一个 kv 文件并使用 Builder.load_string(f.read()) 加载它时才有效。 如果该 kv 使用 #:include anotherfile.kv,则该文件将使用错误的字符集加载。
解决方案 1:将所有 kv 代码放入一个文件中
解决方案2:

for kvfile in ['file1.kv', 'file2.kv']:
         with open(kvfile, encoding='utf8') as f:
             Builder.load_string(f.read())

好吧,我对像“Número”或“veículo”这样的词也有同样的错误。 我尝试使用以下代码:

from kivy.lang import Builder
with open('myApp.kv', encoding='utf8') as f: 
    Builder.load_string(f.read())

但是我在这样做时遇到了问题。 当我运行应用程序时,我可以看到两个不同的标签重叠。
解决方案是将 kv 文件保存在子目录中,然后像这样调用 with open:

with open('./kvfile/myApp.kv', encoding='utf-8') as f:
            Builder.load_string(f.read())

问题已解决,因为自动加载不会在与 main.py 相同的目录中找到 kv 文件。 所以它不会复制可视化。

@piontk嘿,我认为这将是我的救赎,但是当我尝试时,它说“编码”不是“打开”的有效参数。 为什么? (另外,对不起,如果这是一个愚蠢的问题,这是我有史以来的第一个应用程序)

好的,我知道这并不理想,但如果这些选项都不适合您,您可以将所需的字符串设置为 .py 文件的主应用程序类中的变量,该文件具有 utf-8 编码,然后访问它在您的 .kv 文件中。
#.py
class MainApp(App):
struser = ('Nome de usuário')

#.kv
Label:
text: app.struser

为我工作

此页面是否有帮助?
0 / 5 - 0 等级