Python 3.x 为什么一些表情符号会导致Python/Idle在Ubuntu上崩溃?

Python 3.x 为什么一些表情符号会导致Python/Idle在Ubuntu上崩溃?,python-3.x,ubuntu-18.04,python-idle,emoticons,Python 3.x,Ubuntu 18.04,Python Idle,Emoticons,我在Ubuntu 20.04LTS下使用Idle运行的Python代码打印包含表情符号的字符串时遇到问题。该代码在Windows10下运行良好,但当我尝试在Ubuntu下运行它时,试图查看一些字符串会导致Python/Idle崩溃,而不会显示任何有用的错误消息。表情符号本身似乎是问题所在,但不是所有的表情符号。例如,128516(笑着的脸和微笑的眼睛)是正常的,而128077(竖起大拇指)是导致碰撞的原因。两台电脑都运行Python 3.8.6,Idle显示相同的版本号 我创建了一个代码片段来演

我在Ubuntu 20.04LTS下使用Idle运行的Python代码打印包含表情符号的字符串时遇到问题。该代码在Windows10下运行良好,但当我尝试在Ubuntu下运行它时,试图查看一些字符串会导致Python/Idle崩溃,而不会显示任何有用的错误消息。表情符号本身似乎是问题所在,但不是所有的表情符号。例如,128516(笑着的脸和微笑的眼睛)是正常的,而128077(竖起大拇指)是导致碰撞的原因。两台电脑都运行Python 3.8.6,Idle显示相同的版本号

我创建了一个代码片段来演示这个问题

def make_uchr(code: str):
    return chr(int(code.lstrip("U+").zfill(8), 16))

def calc1char(intdecimal):   
   # print()  128516 is ok...  128077 crashes on Ubuntu
          
    strhex = hex(intdecimal)[2:]
    strUhex  = "U+"+strhex
    stroutput = make_uchr(strUhex)
    return stroutput
    
def main():

    while True:
        try:
            print("Enter a decimal integer or ctrl+C to exit...")
            print("Try 128516, then try 128077.")
            strdecimal = input('Enter your choice: ')
            intdecimal = int(strdecimal)
            stroutput = calc1char(intdecimal)
            print("The corresponding character is:")
            print(stroutput)
            print()
        except KeyboardInterrupt:
            break

if __name__ == '__main__':
    main()
在Windows 10下运行时,无论是通过Idle运行还是从命令提示符运行,此代码都不会出现任何问题。在Ubuntu下,当使用Idle运行时,某些代码(例如128077)的Idle崩溃,并且没有任何可见的错误消息。从终端运行或使用Pycharm时,预期的表情会打印到控制台。我最近升级了Ubuntu18.04LTS,问题也在那里出现了

在问题变得明显的代码中,带有表情符号的字符串将正确导出到文本文件,我有一个解决方法来清理在Ubuntu下运行时查看的字符串,即

if platform.system() == "Linux":  
    strmsg = (strmsg.encode("utf-8", errors='replace'))
    strmsg = str(strmsg.decode("ascii", errors='replace')) 
这将使用问号代替代码大于127的其他字符

然而,我很好奇是否有解决问题的方法,而不是解决方法。如有任何建议,将不胜感激


下面是另一个使用GUI示例的变体

from tkinter import *
import tkinter as tk

def make_uchr(code: str):
    return chr(int(code.lstrip("U+").zfill(8), 16))

def calc1char(intdecimal):   
          
    strhex = hex(intdecimal)[2:]
    strUhex  = "U+"+strhex
    stroutput = make_uchr(strUhex)
    return stroutput

def printtoconsole():

    intdecimal = int(entry_decimal.get())
    stroutput = calc1char(intdecimal)
    print(stroutput)

def printtolabel():

    intdecimal = int(entry_decimal.get())
    stroutput = calc1char(intdecimal)    
    label_output.configure(text=stroutput)

def printtoentry():

    intdecimal = int(entry_decimal.get())
    stroutput = calc1char(intdecimal)
    entry_output.delete(0,len(entry_output.get()))
    entry_output.delete(0,len(entry_output.get()))
    entry_output.insert(INSERT, stroutput)
    
def printtotext():
    intdecimal = int(entry_decimal.get())
    stroutput = calc1char(intdecimal)
    text_box.delete("1.0", END)
    text_box.insert(INSERT,stroutput)    
    text_box.pack()
    
def main():

    window = tk.Tk()
    window.geometry("300x300")
    window.title("Emoticons  !")

    decimal_var = tk.StringVar()
    strentryoutput_var = tk.StringVar()
    strdecimal = "128516"

    decimal_var.set(strdecimal)

    global entry_decimal, text_box, label_output, entry_output

    button1=Button(window, text="Print()",   command=printtoconsole)
    button2=Button(window, text="To Label",   command=printtolabel)
    button3=Button(window, text="To Entry",   command=printtoentry)
    button4=Button(window, text="To Text",   command=printtotext)

    entry_decimal = Entry(window, textvariable = decimal_var)
    label_decimal = Label(window, text = "Enter decimal")
    label_output = Label(window, text = "label to show output")
    entry_output = Entry(window, textvariable = strentryoutput_var)
    text_output = Text(window)
    text_box = Text(text_output)

    button1.place(x=10, y=50)
    button2.place(x=10, y=100)
    button3.place(x=10, y=150)
    button4.place(x=10, y=200)

    label_decimal.place(x=10, y=10) 
    entry_decimal.place(x=100, y=10)
    label_output.place(x=100, y=100)
    entry_output.place(x=100, y=150, width=50)
    text_output.place(x=100, y=200, width=50, height=30)


if __name__ == '__main__':
    main()
这段新代码使用GUI提供4个按钮,可以将表情打印到控制台、标签小部件、条目小部件或文本小部件。在Windows 10上,十进制范围为128547到128549,每个按钮上的表情符号打印都没有问题。在Ubuntu 20.04上,128547和128549的所有按钮都能正常工作。但是,对于128548,打印按钮没有输出,但不会失败。标签、条目和文本按钮导致GUI关闭,但保持控制台打开并重置,显示“===Restart:Shell====>>”。然后可以使用F5从编辑器窗口重新启动。
在Ubuntu上,条目按钮需要点击两次才能更新表情,而在Windows下,点击一次就足够了。奇怪,但可能是另一件事……

关于Issue4225 Python问题()的评论,下面给出了在终端窗口中运行的代码,作为Linux和MacOS系统的简单测试,以显示字符是否会导致问题

    $ wish
    % label .l -text 'paste an emoticon graphic here'
如果要打印字符,则输出以下内容:“.l”

对于麻烦的字符,以下错误是典型的

% X Error of failed request:  BadLength (poly request too large or internal Xlib length error)
  Major opcode of failed request:  139 (RENDER)
  Minor opcode of failed request:  20 (RenderAddGlyphs)
  Serial number of failed request:  599
  Current serial number in output stream:  599 
这也意味着字体包“fonts noto color emoji”与Ubuntu上Tk窗口的崩溃有关。当我卸载这种字体时,Ubuntu中的崩溃行为停止了——尽管有几个表情符号不再可用

进一步在互联网上搜索“RenderAddGlyphs”错误消息,发现以下相关主题的链接。 和
第二个链接的一个建议是安装“Unifonts”包。虽然这不是表情符号最详细的表示形式——也是单色的,但它确实有一个显著的好处,即在Ubuntu 20.04上运行的Tk(版本:8.6.10)不再在遇到以前麻烦的字符时崩溃。到目前为止,这已被证明是解决我最初问题的一个足够好的方法…

您可以通过在Ubuntu上安装ttf古字体symbola来修复它

sudo apt-get install -y ttf-ancient-fonts-symbola

当Windows上的3.10处于空闲状态时,
chr(128516)+''+chr(128077)
产生
“也许值得解释一下我在主代码中试图实现的目标。其目的是使用Python从手机消息系统的xml备份中提取sms消息。这涉及到使用各种tkinter小部件来提供图形输出。表情符号有时可以包含在这些消息的文本中,而不会破坏图形界面的表情符号在树或文本小部件中显示为单色表示。可以显示许多表情符号,例如以下范围内带有十进制代码的表情符号。128512-128547;  128549-128555;  128557-128576理想情况下,目标是找到解决问题的方法,即并非所有表情符号都会打印到空闲控制台或显示在tkinter小部件中,并且确实会导致程序在没有任何警告的情况下崩溃。退一步是找到一个解决方案,解决某些表情导致崩溃的问题,并在程序崩溃之前以某种方式捕获问题,同时让不会导致问题的表情正常显示。同样,我只是在运行Ubuntu20.04的PC上通过Idle运行这个Python程序时看到了这个问题。在Windows10下运行时,我没有看到这种问题。Ubuntu使用的是什么tcl/tk?查看帮助=>关于空闲。请定义“崩溃”:Shell挂起?闲置冷冻?空闲消失了?tcl/tk仅支持前2**16个码点(BMP平面)。tkinter对*nix和Windows显示其他(星体)角色的部分支持是在一年多前添加的。(他们仍然把编辑搞得一团糟。)我开始考虑mac和Ubuntu的问题。如果你有一个bpo账户,并且在这个问题上爱管闲事来回答问题,这可能会有所帮助。Ubuntu PC上显示的Tk版本是8.6.10。运行原始问题中显示的代码段时,如果输入128077、128548或128556,Idle将通过关闭控制台窗口和编辑器窗口而失败。当时我确实打开了另一个空闲编辑器,但它仍然打开。第二个编辑器窗口的出现不会改变第一个编辑器窗口失败的方式。我将看一看Python bug页面。